Channel state, synth_process stub

This commit is contained in:
coreydunn 2023-07-27 10:04:44 -05:00
parent 79efcf3bbe
commit 93e305f311
4 changed files with 82 additions and 58 deletions

6
main.c
View File

@ -158,14 +158,14 @@ int play_stream(const void*input,void*output,
{ {
size_t n=MIN(synth->playback_pos+count,SY_BUFFERSIZE); size_t n=MIN(synth->playback_pos+count,SY_BUFFERSIZE);
size_t m=n-synth->playback_pos; size_t m=n-synth->playback_pos;
/* memcpy(out,&synth->channel[synth->current_channel].buffer[synth->playback_pos],m*sizeof(float)); */ /* memcpy(out,&synth->channel[synth->current_channel].buffer[0][synth->playback_pos],m*sizeof(float)); */
// Mix all channels // Mix all channels
for(size_t i=0;i<m;++i) for(size_t i=0;i<m;++i)
{ {
out[i]=synth->channel[0].buffer[synth->playback_pos+i]; out[i]=synth->channel[0].buffer[0][synth->playback_pos+i];
for(size_t j=1;j<synth->nchannels;++j) for(size_t j=1;j<synth->nchannels;++j)
out[i]+=synth->channel[j].buffer[synth->playback_pos+i]; out[i]+=synth->channel[j].buffer[0][synth->playback_pos+i];
out[i]/=synth->nchannels; out[i]/=synth->nchannels;
} }
synth->playback_pos=MIN(synth->playback_pos+count,SY_BUFFERSIZE); synth->playback_pos=MIN(synth->playback_pos+count,SY_BUFFERSIZE);

89
synth.c
View File

@ -10,18 +10,39 @@
#define M_PI 3.14159 #define M_PI 3.14159
#endif #endif
// Process channel buffer
void synth_process(Synth*synth)
{
memset(synth->channel[synth->current_channel].buffer[0],0,SY_BUFFERSIZE*4);
}
void synth_create_channel(Synth*synth)
{
memset(synth->channel[0].buffer[0],0,SY_BUFFERSIZE*sizeof(float));
memset(synth->channel[1].buffer[1],0,SY_BUFFERSIZE*sizeof(float));
synth->channel[synth->current_channel].freq=synth->knobs[K_FREQ].value;
synth->channel[synth->current_channel].on=true;
synth->channel[synth->current_channel].aenv_time=0;
synth->channel[synth->current_channel].offset=0;
synth->channel[synth->current_channel].playback_buffer=0;
}
/* void synth_next_buffer(Synth*synth) */
/* { */
/* } */
void synth_recalc(Synth*synth) void synth_recalc(Synth*synth)
{ {
memset(synth->channel[synth->current_channel].buffer,0,SY_BUFFERSIZE*4);
float lp=synth->knobs[K_LP].value;
float hp=synth->knobs[K_HP].value;
float lfo1_buffer[SY_BUFFERSIZE]={0}; float lfo1_buffer[SY_BUFFERSIZE]={0};
float lfo2_buffer[SY_BUFFERSIZE]={0}; float lfo2_buffer[SY_BUFFERSIZE]={0};
uint32_t oscillator_vol[]={K_OSC1_VOL,K_OSC2_VOL,K_OSC3_VOL,K_OSC4_VOL}; const uint32_t oscillator_vol[]={K_OSC1_VOL,K_OSC2_VOL,K_OSC3_VOL,K_OSC4_VOL};
uint32_t oscillator_wavef[]={K_OSC1_WAVEF,K_OSC2_WAVEF,K_OSC3_WAVEF,K_OSC4_WAVEF}; const uint32_t oscillator_wavef[]={K_OSC1_WAVEF,K_OSC2_WAVEF,K_OSC3_WAVEF,K_OSC4_WAVEF};
uint32_t oscillator_duty[]={K_OSC1_PHASE,K_OSC2_PHASE,K_OSC3_PHASE,K_OSC4_PHASE}; const uint32_t oscillator_duty[]={K_OSC1_PHASE,K_OSC2_PHASE,K_OSC3_PHASE,K_OSC4_PHASE};
uint32_t oscillator_det[]={K_OSC1_DET,K_OSC2_DET,K_OSC3_DET,K_OSC4_DET}; const uint32_t oscillator_det[]={K_OSC1_DET,K_OSC2_DET,K_OSC3_DET,K_OSC4_DET};
// Clear buffer
memset(synth->channel[synth->current_channel].buffer[0],0,SY_BUFFERSIZE*4);
// Calculate lfo1 (master amp) // Calculate lfo1 (master amp)
if(synth->knobs[K_LFO1_VOL].value>0&& if(synth->knobs[K_LFO1_VOL].value>0&&
@ -171,7 +192,7 @@ void synth_recalc(Synth*synth)
float duty=synth->knobs[oscillator_duty[cur_osc]].value; float duty=synth->knobs[oscillator_duty[cur_osc]].value;
bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0; bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0;
if(fr==0.0)break; if(fr==0.0)break;
gen_sin(synth->channel[synth->current_channel].buffer,amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,0); gen_sin(synth->channel[synth->current_channel].buffer[0],amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,0);
} }
// Triangle // Triangle
@ -184,7 +205,7 @@ void synth_recalc(Synth*synth)
float duty=synth->knobs[oscillator_duty[cur_osc]].value; float duty=synth->knobs[oscillator_duty[cur_osc]].value;
bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0; bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0;
if(fr==0.0)break; if(fr==0.0)break;
gen_tri(synth->channel[synth->current_channel].buffer,amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,0); gen_tri(synth->channel[synth->current_channel].buffer[0],amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,0);
} }
// Sawtooth // Sawtooth
@ -197,7 +218,7 @@ void synth_recalc(Synth*synth)
float duty=synth->knobs[oscillator_duty[cur_osc]].value; float duty=synth->knobs[oscillator_duty[cur_osc]].value;
bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0; bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0;
if(fr==0.0)break; if(fr==0.0)break;
gen_saw(synth->channel[synth->current_channel].buffer,amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,0); gen_saw(synth->channel[synth->current_channel].buffer[0],amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,0);
} }
// Pulse // Pulse
@ -214,7 +235,7 @@ void synth_recalc(Synth*synth)
synth->knobs[K_LFO2_FREQ].value>0) synth->knobs[K_LFO2_FREQ].value>0)
duty_buf=lfo2_buffer; duty_buf=lfo2_buffer;
if(fr==0.0)break; if(fr==0.0)break;
gen_pul(synth->channel[synth->current_channel].buffer,amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,duty_buf,0); gen_pul(synth->channel[synth->current_channel].buffer[0],amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,duty,duty_buf,0);
} }
// Noise // Noise
@ -225,7 +246,7 @@ void synth_recalc(Synth*synth)
float fr=(synth->knobs[K_FREQ].value/synth->knobs[K_FREQ].maxval)*MAXFREQ; float fr=(synth->knobs[K_FREQ].value/synth->knobs[K_FREQ].maxval)*MAXFREQ;
fr+=SEMITONE(fr,synth->knobs[K_DET].value); fr+=SEMITONE(fr,synth->knobs[K_DET].value);
if(fr==0.0)break; if(fr==0.0)break;
gen_nse(synth->channel[synth->current_channel].buffer,amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,0); gen_nse(synth->channel[synth->current_channel].buffer[0],amp,fr,mix,SY_BUFFERSIZE,synth->samplerate,0);
} }
} }
@ -241,13 +262,13 @@ void synth_recalc(Synth*synth)
amp+=lfo1_buffer[i%SY_BUFFERSIZE]; amp+=lfo1_buffer[i%SY_BUFFERSIZE];
amp/=2.0; amp/=2.0;
} }
synth->channel[synth->current_channel].buffer[i]*=amp; synth->channel[synth->current_channel].buffer[0][i]*=amp;
} }
// Convolution low-pass filter // Convolution low-pass filter
if(synth->knobs[K_AMP].value!=0) if(synth->knobs[K_AMP].value!=0)
{ {
if((size_t)lp>0) if((size_t)synth->knobs[K_LP].value>0)
{ {
size_t attacklen=synth->knobs[K_FENV_ATK].value*SY_BUFFERSIZE; size_t attacklen=synth->knobs[K_FENV_ATK].value*SY_BUFFERSIZE;
@ -256,21 +277,21 @@ void synth_recalc(Synth*synth)
float mult=((float)i)/attacklen; float mult=((float)i)/attacklen;
float sum=0; float sum=0;
for(int32_t j=MAX(1,i-lp);j<=i;++j) for(int32_t j=MAX(1,i-synth->knobs[K_LP].value);j<=i;++j)
sum+=synth->channel[synth->current_channel].buffer[j]; sum+=synth->channel[synth->current_channel].buffer[0][j];
// Weight for filter wet/dry // Weight for filter wet/dry
{ {
float f_val=sum/(lp+1); float f_val=sum/(synth->knobs[K_LP].value+1);
float o_val=synth->channel[synth->current_channel].buffer[i]; float o_val=synth->channel[synth->current_channel].buffer[0][i];
float o_mult=MAX(0,1.0-mult); float o_mult=MAX(0,1.0-mult);
if(mult==0) if(mult==0)
synth->channel[synth->current_channel].buffer[i]=o_val; synth->channel[synth->current_channel].buffer[0][i]=o_val;
else if(mult==1||o_mult==0) else if(mult==1||o_mult==0)
synth->channel[synth->current_channel].buffer[i]=f_val; synth->channel[synth->current_channel].buffer[0][i]=f_val;
else else
synth->channel[synth->current_channel].buffer[i]=f_val*mult+o_val*MAX(0,1.0-mult); synth->channel[synth->current_channel].buffer[0][i]=f_val*mult+o_val*MAX(0,1.0-mult);
} }
} }
@ -280,15 +301,15 @@ void synth_recalc(Synth*synth)
// High-pass filter // High-pass filter
if(synth->knobs[K_AMP].value!=0) if(synth->knobs[K_AMP].value!=0)
{ {
if((size_t)hp>0) if((size_t)synth->knobs[K_HP].value>0)
{ {
for(int32_t i=1;i<SY_BUFFERSIZE;++i) for(int32_t i=1;i<SY_BUFFERSIZE;++i)
{ {
float sum=0; float sum=0;
for(int32_t j=MAX(1,i-hp);j<=i;++j) for(int32_t j=MAX(1,i-synth->knobs[K_HP].value);j<=i;++j)
sum+=synth->channel[synth->current_channel].buffer[j]; sum+=synth->channel[synth->current_channel].buffer[0][j];
synth->channel[synth->current_channel].buffer[i]-=sum/(hp+1); synth->channel[synth->current_channel].buffer[0][i]-=sum/(synth->knobs[K_HP].value+1);
} }
} }
@ -300,7 +321,7 @@ void synth_recalc(Synth*synth)
for(size_t i=0;i<attacklen;++i) for(size_t i=0;i<attacklen;++i)
{ {
float mult=((float)i)/attacklen; float mult=((float)i)/attacklen;
synth->channel[synth->current_channel].buffer[i]*=mult; synth->channel[synth->current_channel].buffer[0][i]*=mult;
} }
} }
@ -310,7 +331,7 @@ void synth_recalc(Synth*synth)
for(size_t i=SY_BUFFERSIZE-releaselen;i<SY_BUFFERSIZE;++i) for(size_t i=SY_BUFFERSIZE-releaselen;i<SY_BUFFERSIZE;++i)
{ {
float mult=((float)SY_BUFFERSIZE-i)/releaselen; float mult=((float)SY_BUFFERSIZE-i)/releaselen;
synth->channel[synth->current_channel].buffer[i]*=mult; synth->channel[synth->current_channel].buffer[0][i]*=mult;
} }
} }
@ -319,10 +340,10 @@ void synth_recalc(Synth*synth)
{ {
for(size_t i=0;i<SY_BUFFERSIZE;++i) for(size_t i=0;i<SY_BUFFERSIZE;++i)
{ {
if(synth->channel[synth->current_channel].buffer[i]>synth->knobs[K_LIM].value) if(synth->channel[synth->current_channel].buffer[0][i]>synth->knobs[K_LIM].value)
synth->channel[synth->current_channel].buffer[i]=synth->knobs[K_LIM].value; synth->channel[synth->current_channel].buffer[0][i]=synth->knobs[K_LIM].value;
else if(synth->channel[synth->current_channel].buffer[i]<-synth->knobs[K_LIM].value) else if(synth->channel[synth->current_channel].buffer[0][i]<-synth->knobs[K_LIM].value)
synth->channel[synth->current_channel].buffer[i]=-synth->knobs[K_LIM].value; synth->channel[synth->current_channel].buffer[0][i]=-synth->knobs[K_LIM].value;
} }
} }
@ -332,7 +353,7 @@ void synth_recalc(Synth*synth)
for(size_t i=SY_BUFFERSIZE+1;i<SY_BUFFERSIZE;++i) for(size_t i=SY_BUFFERSIZE+1;i<SY_BUFFERSIZE;++i)
{ {
float mult=((float)SY_BUFFERSIZE-i)/releaselen; float mult=((float)SY_BUFFERSIZE-i)/releaselen;
synth->channel[synth->current_channel].buffer[i]*=mult; synth->channel[synth->current_channel].buffer[0][i]*=mult;
} }
} }
@ -343,10 +364,8 @@ void synth_recalc(Synth*synth)
void synth_new(Synth*s) void synth_new(Synth*s)
{ {
if(!s)return; if(!s)return;
/* memset(s->channel[s->current_channel].buffer,0,SY_BUFFERSIZE*(s->bitrate/8)); */
/* memset(&s->wave,0,sizeof(WAVE)); */
/* memset(&s->knobs,0,sizeof(Knob)*SY_NKNOBS); */
memset(s,0,sizeof(Synth));
s->octave=3; s->octave=3;
s->play_waveform=false; s->play_waveform=false;
s->recalculate_waveform=true; s->recalculate_waveform=true;

16
synth.h
View File

@ -23,7 +23,13 @@
typedef struct Channel typedef struct Channel
{ {
float buffer[SY_BUFFERSIZE]; bool on; // Currently playing?
float aenv_time; // Time in aenv_lvl
float buffer[2][SY_BUFFERSIZE]; // Double-buffers
float freq; // Frequency
size_t aenv_lvl; // 0:A, 1:D, 2:S, 3:R
size_t offset; // Offset for oscillators
size_t playback_buffer; // Rendered buffer
} Channel; } Channel;
typedef struct Synth typedef struct Synth
@ -34,11 +40,7 @@ typedef struct Synth
bool cleared; // Buffer was cleared bool cleared; // Buffer was cleared
bool play_waveform; // Are we currently rendering? bool play_waveform; // Are we currently rendering?
bool recalculate_waveform; // When to regenerate bool recalculate_waveform; // When to regenerate
float amp; // Amplitude
float freq; // Frequency in Hertz
float octave; // Octave for keyboard float octave; // Octave for keyboard
size_t bitrate; // Bits per sample
size_t bufsize; // Size of buffer
size_t current_channel; // Which channel to render to size_t current_channel; // Which channel to render to
size_t nchannels; size_t nchannels;
size_t playback_pos; // Current position in playback size_t playback_pos; // Current position in playback
@ -51,8 +53,10 @@ typedef struct Note
float freq; float freq;
} Note; } Note;
void synth_recalc(Synth*synth); void synth_create_channel(Synth*synth);
void synth_new(Synth*s); void synth_new(Synth*s);
void synth_process(Synth*synth);
void synth_recalc(Synth*synth);
size_t gen_sin( size_t gen_sin(
float*buffer, float*buffer,

29
ui.c
View File

@ -92,6 +92,7 @@ void ui_update(Ui*ui)
ui->synth->recalculate_waveform=true;\ ui->synth->recalculate_waveform=true;\
ui->synth->play_waveform=true;\ ui->synth->play_waveform=true;\
ui->synth->playback_pos=0;\ ui->synth->playback_pos=0;\
synth_create_channel(ui->synth);\
}while(0) }while(0)
#define oct(x) ((x)*(float)(pow(2,((int32_t)ui->synth->knobs[K_OCT].value-4)))) #define oct(x) ((x)*(float)(pow(2,((int32_t)ui->synth->knobs[K_OCT].value-4))))
@ -262,9 +263,6 @@ void ui_update(Ui*ui)
case SDLK_u:play_note(oct(987.77));break; case SDLK_u:play_note(oct(987.77));break;
case SDLK_i:play_note(oct(1046.5));break; case SDLK_i:play_note(oct(1046.5));break;
#undef oct
#undef play_note
case SDLK_F1: case SDLK_F1:
ui->synth->recalculate_waveform=true; ui->synth->recalculate_waveform=true;
break; break;
@ -277,7 +275,7 @@ void ui_update(Ui*ui)
if(f) if(f)
{ {
fwrite(&ui->synth->wave,1,sizeof(WAVE),f); fwrite(&ui->synth->wave,1,sizeof(WAVE),f);
fwrite(ui->synth->channel[ui->synth->current_channel].buffer,1,SY_BUFFERSIZE*sizeof(float),f); fwrite(ui->synth->channel[ui->synth->current_channel].buffer[0],1,SY_BUFFERSIZE*sizeof(float),f);
fclose(f); fclose(f);
printf("Wrote file '%s'\n",fname); printf("Wrote file '%s'\n",fname);
} }
@ -285,10 +283,12 @@ void ui_update(Ui*ui)
break; break;
case SDLK_SPACE: case SDLK_SPACE:
ui->synth->playback_pos=0; play_note(ui->synth->knobs[K_FREQ].value);
ui->synth->play_waveform=true;
break; break;
#undef oct
#undef play_note
} }
break; break;
@ -311,6 +311,7 @@ void ui_update(Ui*ui)
// Recalculate waveform // Recalculate waveform
if(ui->synth->recalculate_waveform) if(ui->synth->recalculate_waveform)
/* synth_process(ui->synth); */
synth_recalc(ui->synth); synth_recalc(ui->synth);
ui->synth->nchannels=ui->synth->knobs[K_NCH].value; ui->synth->nchannels=ui->synth->knobs[K_NCH].value;
@ -331,7 +332,7 @@ void ui_update(Ui*ui)
// Draw realtime oscilloscope // Draw realtime oscilloscope
for(size_t i=0;i<ui->synth->nchannels;++i) for(size_t i=0;i<ui->synth->nchannels;++i)
draw_oscilloscope(ui,i,152*(i+1)+17,2,152-16,70); draw_oscilloscope(ui,i,152*(i+1)+16,2,152-16,70);
// Spectrum analyzer? // Spectrum analyzer?
/* { */ /* { */
@ -345,10 +346,10 @@ void ui_update(Ui*ui)
/* size_t f_lp=f-1; */ /* size_t f_lp=f-1; */
/* size_t f_hp=f+1; */ /* size_t f_hp=f+1; */
/* for(int32_t j=MAX(1,i-f_lp);j<=i;++j) */ /* for(int32_t j=MAX(1,i-f_lp);j<=i;++j) */
/* sum_lp+=ui->synth->channel[synth->current_channel].buffer[j]; */ /* sum_lp+=ui->synth->channel[synth->current_channel].buffer[0][j]; */
/* sum_lp/=f_lp+1; */ /* sum_lp/=f_lp+1; */
/* for(int32_t j=MAX(1,i-f_hp);j<=i;++j) */ /* for(int32_t j=MAX(1,i-f_hp);j<=i;++j) */
/* sum_hp+=ui->synth->channel[synth->current_channel].buffer[j]; */ /* sum_hp+=ui->synth->channel[synth->current_channel].buffer[0][j]; */
/* sum_hp/=f_hp+1; */ /* sum_hp/=f_hp+1; */
/* sum_hp=sum_lp-f_hp; */ /* sum_hp=sum_lp-f_hp; */
/* SDL_RenderDrawLine(ui->r,f*10,300,f*10,300+sum_hp); */ /* SDL_RenderDrawLine(ui->r,f*10,300,f*10,300+sum_hp); */
@ -363,7 +364,7 @@ void ui_update(Ui*ui)
/* { */ /* { */
/* float sum=0; */ /* float sum=0; */
/* for(int32_t j=f;j>=0;--j) */ /* for(int32_t j=f;j>=0;--j) */
/* sum+=ui->synth->channel[synth->current_channel].buffer[j]; */ /* sum+=ui->synth->channel[synth->current_channel].buffer[0][j]; */
/* sum/=f+1; */ /* sum/=f+1; */
/* SDL_RenderDrawLine(ui->r,f*10,400,f*10,400-sum*80); */ /* SDL_RenderDrawLine(ui->r,f*10,400,f*10,400-sum*80); */
/* } */ /* } */
@ -528,8 +529,8 @@ void draw_waveform(Ui*ui,uint32_t channel,uint32_t wf_x,uint32_t wf_y,uint32_t w
{ {
float xratio=(float)wf_w/SY_BUFFERSIZE; float xratio=(float)wf_w/SY_BUFFERSIZE;
float yratio=(float)wf_h/2.0; float yratio=(float)wf_h/2.0;
float y1=ui->synth->channel[channel].buffer[i-1]; float y1=ui->synth->channel[channel].buffer[0][i-1];
float y2=ui->synth->channel[channel].buffer[i]; float y2=ui->synth->channel[channel].buffer[0][i];
y1=(y1>1?1:(y1<-1?-1:y1)); y1=(y1>1?1:(y1<-1?-1:y1));
y2=(y2>1?1:(y2<-1?-1:y2)); y2=(y2>1?1:(y2<-1?-1:y2));
SDL_RenderDrawLine(ui->r, SDL_RenderDrawLine(ui->r,
@ -564,8 +565,8 @@ void draw_oscilloscope(Ui*ui,uint32_t channel,uint32_t wf_x,uint32_t wf_y,uint32
++i ++i
) )
{ {
float y1=MIN(ui->synth->channel[channel].buffer[i-1],1.0); float y1=MIN(ui->synth->channel[channel].buffer[0][i-1],1.0);
float y2=MIN(ui->synth->channel[channel].buffer[i],1.0); float y2=MIN(ui->synth->channel[channel].buffer[0][i],1.0);
SDL_RenderDrawLine(ui->r, SDL_RenderDrawLine(ui->r,
wf_x+((float)(i-ui->synth->playback_pos)-1)/SY_BSIZE*wf_w,wf_y+MIN(MAX(wf_h/2-y1*wf_h,wf_y),wf_h), wf_x+((float)(i-ui->synth->playback_pos)-1)/SY_BSIZE*wf_w,wf_y+MIN(MAX(wf_h/2-y1*wf_h,wf_y),wf_h),
wf_x+((float)(i-ui->synth->playback_pos))/SY_BSIZE*wf_w,wf_y+MIN(MAX(wf_h/2-y2*wf_h,wf_y),wf_h) wf_x+((float)(i-ui->synth->playback_pos))/SY_BSIZE*wf_w,wf_y+MIN(MAX(wf_h/2-y2*wf_h,wf_y),wf_h)