Академический Документы
Профессиональный Документы
Культура Документы
Theblogatthebottomofthesea
ProgrammingandGamedevStuff
DIYSynth1:SoundOutput
PostedonMay142012byDemofox
ThisisapartoftheDIYSynthesizerseriesofpostswhereeachpostisroughlybuiltupontheknowledgeofthe
previousposts.Ifyouarelost,checktheearlierposts!
Thisisthefirstinaseriesoftutorialsonhowtomakeyourownsoftwaresynthesizer.
ThesetutorialsareaimedatC++programmers,andtheexamplecodeismeanttobeaseasytounderstandas
possibleandhaveasfewdependenciesaspossible.Thecodeoughttocompileandrunforyounomatterwhat
systemorcompileryouareusingwithminimalifanychangesrequired.
Youcandownloadthefullsourceforthischapterhere:DIYSynthesizerChapter1SourceCode
WaveFileFormat
Sincemakingsoundcomeoutofcomputerspeakersvariesalotbetweendifferentsystems,wellstartoutjust
writinga.wavefile.
Ifyouwanttojumpintodoingrealtimeaudio,irecommendportaudio(http://www.portaudio.com/),andialso
recomendlibsndfileforreadingandwritingotheraudiofileformats(http://www.meganerd.com/libsndfile/).
Ifoundthese2linksreallyhelpfulinunderstandingthewavefileformat:
http://www.piclist.com/techref/io/serial/midi/wave.html
https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
Theresalotofoptionalpartsofawavefileheader,butweareonlygoingtofocusonthebareminimumrequiredto
getthejobdone.Hereswhatourwavefileheaderstructlookslike:
//thisstructistheminimalrequiredheaderdataforawavfile
structSMinimalWaveFileHeader
{
//themainchunk
http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/ 1/6
11/4/2017 DIYSynth1:SoundOutput|Theblogatthebottomofthesea
unsignedcharm_szChunkID[4];
uint32m_nChunkSize;
unsignedcharm_szFormat[4];
//subchunk1"fmt"
unsignedcharm_szSubChunk1ID[4];
uint32m_nSubChunk1Size;
uint16m_nAudioFormat;
uint16m_nNumChannels;
uint32m_nSampleRate;
uint32m_nByteRate;
uint16m_nBlockAlign;
uint16m_nBitsPerSample;
//subchunk2"data"
unsignedcharm_szSubChunk2ID[4];
uint32m_nSubChunk2Size;
//thencomesthedata!
};
Andboringly,heresthefunctionthatfillsoutthestructandwritesittodisk:
boolWriteWaveFile(constchar*szFileName,void*pData,int32nDataSize,int16nNumChannels,int32
nSampleRate,int32nBitsPerSample)
{
//openthefileifwecan
FILE*File=fopen(szFileName,"w+b");
if(!File)
{
returnfalse;
}
SMinimalWaveFileHeaderwaveHeader;
//filloutthemainchunk
memcpy(waveHeader.m_szChunkID,"RIFF",4);
waveHeader.m_nChunkSize=nDataSize+36;
memcpy(waveHeader.m_szFormat,"WAVE",4);
//filloutsubchunk1"fmt"
memcpy(waveHeader.m_szSubChunk1ID,"fmt",4);
waveHeader.m_nSubChunk1Size=16;
waveHeader.m_nAudioFormat=1;
waveHeader.m_nNumChannels=nNumChannels;
waveHeader.m_nSampleRate=nSampleRate;
waveHeader.m_nByteRate=nSampleRate*nNumChannels*nBitsPerSample/8;
waveHeader.m_nBlockAlign=nNumChannels*nBitsPerSample/8;
waveHeader.m_nBitsPerSample=nBitsPerSample;
http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/ 2/6
11/4/2017 DIYSynth1:SoundOutput|Theblogatthebottomofthesea
//filloutsubchunk2"data"
memcpy(waveHeader.m_szSubChunk2ID,"data",4);
waveHeader.m_nSubChunk2Size=nDataSize;
//writetheheader
fwrite(&waveHeader,sizeof(SMinimalWaveFileHeader),1,File);
//writethewavedataitself
fwrite(pData,nDataSize,1,File);
//closethefileandreturnsuccess
fclose(File);
returntrue;
}
Nothingtoocrazyorallthatinteresting,butitgetsthejobdone.Again,checkoutthoselinksaboveifyouare
interestedinthedetailsofwhythingsarewrittenthewaytheyare,orwhatotheroptionsthereare.
GeneratingaMonoWaveFile
Now,finallysomethinginteresting,wearegoingtogeneratesomeaudiodataandmakearealwavefile!
Sincetheyareeasytogenerate,welluseasawtoothwaveforoursound.Formoreinformationaboutsawtooth
waves,checkoutthiswikipediapage:http://en.wikipedia.org/wiki/Sawtooth_wave.
intnSampleRate=44100;
intnNumSeconds=4;
intnNumChannels=1;
Thesampleratedefineshowmanysamplesofaudiodatatherearepersecond.Astreamofaudiodataisnothing
morethanastreamofnumbers,andeachnumberisasingleaudiosample,sothesamplerateisjusthowmany
numberstherearepersecondofaudiodata.Thelessnumbersyouuse,thelesshorizontalresolutionyoursound
filehas,or,thelesstimesthewavedatacanchangeinamplitudepersecond.
Thesampleratealsodefinesthemaximumfrequencyyoucanstoreintheaudiostream.Themaximumfrequency
youcanstoreishalfofthesamplerate.Inotherwords,witha44100samplerate,themaximumfrequencyyoucan
storeis22,050hz.Themaximumaudiblefrequencyforthehumanearisabout20,000hzsousingasamplerateof
44100oughttobeprettygoodformostneeds(youmightneedtogohigher,forcomplextechnicalreasons,butthis
isinfoenoughfornow!).Heressomeinterestinginfoaboutaudiofrequencies:
http://en.wikipedia.org/wiki/Audio_frequency
Thenumberofsecondsishowlong(inseconds)thewavegoesonfor,andthenumberofchannelsishowmany
audiochannelsthereare.Sincethisisamonosound,thereisonlyoneaudiochannel.
intnNumSamples=nSampleRate*nNumChannels*nNumSeconds;
int32*pData=newint32[nNumSamples];
Herewecalculatehowmanyactualaudiosamplesthereareandthenallocatespacetoholdtheaudiodata.Weare
using32bitintegers,butyoucouldalsouse16bitintegers.Thenumberofbitsinyouraudiosamplesindicatesthe
verticalresolutionofyouraudiodata,orhowmanyuniquevaluesthereare.in16bitints,thereare65536different
http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/ 3/6
11/4/2017 DIYSynth1:SoundOutput|Theblogatthebottomofthesea
values,andin32bitsthereare4.2billiondifferentvalues.Ifyouthinkaboutyourdataasplotsonagraph
(essentially,whatitis,whereXistimeandYiswaveamplitude)themorebitspersample,andthehigherthe
samplerate,thecloseryourgraphcanbetowhateverrealvaluesyouaretryingtouse(suchasasinewave).Less
bitsandalowersampleratemeanitsfartherawayfromtherealdatayouaretryingtomodel,whichwillcausethe
audiotosoundlesscorrect.
int32nValue=0;
for(intnIndex=0;nIndex<nNumSamples;++nIndex)
{
nValue+=8000000;
pData[nIndex]=nValue;
}
Hereweareactuallycreatingourwavedata.Weareusingthefactthatifyouhaveanintnearthemaximumvalue
youcanstore,andthenaddsomemore,itwillwraparoundtotheminimumvaluetheintcanstore.Ifyoulookat
thisonagraph,itlookslikeasawtoothwave,iewearecreatingasawtoothwave!Normallyyouwouldntcreate
themthiswaybecausethewaywearedoingitisharshontheear,andintroducessomethingcalledaliasing
(http://en.wikipedia.org/wiki/Aliasing).Inalatertutorialwellseehowtocreateabandlimitedsawtoothwaveto
makehigherqualitysound,butfornowthiswillworkfile!
youcanchangehowmuchisaddedtonValuetochangethefrequencyoftheresultingwave.Addasmallernumber
tomakeitalowerfrequency,addahighernumbertomakeitahigherfrequency.Wellgetintothemathofmore
finelycontrollingfrequencyinanotherchaptersoyoucanactuallymatchyourwavestonotesyouwatchtohit.
WriteWaveFile("outmono.wav",pData,nNumSamples*
sizeof(pData[0]),nNumChannels,nSampleRate,sizeof(pData[0])*8);
delete[]pData
Lastlywewriteourwavefileandfreeourmemory.
Tada!Alldone,wehaveasawtoothmonowavefilewrittenout,giveitalisten!
DIYSynthesizerChapter1:outmono.wav
WritingaStereoFile
Theonlythingthathasreallychangedinthestereofileisthatthereare2channelsinsteadof1,andhowwe
generatetheaudiodataisslightlydifferent.Sincethereare2channels,oneforleft,oneforright,thereisactually
doubletheaudiodataforthesamesamplerateandtimelengthwavefile,sinceitneedsafullsetofdataforeach
channel.
Theaudiodataitselfisinterleaved,meaningthatthefirstaudiosampleisfortheleftchannel,thesecondsampleis
fortherightchannel,thethirdsampleisfortheleftchannel,andsoon.
Hereshowtheaudioisgenerated:
int32nValue1=0;
int32nValue2=0;
for(intnIndex=0;nIndex<nNumSamples;nIndex+=2)
{
http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/ 4/6
11/4/2017 DIYSynth1:SoundOutput|Theblogatthebottomofthesea
nValue1+=8000000;
nValue2+=12000000;
pData[nIndex]=nValue1;//leftchannel
pData[nIndex+1]=nValue2;//rightchannel
}
Notethatfortherightchannelwewriteadifferentfrequencywave.Ididthissothatyoucantellthedifference
betweenthisandthemonofile.Playaroundwiththevaluesandtrymutingonechannelortheothertoconvince
yourselfthatitreallyisastereofile!
DIYSynthesizerChapter1:outstereo.wav
UntilNextTime
Thatsallforchapter1,thanksforreading.
Nextupwelltalkaboutthebasicwaveformssine,square,saw,square,andnoiseandwelltalkmoreabout
frequencyandoscillators.
Likethis:
Like
Bethefirsttolikethis.
Related
Comments
0comments
Addacomment...
FacebookCommentsPlugin
PostedinAudioSynthesis permalink[http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/]
http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/ 5/6
11/4/2017 DIYSynth1:SoundOutput|Theblogatthebottomofthesea
AboutDemofox
I'magameandengineprogrammeratBlizzardEntertainmentandhavebeenmakinggamessince1990(startingoutwith
QBasicandTI85games)Myshippedtitlesinclude:*HeroesoftheStorm*StarCraftII:HeartoftheSwarm&Legacyof
thevoid*InsanelyTwistedShadowPlanet(PC)*GothamCityImpostors(PC,360,PS3)*LineRider(PC,Wii,DS)Ialso
likehiking,makingmusic,learningcoolnewstuffandattemptingtheimpossible.
ViewallpostsbyDemofox
http://blog.demofox.org/2012/05/14/diysynthesizerchapter1soundoutput/ 6/6