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 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
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)
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;
}
synth->playback_pos=MIN(synth->playback_pos+count,SY_BUFFERSIZE);

89
synth.c
View File

@ -10,18 +10,39 @@
#define M_PI 3.14159
#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)
{
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 lfo2_buffer[SY_BUFFERSIZE]={0};
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};
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_vol[]={K_OSC1_VOL,K_OSC2_VOL,K_OSC3_VOL,K_OSC4_VOL};
const uint32_t oscillator_wavef[]={K_OSC1_WAVEF,K_OSC2_WAVEF,K_OSC3_WAVEF,K_OSC4_WAVEF};
const uint32_t oscillator_duty[]={K_OSC1_PHASE,K_OSC2_PHASE,K_OSC3_PHASE,K_OSC4_PHASE};
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)
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;
bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0;
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
@ -184,7 +205,7 @@ void synth_recalc(Synth*synth)
float duty=synth->knobs[oscillator_duty[cur_osc]].value;
bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0;
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
@ -197,7 +218,7 @@ void synth_recalc(Synth*synth)
float duty=synth->knobs[oscillator_duty[cur_osc]].value;
bool mix=cur_osc>0&&synth->knobs[oscillator_vol[cur_osc-1]].value>0;
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
@ -214,7 +235,7 @@ void synth_recalc(Synth*synth)
synth->knobs[K_LFO2_FREQ].value>0)
duty_buf=lfo2_buffer;
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
@ -225,7 +246,7 @@ void synth_recalc(Synth*synth)
float fr=(synth->knobs[K_FREQ].value/synth->knobs[K_FREQ].maxval)*MAXFREQ;
fr+=SEMITONE(fr,synth->knobs[K_DET].value);
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/=2.0;
}
synth->channel[synth->current_channel].buffer[i]*=amp;
synth->channel[synth->current_channel].buffer[0][i]*=amp;
}
// Convolution low-pass filter
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;
@ -256,21 +277,21 @@ void synth_recalc(Synth*synth)
float mult=((float)i)/attacklen;
float sum=0;
for(int32_t j=MAX(1,i-lp);j<=i;++j)
sum+=synth->channel[synth->current_channel].buffer[j];
for(int32_t j=MAX(1,i-synth->knobs[K_LP].value);j<=i;++j)
sum+=synth->channel[synth->current_channel].buffer[0][j];
// Weight for filter wet/dry
{
float f_val=sum/(lp+1);
float o_val=synth->channel[synth->current_channel].buffer[i];
float f_val=sum/(synth->knobs[K_LP].value+1);
float o_val=synth->channel[synth->current_channel].buffer[0][i];
float o_mult=MAX(0,1.0-mult);
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)
synth->channel[synth->current_channel].buffer[i]=f_val;
synth->channel[synth->current_channel].buffer[0][i]=f_val;
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
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)
{
float sum=0;
for(int32_t j=MAX(1,i-hp);j<=i;++j)
sum+=synth->channel[synth->current_channel].buffer[j];
synth->channel[synth->current_channel].buffer[i]-=sum/(hp+1);
for(int32_t j=MAX(1,i-synth->knobs[K_HP].value);j<=i;++j)
sum+=synth->channel[synth->current_channel].buffer[0][j];
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)
{
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)
{
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)
{
if(synth->channel[synth->current_channel].buffer[i]>synth->knobs[K_LIM].value)
synth->channel[synth->current_channel].buffer[i]=synth->knobs[K_LIM].value;
else if(synth->channel[synth->current_channel].buffer[i]<-synth->knobs[K_LIM].value)
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[0][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[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)
{
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)
{
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->play_waveform=false;
s->recalculate_waveform=true;

16
synth.h
View File

@ -23,7 +23,13 @@
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;
typedef struct Synth
@ -34,11 +40,7 @@ typedef struct Synth
bool cleared; // Buffer was cleared
bool play_waveform; // Are we currently rendering?
bool recalculate_waveform; // When to regenerate
float amp; // Amplitude
float freq; // Frequency in Hertz
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 nchannels;
size_t playback_pos; // Current position in playback
@ -51,8 +53,10 @@ typedef struct Note
float freq;
} Note;
void synth_recalc(Synth*synth);
void synth_create_channel(Synth*synth);
void synth_new(Synth*s);
void synth_process(Synth*synth);
void synth_recalc(Synth*synth);
size_t gen_sin(
float*buffer,

29
ui.c
View File

@ -92,6 +92,7 @@ void ui_update(Ui*ui)
ui->synth->recalculate_waveform=true;\
ui->synth->play_waveform=true;\
ui->synth->playback_pos=0;\
synth_create_channel(ui->synth);\
}while(0)
#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_i:play_note(oct(1046.5));break;
#undef oct
#undef play_note
case SDLK_F1:
ui->synth->recalculate_waveform=true;
break;
@ -277,7 +275,7 @@ void ui_update(Ui*ui)
if(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);
printf("Wrote file '%s'\n",fname);
}
@ -285,10 +283,12 @@ void ui_update(Ui*ui)
break;
case SDLK_SPACE:
ui->synth->playback_pos=0;
ui->synth->play_waveform=true;
play_note(ui->synth->knobs[K_FREQ].value);
break;
#undef oct
#undef play_note
}
break;
@ -311,6 +311,7 @@ void ui_update(Ui*ui)
// Recalculate waveform
if(ui->synth->recalculate_waveform)
/* synth_process(ui->synth); */
synth_recalc(ui->synth);
ui->synth->nchannels=ui->synth->knobs[K_NCH].value;
@ -331,7 +332,7 @@ void ui_update(Ui*ui)
// Draw realtime oscilloscope
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?
/* { */
@ -345,10 +346,10 @@ void ui_update(Ui*ui)
/* size_t f_lp=f-1; */
/* size_t f_hp=f+1; */
/* 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; */
/* 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=sum_lp-f_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; */
/* 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; */
/* 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 yratio=(float)wf_h/2.0;
float y1=ui->synth->channel[channel].buffer[i-1];
float y2=ui->synth->channel[channel].buffer[i];
float y1=ui->synth->channel[channel].buffer[0][i-1];
float y2=ui->synth->channel[channel].buffer[0][i];
y1=(y1>1?1:(y1<-1?-1:y1));
y2=(y2>1?1:(y2<-1?-1:y2));
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
)
{
float y1=MIN(ui->synth->channel[channel].buffer[i-1],1.0);
float y2=MIN(ui->synth->channel[channel].buffer[i],1.0);
float y1=MIN(ui->synth->channel[channel].buffer[0][i-1],1.0);
float y2=MIN(ui->synth->channel[channel].buffer[0][i],1.0);
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))/SY_BSIZE*wf_w,wf_y+MIN(MAX(wf_h/2-y2*wf_h,wf_y),wf_h)