Real-Time Music Synthesis & Embedded Applications     
by Max I. Fomitchev and Joe Hershberger

Example 1: 

memset(pMixBuffer, 0, BUFFER_SIZE);
for ( int i = 0; i < MAX_CHANNELS; i++ )
{
    int NewLength = Sample[i].Size*BASE_FREQ/NewFreq;
    for ( int k = 0; k < NewLeingth; k++ )
        pMixBuffer[k] += Sample[i].pData[k*NewFreq/BASE_FREQ]/4;
}


Example 2:  

void Synthesize()
{
    BYTE t;
    if ( noteCounter >= controls.Beat )
    {
        // Reset note counter
        noteCounter = 0;
        // Reset time counter
        timeCounter = 0;
        // Process buttons press events
        ...
        // Read knob potentiometers
    ...
        // Generate new musical score measure
       GeneratePattern();
    }
    else
    {
        // Increase time counter
        timeCounter++;
        // Reset time counter
        if ( timeCounter >= noteDuration )
        {
            timeCounter = 0;
            noteCounter++;
        }
    }
    // Synthesize actual music
    doSynth();
}


Example 3: 

typedef struct tagSNOTE {
    unsigned short long pos;// Current sample playback position
    WORD    newFreq;        // New note frequency
    BYTE    patch;
} SNOTE;


Listing One:
void doSynth()
{
    WORD Index;
    short S;
    WORD SampSize[4];
    NOTE ActualNote;
    TNOTE* pTonalityNote;
    rom SAMPLE* pSampData[4];
    SAMPLE* pBuffer;

    // Select buffer
    if ( nBuffer )
        pBuffer = pMixBuffer2;
    else
        pBuffer = pMixBuffer1;
    // Ready to add next note the channel
    if ( !timeCounter )
    {
        // Add notes to drum channel 0
        ActualNote = pPattern[0].Notes[noteCounter];
        if ( ActualNote.key )
        {
            // Add note to channel
            pTonalityNote = &pTonality[ActualNote.key - 1];
            ActualNote.key = pTonalityNote->key;
            ActualNote.octave += pTonalityNote->octave;
            chan[0].newFreq = 0;
            chan[0].pos = 0;
            chan[0].patch = ActualNote.patch;
        }
        else
            lights[0] = 2;
        // Add notes to channel 1
        ...
        // Add notes to channel 2
        ...
        // Add notes to channel 3
        ...
    }
    k = 0;
    pSampData[0] = pRomSample[chan[0].patch].pData + chan[0].pos;
    pSampData[1] = pRomSample[chan[1].patch].pData;
    pSampData[2] = pRomSample[chan[2].patch].pData;
    pSampData[3] = pRomSample[chan[3].patch].pData;
    SampSize[0]  = pRomSample[chan[0].patch].size;
    SampSize[1]  = pRomSample[chan[1].patch].size;
    SampSize[2]  = pRomSample[chan[2].patch].size;
    SampSize[3]  = pRomSample[chan[3].patch].size;
    // Add channel samples to the buffer
    do {
        // Drum channel 0
        if ( chan[0].pos < SampSize[0] )
        {
            S = *pSampData[0];
            pSampData[0]++;
            chan[0].pos++;
        }
        else
            S = 0; // Silence
        // Synthesize channel 1
        Index = chan[1].pos>>6;
        if ( Index < SampSize[1] )
        {
            // Nearest neighbour resampling
            S += pSampData[1][Index];
            chan[1].pos += chan[1].newFreq;
        }
        // Synthesize channel 2
        Index = chan[2].pos>>6;
        if ( Index < SampSize[2] )
        {
            // Nearest neighbour resampling
            S += pSampData[2][Index];
            chan[2].pos += chan[2].newFreq;
        }
        // Synthesize channel 3
       Index = chan[3].pos>>6;
        if ( Index < SampSize[3] )
        {
            // Nearest neighbour resampling
            S += pSampData[3][Index];
            chan[3].pos += chan[3].newFreq;
        }
        // Downscale and make unsigned (higher quality mixing)
        S >>= 2;
        S += 128;
        *pBuffer = (BYTE)S;
        pBuffer++;
        k++;
    } while ( k != 0U );
}





1


