From f6cb1880dfe6f83fba061280a2b556d75f93c57b Mon Sep 17 00:00:00 2001 From: Edouard Dupin Date: Tue, 24 Jul 2012 22:24:38 +0200 Subject: [PATCH] add basic generator --- .gitignore | 67 ++++ jni/appl/Gui/MainWindows.cpp | 2 + jni/appl/generator.cpp | 616 +++++++++++++++++++++++++++++++++++ jni/appl/generator.h | 33 ++ jni/file.mk | 4 +- 5 files changed, 721 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 jni/appl/generator.cpp create mode 100644 jni/appl/generator.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ec3ab71 --- /dev/null +++ b/.gitignore @@ -0,0 +1,67 @@ + +################################### +# folders +################################### +CVS +.svn +.gitk-tmp.* +Object/ +doxygen/API/ +doxygen/ALL/ +bin/ +gen/ +linux/ +obj/ + +################################### +# backup files +################################### +*~ +*.swp +*.old +*.bck + +################################### +# Compiled source # +################################### +*.com +*.class +*.dll +*.exe +*.o +*.so +*.pyc +tags +edn +out +edn_debug +edn_release + +################################### +# Packages # +################################### +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +################################### +# Logs and databases # +################################### +*.log +*.sql +*.sqlite + +################################### +# OS generated files # +################################### +.DS_Store? +ehthumbs.db +Icon? +Thumbs.db diff --git a/jni/appl/Gui/MainWindows.cpp b/jni/appl/Gui/MainWindows.cpp index 75f6ce6..0a85c1c 100644 --- a/jni/appl/Gui/MainWindows.cpp +++ b/jni/appl/Gui/MainWindows.cpp @@ -42,6 +42,8 @@ #include #include +#include + #undef __class__ #define __class__ "MainWindows" diff --git a/jni/appl/generator.cpp b/jni/appl/generator.cpp new file mode 100644 index 0000000..89fba26 --- /dev/null +++ b/jni/appl/generator.cpp @@ -0,0 +1,616 @@ +/** + ******************************************************************************* + * @file appl/generator.h + * @brief Fx Creator : audio generator (header) + * @author Edouard DUPIN + * @date 24/07/2012 + * @par Project + * fxCreator + * + * @par Copyright + * Copyright 2010 Edouard DUPIN, all right reserved + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY. + * + * Licence summary : + * You can modify and redistribute the sources code and binaries. + * You can send me the bug-fix + * You can not earn money with this Software (if the source extract from Edn + * represent less than 50% of original Sources) + * Term of the licence in in the file licence.txt. + * + ******************************************************************************* + */ + +#include +#include + +#include +#include +#include +#include +#include + + +#undef __class__ +#define __class__ "generator" + + +#define rnd(n) (rand()%(n+1)) + +#define PI 3.14159265f + +float frnd(float range) +{ + return (float)rnd(10000)/10000*range; +} + +int32_t wave_type; + +float p_base_freq; +float p_freq_limit; +float p_freq_ramp; +float p_freq_dramp; +float p_duty; +float p_duty_ramp; + +float p_vib_strength; +float p_vib_speed; +float p_vib_delay; + +float p_env_attack; +float p_env_sustain; +float p_env_decay; +float p_env_punch; + +bool filter_on; +float p_lpf_resonance; +float p_lpf_freq; +float p_lpf_ramp; +float p_hpf_freq; +float p_hpf_ramp; + +float p_pha_offset; +float p_pha_ramp; + +float p_repeat_speed; + +float p_arp_speed; +float p_arp_mod; + +float master_vol=0.05f; + +float sound_vol=0.5f; + + +bool playing_sample=false; +int32_t phase; +double fperiod; +double fmaxperiod; +double fslide; +double fdslide; +int32_t period; +float square_duty; +float square_slide; +int32_t env_stage; +int32_t env_time; +int32_t env_length[3]; +float env_vol; +float fphase; +float fdphase; +int32_t iphase; +float phaser_buffer[1024]; +int32_t ipp; +float noise_buffer[32]; +float fltp; +float fltdp; +float fltw; +float fltw_d; +float fltdmp; +float fltphp; +float flthp; +float flthp_d; +float vib_phase; +float vib_speed; +float vib_amp; +int32_t rep_time; +int32_t rep_limit; +int32_t arp_time; +int32_t arp_limit; +double arp_mod; + +float* vselected=NULL; +int32_t vcurbutton=-1; + +int32_t wav_bits=16; +int32_t wav_freq=44100; + +int32_t file_sampleswritten; +float filesample=0.0f; +int32_t fileacc=0; + +void ResetParams() +{ + wave_type=0; + + p_base_freq=0.3f; + p_freq_limit=0.0f; + p_freq_ramp=0.0f; + p_freq_dramp=0.0f; + p_duty=0.0f; + p_duty_ramp=0.0f; + + p_vib_strength=0.0f; + p_vib_speed=0.0f; + p_vib_delay=0.0f; + + p_env_attack=0.0f; + p_env_sustain=0.3f; + p_env_decay=0.4f; + p_env_punch=0.0f; + + filter_on=false; + p_lpf_resonance=0.0f; + p_lpf_freq=1.0f; + p_lpf_ramp=0.0f; + p_hpf_freq=0.0f; + p_hpf_ramp=0.0f; + + p_pha_offset=0.0f; + p_pha_ramp=0.0f; + + p_repeat_speed=0.0f; + + p_arp_speed=0.0f; + p_arp_mod=0.0f; +} + +bool LoadSettings(char* filename) +{ + FILE* file=fopen(filename, "rb"); + if(!file) + return false; + + int version=0; + fread(&version, 1, sizeof(int), file); + if(version!=100 && version!=101 && version!=102) + return false; + + fread(&wave_type, 1, sizeof(int), file); + + sound_vol=0.5f; + if(version==102) + fread(&sound_vol, 1, sizeof(float), file); + + fread(&p_base_freq, 1, sizeof(float), file); + fread(&p_freq_limit, 1, sizeof(float), file); + fread(&p_freq_ramp, 1, sizeof(float), file); + if(version>=101) + fread(&p_freq_dramp, 1, sizeof(float), file); + fread(&p_duty, 1, sizeof(float), file); + fread(&p_duty_ramp, 1, sizeof(float), file); + + fread(&p_vib_strength, 1, sizeof(float), file); + fread(&p_vib_speed, 1, sizeof(float), file); + fread(&p_vib_delay, 1, sizeof(float), file); + + fread(&p_env_attack, 1, sizeof(float), file); + fread(&p_env_sustain, 1, sizeof(float), file); + fread(&p_env_decay, 1, sizeof(float), file); + fread(&p_env_punch, 1, sizeof(float), file); + + fread(&filter_on, 1, sizeof(bool), file); + fread(&p_lpf_resonance, 1, sizeof(float), file); + fread(&p_lpf_freq, 1, sizeof(float), file); + fread(&p_lpf_ramp, 1, sizeof(float), file); + fread(&p_hpf_freq, 1, sizeof(float), file); + fread(&p_hpf_ramp, 1, sizeof(float), file); + + fread(&p_pha_offset, 1, sizeof(float), file); + fread(&p_pha_ramp, 1, sizeof(float), file); + + fread(&p_repeat_speed, 1, sizeof(float), file); + + if(version>=101) + { + fread(&p_arp_speed, 1, sizeof(float), file); + fread(&p_arp_mod, 1, sizeof(float), file); + } + + fclose(file); + return true; +} + +bool SaveSettings(char* filename) +{ + FILE* file=fopen(filename, "wb"); + if(!file) + return false; + + int version=102; + fwrite(&version, 1, sizeof(int), file); + + fwrite(&wave_type, 1, sizeof(int), file); + + fwrite(&sound_vol, 1, sizeof(float), file); + + fwrite(&p_base_freq, 1, sizeof(float), file); + fwrite(&p_freq_limit, 1, sizeof(float), file); + fwrite(&p_freq_ramp, 1, sizeof(float), file); + fwrite(&p_freq_dramp, 1, sizeof(float), file); + fwrite(&p_duty, 1, sizeof(float), file); + fwrite(&p_duty_ramp, 1, sizeof(float), file); + + fwrite(&p_vib_strength, 1, sizeof(float), file); + fwrite(&p_vib_speed, 1, sizeof(float), file); + fwrite(&p_vib_delay, 1, sizeof(float), file); + + fwrite(&p_env_attack, 1, sizeof(float), file); + fwrite(&p_env_sustain, 1, sizeof(float), file); + fwrite(&p_env_decay, 1, sizeof(float), file); + fwrite(&p_env_punch, 1, sizeof(float), file); + + fwrite(&filter_on, 1, sizeof(bool), file); + fwrite(&p_lpf_resonance, 1, sizeof(float), file); + fwrite(&p_lpf_freq, 1, sizeof(float), file); + fwrite(&p_lpf_ramp, 1, sizeof(float), file); + fwrite(&p_hpf_freq, 1, sizeof(float), file); + fwrite(&p_hpf_ramp, 1, sizeof(float), file); + + fwrite(&p_pha_offset, 1, sizeof(float), file); + fwrite(&p_pha_ramp, 1, sizeof(float), file); + + fwrite(&p_repeat_speed, 1, sizeof(float), file); + + fwrite(&p_arp_speed, 1, sizeof(float), file); + fwrite(&p_arp_mod, 1, sizeof(float), file); + + fclose(file); + return true; +} + +void ResetSample(bool restart) +{ + if(!restart) { + phase=0; + } + fperiod=100.0/(p_base_freq*p_base_freq+0.001); + period=(int)fperiod; + fmaxperiod=100.0/(p_freq_limit*p_freq_limit+0.001); + fslide=1.0-pow((double)p_freq_ramp, 3.0)*0.01; + fdslide=-pow((double)p_freq_dramp, 3.0)*0.000001; + square_duty=0.5f-p_duty*0.5f; + square_slide=-p_duty_ramp*0.00005f; + if(p_arp_mod>=0.0f) { + arp_mod=1.0-pow((double)p_arp_mod, 2.0)*0.9; + } else { + arp_mod=1.0+pow((double)p_arp_mod, 2.0)*10.0; + } + arp_time=0; + arp_limit=(int)(pow(1.0f-p_arp_speed, 2.0f)*20000+32); + if(p_arp_speed==1.0f) { + arp_limit=0; + } + if(!restart) { + // reset filter + fltp=0.0f; + fltdp=0.0f; + fltw=pow(p_lpf_freq, 3.0f)*0.1f; + fltw_d=1.0f+p_lpf_ramp*0.0001f; + fltdmp=5.0f/(1.0f+pow(p_lpf_resonance, 2.0f)*20.0f)*(0.01f+fltw); + if(fltdmp>0.8f) { + fltdmp=0.8f; + } + fltphp=0.0f; + flthp=pow(p_hpf_freq, 2.0f)*0.1f; + flthp_d=1.0+p_hpf_ramp*0.0003f; + // reset vibrato + vib_phase=0.0f; + vib_speed=pow(p_vib_speed, 2.0f)*0.01f; + vib_amp=p_vib_strength*0.5f; + // reset envelope + env_vol=0.0f; + env_stage=0; + env_time=0; + env_length[0]=(int)(p_env_attack*p_env_attack*100000.0f); + env_length[1]=(int)(p_env_sustain*p_env_sustain*100000.0f); + env_length[2]=(int)(p_env_decay*p_env_decay*100000.0f); + + fphase=pow(p_pha_offset, 2.0f)*1020.0f; + if(p_pha_offset<0.0f) { + fphase=-fphase; + } + fdphase=pow(p_pha_ramp, 2.0f)*1.0f; + if(p_pha_ramp<0.0f) { + fdphase=-fdphase; + } + iphase=abs((int)fphase); + ipp=0; + for(int i=0;i<1024;i++) { + phaser_buffer[i]=0.0f; + } + + for(int i=0;i<32;i++) { + noise_buffer[i]=frnd(2.0f)-1.0f; + } + + rep_time=0; + rep_limit=(int)(pow(1.0f-p_repeat_speed, 2.0f)*20000+32); + if(p_repeat_speed==0.0f) { + rep_limit=0; + } + } +} + +void PlaySample() +{ + ResetSample(false); + playing_sample=true; +} + +void SynthSample(int length, float* buffer, FILE* file) +{ + for(int i=0;i=rep_limit) { + rep_time=0; + ResetSample(true); + } + + // frequency envelopes/arpeggios + arp_time++; + if(arp_limit!=0 && arp_time>=arp_limit) { + arp_limit=0; + fperiod*=arp_mod; + } + fslide+=fdslide; + fperiod*=fslide; + if(fperiod>fmaxperiod) { + fperiod=fmaxperiod; + if(p_freq_limit>0.0f) { + playing_sample=false; + } + } + float rfperiod=fperiod; + if(vib_amp>0.0f) { + vib_phase+=vib_speed; + rfperiod=fperiod*(1.0+sin(vib_phase)*vib_amp); + } + period=(int)rfperiod; + if(period<8) { + period=8; + } + square_duty+=square_slide; + if(square_duty<0.0f) { + square_duty=0.0f; + } + if(square_duty>0.5f) { + square_duty=0.5f; + } + // volume envelope + env_time++; + if(env_time>env_length[env_stage]) { + env_time=0; + env_stage++; + if(env_stage==3) { + playing_sample=false; + } + } + if(env_stage==0) { + env_vol=(float)env_time/env_length[0]; + } + if(env_stage==1) { + env_vol=1.0f+pow(1.0f-(float)env_time/env_length[1], 1.0f)*2.0f*p_env_punch; + } + if(env_stage==2) { + env_vol=1.0f-(float)env_time/env_length[2]; + } + + // phaser step + fphase+=fdphase; + iphase=abs((int)fphase); + if(iphase>1023) { + iphase=1023; + } + + if(flthp_d!=0.0f) { + flthp*=flthp_d; + if(flthp<0.00001f) { + flthp=0.00001f; + } + if(flthp>0.1f) { + flthp=0.1f; + } + } + + float ssample=0.0f; + for(int si=0;si<8;si++) // 8x supersampling + { + float sample=0.0f; + phase++; + if(phase>=period) { + phase%=period; + if(wave_type==3) { + for(int i=0;i<32;i++) { + noise_buffer[i]=frnd(2.0f)-1.0f; + } + } + } + // base waveform + float fp=(float)phase/period; + switch(wave_type) + { + case 0: // square + if(fp0.1f) { + fltw=0.1f; + } + if(p_lpf_freq!=1.0f) { + fltdp+=(sample-fltp)*fltw; + fltdp-=fltdp*fltdmp; + } else { + fltp=sample; + fltdp=0.0f; + } + fltp+=fltdp; + // hp filter + fltphp+=fltp-pp; + fltphp-=fltphp*flthp; + sample=fltphp; + // phaser + phaser_buffer[ipp&1023]=sample; + sample+=phaser_buffer[(ipp-iphase+1024)&1023]; + ipp=(ipp+1)&1023; + // final accumulation and envelope application + ssample+=sample*env_vol; + } + ssample=ssample/8*master_vol; + + ssample*=2.0f*sound_vol; + + if(buffer!=NULL) { + if(ssample>1.0f) { + ssample=1.0f; + } + if(ssample<-1.0f) { + ssample=-1.0f; + } + *buffer++=ssample; + } + if(file!=NULL) { + // quantize depending on format + // accumulate/count to accomodate variable sample rate? + ssample*=4.0f; // arbitrary gain to get reasonable output volume... + if(ssample>1.0f) { + ssample=1.0f; + } + if(ssample<-1.0f) { + ssample=-1.0f; + } + filesample+=ssample; + fileacc++; + if(wav_freq==44100 || fileacc==2) { + filesample/=fileacc; + fileacc=0; + if(wav_bits==16) { + short isample=(short)(filesample*32000); + fwrite(&isample, 1, 2, file); + } else { + unsigned char isample=(unsigned char)(filesample*127+128); + fwrite(&isample, 1, 1, file); + } + filesample=0.0f; + } + file_sampleswritten++; + } + } +} + + +//lets use SDL in stead +static void SDLAudioCallback(int16_t *stream, int32_t len) +{ + if (playing_sample) { + float fbuf[len]; + memset(fbuf, 0, sizeof(int32_t)); + SynthSample(len, fbuf, NULL); + while (len--) { + float f = fbuf[len]; + if (f < -1.0) { + f = -1.0; + } + if (f > 1.0) { + f = 1.0; + } + stream[len] = (int16_t)(f * 32767); + } + } else { + memset(stream, 0, len*sizeof(int16_t)); + } +} + +bool ExportWAV(char* filename) +{ + FILE* foutput=fopen(filename, "wb"); + if(!foutput) { + return false; + } + // write wav header + uint32_t dword=0; + uint16_t word=0; + fwrite("RIFF", 4, 1, foutput); // "RIFF" + dword=0; + fwrite(&dword, 1, 4, foutput); // remaining file size + fwrite("WAVE", 4, 1, foutput); // "WAVE" + + fwrite("fmt ", 4, 1, foutput); // "fmt " + dword=16; + fwrite(&dword, 1, 4, foutput); // chunk size + word=1; + fwrite(&word, 1, 2, foutput); // compression code + word=1; + fwrite(&word, 1, 2, foutput); // channels + dword=wav_freq; + fwrite(&dword, 1, 4, foutput); // sample rate + dword=wav_freq*wav_bits/8; + fwrite(&dword, 1, 4, foutput); // bytes/sec + word=wav_bits/8; + fwrite(&word, 1, 2, foutput); // block align + word=wav_bits; + fwrite(&word, 1, 2, foutput); // bits per sample + + fwrite("data", 4, 1, foutput); // "data" + dword=0; + int foutstream_datasize=ftell(foutput); + fwrite(&dword, 1, 4, foutput); // chunk size + + // write sample data + file_sampleswritten=0; + filesample=0.0f; + fileacc=0; + PlaySample(); + while(playing_sample) { + SynthSample(256, NULL, foutput); + } + + // seek back to header and write size info + fseek(foutput, 4, SEEK_SET); + dword=0; + dword=foutstream_datasize-4+file_sampleswritten*wav_bits/8; + fwrite(&dword, 1, 4, foutput); // remaining file size + fseek(foutput, foutstream_datasize, SEEK_SET); + dword=file_sampleswritten*wav_bits/8; + fwrite(&dword, 1, 4, foutput); // chunk size (data) + fclose(foutput); + + return true; +} + + + diff --git a/jni/appl/generator.h b/jni/appl/generator.h new file mode 100644 index 0000000..1adee55 --- /dev/null +++ b/jni/appl/generator.h @@ -0,0 +1,33 @@ +/** + ******************************************************************************* + * @file appl/generator.cpp + * @brief Fx Creator : audio generator (Sources) + * @author Edouard DUPIN + * @date 24/07/2012 + * @par Project + * fxCreator + * + * @par Copyright + * Copyright 2010 Edouard DUPIN, all right reserved + * + * This software is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY. + * + * Licence summary : + * You can modify and redistribute the sources code and binaries. + * You can send me the bug-fix + * You can not earn money with this Software (if the source extract from Edn + * represent less than 50% of original Sources) + * Term of the licence in in the file licence.txt. + * + ******************************************************************************* + */ + +#ifndef __GENERATOR_H__ +#define __GENERATOR_H__ + +namespace generator { + +}; + +#endif diff --git a/jni/file.mk b/jni/file.mk index b928538..3283204 100644 --- a/jni/file.mk +++ b/jni/file.mk @@ -5,7 +5,9 @@ ############################################################################### # Globals debug tool: -FILE_LIST+= appl/Debug.cpp +FILE_LIST+= appl/Debug.cpp \ + appl/globalMsg.cpp \ + appl/generator.cpp # Gui: FILE_LIST+= appl/Gui/MainWindows.cpp