Вы находитесь на странице: 1из 6

11/4/2017 DIYSynth1:SoundOutput|Theblogatthebottomofthesea

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

DIYSynth3:Sampling,Mixing, DIYSynth2:CommonWave DIYSynth:FlangeEffect


andBandLimitedWaveForms Forms March162015
June182012 May192012 In"AudioSynthesis"
In"AudioSynthesis" In"AudioSynthesis"

Comments
0comments

0Comments Sortby Oldest

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

Вам также может понравиться