in libs/mixer/melody.cpp [224:345]
int WSynthesizer::fillSamples(int16_t *dst, int numsamples) {
if (numsamples <= 0)
return 1;
int timeLeft = updateQueues();
int res = waiting != NULL;
// if there's a pending sound to be started somewhere during numsamples,
// split the call into two
if (timeLeft < numsamples) {
fillSamples(dst, timeLeft);
LOG("M split %d", timeLeft);
fillSamples(dst + timeLeft, numsamples - timeLeft);
return 1;
}
memset(dst, 0, numsamples * 2);
uint32_t samplesPerMS = (sampleRate << 8) / 1000;
float toneStepMult = (1024.0 * (1 << 16)) / sampleRate;
const int MAXVAL = (1 << (OUTPUT_BITS - 1)) - 1;
for (unsigned i = 0; i < MAX_SOUNDS; ++i) {
PlayingSound *snd = &playingSounds[i];
if (snd->sound == NULL)
continue;
res = 1;
SoundInstruction *instr = NULL;
gentone_t fn = NULL;
snd->currInstr--;
uint32_t toneStep = 0;
int32_t toneDelta = 0;
int32_t volumeStep = 0;
uint32_t tonePosition = snd->tonePosition;
uint32_t samplesLeft = 0;
uint8_t wave = 0;
int32_t volume = 0;
for (int j = 0; j < numsamples; ++j) {
if (samplesLeft == 0) {
snd->currInstr++;
if (snd->currInstr >= snd->instrEnd) {
break;
}
SoundInstruction copy = *snd->currInstr;
instr = ©
CLAMP(20, instr->frequency, 20000);
CLAMP(20, instr->endFrequency, 20000);
CLAMP(0, instr->startVolume, 1023);
CLAMP(0, instr->endVolume, 1023);
CLAMP(1, instr->duration, 60000);
wave = instr->soundWave;
fn = getWaveFn(wave);
samplesLeft = (uint32_t)(instr->duration * samplesPerMS >> 8);
// make sure the division is signed
volumeStep =
(int)((instr->endVolume - instr->startVolume) << 16) / (int)samplesLeft;
if (j == 0 && snd->prevVolume != -1) {
// restore previous state
samplesLeft = snd->samplesLeftInCurr;
volume = snd->prevVolume;
toneStep = snd->prevToneStep;
toneDelta = snd->prevToneDelta;
} else {
LOG("#sampl %d %p", samplesLeft, snd->currInstr);
volume = instr->startVolume << 16;
LOG("%d-%dHz %d-%d vol", instr->frequency, instr->endFrequency,
instr->startVolume, instr->endVolume);
toneStep = (uint32_t)(toneStepMult * instr->frequency);
if (instr->frequency != instr->endFrequency) {
uint32_t endToneStep = (uint32_t)(toneStepMult * instr->endFrequency);
toneDelta = (int32_t)(endToneStep - toneStep) / (int32_t)samplesLeft;
} else {
toneDelta = 0;
}
}
}
int v = fn(snd, (tonePosition >> 16) & 1023, tonePosition >> 26);
v = (v * (volume >> 16)) >> (10 + (16 - OUTPUT_BITS));
// if (v > MAXVAL)
// target_panic(123);
dst[j] += v;
tonePosition += toneStep;
toneStep += toneDelta;
volume += volumeStep;
samplesLeft--;
}
if (snd->currInstr >= snd->instrEnd) {
snd->sound->state = SoundState::Done;
snd->sound = NULL;
} else {
snd->tonePosition = tonePosition;
if (samplesLeft == 0)
samplesLeft++; // avoid infinite loop in next iteration
snd->samplesLeftInCurr = samplesLeft;
snd->prevVolume = volume;
snd->prevToneDelta = toneDelta;
snd->prevToneStep = toneStep;
}
}
currSample += numsamples;
for (int j = 0; j < numsamples; ++j) {
if (dst[j] > MAXVAL)
dst[j] = MAXVAL;
else if (dst[j] < -MAXVAL)
dst[j] = -MAXVAL;
}
return res;
}