byte metronomeTick(byte midiNote, byte volume) { byte i = findNoteIndex(); initNote(i, midiNote); note[i].startTime = millis(); note[i].waveform = METRONOME_WAVEFORM; note[i].waveformBuf = waveformBuffers[METRONOME_WAVEFORM]; note[i].isSample = true; note[i].sampleLength = sampleLength[METRONOME_WAVEFORM - N_WAVEFORMS]; note[i].envelopePhase = ATTACK; note[i].volIndex = volume; note[i].volume = volume; note[i].volumeNext = volume; setPhaseIncrement(i); return i; }
byte doNoteOn(byte channelNum, byte midiNote, byte velocity) { byte i = findNoteIndex(); if (velocity > MAX_VELOCITY) { velocity = MAX_VELOCITY; } initNote(i, midiNote); note[i].startTime = millis(); note[i].midiChannel = channelNum; byte waveformNum = settings[channelNum-1].waveform; note[i].waveform = waveformNum; note[i].waveformBuf = waveformBuffers[waveformNum]; if (waveformNum >= N_WAVEFORMS) { note[i].isSample = true; note[i].sampleLength = sampleLength[waveformNum - N_WAVEFORMS]; } note[i].envelopePhase = ATTACK; note[i].volIndexInc = 1; note[i].volLevelDuration = settings[channelNum-1].attackVolLevelDuration; note[i].volLevelRemaining = settings[channelNum-1].attackVolLevelDuration; note[i].targetVolIndex = map(velocity, 0, MAX_VELOCITY, 0, MAX_NOTE_VOL); if ((settings[channelNum-1].attackVolLevelDuration > 0) && (!note[i].isSample)) { note[i].volIndex = 0; note[i].targetVolIndex = inverseAttackLogVolume[logVolume[note[i].targetVolIndex]]; } else { // optimize if there is no attack. go directly to target volume note[i].volIndex = note[i].targetVolIndex; note[i].volume = logVolume[note[i].volIndex]; note[i].volumeNext = note[i].volume; } // Restart filter LFO lfoPhase[LFO_FILTER] = 0; return i; }
int lb302Synth::process(sampleFrame *outbuf, const int size) { const float sampleRatio = 44100.f / engine::mixer()->processingSampleRate(); float w; float samp; // Hold on to the current VCF, and use it throughout this period lb302Filter *filter = vcf; if( release_frame == 0 || ! m_playingNote ) { vca_mode = 1; } if( new_freq ) { //printf(" playing new note..\n"); lb302Note note; note.vco_inc = GET_INC( true_freq ); note.dead = deadToggle.value(); initNote(¬e); new_freq = false; } // TODO: NORMAL RELEASE // vca_mode = 1; for( int i=0; i<size; i++ ) { // start decay if we're past release if( i >= release_frame ) { vca_mode = 1; } // update vcf if(vcf_envpos >= ENVINC) { filter->envRecalc(); vcf_envpos = 0; if (vco_slide) { vco_inc = vco_slidebase - vco_slide; // Calculate coeff from dec_knob on knob change. vco_slide -= vco_slide * ( 0.1f - slide_dec_knob.value() * 0.0999f ) * sampleRatio; // TODO: Adjust for ENVINC } } sample_cnt++; vcf_envpos++; //int decay_frames = 128; // update vco vco_c += vco_inc; if(vco_c > 0.5) vco_c -= 1.0; switch(int(rint(wave_shape.value()))) { case 0: vco_shape = SAWTOOTH; break; case 1: vco_shape = TRIANGLE; break; case 2: vco_shape = SQUARE; break; case 3: vco_shape = ROUND_SQUARE; break; case 4: vco_shape = MOOG; break; case 5: vco_shape = SINE; break; case 6: vco_shape = EXPONENTIAL; break; case 7: vco_shape = WHITE_NOISE; break; case 8: vco_shape = BL_SAWTOOTH; break; case 9: vco_shape = BL_SQUARE; break; case 10: vco_shape = BL_TRIANGLE; break; case 11: vco_shape = BL_MOOG; break; default: vco_shape = SAWTOOTH; break; } // add vco_shape_param the changes the shape of each curve. // merge sawtooths with triangle and square with round square? switch (vco_shape) { case SAWTOOTH: // p0: curviness of line vco_k = vco_c; // Is this sawtooth backwards? break; case TRIANGLE: // p0: duty rev.saw<->triangle<->saw p1: curviness vco_k = (vco_c*2.0)+0.5; if (vco_k>0.5) vco_k = 1.0- vco_k; break; case SQUARE: // p0: slope of top vco_k = (vco_c<0)?0.5:-0.5; break; case ROUND_SQUARE: // p0: width of round vco_k = (vco_c<0)?(sqrtf(1-(vco_c*vco_c*4))-0.5):-0.5; break; case MOOG: // Maybe the fall should be exponential/sinsoidal instead of quadric. // [-0.5, 0]: Rise, [0,0.25]: Slope down, [0.25,0.5]: Low vco_k = (vco_c*2.0)+0.5; if (vco_k>1.0) { vco_k = -0.5 ; } else if (vco_k>0.5) { w = 2.0*(vco_k-0.5)-1.0; vco_k = 0.5 - sqrtf(1.0-(w*w)); } vco_k *= 2.0; // MOOG wave gets filtered away break; case SINE: // [-0.5, 0.5] : [-pi, pi] vco_k = 0.5f * Oscillator::sinSample( vco_c ); break; case EXPONENTIAL: vco_k = 0.5 * Oscillator::expSample( vco_c ); break; case WHITE_NOISE: vco_k = 0.5 * Oscillator::noiseSample( vco_c ); break; case BL_SAWTOOTH: vco_k = BandLimitedWave::oscillate( vco_c + 0.5f, BandLimitedWave::pdToLen( vco_inc ), BandLimitedWave::BLSaw ) * 0.5f; break; case BL_SQUARE: vco_k = BandLimitedWave::oscillate( vco_c + 0.5f, BandLimitedWave::pdToLen( vco_inc ), BandLimitedWave::BLSquare ) * 0.5f; break; case BL_TRIANGLE: vco_k = BandLimitedWave::oscillate( vco_c + 0.5f, BandLimitedWave::pdToLen( vco_inc ), BandLimitedWave::BLTriangle ) * 0.5f; break; case BL_MOOG: vco_k = BandLimitedWave::oscillate( vco_c + 0.5f, BandLimitedWave::pdToLen( vco_inc ), BandLimitedWave::BLMoog ); break; } //vca_a = 0.5; // Write out samples. #ifdef LB_FILTERED //samp = vcf->process(vco_k)*2.0*vca_a; //samp = vcf->process(vco_k)*2.0; samp = filter->process(vco_k) * vca_a; //printf("%f %d\n", vco_c, sample_cnt); //samp = vco_k * vca_a; if( sample_cnt <= 4 ) { // vca_a = 0; } #else //samp = vco_k*vca_a; #endif /* float releaseFrames = desiredReleaseFrames(); samp *= (releaseFrames - catch_decay)/releaseFrames; */ //LB302 samp *= (float)(decay_frames - catch_decay)/(float)decay_frames; for( int c = 0; c < DEFAULT_CHANNELS; c++ ) { outbuf[i][c] = samp; } // Handle Envelope if(vca_mode==0) { vca_a+=(vca_a0-vca_a)*vca_attack; if(sample_cnt>=0.5*engine::mixer()->processingSampleRate()) vca_mode = 2; } else if(vca_mode == 1) { vca_a *= vca_decay; // the following line actually speeds up processing if(vca_a < (1/65536.0)) { vca_a = 0; vca_mode = 3; } } } return 1; }
int lb302Synth::process(sampleFrame *outbuf, const Uint32 size) { unsigned int i; float w; float samp; if( delete_freq == current_freq ) { // Normal release delete_freq = -1; vca_mode = 1; } if( new_freq > 0.0f ) { //printf(" playing new note..\n"); lb302Note note; note.vco_inc = GET_INC( true_freq ); //printf("GET_INC %f %f %d\n", note.vco_inc, new_freq, vca_mode ); ///**vco_detune*//engine::getMixer()->processingSampleRate(); // TODO: Use actual sampling rate. //printf("VCO_INC = %f\n", note.vco_inc); note.dead = deadToggle.value(); initNote(¬e); //printf("%f %f, ", vco_inc, vco_c); current_freq = new_freq; new_freq = -1.0f; //printf("GOT_INC %f %f %d\n\n", note.vco_inc, new_freq, vca_mode ); } // TODO: NORMAL RELEASE // vca_mode = 1; for(i=0;i<size;i++) { // update vcf if(vcf_envpos >= ENVINC) { vcf->envRecalc(); vcf_envpos = 0; if (vco_slide) { vco_inc=vco_slidebase-vco_slide; // Calculate coeff from dec_knob on knob change. vco_slide*= 0.9+(slide_dec_knob.value()*0.0999); // TODO: Adjust for Hz and ENVINC } } sample_cnt++; vcf_envpos++; //int decay_frames = 128; // update vco vco_c += vco_inc; if(vco_c > 0.5) vco_c -= 1.0; /*LB303 if (catch_decay > 0) { if (catch_decay < decay_frames) { catch_decay++; } }*/ switch(int(rint(wave_shape.value()))) { case 0: vco_shape = SAWTOOTH; break; case 1: vco_shape = TRIANGLE; break; case 2: vco_shape = SQUARE; break; case 3: vco_shape = ROUND_SQUARE; break; case 4: vco_shape = MOOG; break; case 5: vco_shape = SINE; break; case 6: vco_shape = EXPONENTIAL; break; case 7: vco_shape = WHITE_NOISE; break; default: vco_shape = SAWTOOTH; break; } // add vco_shape_param the changes the shape of each curve. // merge sawtooths with triangle and square with round square? switch (vco_shape) { case SAWTOOTH: // p0: curviness of line vco_k = vco_c; // Is this sawtooth backwards? break; case TRIANGLE: // p0: duty rev.saw<->triangle<->saw p1: curviness vco_k = (vco_c*2.0)+0.5; if (vco_k>0.5) vco_k = 1.0- vco_k; break; case SQUARE: // p0: slope of top vco_k = (vco_c<0)?0.5:-0.5; break; case ROUND_SQUARE: // p0: width of round vco_k = (vco_c<0)?(sqrtf(1-(vco_c*vco_c*4))-0.5):-0.5; break; case MOOG: // Maybe the fall should be exponential/sinsoidal instead of quadric. // [-0.5, 0]: Rise, [0,0.25]: Slope down, [0.25,0.5]: Low vco_k = (vco_c*2.0)+0.5; if (vco_k>1.0) { vco_k = -0.5 ; } else if (vco_k>0.5) { w = 2.0*(vco_k-0.5)-1.0; vco_k = 0.5 - sqrtf(1.0-(w*w)); } vco_k *= 2.0; // MOOG wave gets filtered away break; case SINE: // [-0.5, 0.5] : [-pi, pi] vco_k = 0.5f * Oscillator::sinSample( vco_c ); break; case EXPONENTIAL: vco_k = 0.5 * Oscillator::expSample( vco_c ); break; case WHITE_NOISE: vco_k = 0.5 * Oscillator::noiseSample( vco_c ); break; } //vca_a = 0.5; // Write out samples. #ifdef LB_FILTERED //samp = vcf->process(vco_k)*2.0*vca_a; //samp = vcf->process(vco_k)*2.0; samp = vcf->process(vco_k) * vca_a; //printf("%f %d\n", vco_c, sample_cnt); //samp = vco_k * vca_a; if( sample_cnt <= 4 ) { // vca_a = 0; } #else //samp = vco_k*vca_a; #endif /* float releaseFrames = desiredReleaseFrames(); samp *= (releaseFrames - catch_decay)/releaseFrames; */ //LB302 samp *= (float)(decay_frames - catch_decay)/(float)decay_frames; for(int c=0; c<DEFAULT_CHANNELS; c++) { outbuf[i][c]=samp; } /*LB303 if((int)i>=release_frame) { vca_mode=1; } */ // Handle Envelope if(vca_mode==0) { vca_a+=(vca_a0-vca_a)*vca_attack; if(sample_cnt>=0.5*engine::getMixer()->processingSampleRate()) vca_mode = 2; } else if(vca_mode == 1) { vca_a *= vca_decay; // the following line actually speeds up processing if(vca_a < (1/65536.0)) { vca_a = 0; vca_mode = 3; } } } return 1; }