Tweak note-change detection

Values have been tuned to ensure samples aren't retriggered during
Mario's jump, but are generally retriggered in every other situation
where the frequency is changed. Retriggering more often makes the music
in games like Pictionary and Rad Gravity sound _way_ better, as well as
the sound effects in games with slower music.

* do not repeat samples for sustained notes; this never sounds great.
* reset after _any_ frequency change if we have been sitting on the
  same note for longer than a couple of frames.
* fix the "reset if the note has jumped by ~2 semitones" logic, which
  was *wildly* wrong.
This commit is contained in:
Jeremy Penner 2024-11-30 22:14:20 -05:00
parent 9ff9fe2bb8
commit 0f73094113

View file

@ -38,14 +38,22 @@ Sample.prototype = {
this.index += this.increment / clocksPerPeriod; this.index += this.increment / clocksPerPeriod;
}, },
reset: function() { this.index = 0; }, reset: function() { this.index = 0; },
freqFromTimer: function(timer) {
// timer -> frequency
// clocksPerPeriodTriangle = 8, clocksPerPeriodPulse = 4
// fTriangle = fCPU/(32*(t + 1))
// fpulse = fCPU/(16*(t+1)
return 1789773 / (4 * this.clocksPerPeriod * (timer + 1));
},
sample: function(timer, maxTimer, volume) { sample: function(timer, maxTimer, volume) {
const timerIncreasing = maxTimer - timer; const timerIncreasing = maxTimer - timer;
if (maxTimer !== this.prevMaxTimer) { if (maxTimer !== this.prevMaxTimer) {
if (this.prevMaxTimer) { if (this.prevMaxTimer) {
var ratio = this.prevMaxTimer < maxTimer ? maxTimer / this.prevMaxTimer : this.prevMaxTimer / maxTimer; var ratio = this.freqFromTimer(this.prevMaxTimer) / this.freqFromTimer(maxTimer);
var semitoneInterval = 1.059463; if (ratio < 1) { ratio = 1/ratio };
if (ratio >= semitoneInterval * 2 || this.clocksSinceMaxTimerChange > 210000 || this.index >= this.samples.length) { var significantNoteChange = 1.1;
this.index = 0; if ((this.clocksSinceMaxTimerChange > 130000) || ratio >= significantNoteChange) {
this.reset();
} }
} }
this.prevMaxTimer = maxTimer; this.prevMaxTimer = maxTimer;