#help_index "Snd/Snd Files" #define SNDFILE_SAMPLE_RATE 8000 //Header for a ".SND" file class CFileSND { //big endian U32 signature; //0x646e732e U32 offset; //24 U32 data_size; U32 coding; //3=16bit uncompressed U32 sample_rate; //Hz U32 channels; //1=mono I16 body[1]; }; //This is a windows media constraint. #define MAX_SND_FILE_DATA 0x7FF00 public I64 SndFileCreate(U8 *base_filename,F64 normalized_vol=1.0,F64 averaging=0.0,I64 waveform=WF_NULL, F64 reverb_delay=0,F64 reverb_intensity=0) //Use "snd_record" flag to start or stop //recording, then call this routine. //Averaging should be a num from 0.0 to 0.999. //Vol should be from 0.0 to 1.0. //If waveform is $LK,"WF_NULL","MN:WF_NULL"$, the original passed to $LK,"Snd","MN:Snd"$() will be used. //Set reverb_delay to like 0.3 sec and reverb_intensity to like 0.4. { I64 i,k,cnt,cnt2,level,file_num; F64 avg,dt; CFileSND *s; CSndWaveCtrl *swc=SndWaveCtrlNew(SNDFILE_SAMPLE_RATE,16,1); CSndData *d,*d1; U8 *name,*name2; snd_record=FALSE; dt=snd_record_root.last->time_stamp-snd_record_root.next->time_stamp; if (!dt) return 0; cnt=dt*SNDFILE_SAMPLE_RATE; cnt++; //terminator name=StrNew(base_filename); FileExtRem(name); s=CAlloc(offset(CFileSND.body)+cnt*sizeof(I16)); s->signature=0x646e732e; s->offset=EndianU32(offset(CFileSND.body)); s->coding=EndianU32(3); s->sample_rate=EndianU32(SNDFILE_SAMPLE_RATE); s->channels=EndianU32(1); d=snd_record_root.next; k=0; while (d->next!=&snd_record_root) { d1=d->next; dt=d1->time_stamp-d->time_stamp; cnt2=dt*SNDFILE_SAMPLE_RATE; SndWaveAddBuf(swc,&s->body[k],cnt2,d->freq,waveform ?waveform:d->waveform,d->amp*normalized_vol); k+=cnt2; QueRem(d); Free(d); d=d1; } //Average if (averaging) { avg=0; for (i=0;ibody[i]=avg=LowPass1(averaging,avg,s->body[i],1.0); } //reverb if (reverb_intensity) { if (dt=reverb_delay*SNDFILE_SAMPLE_RATE) for (i=dt;ibody[i]+=reverb_intensity*s->body[i-dt]; } //Get rid of D.C. component for (k=0;k<3;k++) { level=0; for (i=0;ibody[i]; level/=cnt-1; for (i=0;ibody[i]=LimitI64(s->body[i]-level,MIN_I16,MAX_I16); } for (i=0;ibody[i]=EndianU16(s->body[i]); s->body[cnt-1]=0; d=snd_record_root.next; while (d!=&snd_record_root) { d1=d->next; QueRem(d); Free(d); d=d1; } name2=MAlloc(StrLen(name)+3+1+3+1); cnt2=cnt; file_num=0; while (cnt2>0) { i=cnt2; if (i>MAX_SND_FILE_DATA) i=MAX_SND_FILE_DATA; s->data_size=EndianU32(i*sizeof(I16)); MemCpy(s->body,&s->body[file_num*MAX_SND_FILE_DATA],i*sizeof(I16)); SPrintF(name2,"%s%03d.SND",name,file_num++); FileWrite(name2,s,offset(CFileSND.body)+i*sizeof(I16)); cnt2-=i; } Free(s); Free(name); Free(name2); SndWaveCtrlDel(swc); return cnt; } public U0 SndFileWrite(U8 *filename,SND_IN_CONTAINER *buf,I64 cnt) { CFileSND *s; I64 i,j,l=SND_SAMPLE_RATE/SNDFILE_SAMPLE_RATE; F64 level,a1,a2; cnt/=l; s=CAlloc(offset(CFileSND.body)+cnt*sizeof(I16)); s->signature=0x646e732e; s->offset=EndianU32(offset(CFileSND.body)); s->coding=EndianU32(3); s->sample_rate=EndianU32(SNDFILE_SAMPLE_RATE); s->channels=EndianU32(1); s->data_size=EndianU32(cnt*sizeof(I16)); //Get rid of D.C. component j=cnt*l; level=0; for (i=0;ibody[i]=EndianU16(buf[j]); j+=l; } FileWrite(filename,s,offset(CFileSND.body)+cnt*sizeof(I16)); Free(s); } public U0 SndFileView(U8 *name,Bool zoom=FALSE) { I64 i,start,end,w=Fs->win_pixel_width,h=Fs->win_pixel_height; F64 x_scale,y_scale; CFileSND *s=FileRead(name); if (s) { s->data_size=EndianU32(s->data_size)/sizeof(I16); for (i=0;idata_size;i++) s->body[i]=EndianU16(s->body[i]); start=1; end=s->data_size; if (zoom) { for (i=1;ibody[i]!=s->body[i-1]) { start=i; break; } if (s->data_size-start>w) end=start+w; } "$$CL$$"; DCFill; CDC *dc=DCAlias; dc->color=GREEN; x_scale=ToF64(w)/(end-start+1); y_scale=ToF64(h)/MAX_U16; for (i=start;ibody[i]+MAX_I16), x_scale*(i-start-1),y_scale*(s->body[i-1]+MAX_I16)); Free(s); PressAKey; DCFill; DCDel(dc); } } CFileSND *snd_play_snd_file=NULL; I64 snd_play_start_buf_num,snd_play_samples_per_sample; Bool snd_play_done=TRUE,snd_play_single_done; U0 (*fp_snd_play_task_end_cb)()=NULL; U0 (*fp_snd_play_old_fill_buf)(SND_OUT_CONTAINER *buf,I64 buf_num)=NULL; CFileSND *SndFileLoad(U8 *name) { I64 i; CFileSND *s=FileRead(name); if (s) { s->data_size=EndianU32(s->data_size)/sizeof(I16); for (i=0;idata_size;i++) s->body[i]=EndianU16(s->body[i]); } return s; } U0 SndFileFillBuf(SND_OUT_CONTAINER *buf,I64 buf_num) { I64 i,j,k,m; if (snd_play_done) return; buf_num-=snd_play_start_buf_num; j=buf_num*(SND_BUF_LEN/SND_OCHANNELS*SNDFILE_SAMPLE_RATE/SND_SAMPLE_RATE); i=j%snd_play_snd_file->data_size; k=j%snd_play_samples_per_sample; j=0; while (jbody[i++]<<16; while (j=snd_play_snd_file->data_size) { while (jtask_end_cb; Fs->task_end_cb=&SndFilePlayTaskEndCB; snd_play_start_buf_num=snd_obuf_num; snd_play_done=FALSE; fp_snd_play_old_fill_buf=fp_snd_fill_buf; fp_snd_fill_buf=&SndFileFillBuf; try { while (!snd_play_done) Sleep(1); } catch { snd_play_done=TRUE; fp_snd_fill_buf=fp_snd_play_old_fill_buf; Fs->task_end_cb=fp_snd_play_task_end_cb; Free(snd_play_snd_file); snd_play_snd_file=NULL; } fp_snd_fill_buf=fp_snd_play_old_fill_buf; Fs->task_end_cb=fp_snd_play_task_end_cb; Free(snd_play_snd_file); snd_play_snd_file=NULL; } snd_play_single_done=TRUE; } public U0 SndFilePlaySeq(U8 *snz_filename,I64 num) { //This has gaps between files. I might fix it someday. You fix it;-) I64 i; Bool old_preempt=Preempt(OFF),old_idle; U8 *fname=StrNew(snz_filename),*fname2; FileExtRem(fname); old_idle=LBts(&Fs->task_flags,TASKf_IDLE); for (i=0;itask_flags,TASKf_IDLE,old_idle); Free(fname); Preempt(old_preempt); } #help_index ""