int WSynthesizer::fillSamples()

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 = &copy;
                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;
}