hschumann2/TempleOS-Source-Code
0832
1 2#help_index "Snd/Math;Math"3public F64 Saw(F64 t,F64 period)4{//Sawtooth. 0.0 - 1.0 think "(Sin+1)/2"5 if (period) {6 if (t>=0.0)7 return t%period/period;8 else9 return 1.0+t%period/period;10 } else11 return 0.0;12}13 14public F64 FullSaw(F64 t,F64 period)15{//Plus&Minus Sawtooth. 1.0 - -1.0 think "Sin"16 if (period) {17 if (t>=0.0)18 return 2.0*(t%period/period)-1.0;19 else20 return 2.0*(t%period/period)+1.0;21 } else22 return 0.0;23}24 25public F64 Caw(F64 t,F64 period)26{//Cawtooth. 1.0 - 0.0 think "(Cos+1)/2"27 if (period) {28 if (t>=0.0)29 return 1.0-t%period/period;30 else31 return -(t%period)/period;32 } else33 return 1.0;34}35 36public F64 FullCaw(F64 t,F64 period)37{//Plus&Minus Cawtooth. 1.0 - -1.0 think "Cos"38 if (period) {39 if (t>=0.0)40 return -2.0*(t%period/period)+1.0;41 else42 return -2.0*(t%period/period)-1.0;43 } else44 return 1.0;45}46 47public F64 Tri(F64 t,F64 period)48{//Triangle waveform. 0.0 - 1.0 - 0.049 if (period) {50 t=2.0*(Abs(t)%period)/period;51 if (t<=1.0)52 return t;53 else54 return 2.0-t;55 } else56 return 0.0;57}58 59public F64 FullTri(F64 t,F64 period)60{//Plus&Minus Triangle waveform. 0.0 - 1.0 - 0.0 - -1.0 -0.061 if (period) {62 t=4.0*(t%period)/period;63 if (t<=-1.0) {64 if (t<=-3.0)65 return t+4.0;66 else67 return -2.0-t;68 } else {69 if (t<=1.0)70 return t;71 else if (t<=3.0)72 return 2.0-t;73 else74 return t-4.0;75 }76 } else77 return 0.0;78}79 80#help_index "Snd/Math"81 82public I8 Note2Ona(I64 note,I64 octave=4)83{//Note to ona. Mid C is ona=51, note=3 and octave=4.84 if (note<3)85 return (octave+1)*12+note;86 else87 return octave*12+note;88}89 90public I8 Ona2Note(I8 ona)91{//Ona to note in octave. Mid C is ona=51, note=3 and octave=4.92 return ona%12;93}94 95public I8 Ona2Octave(I8 ona)96{//Ona to octave. Mid C is ona=51, note=3 and octave=4.97 I64 note=ona%12,octave=ona/12;98 if (note<3)99 return octave-1;100 else101 return octave;102}103 104F64 SinPhaseCont(F64 last_y,F64 last_dydt,105 F64 current_amp,F64 phase_offset)106{//Next sample of sin waveform.107 F64 phase;108 phase=last_y/current_amp;109 if (phase>1.0) phase=1.0;110 if (phase<-1.0) phase=-1.0;111 if (last_dydt<0)112 phase=pi-ASin(phase);113 else114 phase=ASin(phase);115 return phase-phase_offset;116}117 118public CSndWaveCtrl *SndWaveCtrlNew(I64 sample_rate=8000,I64 sample_bits=24,119 I64 channels=2,CTask *mem_task=NULL)120{//MAlloc ctrl struct for generating waveforms.121 CSndWaveCtrl *swc=CAlloc(sizeof(CSndWaveCtrl),mem_task);122 swc->freq_multiplier=1.0;123 swc->amp_multiplier=1.0;124 swc->sample_rate=sample_rate;125 swc->sample_bits=sample_bits;126 swc->channels=channels;127 swc->last_dydt=1.0;128 return swc;129}130 131public U0 SndWaveCtrlDel(CSndWaveCtrl *swc)132{//Free waveform ctrl.133 Free(swc);134}135 136#define WF_NULL 0137#define WF_SQUARE 1138#define WF_SINE 2139#define WF_TRI 3140#define WF_SAWTOOTH 4141#define WF_NOISE 5142#define WF_WAVEFORMS_NUM 6143 144public U0 SndWaveAddBuf(CSndWaveCtrl *swc,U8 *buf,I64 num_samples,145 F64 _freq,I64 _waveform=WF_SQUARE,F64 _amp=1.0,F64 _left=1.0, F64 _right=1.0)146{//Add waveform to buffer.147//num_samples is multiplied by channels to get buf_len.148 //left,right range from 0.0-1.0149 //Supports 16,24 and 32 bits150 I64 reg i,reg j,reg k;151 F64 a,f,amp,reg phase;152 if (!swc) return;153 _freq*=swc->freq_multiplier;154 _amp*=swc->amp_multiplier;155 if (!_freq||!_amp) {156 swc->last_y=swc->phase=0;157 swc->last_dydt=1.0;158 } else {159 phase=swc->phase;160 i=0;161 amp=Min(I32_MAX,I32_MAX*_amp);162 f=2*pi/swc->sample_rate*_freq;163 switch (_waveform) {164 case WF_NOISE:165 a=2.0/pi*amp;166 break;167 case WF_SAWTOOTH:168 a=amp/pi;169 break;170 case WF_SINE:171 phase=SinPhaseCont(swc->last_y,swc->last_dydt,amp,0.0);172 break;173 }174 while (phase<0)175 phase+=2*pi;176 while (phase>=2*pi)177 phase-=2*pi;178 num_samples*=swc->channels;179 while (i<num_samples) {180 switch (_waveform) {181 case WF_SQUARE:182 if (phase>=pi)183 j=-amp;184 else185 j=amp;186 break;187 case WF_SINE:188 j=amp*Sin(phase);189 break;190 case WF_TRI:191 if (phase>=pi) {192 swc->last_y=swc->next_y;193 swc->next_y=-amp*Sign(swc->last_y)+.00001;194 phase-=pi;195 }196 j=(swc->last_y*(pi-phase)+swc->next_y*phase)/pi;197 break;198 case WF_SAWTOOTH:199 j=a*(phase-pi);200 break;201 case WF_NOISE:202 if (phase<pi) {203 if (phase<f) {204 swc->last_y=swc->next_y;205 swc->next_y=a*RandI16/U16_MAX;206 }207 j=swc->last_y*(pi-phase)+swc->next_y*phase;208 } else {209 if (phase-pi<f) {210 swc->last_y=swc->next_y;211 swc->next_y=a*RandI16/U16_MAX;212 }213 j=swc->last_y*(2.0*pi-phase)+swc->next_y*(phase-pi);214 }215 break;216 }217//left channel218 k=j*_left;219 if (swc->sample_bits==16) {220 k>>=16;221 buf(I16 *)[i++]+=k;222 } else {223 if (swc->sample_bits==24)224 k&=0xFFFFFF00;225 buf(I32 *)[i++]+=k;226 }227//right channel228 if (swc->channels==2) {229 k=j*_right;230 if (swc->sample_bits==16) {231 k>>=16;232 buf(I16 *)[i++]+=k;233 } else {234 if (swc->sample_bits==24)235 k&=0xFFFFFF00;236 buf(I32 *)[i++]+=k;237 }238 }239 phase+=f;240 while (phase>=2*pi)241 phase-=2*pi;242 }243 if (_waveform==WF_SINE) {244 swc->last_y=amp*Sin(phase);245 swc->last_dydt=Cos(phase);246 }247 swc->phase=phase;248 }249}250 