main/alles.c
void fill_audio_buffer(float seconds) {
    // if seconds < 0, just do this once, but otherwise, compute iterations
    uint16_t iterations = 1;
    if(seconds > 0) {
        iterations = ((seconds * SAMPLE_RATE) / BLOCK_SIZE)+1;
    }
    for(uint16_t iter=0;iter<iterations;iter++) {
        // Check to see which sounds to play 
        int64_t sysclock = esp_timer_get_time() / 1000;
        
        // We could save some CPU by starting at a read pointer, depends on how big this gets
        for(uint16_t i=0;i<EVENT_FIFO_LEN;i++) {
            if(events[i].status == SCHEDULED) {
                // By now event.time is corrected to our sysclock (from the host)
                if(sysclock >= events[i].time) {
                    play_event(events[i]);
                    events[i].status = PLAYED;
                }
            }
        }

        // Clear out the accumulator buffer
        for(uint16_t i=0;i<BLOCK_SIZE;i++) floatblock[i] = 0;

        // Save the current global synth state to the modifiers         
        mglobal.resonance = global.resonance;
        mglobal.filter_freq = global.filter_freq;

        for(uint8_t voice=0;voice<VOICES;voice++) {
            if(synth[voice].status==AUDIBLE) { // skip voices that are silent or LFO sources from playback
                hold_and_modify(voice); // apply ADSR / LFO
                if(synth[voice].wave == FM) render_fm(floatblock, voice);
                if(synth[voice].wave == NOISE) render_noise(floatblock, voice);
                if(synth[voice].wave == SAW) render_saw(floatblock, voice);
                if(synth[voice].wave == PULSE) render_pulse(floatblock, voice);
                if(synth[voice].wave == TRIANGLE) render_triangle(floatblock, voice);
                if(synth[voice].wave == SINE) render_sine(floatblock, voice);
                if(synth[voice].wave == KS) render_ks(floatblock, voice);
                if(synth[voice].wave == PCM) render_pcm(floatblock, voice);
            }
        }

        // Bandlimit the buffer all at once
        blip_the_buffer(floatblock, block, BLOCK_SIZE);

        // If filtering is on, filter the mixed signal
        if(mglobal.filter_freq > 0) {
            filter_update();
            filter_process_ints(block);
        }

#if (DANDAC)
        // "block" until the dac is done writing the current buffer
        while(dac_counter < BLOCK_SIZE) {
            ets_delay_us(200); 
        }
        dac_counter = 0;
#else
        // And write to I2S
        size_t written = 0;
        i2s_write((i2s_port_t)CONFIG_I2S_NUM, block, BLOCK_SIZE * 2, &written, portMAX_DELAY);
        if(written != BLOCK_SIZE*2) {
            printf("i2s underrun: %d vs %d\n", written, BLOCK_SIZE*2);
        }
#endif
    }
}
// This takes scheduled events and plays them at the right time
This takes scheduled events and plays them at the right time
This takes scheduled events and plays them at the right time
void fill_audio_buffer(float seconds) {
    uint16_t iterations = 1;
    if(seconds > 0) {
        iterations = ((seconds * SAMPLE_RATE) / BLOCK_SIZE)+1;
    }
    for(uint16_t iter=0;iter<iterations;iter++) {
        int64_t sysclock = esp_timer_get_time() / 1000;
        for(uint16_t i=0;i<EVENT_FIFO_LEN;i++) {
            if(events[i].status == SCHEDULED) {
                if(sysclock >= events[i].time) {
                    play_event(events[i]);
                    events[i].status = PLAYED;
                }
            }
        }
        for(uint16_t i=0;i<BLOCK_SIZE;i++) floatblock[i] = 0;
        mglobal.resonance = global.resonance;
        mglobal.filter_freq = global.filter_freq;
        for(uint8_t voice=0;voice<VOICES;voice++) {
            if(synth[voice].status==AUDIBLE) { 
                hold_and_modify(voice); 
                if(synth[voice].wave == FM) render_fm(floatblock, voice);
                if(synth[voice].wave == NOISE) render_noise(floatblock, voice);
                if(synth[voice].wave == SAW) render_saw(floatblock, voice);
                if(synth[voice].wave == PULSE) render_pulse(floatblock, voice);
                if(synth[voice].wave == TRIANGLE) render_triangle(floatblock, voice);
                if(synth[voice].wave == SINE) render_sine(floatblock, voice);
                if(synth[voice].wave == KS) render_ks(floatblock, voice);
                if(synth[voice].wave == PCM) render_pcm(floatblock, voice);
            }
        }
        blip_the_buffer(floatblock, block, BLOCK_SIZE);
        if(mglobal.filter_freq > 0) {
            filter_update();
            filter_process_ints(block);
        }
#if (DANDAC)
        while(dac_counter < BLOCK_SIZE) {
            ets_delay_us(200); 
        }
        dac_counter = 0;
#else
        size_t written = 0;
        i2s_write((i2s_port_t)CONFIG_I2S_NUM, block, BLOCK_SIZE * 2, &written, portMAX_DELAY);
        if(written != BLOCK_SIZE*2) {
            printf("i2s underrun: %d vs %d\n", written, BLOCK_SIZE*2);
        }
#endif
    }
}
void fill_audio_buffer ( float seconds ) { uint16_t iterations = 1 ; if ( seconds > 0 ) { iterations = ( ( seconds * SAMPLE_RATE ) / BLOCK_SIZE ) + 1 ; } for ( uint16_t iter = 0 ; iter < iterations ; iter ++ ) { int64_t sysclock = esp_timer_get_time ( ) / 1000 ; for ( uint16_t i = 0 ; i < EVENT_FIFO_LEN ; i ++ ) { if ( events [ i ] . status == SCHEDULED ) { if ( sysclock >= events [ i ] . time ) { play_event ( events [ i ] ) ; events [ i ] . status = PLAYED ; } } } for ( uint16_t i = 0 ; i < BLOCK_SIZE ; i ++ ) floatblock [ i ] = 0 ; mglobal . resonance = global . resonance ; mglobal . filter_freq = global . filter_freq ; for ( uint8_t voice = 0 ; voice < VOICES ; voice ++ ) { if ( synth [ voice ] . status == AUDIBLE ) { hold_and_modify ( voice ) ; if ( synth [ voice ] . wave == FM ) render_fm ( floatblock , voice ) ; if ( synth [ voice ] . wave == NOISE ) render_noise ( floatblock , voice ) ; if ( synth [ voice ] . wave == SAW ) render_saw ( floatblock , voice ) ; if ( synth [ voice ] . wave == PULSE ) render_pulse ( floatblock , voice ) ; if ( synth [ voice ] . wave == TRIANGLE ) render_triangle ( floatblock , voice ) ; if ( synth [ voice ] . wave == SINE ) render_sine ( floatblock , voice ) ; if ( synth [ voice ] . wave == KS ) render_ks ( floatblock , voice ) ; if ( synth [ voice ] . wave == PCM ) render_pcm ( floatblock , voice ) ; } } blip_the_buffer ( floatblock , block , BLOCK_SIZE ) ; if ( mglobal . filter_freq > 0 ) { filter_update ( ) ; filter_process_ints ( block ) ; } #if ( DANDAC ) while ( dac_counter < BLOCK_SIZE ) { ets_delay_us ( 200 ) ; } dac_counter = 0 ; #else size_t written = 0 ; i2s_write ( ( i2s_port_t ) CONFIG_I2S_NUM , block , BLOCK_SIZE * 2 , & written , portMAX_DELAY ) ; if ( written != BLOCK_SIZE * 2 ) { printf ( " \n " , written , BLOCK_SIZE * 2 ) ; } #endif } }
This takes scheduled events and plays them at the right time
This takes scheduled events and plays them at the right time
// if seconds < 0, just do this once, but otherwise, compute iterations // Check to see which sounds to play  // We could save some CPU by starting at a read pointer, depends on how big this gets // By now event.time is corrected to our sysclock (from the host) // Clear out the accumulator buffer // Save the current global synth state to the modifiers          // skip voices that are silent or LFO sources from playback // apply ADSR / LFO // Bandlimit the buffer all at once // If filtering is on, filter the mixed signal // "block" until the dac is done writing the current buffer // And write to I2S