JavaScript for Sound Artists: Learn to Code with the Web Audio...

254

Transcript of JavaScript for Sound Artists: Learn to Code with the Web Audio...

Page 1: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()
Page 2: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()
Page 3: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

JavaScriptforSoundArtistsLearntoCodewiththeWebAudioAPI

Page 4: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

JavaScriptforSoundArtistsLearntoCodewiththeWebAudioAPI

Authoredby:WilliamTurnerEditedby:SteveLeonard

Page 5: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

CRCPressTaylor&FrancisGroup6000BrokenSoundParkwayNW,Suite300BocaRaton,FL33487-2742

©2017byTaylor&FrancisGroup,LLCCRCPressisanimprintofTaylor&FrancisGroup,anInformabusiness

NoclaimtooriginalU.S.Governmentworks

Printedonacid-freepaperVersionDate:20161208

InternationalStandardBookNumber-13:978-1-138-96153-1(Paperback)

Thisbookcontainsinformationobtainedfromauthenticandhighlyregardedsources.Reasonableeffortshavebeenmadetopublishreliable data and information, but the author and publisher cannot assume responsibility for the validity of all materials or theconsequencesoftheiruse.Theauthorsandpublishershaveattemptedtotracethecopyrightholdersofallmaterialreproducedinthis publication and apologize to copyright holders if permission to publish in this form has not been obtained. If any copyrightmaterialhasnotbeenacknowledgedpleasewriteandletusknowsowemayrectifyinanyfuturereprint.

ExceptaspermittedunderU.S.CopyrightLaw,nopartof thisbookmaybe reprinted, reproduced, transmitted,orutilized inanyformbyanyelectronic,mechanical, orothermeans,nowknownorhereafter invented, includingphotocopying,microfilming, andrecording,orinanyinformationstorageorretrievalsystem,withoutwrittenpermissionfromthepublishers.

For permission to photocopy or use material electronically from this work, please access www.copyright.com(http://www.copyright.com/)orcontact theCopyrightClearanceCenter, Inc. (CCC),222RosewoodDrive,Danvers,MA01923,978-750-8400.CCCisanot-for-profitorganizationthatprovideslicensesandregistrationforavarietyofusers.FororganizationsthathavebeengrantedaphotocopylicensebytheCCC,aseparatesystemofpaymenthasbeenarranged.

Trademarknotice:Productorcorporatenamesmaybetrademarksorregisteredtrademarks,andareusedonlyforidentificationandexplanationwithoutintenttoinfringe.

LibraryofCongressCataloging-in-PublicationData

Names:Turner,William(Websitedeveloper),author.|Leonard,Steve(Websitedeveloper),author.Title:JavaScriptforsoundartists:learntocodewiththeWebAudioAPI/WilliamTurner,SteveLeonard.Description:BocaRaton:Taylor&Francis,CRCPress,2017.Identifiers:LCCN2016032832|ISBN9781138961531(pbk.:alk.paper)|ISBN9781138731134(hardback:alk.paper)Subjects:LCSH:Computersoundprocessing.|JavaScript(Computerprogramlanguage)|Webcasting.Classification:LCCTK7881.4.T872017|DDC006.5--dc23LCrecordavailableathttps://lccn.loc.gov/2016032832

VisittheTaylor&FrancisWebsiteathttp://www.taylorandfrancis.com

andtheCRCPressWebsiteathttp://www.crcpress.com

Page 6: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Contents

Preface

Acknowledgment

1.OverviewandSetupWhatIsaProgram?WhatIsJavaScript?HTML,CSS,andJavaScriptWhatIsaWebApplication?WhatIstheWebAudioAPI?SettingUpYourWorkEnvironment

SetupViewinBrowserforWindowsSetupViewinBrowserforMac

HowtoCreateCodeSnippetsAccessingtheChromeDeveloperToolsTroubleshootingProblemsandGettingHelp

2.GettingStartedwithJavaScriptandtheWebAudioAPIHelloSoundProgramVariablesnullDocumentingYourCodewithCommentsExploringVariableswithanOscillatorconsole.log()String

Built-InStringMethods

Page 7: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

toUpperCase()toLowerCase()charAt()replace()slice()

ThelengthPropertyNumbers

HowtoDeterminetheDataTypeofaVariableExamplesofArithmeticOperatorsExamplesofPrecedenceMath.min()andMath.max()Math.ceil()andMath.floor()Math.random()Math.abs()

Number-to-StringConversionArrayspush()pop()shift()unshift()concat()

Summary

3.OperatorsWhatAreOperators?

AssignmentOperatorsAssignmentAdditionAssignmentSubtractionAssignmentMultiplicationAssignmentDivisionAssignmentModuloAssignment

TheBooleanDataTypeComparisonOperators

EqualityOperatorStrictEqualityOperatorGreaterThanandLessThanOperatorsGreaterThanorEqualtoOperatorLessThanorEqualtoOperatorNotEqualtoOperator

Page 8: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

StrictNotEqualtoOperatorLogicalOperatorsTheLogicalANDOperatorTheLogicalOROperatorTheNOTOperator

Summary

4.ConditionalStatementsandLoopsConditionalStatements

TheifStatementTheswitchStatementTernaryOperator

LoopsforLoops

UsingforLoopswithArrayswhileLoopsWhentoUseforLoopsandWhentoUsewhileLoops

Summary

5.FunctionsFunctions—ASimpleExample

PartsofaFunctionFunctionExpressionsAbstractingOscillatorPlaybackAWorkingEffectsBoxExampleTheArgumentsObject

FunctionScopeWhyYouShouldAlwaysDeclareYourVariableswithvar

VariableHoistingHowHoistingAffectsFunctions

AnonymousFunctionsClosures

WhatIsaClosure?CallbackFunctions

WorkingwithJavaScript’sBuilt-InCallbackFunctionsfilter()map()

Recursion

Page 9: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Summary

6.ObjectsJavaScriptDataTypesLoopingthroughObjectsWhentoUseObjectsRatherThanArraysHowtoCheckIfanObjectHasAccesstoaParticularPropertyorMethodCloningObjectsPrototypalInheritanceThe"this"KeywordThebindFunctionSummary

7.NodeGraphsandOscillatorsTheAudioContext()MethodNodeGraphsOscillatorsThestopMethodTheonendedPropertyHowtoStopOscillatorsandRestartThemThetypePropertyThefrequencyPropertyThedetunePropertySummary

8.UsingHTMLandCSStoBuildUserInterfacesWhatIsaUserInterface?

HTMLExplanationoftheHTMLTemplateUnderstandingHTMLElementsFormandInputElements

CSSCommentsElementSelectorsGroupingSelectorsDescendentSelectorsChildSelectors

Page 10: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

classandidModifyingtheAppInterfaceMargin,Border,andPaddingRemovingListElementBulletPointsFontSize,Style(Type),andColorCenteringBlock-LevelElementsSummary

9.DOMProgrammingwithJavaScriptHowDoesJavaScriptCommunicatewiththeDOM?

HTMLJavaScript

BuildingtheApplicationHowtoTriggeranOscillatorbyClickingaButtonTogglingtheStart/StopTextProgrammingtheFrequencySliderChangingtheFrequencyinRealTimeChangingWaveformTypesCompletedCodewithWaveformSelectionGivinganOutlinetotheSelectedWaveformTypeSummary

10.SimplifyingDOMProgrammingwithJQueryWhatIsJQuery?JQuerySetupReferencingJQueryDirectlyUsingJQueryfromaCDNHowtoUseJQuerySelectingHTMLElementsStoringDOMSelectorsasVariablesUsingMethods

HTMLJQuery/JavaScripttoChangeaSinglePropertyJQuery/JavaScripttoChangeMultipleProperties

MethodChainingHTMLCSSJQuery/JavaScriptHTML

Page 11: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

JQuery/JavaScriptThethisKeyword

HTMLJQuery/JavaScript

RefactoringtheOscillatorPlayertoUseJQueryWithoutJQueryWithJQuery

SettingUptheEventListenerfortheUser-SelectedListElementEventListenerwithoutJQueryEventListenerwithJQuery

ModifyingtheCodeinsetIntervalsetIntervalMethodwithoutJQuerysetIntervalMethodwithJQueryonOffMethodwithoutJQuery$onOffSelectorwithJQuery

Summary

11.LoadingandPlayingAudioFilesPrerequisitesTheTwoStepstoLoadinganAudioFileTheXMLHttpRequestObjectgetRequests

AWordonAudioFileTypeCompatibilitySynchronousversusAsynchronousCodeExecutionProcessingtheAudioBufferwiththeNodeGraphSummary

12.FactoriesandConstructorsJavaScriptandtheConceptofClassWhatAreClasses?TheFactoryPatternDynamicObjectExtensionPrivateDataGettersandSettersConstructorsandthenewKeywordAddingMethodstoConstructorsThePrototypeObjectandthePrototypePropertyWhyDoConstructorsExistIfYouCanDotheSameThingwithFactories?

Page 12: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Summary

13.AbstractingtheFileLoaderThinkingaboutCodeAbstractionCreatingtheAbstractionWalkingthroughtheCodeSummary

14.TheNodeGraphandWorkingwithEffectsHowtoThinkAbouttheNodeGraphGainNodesThePlacementofNodesIsUptoYouWhatEffectsAreAvailable?HowtoDeterminetheNodesYouNeedtoCreatetheEffectYouWantAReal-WorldExampleSomeEffectsRequireDevelopmentWorkSummary

15.TheBiquadFilterNodeUsingtheBiquadFilterNodeFilterTypesCreatinganEqualizerGraphicEQParametricEQSummary

16.TheConvolverNodeConvolutionReverbWheretoGetPre-RecordedImpulseResponseFilesUsingImpulseResponseFiles

HTMLJavaScript

ControllingtheAmountofReverberationSummary

17.StereoPanning,ChannelSplitting,andMergingTheStereoPannerNode

Page 13: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheChannelSplitterTheChannelMergerMergingAllChannelsofaMultichannelFileintoaSingleMonoChannelUsingtheMergerandSplitterNodesTogetherSummary

18.TheDelayNodeTheDelayNodeCreatingEchoEffectsCreatingSlapBackEffectsCreatingaPing-PongDelaySummary

19.DynamicRangeCompressionTheDynamicsCompressorNodeSummary

20.TimeTheTimingClockThestartMethodLoopingSoundsUpdateYourAudioLoaderLibraryChangingAudioParametersoverTimeTheAudioParameterMethods

ThesetValueAtTimeMethodTheexponentialRampToValueAtTimeMethodThelinearRampToValueAtTimeMethodThesetTargetAtTime()MethodThesetValueCurveAtTime()Method

Summary

21.CreatingAudioVisualizationsABriefWordonFourierAnalysisABriefExplanationofBinary-CodedDecimalNumbersTheSpectrumAnalyzer

JavaScript/JQueryHTML

Page 14: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

CSSWalkingthroughtheCodeStoringtheFrequencyDatainanArrayHowtoThinkAboutthefrequencyDataArray

BuildingtheDisplayInterfaceConnectingtheAnalyzertotheDOMSummary

22.AddingFlexibilitytotheAudioLoaderAbstractionTheUpdatedInterfaceModifyingtheLibraryModifyingaudioBatchLoaderAnExplanationofthePreviousCodeEditSummary

23.BuildingaStepSequencerTheProblemCanIUsesetIntervalorsetTimeout?TheSolutionHowItWorksChangingTempoBuildingtheSequencerPlayingBackSoundsinSequenceCreatingtheUserInterfaceGrid

HTMLCSS

AddingInteractivitytotheGridElementsSummary

24.AJAXandJSONAJAXJSONMakinganAJAXCalltotheiTunesSearchAPIHowtheCodeWorks

HTMLJavaScript

CreatingYourOwnWebAPItoReferenceSynthesizerPatchDataTheDataStructure

Page 15: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HTMLCSS

HowtheCodeWorksBuildingontheAPIdata.jsmodule.js

ExtendtheJSONObjectSummary

25.TheFutureofJavaScriptandtheWebAudioAPITheWebAudioAPI1.0

3DSpacialPositioningRawModificationofAudioBufferDataSuggestionsforContinuedLearning

JavaScript6node.jsTheWebMIDIAPIOpenSoundControl

SummaryFurtherReadingBookWebsite

Index

Page 16: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Preface

Learningtoprogramcanbedaunting,andwewanttobethefirsttocongratulateyoufortakingonthechallenge!Second,wewanttothankyouforchoosingthisbook.

WhoIsThisBookFor?Thisbook is for anyonewho is involved in theworldof creative audio andwants to learn toprogram using the JavaScript language. There are many programming books directed towardartiststohelpthembuildwebsites,mobileapplications,games,andotherthings,butnexttononeisdirectedexclusively towardthesoundartscommunity.Thisbookisdesignedtofill thisroleandtoteachthefundamentalsofweb-basedsoftwaredevelopment,andspecifically,thebasicsoftheJavaScriptprogramminglanguagetosoundartists.

WhatThisBookIsNotThis book is not an audio technology reference. It does not take the time to explain thefundamentals of audio theory or sound engineering in depth.Words and phrases like dynamicrangecompression,convolutionreverb,andsampleratearethrownaroundlikecandywithonlyacursoryexplanation(iftheyareexplainedatall).Weassumethatyouareeitherfamiliarwithmanyofthesecoreaudioconceptsorknowenoughtofindtheanswersonyourown.Ifyouneedanaccommodatingaudiotechnologyreference,wesuggestDavidMilesHuber’sexcellentbookModernRecordingTechniques,Taylor&Francis.

ThisbookisalsonotdirectedtowardexperiencedprogrammerswhoaresimplyinterestedinJavaScriptortheWebAudioAPI.Ifthisdescribesyou,thenyoumayfindsomevaluehere,butyouarenottheintendedaudience.

Page 17: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HowtoLearntoProgramThefollowingareafewtipstohelpyougetthemostfromthisbook.

MakeConnectionsGenerally, it iseasier to learnnewthingsbymakingassociationsandconnections toareas thatyouarealreadyfamiliarwith.IfyouhaveeverprogrammedasynthoraMIDIsequencer,thenyouhavealreadydoneaformofprogramming.Thecontentsofthisbookaredesignedtobeabridgethatconnectsaworldyouare(presumably)familiarwith(soundandaudiotechnology)toatopicyouarelessfamiliarwith—JavaScriptandprogramming.Wesuggestthatyoutapintowhateverhasdrawnyoutosoundartwhilelearningthematerialinthisbook.

FlowandFrustrationAreNotOppositesIt’sveryimportanttoembraceasenseofflowwhenlearningtoprogram.Itisalsoimportanttoembrace frustration as part of the flow state and not as the antithesis of it. When you learnsomethingnew, theneurons inyourbrainaremakingconnections; thismayphysically feel likefrustration,butitjustmeansyourbrainisrewiring—literally.Embracethis.

MakeItHabitualProgramming isallabout learningabunchof little things thatcombine tomakebig things.Thebestway to learna lotof little things is through repetitionandhabit.Oneway todo this is tosimplyacceptprogrammingasanewpartofyourlifestyleanddoalittlebit(oralot)everyday.

BeCreativeandHavePersonalProjectsItisagoodideatohaveyourownpersonalprogrammingprojects.Themoreyouarepersonallyinvestedinaproject,themoreyouwilllearn.

TalkandTeachOneofthebestwaystovalidateyourownlearningis toteachsomeoneelse.Ifyoudon’thaveanyone to teach, thenyoucansubstitute thisbywriting tutorials.Thiswill forceyou tocollectyourthoughtsandexpressthemclearly.

KeepGoing

Page 18: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Ourfinalpieceofadviceistosimplystickwithit.Bestofluck!Ifyouhaveanyquestionsorcomments,youcanfindusat:http://www.javascriptforsoundartists.com

WilliamTurnerSteveLeonard

Page 19: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Acknowledgment

ThankstotechnicalassistantKeithOppel.

Page 20: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

1OverviewandSetup

WhatIsaProgram?Aprogramisanysetofinstructionsthatiscreatedorfollowed.Inthisbook,wefocusonwritingcomputerprograms,whicharelistsofinstructionsthatacomputercarriesout.Theseinstructionscanbewritten and stored in various forms.Someof the firstmodern computers usedpunchedcards,switches,andcables.Earlyanalogmusicsynthesizerswereatypeofcomputerthatusedapatchbaystyleinterfacetomanuallyallowaprogrammertocreatespecificsounds.

WhatIsJavaScript?JavaScriptisamultipurposeprogramminglanguageinitiallycreatedtoaiddevelopersinaddingdynamicfeaturestowebsites.Thelanguagewasinitiallycreatedin11daysandreleasedin1995by a company called Netscape. Developed by Brendan Eich, its original release name wasLiveScript.WhenNetscape introducedsupport for the language in itsbrowser,LiveScriptwasrenamedJavaScript.AlthoughJavaScript issimilar innameto theJavaprogramminglanguage,they are completely unrelated. Today, JavaScript is used in everything from robotics to homeautomationsystems.

HTML,CSS,andJavaScriptThethreemaintechnologiesusedtobuildwebsitesandwebapplicationsareHTML,CSS,andJavaScript.

HTML stands for hypertext markup language and is the standard by which we createdocuments for the World Wide Web. You program HTML by writing elements (sometimesreferred to as tags for brevity). These elements contain text and other nested elements, whichmakeupthedocument’scontent.

Page 21: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

CSSstandsforcascadingstylesheetsandisatoolusedtomodifyhowHTMLelementsandtext are presented. CSS is primarily a visual design tool. For example, with CSS you couldmodify an HTML element and give it an orange background, change its font size, place itverticallyorhorizontally,orperformanynumberofcreativevisualchanges.

JavaScriptisusedtoaddinteractiveresponsestouserinput.Everytimeauserclicks,scrolls,taps,moves themouse cursor, types, or performs an interactive event, JavaScript code canbetriggeredtochangethepageinsomemanner.TheJavaScriptlanguagewasinitiallydesignedtoperformthesefunctionswithinthecontextofdesigningwebsitesandapplications.

WhatIsaWebApplication?

Page 22: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

A web application is any website that contains more than static, non-interactive pages. Thismeansthat,inawebapplication,thepageshavesomeinteractivecomponentsinadditiontothestatic text and images displayed. In the early days of the World Wide Web, websites werecomposed mostly of collections of static documents connected through highlighted text calledhyperlinks.Thesestaticpageshadnointeractionwithdatabases.Intheearly1990s,thisbegantochange, and web developers began creating websites that had features similar to desktopapplications that allowed users to interact with the page via form fields, buttons, and otherinteractivemeanstosenddataoverawebservertoandfromadatabase.

Early web applications were slow and limited by the technology of the time. In the early2000s,aculminationoftechnicalshiftsthatincludedclient-side-ratherthanserver-side-focusedwebapplicationshelpedmakewebapplicationsmoreresponsive.Partofthisshiftisattributableto a technology called AJAX (asynchronous JavaScript and XML). This technology pusheddynamicwebapplicationdevelopmentforwardbyallowingthebrowsertoretrieveandsenddatatoawebserverwithouthavingtoautomaticallyrefreshthepageintheprocess.AstheJinAJAXindicates, JavaScript is central to this technology, andwebapplicationsbegan to approach theinteractivespeedoftheirdesktopcounterparts.

As you might expect, within the audio world there were attempts to leverage this newtechnology, which resulted in browser-based audio players, editors, and musical instruments.Many of these applications were initially written using a technology called Flash. This is aproprietarytechnologythatrequiredtheusertodownloadandinstallanadditionalplug-intorunallprogramswritteninit.

In2008,anewerversionof theHTMLstandardwaswritten,calledHTML-5.Thisversionincludedanaudioplayer thatcoulddirectlystreamsound filesoffawebserverusingasinglelineofHTMLcode.Theplayeralsoincludedbuilt-in,user-facingcontrolsforplay,fast-forward,rewind,pause,stop,loop,andotheractions.However,forseriousaudiodevelopment,thiswasinadequate. Web application developers and audio aficionados wanted something more fullyfeatured.

WhatIstheWebAudioAPI?TheWebAudioAPIisaseriesofexposedcodepiecesthatyoucanusetoaccomplishmusicalandaudiotasksinawebbrowserwithlesseffortthanifyouweretocreatethemallfromscratch.The unexposed portion of theWeb Audio API lies in the web browser’s source code and iswritten inwhatever language theweb browser itself iswritten in. The technical core ofwebbrowsers is usuallywritten inmultiple lower-level languages,which can include (but are notlimitedto)C++,Java,andmachinelanguage.

TounderstandtheWebAudioAPI,youmustfirstunderstandwhatanAPIis.APIstandsforapplication programming interface. AnAPI is a portion of code that a programmer is givenaccessto,whichcontrolsalargerunseenbodyofcodewithincertainconstraints.Imagineif,inorder to learn how to play your favoritemusical instrument, you had to literally build it fromscratch.Asyoucan imagine, thiswouldgetvery tedious—especially if the instrumentwere tobreak. Thus, it’s much more convenient to learn to play a premade musical instrument. The

Page 23: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

conveniencehere is that theconstructionprocess is removedandyouronlyconcern iswhat isimportant to you, which is the controls needed to use the instrument. In a similar manner,programmerswriteAPIsthatexposeonlysmallpiecesofcodefordeveloperstouse,andthesesmallpiecesofcodeallowyoutodoalotofworkwithminimaleffort.

Inadditiontobeingable to loadandplaybacksoundfiles, theWebAudioAPIalsoallowsyoutogeneratesoundfromscratchintheformofoscillators.Youcanthenmanipulateanysoundplayback or generation using filters, reverb effects, dynamic compressors, delay effects, and ahostofotheroptions.

SettingUpYourWorkEnvironmentTobeginworking,youmustfirstdeterminewhatbrowseryouaregoingtotroubleshootwith.Inreal-worldenvironments,youwoulduseatestsuitetotroubleshootamongdifferentbrowsersandplatforms.Inthisbook,wearegoingtokeepthingssimpleandonlyuseGoogleChrome.Thenextthingyouneedisacodeeditor.Fortheexercises,weassumeyouwillbeusingtheSublimeTexteditor.Technically,youcanuseanycodeeditoryouwant,butSublimeTextisofferedasafreetrialdownloadandisextremelypowerfulandwidelyused.Wethinkit’sworthyourinvestmentoftimetolearnit.

Thenextthingyouneedtodoiscreateafolderwithabasicworktemplate.

1. If you are not already using it, go to this URL to download and install Google Chrome:https://www.google.com/chrome/browser/desktop/.

2.Gotohttp://www.sublimetext.com/anddownloadandinstallSublimeText.

3.Createafolderonyourdesktoporinadirectoryandcallitwebaudiotemplate.

4.OpenSublimeText,and in thewindowthatappears, type thefollowingcode into it.Thensave the file (go to the Filemenu in SublimeText and clickSave As) as index.html andchooseyourwebaudiotemplatefolderasthedirectorytosaveitin.

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>app</title><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head><!--__________________________________________BEGINAPP--><body>

</body><!--____________________________________________ENDAPP--></html>

5.Insidethewebaudiotemplatefolder,createanotherfoldercalledcss.

Page 24: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

6.InSublimeText,createanewfilebygoingtotheFilemenuandclickNew.Savethisfileinyourcssfolderasapp.css.Leavethecontentsofthisfileempty.

7.Inthewebaudiotemplatefolder,createanotherfoldercalledjs.

8. Create a new empty document in Sublime Text, then type "use strict"; (includingquotations and semicolon) at the top of it and save it as app.js in the js folder you justcreated. This places your JavaScript in strict mode. Strict mode is a restrictive form ofJavaScriptthatenforcesbetterprogrammingpractices.AllJavaScriptcodeexamplesinthisbookwillassumeyouhavestrictmodeenabled.

You are now going to add a few extensions to SublimeText thatwillmakeworkingwith theeditoreasierinthelongterm.Todothis,youmustfirstdownloadandinstallthepackagemanagerplug-in. Go to the following link and follow the directions on the left side of the window:https://packagecontrol.io/installation.Whendone,closetheconsolebyenteringthekeys:Ctrl+`(apostrophe,onthekeywiththe~).

1. In the Sublime Text menu, go to Tools >Command Palette, and in the form field thatappears,typeinstall.YoushouldseeanoptionmenuappearthatsaysPackagecontrol:Installpackage.Clickthismenuoption.

2.Anotherformfieldwithaseriesofoptionsappears.Thisformfieldallowsyoutosearchandexplorevariousplug-insforSublimeText.Youarenowgoingtoinstallaplug-inthatallowsyoutocreatealocalwebserverthatwillbenecessarywhenworkingwithaudiofiles.Intheformfield,typeSublimeserver.Alistofsearchresultsshouldappear.Clickthefirstone. Look at the bottom of the Sublime Textwindow, and you should see “installing” insmall text.When this process is done, quit and restart Sublime Text.We will cover thespecificsof thewebserver ina laterchapter.Butrestassuredthat thissetupwillbe timewell spent. To verify that the plug-in is installed, go to Tools > SublimeServer > StartSublimeServer. Open your web browser to http://localhost:8080/, and it should displaySublimeServeratthetopofthepage.

3.Thislastplug-inyouaregoingtoinstallletsyouopenHTMLfilesinChromefromwithinSublimeText.ToinstalltheViewinBrowserplug-in,gotoTools>CommandPaletteandin the form field that appears, typeinstall. ClickPackage control: Install package.Then do a search forView inBrowser, and select the first option that appears.Once theinstallationisdone,youwillneedtogotothefollowingmenutosetuptheplug-intoworkwithChrome.

SetupViewinBrowserforWindowsInSublimeText,go to thePreferencesmenuandclickPackageSettings.Lookfor theView inBrowsermenuitem,hoveroverit,andselectSettings–Default.Selectallthecodeyouseeandcopyit.YouarenowgoingtopasteitintotheSettings–Userpageof thesameplug-in.SogobacktothePreferencesmenuandselectPackageSettings>ViewinBrowser>Settings–User.

Page 25: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Pasteallthecodeyoujustcopiedintothiswindow.Attheverybottom,youshouldseealineofcodethatsays“browser”:“firefox”.Changethewordfirefoxtoeitherchrome,orchrome64 ifyouhavea64-bitoperatingsystem.Itshouldlooklikethis:“browser”:“chrome”or“browser”:“chrome64”.IfyouopenanemptydocumentinSublimeTextandusethekeycommandCtrl+Alt+V,Chromeshouldlaunchandopenthatpage.

SetupViewinBrowserforMacAs soon as the plug-in is downloaded, you should be able to open an empty Sublime TextdocumentinChromeusingthekeycommandControl+Option+C.

HowtoCreateCodeSnippetsItcanbehelpfultoknowhowtocreatecodesnippetsthatyoucanaccesswithoutwritingthemoutcharacter-by-charactereverytime.Thankfully,SublimeTexthasafeaturethatallowsyoutodothiswithsnippets.Tocreateasnippet,dothefollowingsteps:

1.InSublimeTextmenu,gotoTools>NewSnippet.

2.Inthewindowthatappears,deleteeverythingonline3andpastethefollowingtext:Thisisatestsnippet.

3.Online6,removethe<!--and-->charactersandtypethewordtestinbetweenthetwoelements.Theresultshouldlooklikethis:<tabTrigger>test</tabTrigger>.

Page 26: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

4.Savethefileinthedefaultdirectorythatappearsandcallittest.sublime-snippet.

5.Openyourindex.htmlfileinSublimeText,typethewordtest,thentaptheTABbuttononyourkeyboard.Thephrase"thisisatestsnippet"shouldappearintheeditor.

AccessingtheChromeDeveloperToolsGoogleChromehasabuilt-insuiteoftroubleshootingtoolscalledtheChromeDeveloperTools.Youcanaccessthesetoolsbyopeningthebrowserandusingthekeycommands:

WindowsOSorLinux:Ctrl+Shift+J

Mac:Command+Option+J

Wearenotgoingtogoovertheutilityofthedevelopertoolsjustyet,buttheywillbehighlightedthroughoutthebook.

TroubleshootingProblemsandGettingHelpIfyouhaveanytrouble,tryusingsearchenginestoresearchsolutions.Oneverygoodresourceishttp://stackoverflow.com,whichisacommunityofprogrammerswhoaskandanswerquestions.TheyhaveanicesectiononJavaScriptaswellasalivelyWebAudioAPIcommunitythatyoucanfindat:http://stackoverflow.com/questions/tagged/web-audio.

Page 27: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

2GettingStartedwithJavaScriptandtheWebAudioAPI

HelloSoundProgramInanintroductiontoaprogramminglanguage,thefirstprogramyouwriteisoftencalled“HelloWorld,”which prints thewords “HelloWorld” on the screen. Becausewe are using theWebAudioAPItocreatesounds,thissectionexplainshowtocreatea“HelloSound”applicationthatimmediatelyplaysasoundwhenyourunit.

Copythefolderwebaudiotemplatefromthelastchaptertoanewdirectory,andrenamethecopytohello_sound.

Typethecodebelowintotheapp.jsfilethatispresentwithinthehello_soundfolder.Saveitandthenlaunchtheindex.html filefromyourwebbrowser.Youshouldhearabasicsinewaveoscillatorplaying.varaudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sine";osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

AfteryouverifythattheHelloSoundprogramworks,closethebrowser.YoujustwroteyourfirstWebAudioAPIprogram!

Thecodeyoujustranisabasicoscillatorgenerationandplaybackscript.Thefirstlineinthescriptiscalledthe“AudioContext”andthistellsthebrowserthatyouareusingtheWebAudioAPI.Thenextlineofcodecreatesanoscillator.Thethirdlineofcodeassignsawaveformtypetothe oscillator, whereas line four connects the oscillator to a virtual audio output called thedestination, which is analogous to the speakers of your computer. The last line starts theoscillator playing.Wewill cover detailed operation of theWebAudioAPI in future chapters.First,though,weneedtocoverthebasicsoftheJavaScriptlanguage.

Page 28: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

VariablesOneof the first steps inwritingaprogram isunderstandingvariablesandvariableassignment.Variablesarewordformsthatareusedtostoredata.Forexample:varwaveformType="sawtooth";

Thevariable here is namedwaveformType.This is precededby thevar keyword.Youalwaysspecifythevarkeywordpriortodeclaringthevariable.Declaringavariablemeansyouarecreatinganewvariable.Afterthevarkeyword,youtypeaspaceandgiveanametoyourvariable.Variablenamesaretypicallyareflectionofsomethingtheyrepresent.Inthiscase, thevariable is being used to describe a type of oscillator waveform and so is namedwaveformType. You probably noticed the odd capitalization of the word “type” inwaveformType. The convention of capitalizing words to distinguish them within variablenamesiscalledcamelcase.Thisconventionisusedbecausevariablenamescannotcontainwhitespacetoseparatethem.Ifyourewrotethevariableinthefollowingmanner,yougetanerror:varwaveformtype="sawtooth";//____returnsanerror

Type theabovecode into theapp.js fileofyourhello_sound template.LaunchChromeandopenthedevelopertools(Windows:Ctrl+Shift+JorMac:Command+Option+J).Insidetheconsoletab,youshouldseeanerrorsimilartotheoneinthefollowingimage.

Thetextingrayistheactualerrorandisidentifiedasasyntaxerror.Totherightoftheerror,youcanseethefileandthelinenumberwheretheerroroccurred.Thisnumbercorrespondstothelinenumber inyour file,whichmightdiffer fromtheone in the image.Afteryousee theerror,removethelineyouaddedthatiscausingtheerrorinapp.jsandsavethefile.

Afteryoudeclareandnameavariable,youcanassignsomedatatoit.Youusetheassignmentoperator“=”todothis.

ItisimportanttounderstandthatinJavaScriptthe“=”symbolisnotcalledtheequalsignanditsfunctionalitydoesnotmeanequalto.The“=”symbolindicatesassignment,soitiscalledtheassignmentoperator.Thevalueontherightsideoftheassignmentoperatorcontainsthedatayouwant to assign to the variable name on the left side. In the following example, the string"sawtooth"isassignedtothevariablewaveformType.varwaveformType="sawtooth";

When you assign a string of words to a variable, you must place them between quotationmarks.Theresultingdatatypeiscalledastring.Datatypesrepresentthetypesofdatathatyou

Page 29: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

canuseinyourprogram.Differentprogramminglanguageshavedifferentdatatypes.JavaScripthassixdatatypes,andoneoftheseisthestringdatatype(seeChapter6foralistofJavaScriptdatatypes).

Afteryouassigndatatoyourvariable,youmustendthevariabledeclarationwithasemicolon.Insummary,therearefivepartstoavariabledeclaration:

■Thevarkeyword

■Thevariablename

■Theassignmentoperator

■Thedatayouwishtoassigntothevariable

■Theclosingsemicolon

Youcanassignmultiplevariablesatonceusingthefollowingsyntax:varosc1=1200,osc2=1300,osc3=100;

In some cases, you might want to declare a variable and not assign data to it, as in thefollowingexample:varwaveformType;

If you do this, JavaScript automatically assigns undefined to it. You can also assignundefinedexplicitlylikethis:

varwaveformType=undefined;

Thekeywordundefined is another JavaScriptdata type.Notice thatundefined is notenclosedinquotationmarksbecauseitisnotastringbutrepresentsadatatype.

nullThe primitive valuenull is similar to the primitive valueundefined. Both can act as aplaceholderforemptyvariables.Whenthetypeofoperator(discussedlaterinthischapter)isusedtodeterminethetypeofnull,theresultisobject.Thisisnotwhatyoumightexpectandisaflawinthelanguage.Thecorrectreturnedvalueshouldbenull.Becauseofthis,wesuggestthatyouneverusenullandalwaysuseundefined.

DocumentingYourCodewithComments

Page 30: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Whenyouareprogramming,itisagoodhabittotypemessagesintoyourcodethatareintendedtobe read by human beings (yourself or others) and not be interpreted by the computer. Thesemessagesarecalledcomments.Youcanwrite either single-lineormultiline comments inyourprogram,andtheylooklikethis://Thisisasinglelinecomment.//Itbeginswithtwoforwardslashcharacters//Theseendattheendoftheline/*Thisisamulti-linecommentandbeginswithaforwardslashandasterisk.Itendswithanasteriskandaforwardslash*/

Inareal-worldscenario,wemightcommentourcodelikethis:varwaveformType="sawtooth";//oscillatorvariable

Allthecharactersfromthe//totheendofthelineareignoredbythecomputer.

ExploringVariableswithanOscillatorNowthatyouunderstandwhatvariablesare,thefollowingexampleshowshowyouusethem.

Open up the code you wrote at the beginning of this chapter, and add the variablewaveformTypetoit,asinthefollowingcode:varaudioContext=newAudioContext();varwaveformType="sawtooth";//___addedvariablevarosc=audioContext.createOscillator();osc.type="sine";osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

Replacetheosc.typeassignmentwiththewaveformTypevariablelikethis:varaudioContext=newAudioContext();varwaveformType="sawtooth";//___addedvariablevarosc=audioContext.createOscillator();osc.type=waveformType;//__Assignedittoouroscillatortypeosc.connect(audioContext.destination);osc.start(audioContext.currentTime);

Launchyourwebbrowser,andinsteadofhearingasinewaveform,youshouldhearasawtoothwaveform.

In this example, the following declarations assign values to variables that represent otherwaveformtypes.varaudioContext=newAudioContext();//___4variablesthatrepresentoscillatorwaveformsvarsaw="sawtooth";varsine="sine";vartri="triangle";varsquare="square";//___AvariableintendedtocontainoneofthesewaveformsvarcurrentWaveform=undefined;currentWaveform=square;

Page 31: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//_____________________________Startofoscillatorvarosc=audioContext.createOscillator();osc.type=currentWaveform;//Assignedittoouroscillatortypeosc.connect(audioContext.destination);osc.start(audioContext.currentTime);

Eachofthefournewvariablescontainsastringthatrepresentsanoscillatorwaveformtype.ThesquarevariableisassignedtothecurrentWaveformvariableinthefollowingline:

currentWaveform=square;

Notice thatnonewdeclaration is required for thecurrentWaveform variable to assign(andreplace)whateverwaspreviouslyassignedtoit.Thenewdataontherightsideof“=” isassignedtocurrentWaveform.Ifyoulaunchyourwebbrowser,youwillhearasquarewaveplay. In programming, being able to overwrite variables in this manner is referred to asmutability(changeability),andwesaythatvariablesaremutable.Theoppositeofthisiscalledimmutability.

console.log()Whenprogramsbegintogetbig,itcanbedifficulttoknowwhatvalueisassignedtoavariableatany given moment. One way you can find out is by using a built-in feature calledconsole.log().

Thewayyoudo this isby typingconsole.log() intoyourcodeat thepointwhereyouwant to check a given variable’s assignment. You then place the variable name inside theparentheses.

ToseewhatthecurrentWaveformvariablehasasitsassignment,youdothis:varaudioContext=newAudioContext();//Added4variablesthatrepresentoscillatorwaveformsvarsaw="sawtooth";varsine="sine";vartri="triangle";varsquare="square";varcurrentWaveform=undefined;currentWaveform=square;console.log(currentWaveform);//___square//____________________________________Startofoscillatorvarosc=audioContext.createOscillator();osc.type=currentWaveform;//Assignedittoouroscillatortypeosc.connect(audioContext.destination);osc.start(audioContext.currentTime);

LaunchChrome,openthedevelopertoolsandclicktheconsoletab;youwillseetheoutputofourconsole.log().

Onethingtorememberis thatbecausevariablescanhavedifferentvaluesatdifferent times,theoutputofconsole.log()dependsonwhereitisplacedintheprogram.Ifyoumodifythelast example and place console.log() immediately after the currentWaveformvariable,whichhasundefinedassignedtoit,thenundefinedisoutputtothelog.

Page 32: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//__________AvariableintendedtocontainoneofthesewaveformsvarcurrentWaveform=undefined;console.log(currentWaveform);//______resultsin"undefined"currentWaveform=square;

Sofarwe’vementionedthreeofthesixdatatypesinJavaScript.Thefirstwasstring, thesecondwasundefined,andthelastwasnull.

Beforewegofurther,let’sexplorethestringdatatypeabitmoreindepth.

StringAs we already discovered, strings are denoted by quotation marks. The variable below is astring:varoscillator="square";

You can manipulate strings in different ways. One of the most common is by combiningmultiplestringsintoonestring.Thisiscalledconcatenation,anditworksbyusingtheplussign(+)likethis:varoscillator="saw"+"tooth";console.log(oscillator);//sawtooth

Hereisanotherexampleofconcatenatingtwovariablesandstoringtheminanewvariable.varphrase="Thissoundisan";varsoundType="oscillator";varsentence=phrase+soundType;console.log(sentence);//"Thissoundisanoscillator".

Noticethatstringscancontainwhitespace.Thisisaperfectlyvalidstring,eventhoughitcontainsalotofwhite-spacecharacters:

varmyFavoriteSynthCompany="MyfavoritesynthcompanyisMoog";

Ifyouwanttogetthenumberofcharactersinastring,youcanusewhatiscalledthelengthpropertylikethis:console.log(myFavoriteSynthCompany.length);//33

Theoutputofthelengthpropertyincludesthewhite-spacecharactersofthestring.

Built-InStringMethodsJavaScripthasaseriesofbuilt-intoolscalledmethodsthatallowyoutomanipulatedata.Someofthesemethodsarespecificallydesignedtomanipulatestringdata.

Thesearecalledstringmethods.Toseehowtouseastringmethod,takealookattheexamplesofthetoUpperCase()and

toLowerCase()methods.

Page 33: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

toUpperCase()Thismethodchangesallthecharactersinastringtouppercase.varoscillator="sawtooth";oscillator.toUpperCase();//SAWTOOTH

toLowerCase()Thismethodchangesallthecharactersinastringtolowercase.varoscillator="SAWTOOTH";oscillator.toLowerCase();//"sawtooth"

Someusefulstringmethodsare:

charAt() Returnsacharacteratanygivenindexinastring

replace() Findsandreplacesagroupofcharactersinastring

slice() Extractspartofastring

Youdonotneedtoimmediatelymemorizehoweachofthesemethodsworks,butit’sagoodideatoknowaboutthem.Thisway,whenyoudoneedtoimplementanyofthefunctionalitiestheyprovide,youknowwhichtooltoreachfor.Ifyouwouldliketoexploremorestringmethods,agood resource is the Mozilla Developer Network at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String.

Let’sgothrougheachoneoftheseandexplainhowtousethem.

charAt()Thismethodgetsacharacteratanygivenindexvaluewithinastring.Forexample,ifyouhavethestring"oscillator-1"andwanttoknowwhatthesecondletterofthisstringiswithoutactuallylookingatit,youcandothis:varsound="oscillator";console.log(sound.charAt(1));//"s"

NowyoumightbewonderingwhycharAt(1)returns“s”andnot"o".Thereasonisthatthecountbeginsatzero.So,togetthefirstletterdothis:console.log(sound.charAt(0));//"o"

Whenanindexlistbeginswithzero,itiscalledazero-basedindex.

replace()

Page 34: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thismethodfindsagroupofcharactersinastringandreplacesthemwithanotherstring.Ifyouwanttoreplaceanentireword,youcandoitlikethis:varmyFavoriteSynthCompany="MyfavoritesynthcompanyisMoog.Moogisgreat!";varmyNewFavoriteSynthCompany=myFavoriteSynthCompany.replace("Moog","DaveSmithInstruments");console.log(myNewFavoriteSynthCompany);/*MyfavoritesynthcompanyisDaveSmithInstruments.Moogisgreat!*/

Asyouprobablynoticed,whenusing the replacemethod in thismanner itonly replaces thefirst instanceof thewordyouselect.To replaceall instancesof theword,youneed touse thefollowingsyntaxtogloballyreplacetheminthestring.varmyFavoriteSynthCompany="MyfavoritesynthcompanyisMoog.Moogisgreat!";varmyNewFavoriteSynthCompany=myFavoriteSynthCompany.replace(/Moog/gi,"DaveSmithInstruments");console.log(myNewFavoriteSynthCompany);/*MyfavoritesynthcompanyisDaveSmithInstruments.DaveSmithInstrumentsisgreat!*/

The g stands for global and the i denotes case insensitivity. If you want the stringreplacement to be case sensitive, you use ag and omit thei. These characters are part of apattern-matchinglanguageforstringdatacalledregularexpressions.Regularexpressionsareanadvancedtopicthatwillnotbecoveredfurtherinthisbook.

slice()Thismethodextractspartofastring.varoscillator="sawtooth";varsound=oscillator.slice(0,3);console.log(sound);//saw

LikecharAt(),slice()worksonazero-basedindex.Thismeansthefirstcharacterisalways zero.The slicemethod takes twovalues: a beginning indexvalue and an ending indexvalue.Whenamethodtakesvalues,theyarecalledarguments.ThecharAt()methodtakesoneargument.Theslice()methodtakestwoarguments.Theslicemethod’sfirstargumentiswheretheslicestarts,andthisvalueisincludedintheslice.Thesecondvalueiswherethesliceendsandisnoninclusive.Thismeansallthecharactersupto,butnotincluding,thesecondvalueareincludedintheslice.

ThelengthPropertyThelengthpropertyisanadditionaltoolthatallowsyoutogetthenumberofcharactersinastring.Apropertylookssimilartoamethodbutdoesnotincludeparenthesesanddoesnotrequireargumentstoreturnavalue.Thecharactercountofthelengthpropertystartsatone,notzero.

Page 35: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varinstrument="piano";console.log(instrument.length);//5

Ifyouwanttogetthelastvalueofastring,youcancombinethelengthpropertywith thecharAt()method.This allowsyou to retrieve the last character in a string in amanner thatdoesn’t require you to know how long the string is. The code shows an example of this. Thereason you subtract 1 from the length property is because the length property beginscountingatone,whereascharAt()beginscountingatzero.Therefore,yousubtract1fromthelengthpropertytocompensatefortheoffset.

varsound="oscillator-1";varoscNumber=sound.charAt(sound.length-1);console.log(oscNumber);//1

NumbersInJavaScript,numbersareadistinctdatatype.BelowisavariablenamedfrequencyValue,andit isassignedanumberof200.It is thenassignedtotheoscillator’spitch.IfyouplacethecodebelowinanewJavaScriptfileandrunit,youwillhearanoscillatorplayatafrequencyof200Hz.Modify thenumbervalueassigned to thefrequencyValuevariableand launch thecodetoheartheoscillatorplayatdifferentpitches.varaudioContext=newAudioContext();varfrequencyValue=200;//___CreatevariablefrequencyValuevarwaveform="sawtooth";varosc=audioContext.createOscillator();osc.type=waveform;//_____assignittotheoscillatorspitchosc.frequency.value=frequencyValue;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

HowtoDeterminetheDataTypeofaVariableYoucandiscernthedifferencebetweendatatypesinvariablesbyusingthetypeofoperator.

varwaveform="sine";varpolyphony=16;console.log(typeofwaveform);//stringconsole.log(typeofpolyphony);//number

Unlike strings, numbers do not use quotation marks. In fact, if you did use a number withquotationmarks,itsdatatypewouldnotbenumber,itwouldbestring.

Here’sanexample:varoscillators="6";varpolyphony=6;console.log(typeofoscillators);//stringconsole.log(typeofpolyphony);//number

Page 36: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youcandobasicmathwithnumbersusingthefollowingsymbols.Thesesymbolsarecalledarithmeticoperators.

+ Addition

− Subtraction

* Multiplication

/ Division

% Modulo

ExamplesofArithmeticOperatorsconsole.log(5+5);//10console.log(10-5);//5console.log(5*5);//25console.log(25/5);//5console.log(10%9);//1

Thelastsymbol(%)mightbenewtoyou,andit ispronouncedmoj-uh-loh.Thepurposeofthissymbolistooutputtheremainderofadivision.So,forexample:console.log(12%9);//Thisequals3

The precedent rules of algebra also apply. If you wrap a calculation in parentheses, thecalculationinsidetheparenthesesisperformedfirst.

ExamplesofPrecedencevaroscillator1=1000;varoscillator2=100;varoscillator3=20;varcombinedOscillator=oscillator1+(oscillator2*oscillator3);console.log(combinedOscillator);//3000

Ifyouwanttodomoreelaboratecalculations,JavaScripthasabuilt-intoolcalledtheMathobject,whichallowsyoutouseacollectionofmathmethodstomanipulatenumbers.

So, for example, if youwant to round a decimal number to its nearest integer, you can useMath.round()likethis:Math.round(1000.789);//outputs1001

Someusefulmathobjectmethodsare:

Page 37: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Let’sgoovereachof theseonebyone. Ifyouwould like toexploremoremathmethods, agood site is the Mozilla Developer Network at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math.

Math.min()andMath.max()Math.min() finds the smallest number in a collection of numbers, whereasMath.max()allowsyoutofindthelargestnumberinacollectionofnumbers.Math.min(5000,2000,80);//80Math.max(5000,2000,80);//5000//___________________________Withvariablesvarfreq_1=5000;varfreq_2=2000;varfreq_3=80;Math.min(freq_1,freq_2,freq_3);//80Math.max(freq_1,freq_2,freq_3);//5000

Math.ceil()andMath.floor()Thesetwomethodsturnadecimalnumberintoaninteger.Math.ceil()roundsuptothenexthigher integer value if there are any nonzero digits to the right of the decimal, whereasMath.floor()keepstheintegervalueafterdiscardingthedigitstotherightofthedecimal.Math.ceil(3.00333);//4Math.floor(3.9999);//3

Math.random()Therandommethodcreatesarandomnumberbetweenzeroandone.varrandomNumber=Math.random();console.log(randomNumber);//example:0.019790495047345757

You can combine Math.random() with Math.floor() to create a random numberbetweentwovalues.Theexpressioninthefollowingexamplecreatesarandomintegerbetween20and20,000.

Page 38: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varmax=20000;varmin=20;varrandomInteger=Math.floor(Math.random()*(max-min+1)+min);console.log(randomInteger);//Between20and20000

Math.abs()Theabsmethodallowsyoutogettheabsolutevalueofanumber.varnum=Math.abs(-100);console.log(num);//100

Thisisusefulforfindingthedifferencebetweennumericvariablesofunknownvalues.vara=1000;varb=5000;console.log(Math.abs(b-a));//4000

Number-to-StringConversionIf you want to convert between numbers and numeric strings, you can use the followingtechniques.

Toconvertastringtoanumber,placetheplussymbol(+)beforethestringlikethis:varnumericString="120";varnum=+numericString;//plussymbolconsole.log(num);//120console.log(typeofnum);//number

If youwant to convert a number to a numeric string, concatenate thenumberwith an emptystringlikethis:varnum=80;varnumericString=num+"";console.log(numericString);//80console.log(typeofnumericString);//string

Ifyouattempttodoamathoperationusingnonnumericvalues,sometimesyouwillreceiveareturnedvalueofNaN.Thisstandsfornotanumber.Hereisanexampleofattemptingtoaddtwovaluesinwhichonevalueisanumberandtheotherisnot.varosc1=undefined;varosc2=200;console.log(osc1+osc2);//NaN

Arrays

Page 39: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Arraysareaconstructthatholdsmultiplepiecesofdata.Youcanthinkofthemasvariablesthatholdmorethanoneitem.Arraysareexpressedusingbrackets,whereeachitemisseparatedbyacomma.Eachiteminthearrayisdesignatedanindexnumberwiththefirstitemstartingatzero.varwaveforms=[];//emptyarrayvarwaveforms=["square","sawtooth","triangle","sine"];//arraywithsomedata

Ifyouwanttoaccessanyofthesedata,youcanusethefollowingnotation:waveforms[0];//squarewaveforms[1];//sawtoothwaveforms[2];//trianglewaveforms[3];//sinewaveforms[4];//undefined(nodata)

Ifyouwanttoknowhowmanyitemsareinsideanarray,usethelengthpropertylikethis:

varwaveforms=["square","sawtooth","triangle","sine"];waveforms.length;//4

Arrayscomewithbuilt-inmethodsthatyoucanusetomanipulatethedatainthem.Afulllistofthese are available at the Mozilla Developer Network at this URL:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array. Weareonlygoingtogooverahandfuloftheseandtheyare:

push() Addsadditionalitemstotheendofanarray

pop() Removesasingleitemfromtheendofanarray

shift() Removesasingleitemfromthebeginningofanarray

unshift() Addsadditionalitemstothebeginningofanarray

concat() Concatenatesarraystogetherintoonearray

push()Thismethodaddsitemstotheendofanarray.varsynthFrequencies=[5000,1000,500];synthFrequencies.push(100);/*Thisplacesanewitemattheendofthearray*/console.log(synthFrequencies);//[5000,1000,500,100]

Youcanusethepushmethodtoaddmultipleitemsatonce.varsynthFrequencies=[5000,1000,500];synthFrequencies.push(100,50,30);console.log(synthFrequencies);//[5000,1000,500,100,50,30]

Page 40: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

pop()Thismethodremovesasingleitemattheendofanarray.varsynthFrequencies=[5000,1000,500];synthFrequencies.pop();console.log(synthFrequencies);//[5000,1000]

Ifyouwanttocapturethelastitemyouremovedfromanarrayinavariable,dothis:varsynthFrequencies=[5000,1000,500];varlastItem=synthFrequencies.pop();console.log(lastItem);//500

shift()Thismethodremovesanitemfromthebeginningofanarray.varsynthFrequencies=[5000,1000,500];synthFrequencies.shift();console.log(synthFrequencies);//[1000,500]

Ifyouwanttocapturethefirstitemyouremovedfromanarrayinavariable,dothis:varsynthFrequencies=[5000,1000,500];varfirstItem=synthFrequencies.shift();console.log(firstItem);//5000

unshift()Thismethodaddsnewitemstothebeginningofanarray.varsynthFrequencies=[5000,1000,500];synthFrequencies.unshift(7500,6000);console.log(synthFrequencies);//[7500,6000,5000,1000,500]

concat()Thismethodmergesmultiplearraystogetherintoonearray.vardrumMachines=["MPC","Machine","TR808"];varkeyboards=["Juno","ARP","Jupiter"];varpercussion=["vibraphone","bongos"];varstringed=["guitar","bass","harp"];varinstruments=drumMachines.concat(keyboards,percussion,stringed);console.log(instruments);/*['MPC','Machine','TR808','Juno','ARP','Jupiter','vibraphone','bongos','guitar','bass','harp']*/

Page 41: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

SummaryInthischapter,youlearnedaboutvariables,comments,numbers,strings,andarrays.Inthenextchapter,youwilllearnaboutvariousassignmentandlogicaloperators.

Page 42: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

3Operators

Youlearnedaboutthebasicassignmentoperator(=)andsomeofthearithmeticoperatorsinthepreviouschapter.Inthischapter,wearegoingtoexploreotherassignmentoperators,aswellascomparisonoperators,thatallowyoutodeterminetherelationshipbetweenvariablesandvalues,suchaswhethertheyhavethesamevalue.WewillalsoexploretheBooleandatatype,whichhaseithera trueora falsevalue thatcanbeassigned tovariablesor is the resultofacomparisonoperation.

WhatAreOperators?Operatorsrepresentactionsthatyouusetochangethevalueofavariable,orcomparevaluesorvariables.Thewordoperand isused todescribeavaluebeingused inanoperation involvingoperators. So in the following example, the operands are 300 and 400. The output of thecomparisonissaidtobewhattheexpressionevaluatesto.Inthefollowingexample,theoperationevaluatestofalse.300==400/*Thevalueshere(300and400)arecalledoperands,andtheoutputevaluatestofalse.*/

Operatorsfallintoarithmetic,assignment,orlogicalcategories.Thearithmeticoperatorsthatwecoveredinthepreviouschapterareusedwithnumbers.Theassignmentoperatorsareusedtoassignvalues tovariables.The logicaloperators areused to compare twovalues and returnatrueorfalsevaluebasedontheresultofthecomparison.

AssignmentOperatorsAssignmentoperatorsareusedtoassigndatatovariables.Hereisalistofassignmentoperators:

Page 43: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

AssignmentThisoperatorassignsavaluetoavariable.varosc=100;

Withassignmentoperators,youcanalsoassignvariablestoothervariables.varosc1=100;varosc2=osc1;console.log(osc2);//100

AdditionAssignmentThisoperator incrementsanumericvariableorappendsastringtoavariable.Inthefollowingexample,anoscillatorisassignedavalueof100andthenincrementedby100togiveitavalueof200.varosc=100;osc+=100;console.log(osc);//200

Todemonstratetheuseoftheadditionassignmentoperator, thefollowingcodesetsanever-increasing frequency change to an oscillator and you can listen to the effect.Amethod calledsetInterval()isdefined,althoughthespecificsofsetInterval()arenotimportantatthistime.Whatisimportantisunderstandingthattheadditionassignmentoperatorisincrementingthefrequencyvalueby100every0.5secondswhensetInterval()iscalled.varaudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.frequency.value=300;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);setInterval(function(){osc.frequency.value+=100;/*____Incrementfrequencyvalueby100every0.5seconds*/console.log(osc.frequency.value);//_____Viewchange},500);//________________________500millisecondsis0.5seconds

Page 44: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

When you use the addition assignment operator with a string, the string you supply isconcatenatedwiththevariable.Hereisanexample:varkeyboards="";keyboards+="Korg";keyboards+="Yamaha";keyboards+="Kurzweil";console.log(keyboards);//KorgYamahaKurzweil

SubtractionAssignmentThisoperatorisusedtodecrementanumericvariable.varosc=500;osc-=100;console.log(osc);//400

MultiplicationAssignmentThisoperatormultipliesavariablewithavalueandassignsittothevariable.varosc=200;osc*=2;osc*=2;console.log(osc);//800

DivisionAssignmentThisoperatordividesavariablebyavalueandassignsittothevariable.varosc=200;osc/=2;osc/=2;console.log(osc);//50

ModuloAssignmentThis operator divides a variable by a value and assigns the remainder of that division to thevariable.varosc=200;osc%=150;console.log(osc);//50

TheBooleanDataType

Page 45: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheBooleandata typeiseither trueorfalse.This isconveyedbytheword-formvaluestrueandfalse.Booleansareimportantbecauseyoucanusethemtoprogramonoroff(trueorfalse)valuesintothecode.So,forexample,youcouldusethemasavaluethattogglesanoscillatoronoroff.AssigningaBooleanvaluetoavariableinJavaScriptlookslikethis:varoscillatorIsOn=true;//trueoscillatorIsOn=false;//changedtofalse

Booleanvaluescanalsobetheresultofthecomparisonoperatorsdescribedbeloworusedinconditionalsstatements,whichwewillcoverinthenextchapter.

ComparisonOperatorsComparison operators are used to compare two variables or values. They output atrue orfalse value depending onwhether the variables or values are similar or different from oneanother insomeway.Thesimilarityordifferencebeingtestedfor isdependentontheoperatorused. So, for example, if you test whether two values are the same using the strict equalityoperator (= = =) and they are not the same, the resulting value is false. There are eightcomparisonoperators.

EqualityOperatorThis operator checks whether the left operand is equal to the right operand. It then returns aBooleanvaluetorepresenttheoutcomeofthecomparison.200==200;//true"200hz"=="200hz";//truevarosc1="200hz";varosc2="200hz";console.log(osc1==osc2);//true

Theequalityoperatorcanbeabittrickybecauseitattemptstodoadatatypecoercionbeforecomparingoperands.Datatypecoercionoccurswhenthecodeinterpreter(inourcasethewebbrowser)attemptstoconvertonedatatypeintoanother.Inthefollowingexample,wecomparea

Page 46: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

numberandanumericstring.JavaScripttriestoconvertthestringtoanumberbeforedoingthecomparison.Ifthestringisanumericstring,theconversionissuccessful,andthecomparisonisperformed. In this case, the result of the comparison is the Boolean valuetrue because thenumeric string “200” is successfully converted to the value 200, which matches the value ofosc1.varosc1=200;varosc2="200";console.log(osc1==osc2);//true

Ifanonnumericstringiscomparedagainstanumber,theresultisalwaysfalse.200=="oscillator"//false

StrictEqualityOperatorToprotectagainsttheconfusionoftypecoercionusingtheequalityoperator,youcanusethestrictequalityoperator.Thisoperatordoesnotdodatatypecoercion.Thismeansthat,ifanynumericstring is compared against a number, the result is always false. For newer JavaScriptprogrammers,wesuggestthatyoualwaysusethisoperator.Restrictingyourselftothisoperatorhelpstomitigateproblemsinvolvingcoercionbeforetheystart.//_________________________Examples900===900//truevarosc1=200;varosc2="200";console.log(osc1===osc2);//false

GreaterThanandLessThanOperatorsTheseoperatorsproduceaBooleanresultthatisbasedonwhethertheleftoperandislessthanorgreaterthantherightoperand.100<200//true300<200//false300>200//true300>500//false

Thegreaterthanandlessthanoperatorsdodatatypecoercionasshowninthisexample:600>"500"//true600<"500"//false

GreaterThanorEqualtoOperatorThisoperatorreturnsaBooleanvalueoftrueifthefirstoperandisgreaterthanorequaltothesecondoperand.

Page 47: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varosc1=300;varosc2=500;varosc3=300;osc3>=osc1//trueosc2>=osc1//trueosc1>=osc2//false

Thegreaterthanorequaltooperatordoesdatatypecoercionasshowninthisexample:300>="300"//true

LessThanorEqualtoOperatorThisoperatorreturnsaBooleanvalueoftrueiftheleftoperandislessthanorequaltotherightoperand.300<=300//true300<=500//true300<=200//false

Thelessthanorequaltooperatordoesdatatypecoercionasshownintheseexamples:300<="300"//true300<="500"//true300<="200"//false

NotEqualtoOperatorThis operator is a combination of the NOT symbol and the equal sign. The NOT symbol isexpressedasanexclamationmarkandissometimesreferredtoasthebangoperator.WhenNOTis coupledwith an equal sign to produce the not equal to operator, it can be used to return aBooleanvaluethatisbasedonwhethertwovaluesarenotequaltoeachother.Ifthetwovaluesarenotequal,theresultistrue.Ifthetwovaluesareequal,theresultisfalse.300!=200//true300!=300//false

Thenotequaltooperatordoesdatatypecoercionasshowninthisexample:"300"!=300//false

StrictNotEqualtoOperatorThisoperatorreturnsaBooleanvaluethatisbasedonwhethertwovaluesarenotequaltoeachother.Thestrictnotequaltooperator,unlikethenotequaltooperator,doesnotdotypecoercion."300"!==300//true300!==300//false

Page 48: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

LogicalOperatorsLogicaloperators allowyou tocheck if a collectionof statements is trueor falseand returnaBooleanvaluebasedonthisinformation.

LogicalOperator Name&& AND|| OR! NOT

TheLogicalANDOperatorThelogicalANDoperatorevaluatestotrueonlyifalltheoperandsaretrue.Thewayitworksisthatfirst, thevalueontherightsideoftheoperatorisevaluated,andifitsvalueisfalse,theBooleanvalueoffalse is returned. In this case, thevalueon the left sideof theoperator isneverconsidered!

Ifthevalueontherightsideoftheoperatorevaluatestotrue,thenandonlythendoestheANDoperator check the value on the left side of the operator. If the value on the left side of theoperatorisfalse,thentheBooleanvaluefalseisreturned.InthecasewhereboththevaluesontheleftandrightsidesofthelogicalANDoperatoraretrue,theBooleanvaluetrueisreturned.true&&true//truetrue&&false//falsefalse&&true//falsefalse&&false//false

TheLogicalOROperatorThisoperatorreturnstrueaslongaseitheroftheoperandsistrue.true||true//truetrue||false//truefalse||true//truefalse||false//false

TheNOTOperatorThisoperatorinvertsaBooleanvalue.!false//true!true//false

Anotherwaytolookatthiscodeisthat,ifavalueisnotfalse,thenitistrue,andifitsvalueisnottrue,thenitisfalse.

Page 49: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

InJavaScript,therearesixvaluesthatevaluatetofalse.Theyarethefollowing:

false""nullundefined0NaN

Allothervaluesevaluatetotrue.When you specify the NOT operator twice in a row before a variable or an operand, the

resultantvalueisitsoriginalBooleanvalue.!!false//false!!true//true!!0//false!!""//false!!null//false!!undefined//false!!NaN//false

SummaryInthischapter,youlearnedaboutJavaScriptassignmentandlogicaloperators,theBooleandatatype,andwhatvaluesevaluate tofalse. In thenextchapter,youwill learn to leverage thesetoolsusingtwonewconcepts:conditionalsandloops.

Page 50: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

4ConditionalStatementsandLoops

Conditional statements and loops are two of themostwidely used constructs in programming.Conditionalstatementsallowyourprogramtomakechoicesbasedonasetofcriteria.Loopsuserepetition,allowingyourprogramtocompletemanytasksquickly.

ConditionalStatementsTocreateprogramsthatdomorethanbasiccalculationsorprinttext,theymustbeabletomakedecisions. You can program these decisions by using conditional statements. Conditionalstatements check if a value is true or false and then execute a branch of code based on thiscondition.Wearegoingtogooverthefollowingthreeconditionalstatements:

■if

■switch

■ternary

TheifStatementThesyntaxofanifstatementconsistsoftheifkeyword,apairofparentheses,andtwocurlybraces.Thisiswhatanemptyifstatementlookslike:

if(){}

Touseanifstatement,youplaceavalueorconditioninsidetheparenthesesandsomecodeto execute inside the curlybraces. If the condition inside theparentheses evaluates to true, thecodeinsidethecurlybracesisexecuted.Iftheconditionevaluatestofalse,noactionistakenandthe code inside the curly braces is skipped. In the following code, anif statement is used to

Page 51: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

checkifanoscillatorfrequencyissetto80Hzpriortoplaystart.Ifitis,theoscillatorplays;ifitisnot,thecodeinsidethecurlybracesisignoredandtheoscillatordoesnotplay.//___________________________________BEGINSetupvaraudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=80;osc.connect(audioContext.destination);//___________________________________ENDSetup//___________________________________BEGINCheckfrequencyif(osc.frequency.value===80){osc.start(audioContext.currentTime);}//___________________________________ENDCheckfrequency

If statements can also have an optionalelse branch that executes if the initial conditionevaluatestofalse.Inthefollowingcode,theifstatementcheckstoseeiffrequency.valueis 100Hz. If this condition is true, the oscillator begins to play. If this condition is false, theelsebranchexecutes,assignsfrequency.valueto50Hz,andstartstheoscillatorplaying.//____________________________________BEGINSetupvaraudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=200;osc.connect(audioContext.destination);//____________________________________ENDSetup//____________________________________BEGINConditionalif(osc.frequency.value===100){//__evaluatestofalseosc.start(audioContext.currentTime);}else{//__Sothisplaysosc.frequency.value=50;osc.start(audioContext.currentTime);}//____________________________________ENDConditional

Supposeyouwanttocheckformorethantwoconditionsanddosomethingdifferentforeachone,youcandothisbycreatinganifstatementwithmultipleelseifbranchesinsequence.The finalelse statement catches all conditions that were not met along the way. An emptyexamplelookslikethis:if(){

}elseif(){

}else{

}

Inthefollowingworkingexample,thecodeexecutesandcheckstoseeifosc.typeissetto"sine". If this condition evaluates to false, the else if branch runs and checks if theoscillatortypeissetto"sawtooth".Thisevaluatestotrue,andtheoscillatorstartsplaying.If

Page 52: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

osc.typeisnotsetto"sine"or"sawtooth"(inotherwords,ifbothconditionsevaluatedtofalse),thentheresultisexecutionofconsole.log(),whichoutputs“noconditionmet.”varaudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sawtooth";osc.connect(audioContext.destination);if(osc.type==="sine"){osc.start(audioContext.currentTime);}elseif(osc.type==="sawtooth"){osc.frequency.value=50;osc.start(audioContext.currentTime);}else{console.log("noconditionmet");}

TheswitchStatementIf you catch yourself writing an if statement with a lot of else if branches, you shouldconsiderusingaswitchstatement.Aswitchstatementallowsyoutocheckifavariablehasaparticular value assigned to it and then runs a block of code that begins where that value isdefined.The followingcode is an exampleof an emptyswitch statement.The expression inparenthesesdeterminesavalue.Thecase statementsdefinevalues thatyouwant tocatchandthenrunsomecode.Eachcasestatementisterminatedbyabreakstatementbecauseotherwisethe code following thebreak statement is run.At the endof theswitch statement, you candefinetheoptionaldefaultkeywordthatspecifiesthecodetorunifnoneoftheothercasestatementsevaluatetotrue(thevalueisnotonethatyouexpected).switch(expression){case"value1"://__iftrue//_______thendosomethingbreak;case"value2"://__iftrue//_______thendosomethingbreak;default://____ifallothercasesarefalse//_____________thendothis}

The following code is an example of a switch statement that checks the value of anoscillatortypeandsetsitsfrequencyvaluebasedonitsbeingasine,sawtooth,orsquarewave.Ifthe oscillator is not one of these types, the default branch executes and setsosc.frequency.valueto200.//____________________________BEGINSetupvaraudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sawtooth";osc.connect(audioContext.destination);//____________________________ENDSetup//____________________________BEGINSwitchstatementswitch(osc.type){

Page 53: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

case"sawtooth":osc.frequency.value=50;osc.start(audioContext.currentTime)break;case"sine":osc.frequency.value=100;osc.start(audioContext.currentTime);break;case"square":osc.frequency.value=150;osc.start(audioContext.currentTime);break;default:osc.frequency.value=200;osc.start(audioContext.currentTime);

}//____________________________ENDSwitchstatement

TernaryOperatorIfyouarewritingaconditionalstatementthatcontainsasinglecomparisonclause(itreturnsonlyoneoftwoconditions),thenyoucanuseaternaryoperator.Theternaryoperatorhasthreeparts:anexpressionandtwoexecutedstatements.Thefirstpartisanexpressionthatistestedfortrueorfalseandisseparatedfromtheexecutedcodebyaquestionmark.Iftheexpressionevaluatestotrue,thecodetotheleftofthecolonisrun.Iftheexpressionevaluatestofalse,thecodetotherightofthecolonisrun.Thesyntaxoftheternaryoperatorlookslikethis:/*expression?iftruerunthiscode:iffalserunthiscode*/

The followingcode isanexampleof the ternaryoperator inaction.Thiscodechecks if theoscillatortypeissetto“sawtooth”.Ifitis,thefrequencyissetto50;otherwise,itissetto500.//______________________________BEGINsetupvaraudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sine";osc.connect(audioContext.destination);osc.start(audioContext.currentTime);//_______________________________ENDsetup//_______________________________BEGINTernaryexampleosc.type==="sawtooth"?osc.frequency.value=50:osc.frequency.value=500;//_______________________________ENDTernaryexample

Loops

Page 54: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Computers areverygoodat doing lotsof simple tasksvery fast.Oneof the tools available toleverage this capability is loops. Loops allow you to repeat a task until a condition or set ofconditionsaremet.Wewillcoverthefollowingtypesofloops:

■for

■while

forLoopsThefollowingcodeisanexampleofaforloopthatcountsto16andoutputseachloopnumbertotheconsole.Thetextthatfollowsexplainsthekeywordsandwhateachcomponentoftheforloopdoes.for(vari=0;i<=16;i+=1){console.log(i);}

Afor loop consists of thefor keyword and opening and closing parentheses. Inside theparenthesesarethreepartsseparatedbysemicolons.Thefirstpart istheinitializationvariable,andinthiscaseitissettozero.for(vari=0;i<=16;i+=1){console.log(i);}

The next part is the conditional statement,which is used to determine a condition to checkuponeachiterationoftheloop.Aslongasthisconditionistrue,theloopwilliterate(runanothertime).Inthefollowingexample,theconditiontellstheforlooptocontinueiteratingaslongasthevalueofthevariableiislessthanorequalto16.for(vari=0;i<=16;i+=1){console.log(i);}

Thenextpartisusedtoincrementtheinitializationvariable.Oneachloop,thevariablei isincrementedbyoneandeventuallyreaches17andstopslooping.for(vari=0;i<=16;i+=1){console.log(i);}

Thelastpartofaforloopisthecodeblockthatisdefinedbytheopeningandclosingcurlybraces. Any code that is written in between these curly braces gets repeated for each loopiteration.for(vari=0;i<=16;i+=1){console.log(i);//codeheregetsrepeatedforeachloop}

Page 55: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Whenfor loopsarerun,theyareveryfast.Belowisascriptthatusesanadditionalhelperfunction to pause each iteration of afor loop. The loopmodifies the frequency of a playingoscillatoroneachiteration.Thehelperfunctionpausestheloop(whichisitsonlyfunction),soyoucanheareachchange./*__________________________________BEGINHelperfunction.Ignorethiscodeitissimplybeingusedtopausetheforloop*/functionsleep(milliseconds){varstart=newDate().getTime();for(vari=0;i<1e7;i++){if((newDate().getTime()–start)>milliseconds){break;}}}//__________________________________ENDHelperfunction//__________________________________BEGINWebAudioAPIsetupvaraudioContext=newAudioContext();varosc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=30;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

//__________________________________ENDWebAudioAPIsetup//_________________________________BEGINaudiblefor-loopexamplefor(vari=0;i<10;i+=1){osc.frequency.value+=100;sleep(500);}//_________________________________ENDaudiblefor-loopexample

UsingforLoopswithArraysIt is common to use loops tomodify and extract data from arrays. The following code has anemptyarrayandaforloop.Thefor loopiteratesfourtimes,andoneachiteration,thestring“synth”isconcatenatedwiththeivariableandispushedtothesynthsarray.Theresultisthecreationoffourentriesinthesynthsarray,eachconsistingoftheword“synth”followedbyadashandanumber.varsynths=[];for(vari=1;i<=4;i+=1){synths.push("synth-"+i);}console.log(synths);//['synth-1','synth-2','synth-3','synth-4']

Ifyouwant tomodifyeachvalue inanexistingarray,youcandosoby looping through thearray and modifying the value at each iteration. To do this, set the conditional statementtermination value to the length of the array. In the following code, this is done withsynths.length.Youcan thenaccess the individualvaluesof thearraywithin the loopbyplacingtheiteratorvariableinsidethebracketsnexttoit.

Page 56: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varsynths=['synth-1','synth-2','synth-3','synth-4'];console.log(synths.length);//__Thisis4for(vari=0;i<synths.length;i+=1){console.log(synths[i]);}

Thefollowingcodeshowsamodificationofthepreviouscodewhereeachvalueinthearrayhas“0hz”appendedtoit.

varsynths=['synth-1','synth-2','synth-3','synth-4'];for(vari=0;i<synths.length;i+=1){synths[i]+="0hz";}console.log(synths);/*['synth-10hz','synth-20hz','synth-30hz','synth-40hz']*/

whileLoopsThe while loop is useful when you are unsure of how many iterations will be needed tocomplete a task.A simple example is a livepodcastwebsite that allowsusers to connect andlistenwhileashowisontheair.Asaprogrammeryoumightnotknowhowlongtheshowwilllastbutyouwanttocontinuouslycheckfornewuserconnectionsforthedurationoftheshowandallowthemtolistenin.Thepseudocodeforthisexamplemightlooksomethinglikethis:varonAir=true;while(onAir){//checkfornewvisitorsandconnectthem}

The while loop consist of the while keyword, opening and closing parentheses, andopening and closing curly braces.A conditional statement is placed in the parentheses,whichallows the loop to iterate as long as the condition remains true.When the condition becomesfalse,theloopstops.Thefollowingexampleloopsaslongasthefreqvariableisgreaterthanzero.Ateachiteration,thefreqvariabledecrementsuntilitiszeroandtheloopterminates.varfreq=7000;while(freq>0){console.log(freq);freq-=100;}

WhentoUseforLoopsandWhentoUsewhileLoopsThe rule of thumb for deciding whether to use afor orwhile loop is that afor loop istypicallyusedwhenyouknowthenumberofiterationsthatareneededtocompletetheloop,andawhileloopisusedwhenyoudon’tknowhowmanyiterationsareneededtocompletetheloop.

Page 57: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

SummaryIn thischapter,youhave learnedhow to incorporatedecision-making intoyourprogramsusingconditionalstatements.Youhavealsolearnedhowtouseloopstoaccomplishtasksquicklyandhowloopscanbeleveragedwhenworkingwitharrays.Inthenextchapter,youwilllearnhowtoincorporatefunctionsintoyourprograms.

Page 58: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

5Functions

Inthischapter,youwilllearnaboutfunctions,variouswaystoworkwithfunctions,andvariablescope.Functionsallowyoutowritecodeinawaythatavoidsrepetition.Theyalsoallowyoutoencapsulateyourcodeandperformaspecifictaskbasedonasetofinputs.Scopepertainstothecontext inwhichvariablesaredeclared. JavaScripthandlesvariablesdifferentlydependingontheirscope,andyouwilllearnhowtousevariablesinfunctionswhenwritingprograms.

Functions—ASimpleExampleTo explain functions, let’s look at the design of an audio effects module. Imagine a simplehardware audio effects box equippedwith a single input channel and a single output channel.Nowimaginethiseffectsboxchangestheoriginalinputinsomewaydependingonacollectionofuser-definedsettings.Inthisdesign,theoutputoftheeffectsboxistheresultoftheinputsignalcombinedwiththeusersettingsthatproducesomechangeintheoriginalsignal.

Page 59: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

The following example shows how you might code the effects box example for a fixedselection.TheeffectsBoxfunctiontakesaninput,multipliesthatinputbytwo,andreturnstheresult.functioneffectsBox(input){returninput*2;}console.log(effectsBox(120));//Output240

Thefollowingexampleshowshowyoucanmultiplytheinputbyavalueselectedbytheuser,whichiscodedintheformofaparametercalledmultiplier.functioneffectsBox(input,multiplier){returninput*multiplier;}console.log(effectsBox(120,2));//Output240

PartsofaFunctionTocreateafunction,youstartbytypingthefunctionkeywordfollowedbyafunctionname.Immediately following the function name, you place opening and closing parentheses, and thenimmediatelyaftertheseyouplaceopeningandclosingcurlybraces.functionadd(){//functionbody}

Youcangive thefunctionplaceholdersfor inputvaluescalledparameters,whichyouplaceinsidetheparenthesesandseparatebycommas.functionadd(a,b){

}

The final part of a function is an optional return statement that outputs a value when thefunctioncompletes.functionadd(a,b){returna+b;}

Torunthefunction(alsocalledinvokingthefunction),youtypethefunctionnamefollowedbyanopeningparenthesis. If the functionhasparameters,youentervalues for these,which in thecontext of invoking the function are called arguments. You end the function with a closingparenthesis.add(2,5);//7

Ifyouinvokethefunctionwithargumentsnotdefinedbythefunction,noerrorisreturnedandthesystemignorestheadditionalarguments.add(2,5,999);//__Thethirdargumentisignoredandoutputis7

Page 60: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

FunctionExpressionsAs an alternative to using function declaration syntax, you can write your functions usingexpressionsyntax,whereyouassignthefunctiontoavariablelikethis:varadd=function(a,b){returna+b;};add(2,3);//5

The functionexpressionsyntaxemphasizesan importantaspectof JavaScript functions: theycanbetreatedlikedataandpassedaroundbetweenvariables.Here’sanexampleofthepreviouscodewithavariablenamedcontainerthatstorestheresultofrunningtheaddfunctionwitharguments2and3:varadd=function(a,b){returna+b;};varcontainer=add(2,3);console.log(container);//5

AbstractingOscillatorPlaybackThe following function playOsc plays an oscillator and has two arguments. The first,oscType,determinestheoscillatorwaveformtype,whichfortheWebAudioAPIsupportssine,sawtooth,triangle,andsquareintheformofastring.Thesecondargumentisthefrequencyvalueinhertz.Becausethecodenecessarytogeneratetheoscillatorisencapsulatedinafunction,youcannowinvokethefunctionbywritingonlyonelineofcodeeachtimeyoucreateanoscillator.Thismeansyouavoidtherepetitionofwritingoutalloftheoscillatorcreationcodeeverytimeyoucreatetheoscillator.varaudioContext=newAudioContext();//___Initializeswebaudioapi

functionplayOsc(oscType,freq){varosc=audioContext.createOscillator();osc.type=oscType;osc.frequency.value=freq;//____freqisaparameterosc.connect(audioContext.destination);osc.start(audioContext.currentTime);}

playOsc("sine",330);//____Playsoscillatorat330hz

/*____Wecanplaymultipleoscillatorsatonceusingonlyonelineofcodeeachtime!Addinganothersineat340willcreateapulsatingeffect*/

playOsc("sine",340);

AWorkingEffectsBoxExample

Page 61: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thefollowingcodedemonstratesasimplifiedworkingexampleofhowaneffectsboxmightlookwhen written as a function. The example consists of three functions. The first two functionsgenerate oscillators.The third function is the actualeffectsBox() function that accepts anoscillatorandafiltervalueasinputs,andthenappliesthefiltertotheoscillator.varaudioContext=newAudioContext();//___________________________________BEGINCustomsoundfunctioncustomSound(filterVal){varosc_1=audioContext.createOscillator();varosc_2=audioContext.createOscillator();varfilter=audioContext.createBiquadFilter();filter.type="lowpass";osc_1.type="sawtooth";osc_1.frequency.value=300;osc_2.type="sawtooth";osc_2.frequency.value=402;filter.frequency.value=filterVal||filter.frequency.value;osc_1.connect(filter);osc_2.connect(filter);filter.connect(audioContext.destination);osc_1.start(audioContext.currentTime);osc_2.start(audioContext.currentTime);}//___________________________________ENDCustomsound

//___________________________________BEGINsquarewavefunctionsquare(filterVal){varosc=audioContext.createOscillator();varfilter=audioContext.createBiquadFilter();filter.type="lowpass";osc.type="square";osc.frequency.value=100;filter.frequency.value=filterVal||filter.frequency.value;osc.connect(filter);filter.connect(audioContext.destination);osc.start(audioContext.currentTime);}//___________________________________ENDsquarewave

//___________________________________BEGINeffectsBox

functioneffectsBox(sourceInput,filterParam){sourceInput(filterParam);}//___________________________________ENDeffectsBoxeffectsBox(customSound,80);//Example

TheArgumentsObjectJavaScriptcontainsanarray-likeobjectthatallowsyoutoaccesstheargumentsofafunctionintheformofazero-basedlist.Thispseudo-arraydoesnothaveaccesstoanyofthemethodsofaconventionalarrayexceptthelengthproperty.Thefollowingcodeoutputstheargumentvaluesbyspecifyingtheargumentsobjectinconsole.log().

Page 62: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

functionplayOsc(oscType,freq){console.log(arguments[0]);console.log(arguments[1]);}playOsc("sine",200);//sine200

You can use the arguments object to create default values for function arguments. Thefollowingcodecheckstoseeifanargumentisundefined,andifitis,setsitsvalueto“sawtooth.”functionplayOsc(oscType){//_______SetdefaultofoscTypetosawtoothif(arguments[0]===undefined){oscType="sawtooth";}returnoscType;}console.log(playOsc());//___sawtoothconsole.log(playOsc("sine"));//___sine

Theargumentsobjectcanbecombinedwiththelengthpropertyandaconditionalstatementto ensure that an error is given if any arguments are left empty. To create your own errorstatement,youusethethrowkeyword.Inthefollowingcode,theconditionalstatementcheckstoseeifthenumberofargumentsisnottwo,andiftheconditionalevaluatestotrue,thenanerrorisgiven(orthrown)toindicatethisresult.functionplayOsc(oscType,freq){if(arguments.length!==2){throw“Error!Thisfunctiontakestwoarguments"}}playOsc("sine");//___Error!Thisfunctiontakestwoarguments

Youcanaddanotherchecktoensurethatthecorrectdatatypesarebeingenteredlikethis:functionplayOsc(oscType,freq){if(arguments.length!==2){throw"Error!Thisfunctiontakestwoarguments";}//_____Checkforcorrectargumentdatatypesif(typeofoscType!=="string"||typeoffreq!=="number"){throw"Pleaseenterthecorrectargumenttypes";}}playOsc(100,true);//___Pleaseenterthecorrectargumenttypes

Youcanalsousetheargumentsobjecttolimitanargumenttoalistofspecificvalues.Thefollowingfunctiontakesasingleargumentthatisintendedtobeoneofthefourwaveformtypes.Iftheargumentisnotoneofthesefourvalues,anerroristhrown.Whenthefunctionisinvoked,thecodeloopsthroughanarrayofthefourwaveformtypes.Ifanyofthewaveformtypesmatchestheargumentvalue,avariablenamedwaveformValidissettotheBooleanvaluetrue.Thenaconditional statementchecks thevalueofwaveformValid. If it is false, an error is thrown;otherwise,thefunctionrunstocompletion.functionplayOsc(oscType){varwaveforms=["sawtooth","sine","triange","square"];

Page 63: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varwaveformValid=false;for(vari=0;i<waveforms.length;i+=1){if(arguments[0]===waveforms[i]){waveformValid=true;}}if(waveformValid===false){throw"pleaseentersawtooth,sine,triangleorsquareasanargument"}}playOsc("fatbeats");/*___Error:Uncaughtpleaseentersawtooth,sine,triangleorsquareasanargument___*/playOsc("square");//___works

FunctionScopeScopeisaconceptthatdefineshowonepartofaprogramcanaccessvariablesinanotherpartofaprogram. In theECMAScript5versionof JavaScript, there areonly two formsof scopes: aglobal scope and function scope (also called a local scope).Thismeans that if you declare avariablewithin a function, it is specific to that function and does not conflict with any othervariablesthathavethesamenameandaredefinedoutsideofthatfunction.Functionshaveaccessto their own variables and they also have access to any variables in a higher scope, whichincludestheglobalscope.

In one of our previous examples, we created a function to play an oscillator. Notice thatalthoughtheaudioContextvariableisnotincludedinsidetheplayOsc function, it isstillaccessible.ThisisbecauseaudioContextisdefinedinahigherscope:theglobalscope.//____audioContextisglobalvaraudioContext=newAudioContext();//____playOschasaccesstoitfunctionplayOsc(oscType,freq){varosc=audioContext.createOscillator();osc.type=oscType;osc.frequency.value=freq;//____freqisaparameterosc.connect(audioContext.destination);osc.start(audioContext.currentTime);}playOsc("sine",330);//____Playsoscillatorat330hz

Youcanusefunctionscopetoprotectvariablesdefinedinafunctionnotonlyfromvariablesdefinedinahigherscopebutfromvariablesdefinedinotherfunctions.Inthefollowingexample,therearetwofunctions.Onehasdata,andtheotherwantsdata.Thedataofthefirstfunctionisnotaccessibletotheotherfunctionbecauseitishiddeninalocalscope.functioniHaveData(){vardata="Thedata";}functioniWantData(){returndata;

Page 64: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

}iWantData();//dataisnotdefined

Ifyoudeclare twovariableswith thesamenameandone isgloballyscoped(or inahigherscope)andtheotherislocallyscopedwithinafunction,thelocallyscopedvariableisreferencedwhenthecodeinthefunctionisrunning.

So,forexample,inthefollowingcode,themultFreqfunctiontakesasingleargumentandmultiplies it by a value that is assigned to the multiplier variable. The globally scopedmultiplier is not referenced when multFreq() is running because the function has alocallyscopedvariablewiththesamename.varmultiplier=4;/*______ThisvariableisnotreferencedbymultFreq*/functionmultFreq(frequency){varmultiplier=2;//_____Becausethisonehasthesamenamereturnfrequency*multiplier;}console.log(multFreq(200));//400console.log(multiplier);//4

If the locally scoped multiplier variable declaration inside the previous function isremoved, thenduring functionexecution, the codewill lookoutside the function for avariablewiththereferencedname.varmultiplier=4;functionmultFreq(frequency){/*__Thereisnolocalmultipliervariablesoitfindsoneinthescopeaboveit__*/returnfrequency*multiplier;}console.log(multFreq(200));//800

WhyYouShouldAlwaysDeclareYourVariableswithvar

InJavaScript,theuseofglobalvariablesshouldgenerallybekepttoaminimum.Thisisbecausewhenprogramsgetlarge,theaccumulationofglobalvariablesincreasesthelikelihoodofnamingcollisions. Typically, this is not a problem for small applications. However, when programsbegintogrow,theywillusuallyincorporatelibrariesandthird-partyscriptsthatdependonsomeglobalvariables.Accidentlyoverwritingtheseglobalvariablescancauseyourprogramtobreak.

Whenyoudeclareavariablefromwithinafunctionwithoutthevarstatement,thevariableisreferencedfromtheglobalscopewhenthefunctionisinvoked.Thiscanhavethesideeffectofoverwritingapreexistingglobalvariablewith thesamenameandcreatinganunexpectednamecollision.Thefollowingcodedemonstrateshowthiscanhappen.

The following example contains a global variable called multiplier. There is also avariablecalledmultiplier insideof themultFreq function that isnotdeclaredusing thevarstatement.Whenthefunctionis invoked,themultipliervariablereferencestheglobal

Page 65: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

multipliervariable,changingitsvaluefrom4to2!This isanexampleofwhyyoushouldalwaysdeclareyourvariableswiththevarstatement.varmultiplier=4;functionmultFreq(frequency){multiplier=2;//____________Noticenovardeclaration!returnfrequency*multiplier;}console.log(multFreq(200));//400console.log(multiplier);//____Changedto2!

VariableHoistingWhether you declare your variables globally or within a function, you should always declarethem at the top of the current scope. The reason for this is a phenomenon called hoisting. Tounderstandhoisting,youmustfirstunderstandthatvariabledeclarationandinitializationaretwodifferentthings.Inthefollowingcode,avariableisdeclaredusingthevarstatementandthenitisinitializedonthenextline.varmyData;//_______________________________variabledeclaredmyData="importantdatagoeshere";//__variableinitialized//ThefollowingvariableisdeclaredandinitializedinonelinevarplayOsc=false;

When you declare a variable, the JavaScript interpreter immediately (behind the scenes)decouplesthedeclarationfromtheinitializationandmovesthevariabledeclarationtothetopofthecurrentscope.Thefollowingexampledemonstratesthis.Thecodeontheleftshowsafunctionnamedrunthatcontainsavariablenamedtest,whichisdeclaredafteritisinitialized.Whenthisfunctionisinvoked,JavaScriptchangestheorderandplacesthedeclarationatthetopofthecurrentscope,ineffectmakingthefunctionlookidenticaltothecodeontheright.Thisiswhythegloballyscopedtestvariable isnotoverwrittenwhen thefunction is invoked,even though itappears at first glance that it should be, because the localtest variable is not yet declared.Because of hoisting, it is considered best practice to declare your variables at the top of thecurrentscope,whichiswheretheywillbedeclaredanyway.

Page 66: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HowHoistingAffectsFunctionsInadditiontohoistingaffectingvariables,italsoaffectsfunctions.Andhoistingworksdifferentlybasedonwhetherthefunctioniswrittenwithdeclarationorexpressionsyntax.

Considerthefollowingfunctiondeclaration.Inthiscode,thefunctionisinvokedbeforeit isdeclared,yetitstillworks!Thisisbecausebehindthescenes,thedeclarationishoistedtothetopofthescope,whichallowsyoutoexecutethefunctioneventhoughitisnotyetdeclared.multFreq(200,2);/*__Thisstillworkseventhoughitisinvokedbeforeitisdeclared!_*/functionmultFreq(input,val){returninput*val;}

Thefollowingexampleofthesamefunctionwrittenusingexpressionsyntax,however,throwsan error. This happens because function expressions are treated like variables, with thedeclarationbeinghoistedtothetop.Rememberthattheinitializationofthevariablestillhappenswhere the variable is initialized in the code. In this case, the function is run before theinitialization that defines the function occurs. The lesson here is that when you use functionexpressions,youmustdeclare functionsbeforeyou invoke them.This isgoodpracticewithallyourfunctionsasitmakesyourcodelessconfusingandmorereadable.multFreq(200,2);//___error!“multFreqisnotafunction”.varmultFreq=function(input,val){returninput*val}

AnonymousFunctionsAnonymous functions are functions that do not have a name. Technically, the function in thefollowingcodeisananonymousfunctionbecausethevariableitisassignedtoisnotthefunctionname.Itisthecontainernameforananonymousfunction.varmultFreq=function(input,val){returninput*val;}

Togivethisfunctionaname,youdoitlikethis:varmultFreq=functionnameGoesHere(input,val){returninput*val;}

Note,however,thattoinvokethefunction,youusethevariablenamethatitisassignedto.multFreq(100,2);//200

InJavaScript,itispossibletocreateafunctionthatisinvokedimmediatelyafteritisdeclared.ThistypeoffunctioniscalledanimmediatelyinvokedfunctionexpressionorIIFE(pronounced

Page 67: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

“iffy”).Thismethod is useful if youwant to briefly encapsulate and run a block of code onlyonce.Thesyntaxlookslikethis://______________________BEGINIIFE(functionrun(){return"data";}());//______________________ENDIIFE

Toviewtheoutput,youcanwrapitinconsole.log().console.log(//______________________BEGINIIFE(functionrun(){return"data";}());//______________________ENDIIFE);

Thefirstthingtonoticeisthatthefunctioniswrappedinparentheses.Thisisoptional,butisconsideredbestpracticebecause ithelpsdifferentiate theconstructsyntactically fromnon-IIFEfunctions.(functionrun(){return"data";}());

Thenext thing tonotice is theparentheses toward theendof thefunctionbefore theclosing,encapsulatingparenthesis.Thissyntaxiswhatinvokesthefunction.(functionrun(){return"data";}());

To add parameters and arguments, you put parameters in the first set of parentheses andarugmentsinthesecondsetofparentheses.(functionadd(a,b){//_____parametersreturna+b;}(2,3));//___________________arguments

ClosuresOne of themost difficult aspects of the JavaScript language for new programmers to grasp isclosures.Understanding closureswill ultimately allowyou towrite cleaner codewhile givingyouapowerfultooltosolveahostofproblemsyouwill inevitablyruninto.Understandingtheconceptofclosurecanbeabitdifficultatfirst.But inthelongterm,thebenefitsareworththetimeinvestment.

WhatIsaClosure?

Page 68: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Aclosureisaninnerfunctionthathasaccesstothescopeofitsouterenvironmentevenafterthatouter environment has returned. To understand what this means, you must first solidify yourunderstanding of scope. The following example demonstrates how a function has access to itslocalscope,theglobalscope,anditslocalarguments.varglobalVariable="globalvariable";functiondoSomething(argInput){varlocalVariable="localvariable";console.log(argInput);console.log(globalVariable);console.log(localVariable);}

doSomething("argumentinput");/*_________Thisoutputs:"argumentinput""globalvariable""localvariable"becausethefunctionhasaccesstoitsownscopeandtheouterscope.*/

Ifafunctionisdefinedinsideanotherfunction, it toohasaccess to thedataof theharboringfunction,aswellasitsownlocallyscopedvariables.Inthefollowingexample,testScope()isaharboringfunctionforinnerFunction().varglobalVariable="globalvariable";

functiontestScope(argInput){vartestScopeLocalVariable="localvariablefromtestScope";//____TheinnerfunctionhasaccesstoeverythingoutsideofitfunctioninnerFunction(){varlocalVariable="localvariablefrominnerFunction";console.log(argInput);console.log(globalVariable);console.log(testScopeLocalVariable);console.log(localVariable);}innerFunction();}

testScope("argumentinput");

/*Theconsolelogs:"argumentinput""globalvariable""localvariablefromtestScope""localvariablefrominnerFunction"*/

As we mentioned, a closure is an inner function that has access to the scope of its outerenvironment even after that outer environment has returned. The previous examplesdemonstratedscopeaccess.Thefollowingexampledemonstrateswhatitmeansforafunctiontohavescopeaccessevenafter theouterenvironmenthasreturned.Theouterenvironmentcanbeeithertheglobalenvironmentoranotherfunction.ThefollowingcodeincludestheeffectsBoxfunctionthatcontainsasinglevariablenamedcomponent.TheeffectsBoxfunctionreturnsa function that returns the value ofcomponent.When the initialeffectsBox function isinvoked,itreturnsafunctiondeclarationnamedopenEffectsBox totheouterscope(inthiscase the global scope). This openEffectsBox function declaration is then assigned to a

Page 69: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

variable called getComponent, which is then invoked and returns the string “Pulled outcomponent.”

Theimportantthingtorealizehereisthataclosure(theinnerfunction)canreturndata(suchasthecomponentvariable)fromitscontainingenvironment[inthiscaseeffectsBox()]evenafterthatouterenvironment[effectsBox()]hasreturned.functioneffectsBox(){varcomponent="Pulledoutcomponent";returnfunctionopenEffectsBox(){returncomponent;};}vargetComponent=effectsBox();/*___stores"openEffectsBox"functioninavariable.*/console.log(getComponent());//"Pulledoutcomponent"

The previous example can be modified to demonstrate how state can be modified andretainedusingtheclosure.Inthiscode,thereisanadditionalcountervariablethatincrementseachtimetheinneropenEffectsBoxfunctionisinvoked.Sinceclosuresallowaccesstothescope of a containing function even after that containing function has returned, the returnedfunctioncancontinuetoincrementthecountervariableandhaveaccesstoitsstate.functioneffectsBox(){varcounter=0;varcomponent="Pulledoutcomponent";returnfunctionopenEffectsBox(){returncomponent+""+(counter+=1);};}vargetComponent=effectsBox();//___stores"openEffectsBox"functioninavariable.

getComponent();//"Pulledoutcomponent1"getComponent();//"Pulledoutcomponent2"getComponent();//"Pulledoutcomponent3"getComponent();//"Pulledoutcomponent4"

Hereisanexampleofafunctiondesignedtoplayanoscillatorbyreturninganinnerfunctionthat remembers the outer environment’s state. This example shows how the inner functionaccesses the function arguments of the outer function even after the outer function returns. TheplayOscfunctiontakesparametertype,whereastheinnerfunctionitreturnstakesparameterfreq.Theouterfunctionisinvokedwiththeargument“sine”;thereafter,theinnerfunctionisinvokedwithafrequencyvalue.Theresultisasinewavethatplaysatasetfrequencyvalueof140Hz.varaudioContext=newAudioContext();

functionplayOsc(type){

returnfunction(freq){varosc=audioContext.createOscillator();osc.type=type;osc.frequency.value=freq;osc.connect(audioContext.destination);

Page 70: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

osc.start(audioContext.currentTime);};}varsinewave=playOsc("sine");sinewave(140);//____________Playssinewaveat140hz

Closure isanadvancedconcept thatcanbeused toprotectaportionofaprogramfrom theglobalscope,retainstate,andorganizeyourcode.Itsspecificusecaseswillgraduallybecomemoreapparentasyourskillasaprogrammerdevelops.Fornow,itisimportanttograspwhataclosureis.

CallbackFunctionsA callback is a function that is used as an argument to another function. The followingexampledemonstratesadditionoftwonumbersusingacallback.functiondoMath(callback){returncallback();}

functionaddTwoNumbers(){return2+2;}doMath(addTwoNumbers);//4

When working with callbacks, you will often see function invocations where the callbackdeclarationisplaceddirectlyinafunctionargument.functiondoStuff(callback){returncallback();}

doStuff(function(){//___Callbackdeclarationisuseddirectlyreturn//___data});

Thefollowingfunctionisanexampleofusingacallbacktomakeafunctionmoreflexible.ThecalculateFrequencies function is designed to take three arguments. The first two arenumbersandthethirdisacallbackthatmanipulatestheotherarguments.Iftheuserdoesnotuseacallback,thenthefunctiondefaultstomultiplyingthetwoargumentstogether.functioncalculateFrequencies(a,b,callback){if(callback===undefined){returna*b;}else{returncallback(a,b);}}functiondiff(a,b){returnMath.abs(a-b);}

console.log(calculateFrequencies(200,2));//400___Multipliesnumbers

Page 71: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

console.log(calculateFrequencies(1000,4000,diff));/*3000___usescustomcallbacktofindthedifference*/

Thepreviousexampledemonstrateshowpassingacallbacktoafunctionprovidestheactiontakenbythecallback,whereaspassingnonfunctionvaluesprovidesdatainput.

WorkingwithJavaScript’sBuilt-InCallbackFunctionsLearningtodesignyourownfunctionsthatusecallbacksisanadvancedtopic.Asabeginner,themoreimportantthingforyoutoknowishowtousepreexistingmethodsthathavebeendesignedto use callbacks. The following are two examples of built-in JavaScript methods that usecallbackstohelpyouworkwitharrays.

ArrayMethod Description

filter() Compareseachelementinanarraytoaconditionalstatementandreturnsanewarrayofelementsthatmeetthecondition

map() Callsafunctiononeachelementinanarrayandreturnsanewarraywiththemappedvalueofeachelementintheinputarray

filter()Thefiltermethodcompareseachelementinanarraytoaconditionalstatementandreturnsanew array of only those elements that meet the filter condition. The following example usesfilter()toloopthroughanarrayoffrequencyvaluestocreateanewarrayofvaluesgreaterthanorequalto1000.varfreq1=1200,freq2=570,freq3=100,freq4=1500;

varfrequencyList=[freq1,freq2,freq3,freq4];

varfilteredFrequencies=frequencyList.filter(function(value){returnvalue>=1000;});

console.log(filteredFrequencies);//___[1200,1300]

map()Themap function calls a function on each element in an array and returns a new array thatcontainsthemappeddataforeachelementintheinputarray.

Page 72: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thefollowingexampleusesmap() to add100 toeachvalue inanarrayand returnanewarraynamednewFreqs.varfreqs=[100,200,300];varnewFreqs=freqs.map(function(val){returnval+100;});

console.log(newFreqs);//__[200,300,400]

Thecallbackfunctionsofbothmap()andfilter()takethreearguments.Inorderoftheirposition,thesearevalue,index,andarray.Thevalueargumentisthearrayvalueatthecurrent index, theindex argument is the current indexvalue, and thearray argument is thearraythatthecallbackisbeingappliedto.Inthefollowingexample,amapmethodisappliedtoanarrayandallthreeargumentsareloggedtotheconsole.varfreqs=[100,200,300];varnewFreqs=freqs.map(function(val,index,arr){varmessage="currentvalue:"+val+"currentindexindex:"+index+"array:"+arr;console.log(message);returnval;});/*___Thislogsthefollowingtotheconsolecurrentvalue:100currentindex:0array:100,200,300currentvalue:200currentindex:1array:100,200,300currentvalue:300currentindex:2array:100,200,300*/

RecursionRecursionisanadvancedprogrammingtopic,anditwillonlybeexploredbrieflyinthischapter.

Arecursivefunctionisafunctionthatcallsitself.Thefollowingisanexampleofarecursivefunction.functionx(){returnx()}

Ifyou run thepreviouscode, itwill crashyourbrowser.This isbecause,whena recursivefunctionrunsindefinitely,iteventuallyusesuptheresourcesofyourcodeinterpreter(inthiscasethewebbrowser)andcreatesanerror.Touserecursioneffectively,youneedtosetaconditiontoterminatetherecursion.Thisconditioniscalledthebasecase.

ThefollowingexampleisarecursivefunctionnamedloopFromTothatcontainsaworkingbase case.loopFromTo takes two arguments, and both are numbers. In the function body, aconditionalisusedtocheckiftheargumentnamedstartislessthantheargumentnamedend.Aslongasthisconditionistrue,loopFromTocallsitselfandoneachiterationincrementsthestartargumentbyone.Thiscontinuesuntiltherecursionterminateswhenstartceasestobelessthanendandtheconditionalstatementevaluatestofalse.

Page 73: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

functionloopFromTo(start,end){console.log(start);if(start<end){returnloopFromTo(start+=1,end)}}

loopFromTo(1,8)//______1,2,3,4,5,6,7,8

Recursivefunctionscanbeusedinplaceof loopingconstructsandareaninvaluabletool inmanycomplexalgorithms.If recursionseemsconfusingdon’tworry,youcanprogramperfectlygoodapplicationswhileyoubecomefamiliarwithit.

SummaryInthischapter,youlearnedhowtocreateandusefunctions.Inthenextchapter,youwillexpandyourunderstandingofJavaScripttoincludeaconceptcalledobject-orientatedprogramming.

Page 74: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

6Objects

So far, we discussed five of JavaScript’s six data types. These are string, number, Boolean,undefined,andnull.Thesearecalledprimitivedatatypes.Anythingthatisnotaprimitivedatatypeisoftheobjectdatatype.Inthepreviouschapter,youlearnedaboutfunctions,whichareoftheobjectdata type.Inthischapter,youwill learnhowtoprogramusingobject literals,whicharealsooftheobjectdatatype.

JavaScriptDataTypesTheJavaScriptdatatypesare:

■String

■Number

■Boolean

■Undefined

■Null

■Object

The object data type includes functions, arrays, and object literals.Arrays and functions havealready been explored, so here is a general definition of object literals: Object literals are acollectionofcomma-separatedkey-valuepairsthatarecontainedwithincurlybraces.

Note: Developers in the JavaScript world commonly refer to object literals asobjects.However,objectliteralsandtheobjectdatatypearetwodifferentthings.Onewaytounderstandthedifferenceistorecognizethattheobjectdatatypeisacategorythatcontainsobjectliterals,functions,andarrays.

Page 75: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Inthefollowingcode,anobjectnamedobjiscreatedandthevalueswithincurlybracesareassignedtoit.varobj={key1:"value1",key2:"value2"};

Akeyissimilartoavariable,andavalueissimilartothedataassignedtoavariable.Thekeyandvalueofanobject iscalledaproperty fornonfunctionsassignedtoakey,oramethod forfunctionsassignedtoakey.varobj={key:"value",//___ThisisapropertydoSomething:function(){//___Thisisamethod}};

Conceptually, object literals are used to model real-world elements in your code. So, forexample,thefollowingobjectisusedtomodelamusicalbum.//_________________Thisisanobjectthatcontainsalbumdatavaralbum={name:"ThrillerFunk",artist:"JamesJackson",format:"wave",sampleRate:44100}

Toaccessdatafromanobject,youcanusedotnotation,whichlookslikethis:album.name;//ThrillerFunkalbum.artist;//JamesJacksonalbum.format;//wavealbum.sampleRate;//44100

Alternatively,youcanusebracketnotationtoaccessvaluesinanobject.album["sampleRate"];//44100

Ifyouuseabracketnotation,youmusttypethekeyintheformofastring.album["sampleRate"];//__Thekeyisastring

You can usemethods tomodify or retrieve data from an object. Here is an example of anobjectthatcontainsamethodthatreturnsthenameandartistinformationofanobjectnamedsong.varsong={name:"FunkyShuffle",artist:"JamesJackson",format:"wave",sampleRate:44100,//_____________________________BEGINMethodnameAndArtist:function(){return"Name:"+song.name+"|"+"Artist:"+song.artist}

Page 76: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//_____________________________ENDMethod}

Youcaninvokemethodswithdotnotationandtrailingparentheses.//__________________________________BEGINmethodinvocationsong.nameAndArtist();//Name:FunkyShuffle|Artist:JamesJackson//__________________________________ENDmethodinvocation

LoopingthroughObjectsToloopthroughthekeysandvaluesofanobject,youuseaforin loop.Youcodeaforinlooplikethis:varsong={name:"FunkyShuffle",artist:"JamesJackson",format:"wave",sampleRate:44100}//______________________BEGINforinloopfor(varpropinsong){console.log(prop+":");//__Outputseachkeyconsole.log(song[prop]);//__Outputseachvalue}//______________________ENDforinloop

The structure of aforin loop consists of thefor keyword followed by a variable thatrepresentsthevalueofeachproperty.Inthepreviousexample,thisvariablewasnamedprop.Thevariablenameisfollowedbytheinkeywordandthenameoftheobjectyouwanttoloopthrough.

Oftenyouwillwant tomodifythepropertiesofanobjectyouareloopingthroughwhilenotmodifyinganyofitsmethods.Onewayyoucandothisisbyusingaconditionalstatementandthetypeofoperatortoactonlyonpropertyvaluesthatarenotfunctions.Thisusageisshowninthefollowingcode:varsong={name:"FunkyShuffle",artist:"JamesJackson",format:"wave",sampleRate:44100,nameAndArtist:function(){return"Name:"+song.name+"|"+"Artist:"+song.artist;}};for(varpropinsong){if(typeofsong[prop]!=="function"){console.log(song[prop]);//___Omitsmethods}}

Page 77: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

WhentoUseObjectsRatherThanArraysYouhaveprobablynoticedthatobjectsandarraysaresimilarbecausetheyallowyoutoorganizecollectionsofdata.Ifyouarecuriousaboutwhentouseanarrayratherthananobject,theruleofthumbisthatiftheorderofthedatamatters,youshouldalwaysuseanarray.ThereasonforthisisthatthereisnothingintheJavaScriptspecificationthatguaranteestheorderinwhichkey-valuepairsofanobjectarereturnedinaloop.

HowtoCheckIfanObjectHasAccesstoaParticularPropertyorMethod

Ifyouwanttocheckwhetherapropertyormethodisavailabletoanobject,youcanusetheinoperator.varsong={name:"FunkyShuffle",artist:"JamesJackson",getArtist:function(){returnsong.artist;}};console.log("artist"insong);//trueconsole.log("getArtist"insong);//true

CloningObjectsIfyouwanttocreateanobjectthathasaccesstoanotherobject’spropertiesandmethods,whilebeingextensible,youcanusetheObject.create()function.Thefollowingexampleshowsanobjectbeingclonedusingthismethod.vareffects={reverbs:{hall:"Hallreverbbeingused",plate:"Platereverbbeingused",smallRoom:"Smallroomreverbbeingused"},guitar:{flange:"Flangebeingused",wahWah:"Wahwahbeingused"}};varupdatedEffects=Object.create(effects);console.log(updatedEffects.reverbs);//returnsreverbobjectconsole.log(updatedEffects.guitar);//returnsguitarobject

Youcanthenextendthenewlycreatedobjectwithpropertiesandmethods.

Page 78: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

updatedEffects.filters={lowPass:"Lowpassfilterbeingused",highPass:"Highpassfilterbeingused"};console.log(updatedEffects.filters);//returnsfilterobjectconsole.log(effects.filters);//undefined

PrototypalInheritanceItisimportanttounderstandthatObject.create()doesnotliterallycopythepropertiesandmethodstoanewobjectbutprovidesareferencetothepropertiesandmethodscontainedintheparentobject(s).Thishierarchyofreferencesbetweenobjectsiscalledprototypal inheritance.The following code shows this by cloning multiple objects and including comments of thehierarchyofpropertyaccessibility.varsynth={name:"Moog",polyphony:32};

varsynthWithFilters=Object.create(synth);//clonesynth//synthWithFiltersnowhasaccesstonameandpolyphonypropertiessynthWithFilters.filters=["lowpass","highpass","bandpass"];//addproperty/*Theoriginalsynthobjectdoesnothaveaccesstothefiltersproperty.*/varsynthWithFiltersAndEffects=Object.create(synthWithFilters);//clonesynthWithFilterssynthWithFiltersAndEffects.effects=["reverb","flange","chorus"];//addproperty/*NeitherthesynthobjectnorthesynthWithFiltersobjecthaveaccesstotheeffectsproperty*/

The"this"KeywordJavaScriptcontainsakeywordcalledthis thatisusedinmethodstorefertoanobject.Inthefollowingcode, themethodnamednameAndArtist references its containingobject directlybyusingitsname,whichissong.varsong={name:"FunkyShuffle",artist:"JamesJackson",format:"wave",sampleRate:44100,//_____________________________BEGINMethodnameAndArtist:function(){return"Name:"+song.name+"|"+"Artist:"+song.artist;}//_____________________________ENDMethod};

Page 79: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thereferencetosongcanbereplacedwiththethiskeyword,andtheresultisthesame.nameAndArtist:function(){return"Name:"+this.name+"|"+"Artist:this.artist";};

ThebindFunctionTheusefulnessof thethis keywordbecomesapparentwhenyou realize thatany functionormethodcanbeappliedtoanyobject.Theeasiestwaytodemonstratethisisbyusingthebuilt-inJavaScriptmethodcalledbind.Thebindmethodpointsafunction’sthisvaluetotheobjectspecifiedinthefirstargument(theboundobject).Youcantheninvokethefunctionontheboundobject. In the following code,bind points thegetName function’sthis value to an objectnamedalbum.varsong={name:"FunkyShuffle",artist:"JamesJackson",format:"wave",sampleRate:44100};

functiongetName(){returnthis.name;}vargetNameOfSong=getName.bind(song);/*assignboundfunctiontoavariable*///_______Theninvokeit!console.log(getNameOfSong());//FunkyShuffle

Ifyouwanttospecifyargumentsinafunctioncreatedwithbind,youcandothisinoneoftwoways.The first is to specify the arguments in thenewly created function. In the followingexample, a function nameddescriptor is invoked on an object namedblastSound. AnargumentisthenpassedtothedescribeBlastSoundfunction.varblastSound={name:"Blast"};

functiondescriptor(message){returnthis.name+":"+message;}

vardescribeBlastSound=descriptor.bind(blastSound);console.log(describeBlastSound("Thisisanexplosivesound"));//Blast:Thisisanexplosivesound

Alternatively,youcanspecifytheargumentsinthestatementwhereyoubindthefunctiontotheobject.Youdothisbyfirstspecifyingtheobjecttobindto,thenspecifyingargumentsyouwanttouseandseparatingthemwithcommas,asinthefollowingexample:

Page 80: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

vardescribeBlastSound=descriptor.bind(blastSound,"Thisisanexplosivesound");console.log(describeBlastSound());/*Blast:Thisisanexplosivesound*/

Asyoucansee,evenwhenafunctionhasnotbeenwrittenasamethodonaparticularobject,youcanstillapplythefunctiontothatobject.Thisalsomeansthatyoucanuseamethodofoneobject and apply it to a completelydifferent object.The following codeuses amethodnamedgetNameAndArtistofanobjectnamedsongandappliesittoanobjectnamedAlbum.

varalbum={name:"FunkyShuffle",artist:"JamesJackson",format:"wave",sampleRate:44100};varsong={name:"AnalogueHeaven",artist:"TheKeepItReels",getNameAndArtist:function(){

return"Name:"+this.name+"|Artist:"+this.artist;}};vargetNameOfAlbum=song.getNameAndArtist.bind(album);console.log(getNameOfAlbum());/*Name:FunkyShuffle|Artist:JamesJackson*/

Ifafunctionisinvokedoutsidethecontextofanobject,itsthisvaluepointstooneoftwovalues,dependingonwhetherstrictmodeisusedornot.Ifstrictmodeisused,itsthisvalueisundefined. If strict mode is not used, itsthis value points to an invisible object called theglobalobject,whichcontainsallthebuilt-inpropertiesandmethodsofthewebbrowser.Youcanview the value ofthis by usingconsole.log(this) in the global scopewithout strictmode.

SummaryInthischapter,youlearnedhowtoprogramwithobjects.Inthenextchapter,youwilllearnthebasicsoftheWebAudioAPInodegraphandworkingwithoscillators.

Page 81: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

7NodeGraphsandOscillators

Inpreviouschapters,you learned thebasicsofworkingwithJavaScriptdata typesandhowtousetheWebAudioAPItogeneratebasictones.Inthischapter,youwilluseyourunderstandingofJavaScripttogetabetterunderstandingoftwocorefeaturesoftheWebAudioAPI:nodegraphsandoscillators.

TheAudioContext()MethodTheWebAudioAPIisaccessedbyusingacollectionofpropertiesandmethodsofanobjectthatyoucreateusingtheAudioContext()method.varaudioContext=newAudioContext();

AudioContext() isaconstructor that returnsanobjectwhenyouuse thekeywordnew.ConstructorsandthenewkeywordareexplainedinChapter12.Fornow,theimportantthingtounderstand is that AudioContext() returns an object containing all of the methods andpropertiesthatyouusetoaccesstheWebAudioAPI.

NodeGraphsAnodegraph is a collectionof nodes.Anode in a nodegraph is anobject that represents anaudio input source, such as an oscillator, or an object designed to manipulate an audio inputsource,suchasafilter.Thesenodesareconnectedtogetherusingamethodnamedconnect.

Thefollowingcodeisanexampleofanoscillatornodeconnectedtoafilternode."usestrict";varaudioContext=newAudioContext();//_____________BEGINcreateoscillatorandfiltervarfilter=audioContext.createBiquadFilter();varoscillator=audioContext.createOscillator();

Page 82: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//_____________ENDcreateoscillatorandfilter//______________BEGINconnectoscillatortofilteroscillator.connect(filter);//_____________ENDconnectoscillatortofilter//_____________BEGINconnectfiltertocomputerspeakersfilter.connect(audioContext.destination);//_____________ENDconnectfiltertocomputerspeakers

//_____________BEGINstartoscillatorplaying

oscillator.start(audioContext.currentTime);//_____________ENDstartoscillatorplaying

Inthepreviouscode,theoscillatorobjectiscreatedusingthecreateOscillatormethodoftheaudiocontextandstoredinavariablenamedoscillator.Youcreatethefilterobjectina similar way by invoking the createBiquadFilter method of audioContext. Theoscillator is connected to the filter usingconnect(). Thefilter is connected to apropertynameddestination.Thedestinationrepresentstheoutputofyourcomputer’saudio system. To start the oscillator playing, you use a method of the oscillator objectnamedstart.Thestartmethod takes one argument that determines the time the oscillatorstarts playing. The value ofaudioContext.currentTime is the current time in secondswithintheWebAudioAPI,startingwhenAudioContextwasinvoked.(ThetopicoftimeisdiscussedinChapter20.)

OscillatorsOscillators,likeallWebAudioAPInodes,havetheirowncustompropertiesandmethods.Thefollowingmethodsandpropertiesarediscussedinthischapter.

Method Description

start Startsoscillatorplaying

stop Stopsoscillatorplaying

Property Description

onended Executesacustomfunctionwhenoscillatorstops

type Setsthetypeofwaveformassignedtotheoscillator

frequency Setsthefrequencyvalueoftheoscillatorinhertz

detune Setsanoffsetofthecurrentfrequencyvalueincents

Page 83: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

ThestopMethodThe stop method determines when an oscillator stops. It takes one numeric argument thatrepresentsatimevalueinseconds.Thefollowingcodestartsanoscillatorplayingandstopsit3secondsintothefuture.varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.start(audioContext.currentTime);oscillator.stop(audioContext.currentTime+3);

TheonendedPropertyIfyouwanttolaunchafunctionaftertheoscillatorstopmethodhasrun,youassignthatfunctiontotheonendedproperty.Thefollowingcodeoutputsthestring“Oscillatorhasstopped”totheconsoleafteritsstopmethodcompletes.varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.start(audioContext.currentTime);oscillator.stop(audioContext.currentTime+3);oscillator.onended=function(){console.log("Oscillatorhasstopped");};

HowtoStopOscillatorsandRestartThemWhen an oscillator is stopped, it cannot be restarted. Instead, it must be recreated and thenstarted. To demonstrate this, the following code attempts to restart an oscillator after it hasstopped,whichresultsinfailure.varaudioContext=newAudioContext();varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.start(audioContext.currentTime);oscillator.stop(audioContext.currentTime+3);

oscillator.onended=function(){oscillator.start(audioContext.currentTime);//fails!};

Page 84: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

The following code recreates anoscillator and starts it playing1 second after thepreviousoscillatorstops.varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.start(audioContext.currentTime);oscillator.stop(audioContext.currentTime+3);

oscillator.onended=function(){oscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.start(audioContext.currentTime+1);/*startinonesecond*/};

ThetypePropertyThetypepropertyofanoscillatorsetsitswaveformtypeintheformofastring.Therearefourpredefinedwaveformshapesavailable.

■sawtooth

■sine

■square

■triangle

Page 85: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youassignawaveformtypetoanoscillatorlikethis:varaudioContext=newAudioContext();varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.type="sawtooth";oscillator.start(audioContext.currentTime);

Thedefaultwaveformtypeissine.

ThefrequencyPropertyTo set an oscillator’s frequency, you must set the frequency property to a number. Thefrequencyvalueisrepresentedinhertz.

varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.frequency.value=80;//_____80hertzoscillator.start(audioContext.currentTime);

ThedetunePropertyThedetunepropertyisexpressedincents.IntheWesternmusicscale,thereare100centsperhalf-step note. This makes it easy to create musical note relationships using detune. Thefollowingcodeplaysanoteatafrequencyof130.81hertzandisthefrequencyofaC3note.Theoscillatorstops,andahalf-secondlaterasecondnoteplayswiththesamefrequency.valueandadetune.valueof100cents,makingthenotevalueC#3.

varaudioContext=newAudioContext();varoscillator=audioContext.createOscillator();oscillator.connect(audioContext.destination);oscillator.frequency.value=130.81;//________C3

Page 86: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

oscillator.start(audioContext.currentTime);oscillator.stop(audioContext.currentTime+2);

oscillator.onended=function(){oscillator=audioContext.createOscillator();oscillator.frequency.value=130.81;//C3noteoscillator.detune.value=100;/*setsthenotetoonehalfstephighertoC#3*/oscillator.connect(audioContext.destination);oscillator.start(audioContext.currentTime+0.5);oscillator.stop(audioContext.currentTime+2.5);};

SummaryInthischapter,youlearnedthebasicsofnodegraphsandoscillators.Inthenextchapter,youwilllearn the basics of HTML and CSS and create the interface for your first Web Audio APIapplications.

Page 87: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

8UsingHTMLandCSStoBuildUserInterfaces

In this chapter, youwill learn thebasicsofHTMLandCSS,givingyou thenecessary tools tobuilduserinterfacesforyourWebAudioAPIapplications.Youwilldothisbybuildingauserinterfaceintendedtotriggeranoscillatorthatincludesinteractivecontrolstoselectfrequencyandwaveformtype.Inthenextchapter,youwillcombinetheinterfacewithJavaScriptcodetobuildyourfirstworkinginteractiveapplication.

WhatIsaUserInterface?Auserinterface,alsocalledaUI,isthepartofanapplicationthatauserinteractswith.Amusicsynthesizer’sUI is thekeyboard,aswellas theknobsandsliders thatallowyou tomodify thesound of the instrument. In a website or application, the UI can include buttons, form fields,sliders,scrollbars,andotherelementsthatfacilitateusercontrol.

HTMLHTMLstandsforhypertextmarkuplanguageandisthelanguageusedtocreatestaticwebsites.InChapter1, you learned thatHTMLconsists of elements, sometimes referred to as tags, thatmakeup thepageof anHTMLdocument.Tobe treatedas anHTMLdocument, a filemustbesavedwith.htmlappendedtoitsname.Afileextensionisagroupofcharactersplacedafteraperiodinafilenamethatindicatesthefile’sformat.Inthecaseofafilenamedindex.html,thefileextensionis.html.

The following code is from theHTML template you created in Chapter 1. It consists of acollectionofelementsrequiredtomakeadocumentW3Ccompliant.W3CstandsforWorldWideWeb Consortium; this group is responsible for the development of web standards. UnlikeJavaScript, HTML does not return errors if your code is written incorrectly, so you needadditional tools to findHTML errors. You can test the compliance of anHTML document by

Page 88: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

running your code through the HTML validation tool at the following URL:https://validator.w3.org.<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>app</title><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head><!--_____________________________________________BEGINAPP--><body>

</body><!--_____________________________________________ENDAPP--></html>

ExplanationoftheHTMLTemplateThefirstelementinanHTMLfile,<!DOCTYPE>,declareswhatversionofHTMLthepageiswritten in. ForHTML5, use <!DOCTYPEhtml>.As of thiswriting,HTML5 is the newestversionoftheHTMLspecification.Thenextelement,<html>,encapsulatestheremainderofthecode. <html> represents the “root” of the document and contains the <head> and <body>elements.The<head>elementdescribesinformationaboutthedocument,whereasthe<body>elementdescribesthecontentonthevisiblepage.

Within the<head>element, the<meta> tagdefineswhichkeyboardcharacterencoding isusedonthewebpage.Characterencodingsrepresents thewaythatcharactersonyourphysicalkeyboard get translated to text. UTF-8 coversmost languages and is also the standard for themodernweb.The<title>elementisusedtogiveyourpageatitle.Theremainingcodeinsidethe<head>elementincludesreferencestoexternalfilesthatcontainJavaScriptandCSScode.

Immediately before the body element is a comment.HTML comments arewritten using thefollowingsyntax:<!—commentgoeshere-->

Insidethe<body>elementiswhereyouwritethebulkofyourHTMLcode.Inthefollowingexample, the <p> and <h1> elements between the opening and closing body tags show howHTMLisusedtodisplaytext.The<h1>elementisaheadingelementandthe<p>elementisaparagraphelement.Asthenamesimply,youusetheheadingelementtocreatetitleheadingsandtheparagraphelementtoencapsulatetextthatrepresentsaparagraph.<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>Template</title><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css">

Page 89: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

</head><!--____________________________________________BEGINAPP--><body><h1>CreatinganInterface</h1><p>InthischapterwewillgooverHTMLandCSS</p></body><!--____________________________________________ENDAPP--></html>

UnderstandingHTMLElementsIntheHTMLspecificationthereareover100elementstochoosefrom.Eachoneofthesehasaspecificusecase.AfulllistisavailableatthefollowingURL:https://developer.mozilla.org/en-US/docs/Web/HTML/Element.

Thesheernumberofelementsmaybedauntingatfirst,butonceyouunderstandhowtouseasmallhandfulof theseelements, itbecomeseasier to learn theothers.For thepurposesof thischapter,onlythefollowingelementsareused:

When youwriteHTML andCSS, youmust understand two primary concepts. First,HTMLwebpagesconsistofahierarchyofelementsthatformanestedtree-likestructure.ThisiscalledtheHTMLDocumentObjectModel(orDOMforshort).Thefollowingdiagramreflectsthenodetreeofthepreviousexample.

Page 90: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Second, most elements contain opening and closing tags that are used to encapsulate otherelements. The processes of encapsulating elements within other elements and treating thecontainingelementsasboxesiscommonlyreferredtoastheboxmodel.

Thefollowingcodeemphasizestheboxmodelbyaddingelementsthatcontainotherelements.This includesacontaining<div> that encapsulates a<form>element.The<form> elementthenencapsulates<input>,<span>,and<p>(paragraph)elements.<body><h1>CreatinganInterface</h1><p>InthischapterwewillgooverHTMLandCSS</p><div><form><inputid="on-off"type="button"value="start"><span>Clicktostartoscillator</span><p>Useslidertomodifyfrequency</p><inputtype="range"></form></div></body>

ThetreestructureofthemodifiedHTMLisreflectedinthefollowingdiagram.

Page 91: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Therenderingofthecodelookslikethefollowingfigure.

HTMLelementscomein twocategories:block-leveland inline.Thedifferencebetween thetwoisthatblock-levelelementsdisplayverticallyandinlineelementsdisplayhorizontally.The

Page 92: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<div>and<span> elements are two elements that reflect these characteristics. <div> is ablock-level element and <span> is an inline element. These are both considered genericcontainerelements.Thismeans that theyconveynospecialmeaningbutareuseful tohelp lendstructuretoyourpagewhennootherelementsareappropriate.Thefollowingcodedemonstrateshowtheseelementsareinterpretedwhentheyarerenderedinthebrowser.The<hr>elementisusedsolelytocreateavisualdemarcation(horizontalline)betweenthetwoexamples.<body><span>Thistextisinsideaspan</span><span>Thistextisinsideaspan</span><hr><div>Thistextisinsideadiv</div><div>Thistextisinsideadiv</div></body>

FormandInputElements<form> is a block-level element intended to encapsulate <input> elements. <input>elementsareusedtocreatetextfields,buttons,andrangesliders.Thetypeattributeisusedtodefine the type of data the element is expected to display,which can change how the elementappearsonthepage.Soforexample,ifyousetthetypeattributetorange,itcreatesaslider.

Page 93: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<form><inputtype="range"></form>

Thetypeattributecomeswithabuilt-inlistofpossiblesettings,someofwhichareshowninthefollowingcode.Thevalueattributegivesthe<input>elementadefaultsetting,asshowninthefollowingdemonstrationcode(codethatisnotusedinyourfinalapplication):<body><form><p>Inputelementtypesetto"button"</p><inputtype="button"value="start"><hr><p>Inputelementtypesetto"range"</p><inputtype="range"><hr><p>Inputelementsettoa"number"</p><inputtype="number"value="44.100"><hr><p>Inputelementsettoa"text"</p><inputtype="text"value="sine"></form></body>

CSSCSSstandsforcascadingstylesheets and is the technologyused to stylewebpages andwebapplications. Like HTML, CSS does not throw errors whenwritten improperly. To check forerrors,youcanusetheW3CCSSvalidatortoolatthisURL:https://jigsaw.w3.org/css-validator/.

CSSfilesusethe.cssfileextension.TouseCSSwithanHTMLfile,youmustfirstcreateaCSS document and then connect it to yourHTML document using the <link> element in the<head>.Thefollowingexampleillustratesthisusage,whichisappliedfortheremainderofthischapter.

Page 94: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>CSSandHTML</title><linkrel="stylesheet"href="css/app.css"></head><body><h1>CreatinganInterface</h1><p>InthischapterwewillgooverHTMLandCSS</p><div><form><inputid="on-off"type="button"value="start"><span>Clicktostartoscillator</span><p>Useslidertomodifyfrequency</p><inputtype="range"></form></div></body><html>

To ensure that your CSS document is being read properly, open your HTML document inChromeandopenthedevelopertools.Ifyoumadeanerror,theconsolewillindicatethisinred.

After theCSSfile is linkedyoucanbegin toapplyCSSstyling to theHTMLelements.Forexample,ifyouwanttochangethebackgroundcolorofthepage,inyourCSSfileyouselectthebodyelementandsetthebackground-colorpropertytoacolorvalue.Thisisshowninthefollowingexamplewherethebackgroundcolorischangedtoorange.Asanalternativetousingthenameofthecolor,youcansetthecolorusingahexcolorcodevaluesuchas#ffa500orared–green–bluevaluesuchasrgb(255,165,0).

body{background-color:orange;}

Page 95: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheprocedureforapplyingCSStoanelementisasfollows:

1. Select the element youwant to affect and type its name in yourCSS file. In the previousexample,thiswasbody.

2.Typeanopeningandclosingcurlybrace.Thesetwobracesarecommonlyreferredtoasacodeblock.Insidethecodeblockyouplacepropertiesandsetvaluesfollowingacolon.Inthepreviousexample,thepropertywasbackground-coloranditsvaluewasorange.Eachpropertyvaluesettingendswithasemicolon.

TheCSSspecificationincludesmanyproperties.AfulllistofpropertiesisavailableatthisURL:https://developer.mozilla.org/en-US/docs/Web/CSS/Reference.

CommentsJustlikeHTMLorJavaScript,youcanaddcommentstoyourCSSfileusingthefollowingsyntax:

Page 96: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

/*ThisisaCSScomment*/

ElementSelectorsWhenyouselectelementsdirectly,all instancesof theelement are selectedand the sameCSSstylingisappliedtothem.Forexample,inthefollowingdemonstrationcode,every<div>onthepageisselectedandgivenabackgroundcolorofblue.div{background-color:blue;}

GroupingSelectorsIfyouwant toapplythesamestyles tomultipleselectorsyoucandosoinonelineofcodebygrouping selectors. You do this by separating each element with a comma. The followingdemonstrationcodeselectsthe<p>,<li>,and<h1>elementsandappliesthesamefontcolortoeachone.p,li,h1{color:green;//Changesfontcolorofallthreeelementstogreen}

DescendentSelectorsIfyouwanttoaccessanelementonlyifitisnestedinsideofaparticularelement,youcandothiswith descendent selectors.TheCSS syntax for this type of selector is expressed by typing theparent element, a space, and then the element you want to select. In the following code, adescendantselectorisusedtoselectall<li>elementsthatarenestedinany<div>element.Inthefollowingdemonstrationcode,thefontcolorofeach<li>elementissettoblue.divli{color:blue;}

Itisimportanttorealizethatdescendantselectorsselectallthedescendentelementsnomatterhownestedtheyare.IfthepreviousCSSexamplewereappliedtothefollowingHTMLcode,itwouldchangethefontcolorofallofthe<li>elementstoblueeventhoughtheyarenestedina<ul>element.

<div><ul><li>Item-1</li><li>Item-2</li><li>Item-3</li>

Page 97: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

</ul></div>

ChildSelectorsChildselectorsaresimilar todescendentselectorswiththedifferencethat theselectedelementcanonlybeoneleveldeeprelativetotheparent.Achildselectorismadeusingthe“>”symbolwith the parent element on its left side and the child element on its right. The followingdemonstrationcodewillselectall<li>elementsthatarechildrenof<ul>elements.ul>li{/*dosomething*/}

classandidOften when selecting elements, you do not want to select every element of a particular type.Rather,youmightwant to select either individual instancesof elementsorgroupsof elements.Youcansingleoutanindividualelementforstylingbyusinganidentifiercalledid.Conversely,youcandesignateacollectionofelementsasagroupbyusinganidentifiercalledclass.

To singleout anelementusinganid,youmust firstdefineid as an attribute of anHTMLelement.Thesyntaxlookslikethefollowing:<divid="controls"><!—-content--></div>

InyourCSSyoucan then select this individual elementbypreceding itsidwith a hashtagcharacter.#controls{/*propertiesandvaluesgohere*/}

KeepinmindthatidnamesareintendedtobeusedonlyonceinyourHTMLandareappliedtoasingleelement!

ModifyingtheAppInterfaceIn the following code, an additional<div> is added to the page and encloses a collection ofelements. You might be wondering why <h2> is used as the first element instead of another<h1>.The reason is that thenumbervalueof theheading element is intended to represent theprecedenceoftheinformationcontainedwithinit.Thelowestnumberismostimportantandeach

Page 98: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

highernumberislessimportant.Soforexample,theinformationcontainedinthe<h1>elementshouldtakeprecedencebecauseitconveysmoreoverallmeaningas it relates to thewebpage.Youmightnoticethatthereisasizedifferenceinthewaythebrowserrenderstheseelements.Youshould ignore this sizedifferenceand focusoncontentprecedence.Youcanalwayschange thefont sizeusingCSS tomake theseelementsanysizeyouwant, includingsetting themall to thesamesize.

Thenextelementis<ul>withanidofoscillator-list.Thiselementcontainsaseriesof<li>elements,eachgivenanidnameofaparticularwaveformtype.<ul>isanunorderedlist elementand is intended toencapsulate the<li>elements,whichare list elements.As thenameimplies,theseelementsareusedtocreatelists.<body><h1>CreatinganInterface</h1><p>InthischapterwewillgooverHTMLandCSS</p><div><form><inputid="on-off"type="button"value="start"><span>Clicktostartoscillator</span><p>Useslidertomodifyfrequency</p><inputtype="range"></form></div>

<div><h2>Waveform</h2><ulid="oscillator-list"><liid="sawtooth">sawtooth</li><liid="sine">sine</li><liid="triangle">triangle</li><liid="square">square</li></ul></div></body>

InthefollowingCSS,each<li>elementisselectedviaitsidandgivenabackgroundcolor.

#sawtooth{background-color:#336E91;}

Page 99: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

#sine{background-color:#783d47;}#triangle{background-color:#3b3040;}#square{background-color:#b85635;}

Nowthatyouknowhowtosingleoutanelementusingidselectors,itistimetolearnhowtogroupelementsusingclassselectors.

InyourHTMLdocument,assign the two<div>elements theclassosc-controls. Thenencapsulatethefirst<h1>and<p>insideanew<div>,andplaceanother<div>elementatthebottomofthepagethatcontainsaparagraphelementwiththephrase“JavaScriptforSoundArtistsDemo”insideofit.

Youshouldhaveatotaloffour<div>elementsinthiscode,whichlookslikethis:<body><div><h1>CreatinganInterface</h1><p>InthischapterwewillgooverHTMLandCSS</p></div><divclass="osc-controls"><form><inputid="on-off"type="button"value="start"><span>Clicktostartoscillator</span><p>Useslidertomodifyfrequency</p><inputtype="range"></form></div><divclass="osc-controls"><h2>Waveform</h2><ulid="oscillator-list"><liid="sawtooth">sawtooth</li><liid="sine">sine</li><liid="triangle">triangle</li><liid="square">square</li></ul></div>

Page 100: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<div><p>JavaScriptforSoundArtistsDemo</p></div></body>

Toselecttheosc-controlsclassfromCSS,youmustprefacetheclassnamewithadot.

.osc-controls{/*Noticethedotselector*//*setpropertyvalues*/}

In the following code, theosc-controls class is given a border. Only themiddle two<div>elementsrespondtothesechangesbecausethefirstandthird<div>onthepagedonothavetheclassosc-controlsassignedtothem..osc-controls{border-style:solid;border-color:#BC6527;border-width:2px;border-radius:10px;}

Youmightnoticethatthepagelooksalittleawkwardbecausethestartbuttonisnowpushedupagainsttheleftedgeofitscontainer.Also,thetwo<divs>withbordersarestackeddirectlyontop of one another with no space between them. You could make this look a bit cleaner bycreatingsomespacebetweentheseelements.Todothis,youshouldhaveanunderstandingofthefollowingthreeproperties:margin,border,andpadding.

Margin,Border,andPaddingBoth block-level and inline elements have access to border, margin, and paddingproperties,althoughtheyrespondtothemdifferently.Thesethreepropertiescorrespondtothree

Page 101: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

layersof spacearoundanelement.Theborderpropertycreatesaborderaroundanelement.Thepadding property creates a layer of space that resides inside the border. Themarginpropertycreatesalayerofspacethatresidesoutsidetheborder.

Tocreateabitofspacebetweenthetextanda<div>elementborder,includethefollowingcodeinyourCSSfile:div{padding:20px;}

Ifyouwanttoapplypaddingoramargintoonlyspecificsidesofanelement,youcandosobyusingthefollowingproperties:margin-topmargin-rightmargin-bottommargin-leftpadding-toppadding-rightpadding-bottompadding-left

Page 102: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thetwooutlinesaroundthemiddle<div>elementscouldusesomespacebetweenthem.Thefollowing code creates this space by using the bottom-margin property with a value of20px..osc-controls{border-style:solid;border-color:#BC6527;border-width:2px;border-radius:10px;margin-bottom:20px;}

RemovingListElementBulletPointsThe followingcode removes thebulletpoints fromeach list itemby selectingallof the<li>elementsthataredescendentsofanelementwithanidofoscillator-listandapplyingapropertycalledlist-style-typewithavalueofnone.#oscillator-listli{/*Descendentselector*/list-style-type:none;}

Page 103: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youcanremovethespacepreviouslyoccupiedbythebulletpointsbysettingthepadding-leftpropertytozeroontheparent<ul>element.#oscillator-list{padding-left:0px;}

FontSize,Style(Type),andColorAsatouch-up,thefollowingcodeselectsalltheelementsthatharbortextandsetstheirfontsizeto1.5em,whichisabitlargerthanthecurrentvalue.Anemisequivalenttoaparentelement’sfontsize,or,ifthereisnoparent,thewebbrowser’sdefaulttextsize.Formostwebbrowsers,thisvalueisabout16pixels,whichinCSSiswrittenas16px.Therefore,assumingthereisnoparentelement,2emisequivalentto32pixelsand1.5emto24pixels.p,span,li,input{font-size:1.5em;}

Thedefault font typeforChromeisTimesNewRoman.Youcanchange thefont type ifyoulike.ThefollowingcodechangesthefonttypetoArial.body{background-color:orange;font-family:"Arial";}

The fontcolorof the textdescribing thewaveform types isblack,which isdifficult to readbecausethebackgroundcolorofeach<li>isdark.Thefollowingcodechangesthetextcolorpropertytowhite.#oscillator-listli{list-style-type:none;color:white;}

Page 104: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

CenteringBlock-LevelElementsIfyouwanttocenterablock-levelelement,youcandosobysettingitswidthtoavaluesmallerthanitscontainingelementandapplyingamarginpropertywithavalueof0auto.Thissetsthe left and right margin values to automatically extend to the boundaries of the container,centeringtheelement.Inthefollowingcode,a<div>withaclassofapplicationcontainsalltheHTMLwithinthebodyelement.ItsCSSissettoafixedwidthandcenteredbyspecifyingmargin:0auto.<body><divclass="application"><div><h1>CreatinganInterface</h1><p>InthischapterwewillgooverHTMLandCSS</p></div><divclass="osc-controls"><form><inputid="on-off"type="button"value="start"><span>Clicktostartoscillator</span><p>Useslidertomodifyfrequency</p><inputtype="range"></form></div><divclass="osc-controls"><h2>Waveform</h2><ulid="oscillator-list"><liid="sawtooth">sawtooth</li><liid="sine">sine</li><liid="triangle">triangle</li><liid="square">square</li></ul></div><div>

Page 105: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<p>JavaScriptforSoundArtistsDemo</p></div></div></body>

TheCSSforthenewlycreateddivisasfollows..application{width:550px;margin:0auto;}

Asafinalstep,removethefirst<p>elementandreplacethetextofthe<h1>elementwiththetitleOscillatorGenerator.<divclass="application"><div><h1>OscillatorGenerator</h1></div><divclass="osc-controls"><form><inputid="on-off"type="button"value="start"><span>Clicktostartoscillator</span><p>Useslidertomodifyfrequency</p><inputtype="range"></form></div><divclass="osc-controls"><h2>Waveform</h2><ulid="oscillator-list"><liid="sawtooth">sawtooth</li><liid="sine">sine</li><liid="triangle">triangle</li><liid="square">square</li></ul></div><div>

Page 106: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<p>JavaScriptforSoundArtistsDemo</p></div></div>

SummaryInthischapter,youcreatedtheuserinterfaceforasmallapplication.Inthenextchapter,youwilladdJavaScriptcodetomaketheapplicationfullyfunctional.

Page 107: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

9DOMProgrammingwithJavaScript

ThischaptershowsyouhowtoaddJavaScripttoCSSandHTML.Bytheendofthechapter,youwillhavecreatedafullyfunctioningapplicationwithinteractivecontrols.

HowDoesJavaScriptCommunicatewiththeDOM?

TheDOM(DocumentObjectModel)containsacollectionofJavaScriptpropertiesandmethodsthatallowsyou tomanipulateHTMLelementsand towritecode that responds touser-invokedactionssuchasmouseclicksandformsubmissions.Typically,whenwritinganapplication,youwant toaskyourself two things.Thefirst is,whatdoyouwantorexpect theuser todo? Thesecondis,whatshouldhappeninresponsetouseractions?Soforexample,thefollowingcodecontains a play button, and when a user clicks it the browser runs a built-in function calledalert.Thisfunctiondisplaysapop-upwiththemessage:Youclickedplay.

HTML<body><inputid="play-button"type="button"value="PLAY"></body>

JavaScriptwindow.onload=function(){varplayButton=document.getElementById("play-button");playButton.addEventListener("click",function(){alert("Youclickedtheplaybutton");

Page 108: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

});};

The first lineof JavaScript,window.onload=function(){}, restricts the code inthefunctionscopefromrunninguntilalloftheHTMLcodehasloaded.IftheJavaScriptweretoloadbeforetheHTML,thenanyJavaScriptintendedtoaffectHTMLelementsorrespondtousereventslikemouseclickswouldeithernotberecognizedorwouldbeonlypartiallyrecognized.Theresultineitherofthesecasesisnonworkingcode.

ThenextlineselectsaDOMelementwithanidofplay-buttonandstoresitinavariablecalledplayButton. This is done using getElementById, a method of the documentobject.

Thedocument object is not part of the core JavaScript language. Instead, it is an objectprovidedbytheDOMAPI,makingitpartofthewebbrowser.varplayButton=document.getElementById("play-button");

ThenextlineofcodeappliestheeventListenermethodtotheplayButton.playButton.addEventListener("click",function(){alert("Youclickedtheplaybutton");});

TheplayButton.addEventListenermethodwaits forauser toapplyanactionandtheninvokesacallbackfunction.Inthiscase,theactionisamouseclickandisspecifiedinthefirstargumentof thefunction.Thesecondargumentis thecallback.Thecallbackrunswhentheuserclicksontheelementwiththeidofplay-button,whichinvokesalert().

The JavaScript DOMAPI contains many methods and properties. In this chapter, only thefollowingoftheseareused.

BuildingtheApplication

Page 109: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

In thepreviouschapter,youbuiltauser interfaceusingCSSandHTML.YouarenowgoingtowritethecodetomakethisaworkingJavaScriptapplication.Togetstarted,createacopyofthefinalprojectinChapter8andmakesureyoucreateafolderthatcontainsafilenamedapp.js.Yourdirectorystructureshouldlookliketheoneinthefollowingimage.

Intheapp.jsfile,makesureyouhavestrictmodeenabled.AllJavaScriptcodeiswrittenbelowtheusestrictstring."usestrict";

Setyourindex.htmlfiletoreferencetheapp.jsfile.<head><metacharset="UTF-8"><title>CSSandHTML</title><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head>

HowtoTriggeranOscillatorbyClickingaButtonTheuserinterfaceyoucreatedinthepreviouschaptercontainedabuttonwiththeidofon-off.Youarenowgoingtowritecodetostartanoscillatorplayingwhenthisbuttonisclicked."usestrict";varaudioContext=newAudioContext();window.onload=function(){varonOff=document.getElementById("on-off");onOff.addEventListener("click",function(){varosc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=300;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);});};

Althoughthiscodestartstheoscillatorplaying,itdoesnotstopitfromplaying.ThefollowingchangesimplementthestopfeaturebyaddingaconditionalstatementtoaddEventListener

Page 110: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

tocheckwhetheravariablenamedosc isset tofalse.Ifosc isfalse,anoscillator iscreatedandassignedtoit.ThismakestheBooleanvalueoftheoscvariabletrue,andthestartmethodisinvoked,allowingtheoscillatortoplay.IftheuserclickstheStartbuttonagain,theconditionalstatementseesthattheoscvariablehastheBooleanvaluetrueandrunsthecodeintheelsebranch.Thisstopstheoscillatorfromplayingandresetsosctofalse.

"usestrict";varaudioContext=newAudioContext();window.onload=function(){varonOff=document.getElementById("on-off");/*_________________________________________BEGINsetinitialoscstatetofalse*/

varosc=false;

/*_________________________________________ENDsetinitialoscstatetofalse*/onOff.addEventListener("click",function(){/*_____________________________________BEGINConditionalstatementtocheckifoscisTRUEorFALSE*/if(!osc){/*_________________________Isoscfalse?Ifsothencreateandassignoscillatortooscandplayit.*/

osc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=300;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

/*_________________________________Otherwisestopitandresetosctofalsefornexttime.*/}else{

osc.stop(audioContext.currentTime);osc=false;}/*_____________________________________ENDConditionalstatementtocheckifoscisTRUEorFALSE*/});};

TogglingtheStart/StopTextThough the code in the previous example works, the following feature makes it more user-friendly:Programthebuttontextandassociatedspanelementtexttodisplaythewordsstartorstopdependingonwhethertheoscillatorisplayingornot.

Page 111: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youcanimplementthisfeatureasfollows:"usestrict";varaudioContext=newAudioContext();window.onload=function(){varonOff=document.getElementById("on-off");varspan=document.getElementsByTagName("span")[0];

/*_________________________________________BEGINsetinitialoscstatetofalse*/varosc=false;/*_________________________________________ENDsetinitialoscstatetofalse*/

onOff.addEventListener("click",function(){/*_____________________________________BEGINConditionalstatementtocheckifoscisTRUEorFALSE*/

if(!osc){/*_________________________Isoscfalse?Ifsothencreateandassignoscillatortooscvariableandplayit.*/osc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=300;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);onOff.value="stop";span.innerHTML="Clicktostoposcillator";/*_________________________________Otherwisestopitandresetosctofalsefornexttime.*/}else{

osc.stop(audioContext.currentTime);osc=false;onOff.value="start";span.innerHTML="Clicktostartoscillator";}

/*_____________________________________ENDConditionalstatementtocheckifoscisTRUEorFALSE*/});};

Page 112: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

ThiscodeintroducesanewDOMmethodcalledgetElementsByTagNameaswellastwonew DOM properties: innerHTML and value. The getElementsByTagName methodallowsyoutoselectacollectionofelementsonthepagebytagname.Youcanthenspecifyanindividualelementusingarray-styleindexselectors.Theindexselectionrepresentstheorderoftheelementonthepage,withthefirstelementstartingat0.Toselectthefirstspanelementonthepage, you specify getElementsByTagName(“span”)[0]. If there are several spanelementsandyouwanttoselectthethirdonefromthetopofthepage,youspecifytheindexas2,andtheselectorlookslikethis:

document.getElementsByTagName("span")[2]

ItisimportanttounderstandthatDOMelementsarenotarrays,eventhoughthenotationusedtoselectthemissimilartothatusedforarrays.DOMelementsarereferredtoasnodes.

ProgrammingtheFrequencySliderYouarenowgoingtoaddfunctionality to thefrequencyslider.Thefollowingcodeshowshowyoucapturethevalueofthefrequencysliderwhentheoscillatorisclicked.Thisisdoneusingthevalueproperty.ThevalueisthenstoredinavariablenamedfreqSliderValandrepresentsthe frequency of the oscillator. Additionally, thefreqSliderVal is logged to the console,allowingyoutoseechangesmadetoit."usestrict";varaudioContext=newAudioContext();window.onload=function(){varonOff=document.getElementById("on-off");varspan=document.getElementsByTagName("span")[0];

/*_________________________________________BEGINsetinitialoscstatetofalse*/varosc=false;/*_________________________________________ENDsetinitialoscstatetofalse*/onOff.addEventListener("click",function(){/*_____________________________________BEGINConditionalstatementtocheckifoscisTRUEorFALSE*/varfreqSliderVal=document.getElementsByTagName(“input”)[1].value;

console.log(freqSliderVal);

if(!osc){/*_________________________Isoscfalse?Ifsothencreateandassignoscillatortooscvariableandplayit.*/osc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=freqSliderVal;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);onOff.value="stop";span.innerHTML="Clicktostoposcillator";/*_________________________________Otherwisestopitand

Page 113: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

resetosctofalsefornexttime.*/}else{

osc.stop(audioContext.currentTime);osc=false;onOff.value="start";span.innerHTML="Clicktostartoscillator";}/*_____________________________________ENDConditionalstatementtocheckifoscisTRUEorFALSE*/});};

ChangingtheFrequencyinRealTimeThecodeinthepreviousexampleworks,butthereisacost.Tohearthefrequencychanges,theusermustturntheoscillatoroff,movethefrequencyslider,andthenstarttheoscillatoragain.Youcouldprovideaseamlessexperienceiftheusercouldheartheeffectinrealtimewhilemovingtheslider.To implement this,youcanusesetInterval() tocheck for statechangesof therangesliderandthenapplythemtotheosc.frequencyvalue.

The purpose of setInterval() is to invoke a function repeatedly at a specified timeinterval.Inthefollowingcode,setInterval() takestwoarguments.Thefirstisacallbackand the second is a number that represents amillisecond interval value (in this case, 50ms).WhensetInterval()runs,thecallbackisinvokedrepeatedlyatthetimeintervalspecifiedin thesecondargument.ThefreqSliderValvariablehasbeenplacedoutside the scopeofboththeonOff.addEventListenerandsetIntervalmethodssothatbothofthemhaveaccesstoit.ThesetIntervalmethodcontainsaconditionalthatcheckstoseewhetheroscisfalse,andifsodisplaysthemessage“Oscillatorisstopped.Waitingforoscillatortostart,”intheconsole.Themomenttheoscillatorstarts,setInterval() reassignsfreqSliderValto therespective<input> rangevalueandassigns thatvalue toosc.frequency.value.BecausesetInterval()doesthisin50-msincrements,itcreatesnearreal-timechangeintheoscillatorfrequencywhenyoumovethefrequencyslider."usestrict";varaudioContext=newAudioContext();window.onload=function(){varonOff=document.getElementById("on-off");varspan=document.getElementsByTagName("span")[0];/*_________________________________________BEGINsetinitialoscstatetofalse*/

Page 114: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varosc=false;/*_________________________________________ENDsetinitialoscstatetofalse*/

/*_________________________________________BEGINsetinitialfrequencyvalue*/varfreqSliderVal=document.getElementsByTagName("input")[1].value;/*_________________________________________ENDsetinitialfrequencyvalue*/

/*_________________________________________BEGINcheckrangeslidervalueandsetfrequencyofoscillator*/

setInterval(function(){

if(!osc){

console.log("Oscillatorisstopped.Waitingforoscillatortostart");

}else{

freqSliderVal=document.getElementsByTagName("input")[1].value;osc.frequency.value=freqSliderVal;console.log("Oscillatorisplaying.Frequencyvalueis"+freqSliderVal);}

},50);

/*_________________________________________Endcheckrangeslidervalueandsetfrequencyofoscillator*/

onOff.addEventListener("click",function(){

/*_____________________________________BEGINConditionalstatementtocheckifoscisTRUEorFALSE*/

if(!osc){/*_________________________Isoscfalse?Ifsothencreateandassignoscillatortooscvariableandplayit.*/osc=audioContext.createOscillator();osc.type="sawtooth";osc.frequency.value=freqSliderVal;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);onOff.value="stop";span.innerHTML="Clicktostoposcillator";/*_________________________________Otherwisestopitandresetosctofalsefornexttime.*/}else{

osc.stop(audioContext.currentTime);osc=false;onOff.value="start";span.innerHTML="Clicktostartoscillator";}

/*_____________________________________ENDConditionalstatementtocheckifoscisTRUEorFALSE*/

Page 115: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

});};

ChangingWaveformTypesYouarenowgoingtowritecodetoallowuserstoclickoneofthefourwaveformsonthepageandsettheoscillatortoplaytheselectedwaveform.

Todothis,usetheeventListener()methodtocapturetheidoftheelementclickedbytheuser.Becausetheidofeach<li>isthenameofawaveform,youmustassignthisidtotheosc.typeproperty.Youwantuserstobeabletoupdatethewaveformtypewithouthavingtorepeatedlyrestarttheoscillator,andyoucandothissimilarlytothefrequencysliderchangesinthepreviousexample.

In the following code, you create a variable named selectedWaveform to give theoscillatoradefaultwaveformtypeandtostoreanyselectedwaveformchanges.varselectedWaveform="sawtooth";

Thisvalueisthenassignedtoosc.type.

if(!osc){osc=audioContext.createOscillator();osc.type=selectedWaveform;osc.frequency.value=freqSliderVal;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);onOff.value="stop";span.innerHTML="Clicktostoposcillator";}

Next, create a variable named waveformTypes and assign it the result of callinggetElementsByTagName().ThewaveformTypesvalueisusedtoselectoneofthefour<li>elementsonthepage.varwaveformTypes=document.getElementsByTagName('li');

Next,createafunctionnamedselectthatisusedasacallbackforaseriesofeventlistenersusedtoselecttheidofthe<li>clickedbytheuser.functionselect(){selectedWaveform=document.getElementById(this.id).id;

Page 116: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

console.log(selectedWaveform);//Outputsid}

Next,aforloopisusedtoexamineeach<li>nodeandassignaneventlistenertoeachone.Eacheventlistenerissettorespondtoaclickeventthatinvokesthecallbackfunctionselect.Whentheselectfunctionruns,itcapturestheidofthe<li>elementclickedbytheuser.ThisidisthenstoredintheselectedWaveformvariable.

for(vari=0;i<waveformTypes.length;i++){waveformTypes[i].addEventListener('click',select,false);}

CompletedCodewithWaveformSelection"usestrict";varaudioContext=newAudioContext();window.onload=function(){varonOff=document.getElementById("on-off");varspan=document.getElementsByTagName("span")[0];varosc=false;varfreqSliderVal=document.getElementsByTagName("input")[1].value;

/*_________________________________________BEGINsetselectedwaveformtypevalue*/

varselectedWaveform="sawtooth";/*_________________________________________ENDsetselectedwaveformtypevalue*/

/*_________________________________________BEGINselectall<li>elements*/varwaveformTypes=document.getElementsByTagName('li');/*_________________________________________ENDselectall<li>elements*/

/*_________________________________________BEGINcallbacktoselect<li>byidandassignidnametoselectWaveform*/functionselect(){selectedWaveform=document.getElementById(this.id).id;console.log(selectedWaveform);}

/*_________________________________________ENDcallbacktoselect<li>byidandassignidnametoselectWaveform*/

/*_________________________________________BEGINloopthroughall<li>elementsandsetaclickeventListeneronthem*/

for(vari=0;i<waveformTypes.length;i++){waveformTypes[i].addEventListener('click',select);}

/*_________________________________________ENDloopthroughall<li>elementsandsetaclickeventListeneronthem*/

Page 117: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

setInterval(function(){

if(!osc){

console.log("Oscillatorisstopped.Waitingforoscillatortostart");

}else{

freqSliderVal=document.getElementsByTagName("input")[1].value;osc.frequency.value=freqSliderVal;console.log("Oscillatorisplaying.Frequencyvalueis"+freqSliderVal);osc.type=selectedWaveform;}

},50);

onOff.addEventListener("click",function(){

if(!osc){osc=audioContext.createOscillator();osc.type=selectedWaveform;osc.frequency.value=freqSliderVal;osc.connect(audioContext.destination);osc.start(audioContext.currentTime);onOff.value="stop";span.innerHTML="Clicktostoposcillator";}else{

osc.stop(audioContext.currentTime);osc=false;onOff.value="start";span.innerHTML="Clicktostartoscillator";}});};

GivinganOutlinetotheSelectedWaveformTypeWhenauserselectsawaveformtype,thereisnovisualcuethatidentifiesthetypeselected.Thefollowingcodeaddsawhiteoutlinetotheselectedwaveform.

Page 118: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

IntheCSSfile,createaclassnamedselected-waveformandgiveitanoutlinepropertywith a width of 2 pixels and the color white. Then, add this class dynamically to the<li>elementthatcorrespondstotheselectedwaveformtype.Toremovetheselectedwaveformclassofthepreviouslyselectedelement,useaforlooptoexamineallofthe<li>elementsandinvokeclassList.remove("selected-waveform")oneachone.

IntheCSSfile,createtheclass..selected-waveform{outline:2pxsolidwhite;}

IntheJavaScriptfile,addthefollowingcodetotheselectfunction.functionselect(){

//_____________________________________BEGINselectelementbyidvarselectedWaveformElement=document.getElementById(this.id);//_____________________________________ENDselectelementbyid

selectedWaveform=document.getElementById(this.id).id;console.log(selectedWaveform);

/*_____________________________________BEGINremoveanypreviouslyaddedselected-waveformclasses*/

for(vari=0;i<waveformTypes.length;i+=1){waveformTypes[i].classList.remove("selected-waveform");}/*_____________________________________ENDremoveanypreviouslyaddedselected-waveformclasses*/

/*_____________________________________BEGINaddtheselected-waveformclasstotheselectedelement*/

selectedWaveformElement.classList.add("selected-waveform");/*_____________________________________ENDaddtheselected-waveformclasstotheselectedelement*/}

SummaryInthischapter,youlearnedhowJavaScriptinteractswiththeDOM.Inthenextchapter,youwilllearnthebasicsofalibrarynamedJQuerythatmakesDOMprogrammingwithJavaScripteasier.

Page 119: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

10SimplifyingDOMProgrammingwithJQuery

Inthepreviouschapter,youlearnedhowJavaScriptinteractswiththeDOM.Inthischapter,youwill learnhowtosimplify theprocessofadding interactivecomponents toyourapplicationbyusingalibrarycalledJQuery.TheobjectiveofthischapterisnottoteachyoutheentireJQueryAPI, but to give you the foundational knowledge tomake JQuery a part of your programmingtoolkit.YoucanfindtheJQueryAPIatthisURL:https://api.jquery.com/.

WhatIsJQuery?JQueryisalibrarywritteninJavaScriptintendedprimarilyforDOMmanipulation.Alibraryisacollection of preassembled code pieces designed to make a particular group of tasks easier.JQuery contains a large collection ofmethods and properties that can be used individually orcombinedtohelpeasethecomplexityofJavaScriptDOMprogramming.

JQuerySetupYoucansetupJQueryinoneoftwoways.Thefirstistodownloadthelibraryandreferenceitfrom anHTML file. The second is to reference it from a content delivery network (CDN forshort).ACDNisaserviceaccessiblethroughtheWorldWideWebwhereyoucanreferencecodelibrariesandotherfiles.ThedownsideofusingaCDNisthatyouwillalwaysneedaworkingInternetconnectiontoaccessit.

ReferencingJQueryDirectly

Page 120: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

ToreferenceJQuerydirectly,firstdownloadthelibraryatthisURL:http://jquery.com/.Next,usethefollowingcodeasanexampleofhowtoreferencethelibrary.<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title></title><scripttype="text/javascript"src="js/jquery-2.1.4.min"charset="utf-8"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head><!--_____________________________________________BEGINAPP--><body>

</body><!--_____________________________________________ENDAPP--></html>

UsingJQueryfromaCDNThe following code references JQuery from a Google CDN library collection at this URL:https://developers.google.com/speed/libraries/.<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title></title><scripttype="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"charset="utf-8"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head><!--_____________________________________________BEGINAPP--><body>

</body><!--_____________________________________________ENDAPP--></html>

Inthepreviouschapter,yourJavaScriptcodewasencapsulatedinthefollowingfunction:window.onload=function(){//codegoeshere};

Thiswasdonetoensurethat thecodeloadsafter thebrowserrenders theHTMLdocument.JQuerycomesbundledwithafunctionthatdoesthesamethingwithslightlydifferentsyntax.$(function(){//codegoeshere});

Page 121: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HowtoUseJQueryThemostfundamentalusecasesforJQueryrequireknowledgeoftwothings.ThefirstishowtoselectanHTMLelement.Thesecondishowtodosomethingwiththatelement.

SelectingHTMLElementsThefollowingcodeshowshowtoselectanHTMLelement.$("div")//thisselectsalldivelementsonthepage

The syntax for element selectors always begins with a dollar sign, followed by twoparentheses.Youplace theelementwrapped inquotes inside theparentheses. JQueryselectorsborrowfromCSSselectorsyntax.IfyouknowhowtoselectelementsusingCSS,youcanquicklylearntoselectelementsinJQuery.ThefollowingareafewexamplesofCSSselectorsandtheirJQuerycounterparts.

StoringDOMSelectorsasVariablesInsomecircumstances,youmightfinditaestheticallypreferabletostoreyourDOMselectorsasvariables. The following code is a modified version of the previous example with the divselectorstoredinavariable.ThevariableisprecededbyadollarsigntoemphasizethatitisaJQuery selector. Storing the DOM selector as a variable has the same effect as selecting theelementdirectly.$(function(){var$transportControl=$("div");

});

UsingMethods

Page 122: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

After you have selected an element, you can modify it in some way using JQuery’s built-inmethods.JQuerycomeswithalargecollectionofmethods;however,inthischapterweareonlygoingtousethefollowingmethods:

Thefollowingisanexampleofusingcss()tomodifythelookofanelement.css()canbeused either to change a single property or to set multiple properties using an object as anargument.Anexampleofbothusecasesisgiveninthefollowingcode:

HTML<div>Play</div><div>Stop</div><div>Rewind</div><div>FastForward</div><div>Pause</div>

Tochangeasingleproperty:

JQuery/JavaScripttoChangeaSingleProperty$(function(){$("div").css("background-color","orange");});

Tochangemultipleproperties:

JQuery/JavaScripttoChangeMultipleProperties$(function(){$("div").css({backgroundColor:"orange",width:"100px",borderStyle:"solid"

Page 123: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

});});

MethodChainingIfyouwanttoapplymultiplemethodstoanelement,youcanconnecttheminsuccessionsothattheyareinvokedoneafteranother.Thisiscalledmethodchaining.

Inthefollowingcode,allofthedivelementshavetheirCSSdisplaypropertysettonone.JQuery is used to select the div elements and set their CSS properties using css(). ThefadeInmethodisthenchainedtoeachdiv,sothateverydivon thepagefades inover thecourseof1second(1000milliseconds).ThefirstargumentoffadeIn()isthedurationoftheanimationinmilliseconds.WhenfadeIn()completes,thefadeOutmethodisinvoked,whichfadesoutalldivelementsoverthecourseof1second.

HTML<div>Play</div><div>Stop</div><div>Rewind</div><div>FastForward</div><div>Pause</div>

CSSdiv{display:none;}

JQuery/JavaScript$(function(){$("div").css({backgroundColor:"orange",width:"100px",borderStyle:"solid"}).fadeIn(1000).fadeOut(1000);//exampleofmethodchaining});

The following HTML code contains an input element with its type attribute set tobutton.This isselectedwithJQueryandset torespondtoclickeventsviaanevent listener.Themethodusedforthisison(),whichtakestwoarguments.Thefirstargumentisastringthatdefinestheeventtypeandthesecondisacallbackthatisinvokedwhentheeventisfired.

Page 124: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HTML<inputtype="button"value="Play">

JQuery/JavaScript$(function(){$("input").on("click",function(){//clickeventlisteneralert("Youclickedplay");});});

ThethisKeywordThe this keyword in JQuery can be used as a shorthand for the currently selected DOMelement. The following HTML code contains three input elements. Using JQuery, these threeelementsareassignedaclickevent listener.Whenauserclicksan inputbutton, the$(this)selectorisusedtosingleouttheindividualelementtheuserclicked.Thevalmethodreturnsthevalueattributeoftheclickedelement.

HTML<inputtype="button"value="Play"><inputtype="button"value="Pause"><inputtype="button"value="Stop">

JQuery/JavaScript$(function(){$("input").on("click",function(){/*assigneventlistenertoallinputelements*/console.log($(this).val());/*usethethiskeywordtoaccesstheelementclickedandreturnitsvalueproperty*/});});

RefactoringtheOscillatorPlayertoUseJQueryNow that you understand some JQuery basics, you are going to refactor the application youcreated in thepreviouschapterbyreplacing thebuilt-inJavaScriptDOMmethodswithJQueryselectorsandmethods.

Page 125: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Copythecompletedcodefromthepreviouschaptertoanewdirectory.Inyourindex.htmlfilereferencetheJQuerylibrary.<head><metacharset="UTF-8"><title>CSSandHTML</title><scripttype="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"charset="utf-8"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head>

Replacetheapp.jsfilewithanewemptyfilewiththesamename.Intheoldapplication,youusedthisfunctiontoencapsulateyourcode:

window.onload=function(){}

In the new version of your code, make sure you replace window.onload with theequivalentJQueryfunction.Alsoput"usestrict"andtheAudioContextinstantiationatthetopofthefile,asinthefollowingexample:"usestrict";varaudioContext=newAudioContext();$(function(){//allcodewillgohere});

Next,modifythefirstthreevariablesoftheJavaScriptfiletouseJQueryselectors.

WithoutJQuery

WithJQuery

Page 126: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

This code uses $("#on-off") to select the oscillator start or stop button by id. It isdenotedbythehashselector.Youthenuse$("span")toselectthespanthatcontainsmessagetext.Thisselectionisdonebyelementand,becausethereisonlyonespanelementonthepage,youdonotneedtobemorespecific.Lastly,$("input").eq(1).val()isusedtoselecttherangeslidervalueofthesecondinputelementonthepage,whichisstoredinavariablenamed$freqSliderVal.Thisisdonebymakingageneralelementselectionforallinputelementsandspecifyingthesecondoneonthepagewiththeeq(1)method.Theeq()methodenablesselectionof elements by indexwith its argument being the indexvalue.Once the correct inputelementisselected,val()isusedtogetitsvalueattribute.

SettingUptheEventListenerfortheUser-SelectedListElement

In theoldapplication, theuser interfacecodeforoscillatorselectionwasabitcomplex.First,youneededtocreatealoopthatattachedaclickeventlistenertoall<li>elements.Thenyoucreatedafunctionnamedselecttobeinvokedasacallbackforeachofthoseeventlisteners.Whentheuserclickedan<li>element, theselect()callback looped throughevery<li>and removed any class identifiers titled selected-waveform. It then assigned theselected-waveformclasstoonlytheclickedelement.

WithJQuery,muchofthiscomplexitycanbeavoided.ThefollowingimagesshowthecontrastbetweentheoldversionandarefinedJQueryimplementation.

EventListenerwithoutJQuery

Page 127: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

EventListenerwithJQuery

TherefactoredJQuerycodeassignsaclickeventlistenertoall<li>elements.Whentheuserclicks an <li> element, its id is stored in a variable named selectedWaveform.selectedWaveformisreferencedinahigherscopeandisusedlatertosettheoscillatortype.

Page 128: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheremoveClass()method isused to remove theselected-wavefrom class fromall<li>elements.Thelastlineofcodeuses$(this)toselectthespecific<li>theuserclickedandinvokesaddClass()togiveittheclassselected-waveform.

ModifyingtheCodeinsetIntervalThe only modification you need to make to setInterval is the replacement offreqSliderValwithaJQueryDOMselector.

setIntervalMethodwithoutJQuery

setIntervalMethodwithJQuery

The remaining changes require you tomodify the name of theonOff selector variable to$onOffandreplacetheaddEventListenerwiththeon()methodsettorespondtoclickevents. Then rename the freqSliderVal to $freqSliderVal, replace the

Page 129: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

span.innerHTMLwith$messageText.text(),andlastlyreplaceonOff.valuewiththeJQueryequivalentof$onOff.val().

onOffMethodwithoutJQuery

$onOffSelectorwithJQuery

SummaryIn this chapter, you learned the basics of using JQuery for DOM manipulation. You alsorefactoredthecodeinthepreviouschaptertocontrastthedifferencebetweenworkingwithand

Page 130: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

withoutJQuery.Inthenextchapter,youwilllearnhowtoimportandplaybackaudiofileswiththeWebAudioAPI.

Page 131: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

11LoadingandPlayingAudioFiles

Inthischapter,youwilllearnthebasicsofworkingwithaudiofiles.Thisincludeshowtoload,play,andrunaudiofilesthroughthenodegraphtotakeadvantageofitsbuilt-ineffects.

PrerequisitesTo load and play back audio files, you must be running a web server. Chapter 1 gives youinstructionsabouthowtointegrateawebserverwithSublimeTextbyinstallingapackagecalledSublimeServer.Youraudiofilesarereferencedfromthedirectorythewebserverispointingto,whichyoucansetupasfollows:

1.Createafolderonyourdesktopwithanewprojecttemplate.

2. Start the Sublime Text web server by selecting Tools > SublimeServer > StartSublimeServer.

3.Openthesidebar(ifitisn’talreadyopen)byselectingView>SideBar>ShowSideBar.

4.Dragthetemplatefoldertothesidebarpanel.

5.Openawebbrowserandenter:http://localhost:8080intheURLfield.

6. Click the link to the template folder. An empty screen is displayed because the initialtemplateisempty.

For this exercise, youwill need an audio file that is short and preferably ofMP3 format (forcompatibility issues). The file referenced in the example code is snare.mp3. Create adirectoryinyourtemplatefolderandnameitsounds,thencopyyourMP3filethere.

TheTwoStepstoLoadinganAudioFile

Page 132: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Loadinganaudiofileisdoneintwosteps:

1.StoretheaudiofileinabufferusingtheXMLHttpRequestobject.

2.DecodethebufferwithdecodeAudioData.

In the first step, you use the built-in browser object namedXMLHttpRequest to store thecollectedaudiofileinabuffer.ThisobjectispartofthewebbrowserandisindependentoftheWebAudioAPI.Abufferisasmallpieceofinternalmemoryusedtostoredatasothatitcanbeaccessed quickly. Storing the file this way provides low latency playback and the ability tomodifytherawwaveformdata,whichisusefulforsomeapplications.

Inthesecondstep,youusethedecodeAudioDatamethodtodecode theaudiofilebufferyoucreatedinthefirststep.AftertheWebAudioAPIhasreadanddecodedtheaudiodata,youcanassigntheobjecttoavariableandreferenceitinthenodegraphforplayback.

Thefollowingexampleshowshowyou loadasingleaudiofile,afterwhichyoucanplay itbackbyclickingonthebrowserwindow.Therestofthischapterisdedicatedtoexplainingeachlineinthisexampleandhowallthelinesworktogether.varaudioContext=newAudioContext();varaudioBuffer;vargetSound=newXMLHttpRequest();getSound.open("get","sounds/snare.mp3",true);getSound.responseType="arraybuffer";

getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){audioBuffer=buffer;});};

getSound.send();

functionplayback(){varplaySound=audioContext.createBufferSource();playSound.buffer=audioBuffer;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime);}window.addEventListener("mousedown",playback);

TheXMLHttpRequestObjectThe first step to importing an audio file is to create a newXMLHttpRequest object. Thisobject allowsyou to importdataover thehttp protocol,which is the sameprotocol used toloadwebpages.Thisdatacanthenbestoredinvariousforms.Thecodetocreatetheobjectisasfollows:vargetSound=newXMLHttpRequest();

Page 133: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

The XMLHttpRequest function invocation returns an object literal that is stored in avariablenamedgetSound.Thisisdoneusingthenewkeyword.Thenewkeywordwillnotbecovereduntilthenextchapter,butdon’tworry.Fornow,theimportantthingistounderstandthatXMLHttpRequestisafunctionthatreturnsanobject.Thisobjectcontainsalargecollectionofbuilt-inpropertiesandmethods.Forloadingsoundfiles,youneedfiveofthesemethods:

■open

■responseType

■onload

■response

■send

The next line of code uses the open method to fetch the audio file. This method has threearguments.vargetSound=newXMLHttpRequest();getSound.open("get","sound/snare.mp3",true);

To clearly understand the purpose of the first argument requires a brief explanation of acommandcalledagetrequest.

getRequestsWhen you type aURL into aweb browser and “go” to awebsite, theweb browser does notactually go anywhere.What actually happens is the browser issues a command to thewebsiteserver that initiates a download of theHTML content and other files needed to view it. Thiscommandiscalledagetrequest.Thebeautyofgetrequestsisthatyoucanusethemoutsidethecontextof typingaURLintoabrowser. Inotherwords,youcanwritecode torunget requestsbehind the scenes. This is how XMLHttpRequest is used to pull audio files into yourapplication—andwhythefirstargumentoftheopenmethodis“get”.

The secondargument to theopenmethod is thepath to the file youwant to fetch.For thisexample,anMP3filenamedsnare.mp3isimported.

AWordonAudioFileTypeCompatibilityIt is important to understand that audio file type compatibility is dependent on which webbrowseryouuse.Ifyouwantyourapplicationtobecompatiblewithmultiplewebbrowsers,youhavetoincludemultipleaudiofilesofdifferentformatsandwriteconditionalcodetodeterminewhatformattousebasedontherenderingbrowser.Thethreemostpopularaudiofileformatsfor

Page 134: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

web browsers areWAV,OGG, andMP3.An audio file format compatibility chart for variousbrowsersisavailablehere:http://caniuse.com/#search=audio%20format.

The thirdargument to theopenmethoddetermineswhether theopenoperation isdone inasynchronousorasynchronousmanner.Thetruevalueselectstheasynchronoussetting,whereasfalse selects the synchronous setting.Understanding thedifferencebetween synchronous andasynchronouscodeexecutionisanin-depthtopicandrequiressomeexplaining.

SynchronousversusAsynchronousCodeExecutionWhenthebrowserexecutescode,itdoessofromtoptobottom.Asaresult,afunctionthattakesalongtimetoexecutecreatesanoticeabledelayintheprogramitself.Thisisbecausethecodeisexecutingsynchronously.

WhenyouusetheXMLHttpRequestobject to retrievedatasynchronously fromaserver,thetimedelaybetweenmakingthegetrequestandwhentheactualdataisreturnedcancreateanoticeabledelayintheexecutionofyourprogram.Thisdelayisparticularlynoticeablewhenyouloada largeaudiofileand thenhave towait for itsentirecontents to load intomemorybeforeyourprogramcontinues.

Delays in execution arewhydoing suchoperations synchronously is discouraged anddoingthemasynchronouslyispreferred.Workingasynchronouslyletsyouruntheopenmethodwhileimmediately allowing your program to continue executing to completion. In themeantime, theaudiofilecontinuestoloadbehindthescenes,regardlessofhowlongittakestocomplete.Whentheaudiofileisavailable(whenitisdoneloading),youcanuseit.Whencodeisexecutedinthismanner,wesaythatitisnonblocking.Ofcourse,thedownsideofthisisthatifyouhaveanaudiofileloadinganditistakingalongtime,theuserofyourprogrammightbewonderingwhynothingis playing even though the page has rendered! This problem can be remedied by presenting amessagetouserstowarnthemthattheywillhavetowaitfortheaudiofiletofinishloading.Inthemeantime,theycanexploreotherpartsofyourapplication.

ThenextlineofcodesetsapropertycalledresponseTypetoavalueofarraybuffer.TheresponseTypepropertydefineshowthedatayouareimportingismadeavailabletoyourprogram.Generally,theXMLHttpRequestobjectisusedtofetchtextfiles,andinthosecasesyou might choose one of the other available responseType settings such as text ordocument.Forsoundfiles,arraybufferisused.Thisisageneralcontainerforbinarydatathatisusefulforaudiofiles.vargetSound=newXMLHttpRequest();getSound.open("get","sounds/snare.mp3",true);getSound.responseType="arraybuffer";

Thenextlineofcodebeginswithanonloadfunctionthatisinvokedafterthedata(theaudiofile)hascompletedloading.Withintheonloadfunction,decodingoftheaudiodatatakesplacethat makes it usable by the Web Audio API. You do this with a method calleddecodeAudioData that takes two arguments. The first argument is a property calledresponsethatrepresentstheloaded(andundecoded)audiodata.

Page 135: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){audioBuffer=buffer;});};

Thesecondargumenttotheonloadfunctionisacallbackfunctionthatallowsyoutocapturetheresultofthedecodedaudiodataanddosomethingwithit.Tocapturethedecodedfile,youmustpassitasanargumentofthecallbackfunction.Inthiscase,thenamegivenforthisdecodedinformationisbuffer.Tomakebufferaccessibletotherestoftheprogram,youcanassignittoaglobalvariable.varaudioContext=newAudioContext();varaudioBuffer;vargetSound=newXMLHttpRequest();getSound.open("get","snare.mp3",true);getSound.responseType="arraybuffer";getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){audioBuffer=buffer;//storedasglobalvariable});};

Thelastlineisthesendmethod.ThismethodinitiatestheXMLHttpRequest.getSound.send();

Nowthattheaudiofileisloadedintoabuffer,theplaybackfunctioncontainstherequiredcodetoconnectittothenodegraphandeventuallyplayitback.ThefirstlineassignsamethodcalledcreateBufferSource to avariable.Thismethod isused to create abuffer sourcenodethatisusedforaudiobuffers.Inotherwords,itislikecreateOscillator,butinsteadofbeingusedtocreateoscillators,itisusedtocreateanodethatcanplaybackthecontentsofanaudiobuffer.Toinjecttheaudiobufferintothenodegraph,youneedtoassignittoapropertyofthebuffersourcenodenamedbuffer.functionplayback(){

varplaySound=audioContext.createBufferSource();playSound.buffer=audioBuffer;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime);}

YoucannowconnectthebuffertotheaudioConext.destinationandsetthestarttime.

functionplayback(){

varplaySound=audioContext.createBufferSource();playSound.buffer=audioBuffer;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime);}

Thelastlineofcodeisaneventlistenerthatletsyouplaybackthefilewhenthewindowisclicked.

Page 136: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

window.addEventListener("mousedown",playback);

Ifyouclickonthepage,youshouldheartheaudiofileplay.

ProcessingtheAudioBufferwiththeNodeGraphWhentheaudiobufferisfedintothenodegraph,youcanprocessitwithitsbuilt-ineffects.Inthefollowingcode,thenodegraphconnectionhasbeenmodifiedtoincludeapropertyoftheaudiobuffer namedplaybackRate. This changes the playback speed of the sound.To double thespeed,setthevalueto2;toplaythesoundbackathalfspeed,setthevalueto0.5.functionplayback(){varplaySound=audioContext.createBufferSource();playSound.buffer=audioBuffer;playSound.playbackRate.value=0.5;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime);}

SummaryEach time you want to import an audio file into your program, you must initiateXMLHttpRequestwith all themethod and property settings shown in this chapter.You canimagine that duplicating this code repeatedly for each file is unfeasible for a large-scaleapplication.Byabstractingawaythiscomplexity,youcanprogramasolutiontothisproblemthatletsyouimportmultipleaudiofileswithonlyafewlinesofcode.Inthenexttwochapters,youwilllearnhowtodothiswhilelearningabouttwonewobjectcreationmethodologies:factoriesandconstructors.

Page 137: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

12FactoriesandConstructors

In the previous chapter, you learned how to import audio files. You also learned that loadingmultiple filescan requirea tremendousamountofcodeduplication.Because repeatingcode issomethingthatshouldbeavoided, it isagoodidea toabstractyouraudiofile loadingprogramintoalibrarythatimportsalltherequiredfileswithaminimalamountofcodeduplication.Inthischapter, youwill learn twonewobject creationpatterns to helpyoudo this.The first pattern,called factory, is used to create your audio loader library. The second pattern, calledconstructor,isintroducedprimarilybecauseofitsprevalenceintheJavaScriptworld,makingitanimportantpatterntofamiliarizeyourselfwith.Factoriesandconstructorsarealmostidentical.Thedifference lies solely inminor implementationdetailsandsyntax. Inotherwords,anythingyou can dowith one of these patterns you can dowith the other.Your choice ofwhich to usecomesdowntopersonalchoice.

Inthenextchapter,youwillputwhatyoulearnheretoworkandbuildyouraudiofileloadinglibrary.

JavaScriptandtheConceptofClassProgramming languages that are organized around objects that interact with one another areusually referred to as object oriented. JavaScript is considered an object-oriented language,although it differs from traditional object-oriented languages in one importantway: JavaScriptlackswhatarecalledclasses.

WhatAreClasses?Withmost object-oriented programming languages, to create an object youmust first create aclass,whichisakindofblueprintthatyourobjectisderivedfrom.Forexample,imagineaclassforamixingconsolethatcontainsanumberofaudiochannels.Whenyoucreateanobjectfromthisclass,youhavetheoptiontodeterminethechannelcountonthefly.Inthisregard,theclass

Page 138: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

actsasakindofscaffoldingforthecreationofobjectswhileofferingadegreeofflexibilityforindividualobjectcustomization.

ThebeautyofJavaScriptisthatwhenyoucreateobjectsdirectly,youdonotneedclasses.Infact,classesdon’texist inJavaScript.However, ifyouwant toprograminaclass-basedstyle,youcandosoeasilywitheitheroftwoavailableobjectcreationpatterns:factoryandconstructor.

TheFactoryPatternFactoryisafancytermfordescribingafunctionthatreturnsanobject.functionmakeObj(){varobj={};returnobj;}varnewObj=makeObj();

Youcanusefactoriestosetpropertiesandmethodsontheobjectstheyreturn.Inthefollowingexample,thefactorymakeRecord isusedtocreateobjects thatrepresentmusicalbums.Withfactories,propertyvaluesareassigned to the returnedobject throughfunctionarguments. In thefollowing example, the object’s property values represent information about each record,includingtitle,artist,andyear.functionmakeRecord(title,artist,year){varrecord={};record.title=title;record.artist=artist;record.year=year;

returnrecord;}varweAreHardcore=makeRecord("WeAreHardcore","ThePsychoElectros",2016);

console.log(weAreHardcore.title);//"WeAreHardcore"console.log(weAreHardcore.artist);//"ThePsychoElectros"console.log(weAreHardcore.year);//2016

Ifyouwanttocreatedefaultvaluesforproperties,youcanassignthemlikethis:functionmakeRecord(title,artist,year){varrecord={};record.title=title;record.artist=artist;record.year=year;record.fullAlbum=true;

returnrecord;}

varweAreHardcore=makeRecord("WeAreHardcore","ThePsychoElectros",2016);console.log(weAreHardcore.fullAlbum);//true

Page 139: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youcanalsoincludemethodsinyourfactories.functionmakeRecord(title,artist,year){varrecord={};record.title=title;record.artist=artist;record.year=year;record.summary=function(){return"Title:"+record.title+".Artist:"+record.artist+".Year:"+record.year;};

returnrecord;}varweAreHardcore=makeRecord("WeAreHardcore","ThePsychoElectros",2016);

console.log(weAreHardcore.summary());/*Title:WeAreHardcore.Artist:ThePsychoElectros.Year:2016*/

DynamicObjectExtensionObjectscreatedwithfactories,likeallobjects,canbeextendedtoincludeadditionalpropertiesandmethods.The followingexamplecreatesanewpropertynamedleadSinger andanewmethod named getAllProperties. getAllProperties loops through the objectpropertiesandlogsthosethatarenotfunctionstotheconsole.functionmakeRecord(title,artist,year){varrecord={};record.title=title;record.artist=artist;record.year=year;record.summary=function(){return"Title:"+record.title+".Artist:"+record.artist+".Year:"+record.year;};returnrecord;}

varweAreHardcore=makeRecord("WeAreHardcore","ThePsychoElectros",2016);weAreHardcore.leadSinger="FredTheButcher";weAreHardcore.getAllProperties=function(){for(varpropinweAreHardcore){if(typeofweAreHardcore[prop]!="function"){//_______________Loopignoresmethods!console.log(prop+":"+weAreHardcore[prop]);//____________Onlyloopsthroughproperties}}};

weAreHardcore.getAllProperties();

/*_____________________RESULT

Page 140: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

title:WeAreHardcoreartist:ThePsychoElectrosyear:2016leadSinger:FredTheButcher

___________________________*/

PrivateDataSometimesyouwanttocreatedatathatisaccessibletoyourobjectsbutiseitherinaccessibletotheoutsidescopeorcannotbechanged.Todothis,youcanmakedataprivatebyassigningittoavariableinsidethefactory.Inthefollowingexample,avariablenamedid storessomeprivateinformation.functionmakeRecord(id){varid=id;//Privatedataconsole.log(id+"isprivatedata");varrecord={};returnrecord;}varmyRecord=makeRecord("2323415432");console.log(myRecord.id);/*undefined.Thisisapropertyoftheobject,nottheprivatedata!*/

GettersandSettersPrivatedatacanberetrievedbycreatingamethodinsidethefactorythatisdesignedtoreturnit.Amethodusedtoretrieveprivateinformationiscalledagetter.functionmakeRecord(id){varid=id;varrecord={};record.getId=function(){//getterreturnid;};returnrecord;}

varmyRecord=makeRecord("1121210937");

myRecord.getId();//1121210937

Conversely,methodsthatareusedtomodifyprivatedataarecalledsetters.Inthefollowingcode,asetteriscreatedthatallowsyoutochangethevalueofidwhilerestrictingtheinputtoaten-digitstring.functionmakeRecord(id){varid=id;varrecord={};record.getId=function(){

Page 141: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

returnid;};record.setId=function(newId){if(typeofnewId==="string"&&newId.length===10){id=newId;}else{throw("idmustbeaten-digitstring");}

};returnrecord;

}varmyRecord=makeRecord("9876543210");myRecord.getId();//9876543210myRecord.setId("1000000001");myRecord.getId();//1000000001

ProgrammingwithfactoriesisacommonpatterninJavaScriptandonethatyoushouldbesureto familiarize yourselfwith. Factories give you a simple syntax for abstracting complex code,whileofferingyoutheprivacyoffunctionscopecoupledwiththeflexibilityofobjectextension.

ConstructorsandthenewKeywordAnotherpattern forobject creation is called theconstructor.Like a factory, a constructor is afunction that returns an object. The following code shows an implementation of themakeRecordfactoryusingaconstructor.functionRecord(title,artist,year){this.title=title;this.artist=artist;this.year=year;}varweAreHardcore=newRecord("WeAreHardcore","ThePsychoElectros",2016);

console.log(weAreHardcore.title);//WeAreHardcoreconsole.log(weAreHardcore.artist);//ThePsychoElectrosconsole.log(weAreHardcore.year);//2016

Asyoucansee,therearesomedifferencesbetweenfactoriesandconstructors.Thefirstisthenamingconventionforfunctions.Withconstructors,itisconsideredgoodpracticetonamethemwith a capitalized noun. This convention exists solely to help distinguish constructors fromnonconstructorsanddoesnot throwanerror if it isnotused.The lackofanexplicitlycreatedobjectisthenextdifference.Withconstructors,insteadofimmediatelycreatinganobjectinyourfunctiondeclaration,beginbywritingyourpropertiesusingthethiskeyword.Inaconstructor,thispointstotheobjectthatiscreatedfromit.Thesepropertiesareassignedvaluesthroughtheconstructor function arguments or, if you want to create default values, you can assign themdirectlytotheproperty.functionRecord(title,artist,year){this.title=title;

Page 142: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

this.artist=artist;this.year=year;this.fullAlbum=true;//defaultvalue}

varweAreHardcore=newRecord("WeAreHardcore","ThePsychoElectros",2016);

console.log(weAreHardcore.fullAlbum);//true

Youinvokeaconstructorusingthenewkeyword.Thisisthecommandthattellstheinterpreterthatyouareusingthefunctionasaconstructor.Inresponse,theinterpretercreatesandreturnsanobject. In the previous example, the return value is assigned to the variable namedweAreHardcore.

AddingMethodstoConstructorsIfyouwanttoaddmethodstoconstructors,thesyntaxlookslikethis:functionRecord(title,artist,year){this.title=title;this.artist=artist;this.year=year;}Record.prototype.summary=function(){return"Title:"+this.title+".Artist:"+this.artist+".Year:"+this.year;};

varweAreHardcore=newRecord("WeAreHardcore","ThePsychoElectros",2016);weAreHardcore.summary();/*Title:WeAreHardcore.Artist:ThePsychoElectros.Year:2016*/

Admittedly,thissyntaxisabitoddlooking.So,toclarifywhatishappening,let’slookattwoconceptsinterwovenwithconstructors:theprototypeobjectandtheprototypeproperty.

ThePrototypeObjectandthePrototypePropertyEverytimeyoucreateafunctioninJavaScript,ahiddenobjectgetscreatedinthebackgroundthatistiedtothefunctionthatcreatedit.Thisobjectisnotvisibleoraccessibleanddoesabsolutelynothing unless you decide to use your function as a constructor. If you use your function as aconstructor, this otherwise dormant object becomes accessible through a property calledprototypeandiscalledtheprototypeobject.

When you attachmethods to constructors, you are expected to attach them to the prototypeproperty,whichinturnsattachesthemtothehiddenprototypeobject.Anyobjectsyoucreatewithyourconstructorhaveaccesstothesemethods.

Page 143: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Record.prototype.summary=function(){return"Title:"+this.title+".Artist:"+this.artist+".Year:"+this.year;};

Althoughyoucanattachyourmethodswithoutusing theprototypeproperty, thedrawback tothisapproachis thateverytimeyoucreateanewobject,allof themethodsare initialized,andthis requires more memory. This might have been a concern in 1995 when JavaScript wasdesignedandcomputersweremuchslower,butthelargeamountofavailablememoryinmoderncomputersmakesthisissuenegligible.Thisisthereasonfactoriesareaviablealternative.Thesyntaxforaddingmethodswithoutusingtheprototypeobjectlookslikethis:functionRecord(title,artist,year){this.title=title;this.artist=artist;this.year=year;this.summary=function(){return"Title:"+this.title+".Artist:"+this.artist+".Year:"+this.year;};}

varweAreHardcore=newRecord("WeAreHardcore","ThePsychoElectros",2016);weAreHardcore.summary();/*Title:WeAreHardcore.Artist:ThePsychoElectros.Year:2016*/

You can use getters and setters, as you do with factories, to work with private data inconstructors.Thefollowingexamplecontainsaprivatevariablenamedidandusesagetter toretrieveit,aswellasasetterthatallowsittobechangedtoaten-digitstring.Notethatthegetterandsetterarenotimplementedontheprototypeproperty,becauseiftheywere,theprivatedatawouldnotbeavailabletothem.functionRecord(id){varid=id;this.getId=function(){returnid;};

this.setId=function(newId){if(typeofnewId==="string"&&newId.length===10){id=newId;}else{throw("idmustbeatendigitstring");}

};}varmyRecord=newRecord("9876543210");myRecord.getId();//9876543210

myRecord.setId("0123456789");myRecord.getId();//0123456789

Page 144: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

WhyDoConstructorsExistIfYouCanDotheSameThingwithFactories?

At the timewhenJavaScriptwasdeveloped in1995,oneof themostpopular languages in theworldwasJava.OutofadesiretoappeaseJavadevelopersandlurethemintousingJavaScript,thelanguagewasdesignedtomirrorJava’ssyntax.Partofthiseffortincludedaddingconstructorsto the language thatweredesigned to look like Javaclasses.Thishappened irrespectiveof thefactthatbehindthescenesJavaScriptisnotaclass-basedlanguage.

SummaryIn this chapter, you learned how to create JavaScript pseudoclasses using factories andconstructors.Inthenextchapter,youwillcreateasimplifiedaudiofileloaderlibraryusingthefactorypattern.

Page 145: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

13AbstractingtheFileLoader

Now that you are familiar with factories and constructors from the previous chapter, you canabstracttheaudiobufferloaderyoucreatedinChapter11intoalibrarythatloadsmultiplesoundfilesusinglesscode.Youdothisusingthefactorypattern.

ThinkingaboutCodeAbstractionOrganizingyourcodeintoabstractionscanbeadauntingtask.However,therearetwostepsyoucanfollowtosimplifytheprocess.Thefirststepistodeterminewhetheryouneedanabstractioninthefirstplace.Ifyouarerepeatedlytypingoutalargeamountofcodeforthesametask,thenthe answer is probably yes. The second step, if you decide you need an abstraction, is todeterminewhattypeofinterfaceworksforyourabstraction.YouwereexposedtooneexampleofapopularinterfaceinChapter11,whereyouworkedwiththeJQuerylibrary.JQuery’sinterfaceallowsyoutotreatHTMLelementsasobjectsthatyoucanattachmethodsto.Thisisanexcellentchoiceforaninterface,butsometimesasimplefunctioninvocationthatreturnsastringornumberworks justaswell.Ultimately, itdependsonyourobjectiveand thenatureof thecodeyouareabstracting.

Onewaytohelpyoudecideonthebestapproachistoworkbackwardandwriteouthowyouwould like the interface to look and function prior to implementing it. The interface for theaudiofileabstractionyoucreateinthischapterlookslikethefollowingexample:varsound=audioBatchLoader({kick:"kick.mp3",snare:"snare.mp3",hihat:"hihat.mp3",shaker:"shaker.mp3"});sound.snare.play();//Play

Withthisapproach,afactoryfunctiontakesanobjectasanargument.Theobjectyouinputintothefactorycontainsalistofpropertynames,eachofwhichisassignedadirectoryofanaudiofileintheformofastring.Thebeautyofthisapproachisitsclarityandextensibility.Theinterface

Page 146: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

shown insound.snare.play() attempts to read, somewhat like English, from the list ofsoundfilestoplay.Evenifyouhaveneverseenthiscodebefore,youcanunderstandwhatitisdoing:selectingasoundnamedsnareandplayingit.Decouplingtheobjectthatcontainsmanyaudiofilesfromtheinvokingfunctionmakesthecodeeasiertoread,asshowninthefollowingexample:varaudioFiles={kick:"kick.mp3",snare:"snare.mp3",hihat:"hihat.mp3",shaker:"shaker.mp3"//______hundredsofaudiofilescouldbelistedhere.........};

varsound=audioBatchLoader(audioFiles);sound.snare.play();//Play

Iftheuserofyourabstractiondecidestheywanttoextendittodonewthings,withouthavingtomodifythesourcecodeintheoriginalfunction,theyhavesomeflexibility.Soforexample,iftheywantedtoextendthereturnedobjecttoplaymultipleaudiobuffers,theycoulddothis:sound.playSnareAndShaker=function(){sound.snare.play();sound.shaker.play();};

sound.playSnareAndShaker();//playstwosoundswithonelineofcode

CreatingtheAbstractionThe following code is the finished abstraction. The remainder of this chapter is dedicated tobuildingupthisexamplelinebylineandexplaininghowitworks.CreateanewtemplateprojectandsavethefollowingcodeintheJavaScriptfolderinafilenamedaudiolib.js."usestrict";

varaudioContext=newAudioContext();functionaudioFileLoader(fileDirectory){varsoundObj={};varplaySound=undefined;vargetSound=newXMLHttpRequest();soundObj.fileDirectory=fileDirectory;getSound.open("GET",soundObj.fileDirectory,true);getSound.responseType="arraybuffer";getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){soundObj.soundToPlay=buffer;

});};

getSound.send();

Page 147: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

soundObj.play=function(time){playSound=audioContext.createBufferSource();playSound.buffer=soundObj.soundToPlay;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime+time||audioContext.currentTime);};

soundObj.stop=function(time){playSound.stop(audioContext.currentTime+time||audioContext.currentTime);};returnsoundObj;}

functionaudioBatchLoader(obj){

for(varpropinobj){obj[prop]=audioFileLoader(obj[prop]);

}

returnobj;

}

varsound=audioBatchLoader({

kick:"sounds/kick.mp3",snare:"sounds/snare.mp3",hihat:"sounds/hihat.mp3",shaker:"sounds/shaker.mp3"

});

window.addEventListener("mousedown",function(){sound.snare.play();});

Younowneedtoreferencethefileinyourindex.htmlfile.

<head><metacharset="UTF-8"><title></title><scriptsrc="js/audiolib.js"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head>

Createafoldernamedsounds.Thisisthedirectoryusedtoholdyouraudiofiles.

Page 148: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

WalkingthroughtheCodeThefunctionnamedaudioFileLoadercreatesandreturnsanobjectnamedsoundObj.functionaudioFileLoader(){varsoundObj={};returnsoundObj;};

To specify a directory for the file to be used, a parameter is assigned to a property ofsoundObjnamedfileDirectory.

functionaudioFileLoader(fileDirectory){varsoundObj={};soundObj.fileDirectory=fileDirectory;returnsoundObj;};

Youcannowcreate theXMLHttpRequest object and set all the required properties andmethods.YoucanalsoimplementthedecodeAudioDatamethodtomakethebufferusablebytheWebAudioAPI.Theselinesofcodeshouldalreadybefamiliartoyoubecausetheyarethesame buffer loading and decoding tools you learned about in Chapter 11, with one smalldifference.InChapter11thedecodedbufferwasassignedtoavariablenamedaudioBuffer.In this implementation, the decoded buffer is assigned to a property of soundObj namedsoundToPlay.functionaudioFileLoader(fileDirectory){varsoundObj={};vargetSound=newXMLHttpRequest();soundObj.fileDirectory=fileDirectory;getSound.open("GET",soundObj.fileDirectory,true);getSound.responseType="arraybuffer";getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){soundObj.soundToPlay=buffer;//Propertyassignedbuffer

});

Page 149: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

};

getSound.send();returnsoundObj;}

Youcannowcreateaplaybackmethod that is anextensionofsoundObj toplayback thebuffers.functionaudioFileLoader(fileDirectory){

varsoundObj={};soundObj.fileDirectory=fileDirectory;vargetSound=newXMLHttpRequest();getSound.open("GET",soundObj.fileDirectory,true);getSound.responseType="arraybuffer";getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){soundObj.soundToPlay=buffer;

});};

getSound.send();

soundObj.play=function(time){

varplaySound=audioContext.createBufferSource();playSound.buffer=soundObj.soundToPlay;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime+time||audioContext.currentTime);};

returnsoundObj;

}

Thetime argument of theplay function determines the number of seconds youwant theaudiofiletoplayintothefuture.Thelogicalexpression(audioContext.currentTime+time||audioContext.currentTime)isusedtodeterminewhetherthetimeargumentis empty and, if it is, then the start method does not add additional seconds to the value ofaudioContext.currentTime.Whennoargumentsareset,thesoundplaysimmediately.soundObj.play=function(time){

varplaySound=audioContext.createBufferSource();playSound.buffer=soundObj.soundToPlay;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime+time||audioContext.currentTime);};

Thestopmethodletsusersdeterminewhenasoundwillstopplayback.soundObj.stop=function(time){playSound.stop(audioContext.currentTime+time||

Page 150: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

audioContext.currentTime);}

Youcannowloadthefilesandplaythem.varsound=audioFileLoader("sounds/snare.mp3");window.addEventListener(“mousedown”,function(){sound.play();//playsat"currenttime"becausenoargumentsaresetsound.play(2);//plays2secondsintothefuture});

Thiscodeworks,butitrevealsanewpotentialproblem.Ifyouwanttoloadmultiplefiles,youhavetotypeoutanaudioFileLoaderinvocationforeachone,likethis:varkick=audioFileLoader("sounds/kick.mp3");varsnare=audioFileLoader("sounds/snare.mp3");varhihat=audioFileLoader("sounds/hihat.mp3");varshaker=audioFileLoader("sounds/shaker.mp3");

OnewaytomitigatethisadditionalrepetitionistocreateahelperfunctionthatloopsthroughanobjectthatcontainsacollectionofaudiofiledirectoriesandinvoketheaudioFileloaderoneachfile.Youcanthenreturntheobject.Thiswillalloweachsoundtobeaccessiblevia itspropertyname.Thefollowingcodedemonstratesthis:functionaudioBatchLoader(obj){for(varpropinobj){obj[prop]=audioFileLoader(obj[prop]);}returnobj;}

varsound=audioBatchLoader({kick:"sounds/kick.mp3",snare:"sounds/snare.mp3",hihat:"sounds/hihat.mp3",shaker:"sounds/shaker.mp3"});

Eachfileisnowaccessibleusingthefollowingsyntax:sound.kick.play();sound.snare.play();sound.hihat.play();sound.shaker.play();

Younowhaveaworkinglibrarytoloadmultipleaudiofiles.Thefollowingcodesetsaneventlisteneronthewindow.Ifyouclickit,youwillheartheloadedsoundplay.varsound=audioBatchLoader({

kick:"sounds/kick.mp3",snare:"sounds/snare.mp3",hihat:"sounds/hihat.mp3",shaker:"sounds/shaker.mp3"

});

window.addEventListener("mousedown",function(){

Page 151: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

sound.snare.play();

});

SummaryInthischapter,youlearnedthebasicsofhowtothinkaboutabstraction,whilecreatinganewtoolforloadingandplayingbackmultipleaudiofiles.Inthenextfewchapters,youwilllearnhowtomanipulateaudioviathenodegraphusingvariouseffects.

Page 152: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

14TheNodeGraphandWorkingwithEffects

Uptothispoint,thetopicofthenodegraphhasonlybeenpartiallydescribedandhasbeenusedmostlyasatooltoexplainrelatedconcepts.Inthischapter,youwilllearnhowtoworkwiththenodegraphtodevelopcustomsignalchainsforcomplexaudioapplications.TheWebAudioAPIincludesmanybuilt-inobjectsthatletyoumanipulateaudioincreativeways.Youalsolearnhowtoincludetheseobjectsinyourapplicationsandusethemtocreatecustomizedeffects.

HowtoThinkAbouttheNodeGraphIna real-world recordingstudio,you routeaudio signalsbyconnectingmicrophonesandothersound sources to a soundmixer. The soundmixer is configuredwith its own routing scheme,whichallowsaccesstoequalizers,dynamicsprocessors,andothereffects.TheWebAudioAPInodegraphisdesignedtomirrorthecharacteristicsofareal-worldsoundmixer.Thisisdonebyconnectinginputsourcessuchasoscillatorsandaudiobufferstootherobjectsthatmanipulatethesoniccharacteristicsoftheseinputsourcesinsomeway.Thevariousobjects(includingtheinputsources)thatmakeupthesignalchainsarecallednodesandareconnectedtooneanotherusingamethod namedconnect(). You can think ofconnect() as a virtual audio cable used tochaintheoutputofonenodetotheinputofanothernode.ThefinalendpointconnectionforanyWebAudioapplication isalwaysgoing tobe theaudioContext.destination.You canthink of the audioContext.destination as the speakers of your application. Thiscollectionofconnectionsiswhatisreferredtoasthenodegraph,showninthefigurebelow.

Page 153: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

GainNodesInareal-worldrecordingstudio,youtypicallyuseasoundmixerwithmultiplechannelstripsandaroutingmatrixtosplitandcombineaudiosignals.WiththeWebAudioAPInodegraph,youusegainnodes to split and combine inputsources.Gain nodes allow independent volume controloverinputsourcesandactasvirtualmixingchannels.

Thefollowingcodeisanexampleofcreatingtwooscillatorsandconnectingeachonetoanindependent gain node for individual volume control. These are summed to a third gain node,whichisconnectedtotheaudioContext.destination.//________________________________BEGINcreatesawtoothoscillatorvaroscSaw=audioContext.createOscillator();oscSaw.type="sawtooth";oscSaw.frequency.value=118;oscSaw.start(audioContext.currentTime);//________________________________ENDcreatesawtoothoscillator

/*________________________________BEGINcreategainnodeandconnectsawtoothoscillator*/

vargainSaw=audioContext.createGain();gainSaw.gain.value=0.6;//setvolumeoscSaw.connect(gainSaw);

/*________________________________ENDcreategainnodeandconnectsawtoothoscillator*//*________________________________BEGINcreatetrianglewaveoscillator*/varoscTri=audioContext.createOscillator();oscTri.type="triangle";oscTri.frequency.value=120;oscTri.start(audioContext.currentTime);/*________________________________ENDcreatetrianglewaveoscillator*/

/*________________________________BEGINcreategainnodeandconnecttrianglewaveoscillator*/

vargainTri=audioContext.createGain();gainTri.gain.value=3;//setvolumeoscTri.connect(gainTri);

/*________________________________ENDcreategainnodeandconnect

Page 154: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

trianglewaveoscillator*/

//____SUMBothOscillators___vargainOscSum=audioContext.createGain();gainOscSum.gain.value=1;gainTri.connect(gainOscSum);gainSaw.connect(gainOscSum);//____ConnecttotheaudioContext.destinationgainOscSum.connect(audioContext.destination);

ThePlacementofNodesIsUptoYouItisimportanttorealizethatduetotheflexiblenatureofthenodegraph,youcanplaceyourinputsourcesandothernodesatanypartofthechain.Imagineyouhavetengainnodesallconnectedinseries,andyouwanttoinjectanoscillatorintothesixthone.Thisisperfectlyfinebecausetheoscillatorisunaffectedbythefirstfivegainnodesinthechainbybeingfunneledthroughthelastfive gain nodes prior to reaching the audioContext.destination. This is not just afeatureofgainnodesbut thenatureof thenodegraph.Youcanplaceany inputsource,oranyothernode,anywhereyouwantinthenodegraphsignalchain.Theorderinwhichyouconnectobjectsisdependentontheresultyouwant.

WhatEffectsAreAvailable?Thefollowingchartcontainssomeofthenodesthatarecharacteristicoftheeffectprocessorsyouseeinreal-worldrecordingstudios.Theseeffectsarecalledmodificationnodes,butforclaritytheyarereferredtoaseffectsnodesinthisbook.Thespecificsofeffectsnodesareexploredinlater chapters. The focus of this chapter is to give you a general understanding of how theseeffectsnodescanbeincorporatedintothenodegraph.

Page 155: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HowtoDeterminetheNodesYouNeedtoCreatetheEffectYouWant

Ifyouhavean ideaforaneffectyouwant to incorporate intoyourapplication,youcanfollowthesestepstohelpdeterminethetoolsyouneedtocreateit:

1. Determine the specific type of effect you want (chorus, tremolo, hall reverberation,multiband,EQ,etc.).

2.Determinethenatureoftheeffect.Inotherwords,iftheeffectyouwantisachorus,thenthenatureoftheeffectisanaudibledelay.Iftheeffectyouwantisamultibandequalizer,thenthenatureoftheeffectisaudiofiltering.

3. Research theWebAudioAPI specification to find a node that you can use to create theeffect.Manytimes,creatingtheexacteffectyouwantrequirescombiningdifferentnodesorcombiningsimilarnodeswithslightlymodifiedparameters.

4.InvoketherespectivemethodoftheAudioContexttocreatethenode(ornodesifyouareusing more than one). This is a method that starts with the word create, such ascreateGain()orcreateBiquadFilter().

5.Connecttheobject(orobjectsifyouareusingmorethanone)tothenodegraphinthepartofthesignalchainthatyouwant.

Page 156: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

6.Modifythebuilt-inpropertiesandmethodsoftheobject(s)tomanipulatetheinputsource(s)inthemanneryouwant.

AReal-WorldExampleAssumeyouwanttoapplyalow-pass(alsocalledlowpass)filtertoanoscillator.(Alow-passfilterisafilterthatonlyallowssignalsbelowacertainfrequencytopass.)Todothis,youfirstresearch theWebAudioAPIdocumentation toseewhether this typeof filter issupported.Youcan search the specification directly at: https://www.w3.org/TR/webaudio. An alternativereference(andonethatisabitmorereadable)istheMozillaDeveloperNetworkdocumentationat:https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API.

Whenresearching,doasearchfor“filters”or“lowpass.”Intheresults,youwilldiscoverthatthereisaspecializednodecalledabiquadfilter that isdedicatedtoaudiofiltering.Thisnodeincludesapropertynamedtypethatyoucansettolowpass.Asthevalueimplies,thisfiltertypeisusedtoapplyalow-passfiltertoaninputsource.Toapplythistoyourapplication,youfirstinvokethecreateBiquadFilter()method,whichreturnsanobjectthatyoustoreinavariable.You thenconnect an input source, suchas anoscillatoror arraybuffer, to thisobjectusingtheconnectmethod.varaudioContext=newAudioContext();

varosc=audioContext.createOscillator();osc.start(audioContext.currentTime);varfilter=audioContext.createBiquadFilter();filter.type="lowpass";osc.connect(filter);filter.connect(audioContext.destination);

The final step is to define any additional properties or methods to customize the effect.Propertiesormethodsthatallowyoutocustomizethebehaviorofnodesarecalledaudioparams(shortforaudioparameters).Inthepreviousexample,type isanaudioparam.Thefollowingcodesetsanotheraudioparamnamedfrequencytothevalue250.Thisdefineswherethelow-passfilterbeginstocutoffinthefrequencyspectrum.varaudioContext=newAudioContext();

varosc=audioContext.createOscillator();osc.start(audioContext.currentTime);varfilter=audioContext.createBiquadFilter();filter.type="lowpass";//audioparamfilter.frequency.value=250;//audioparamosc.connect(filter);filter.connect(audioContext.destination);

SomeEffectsRequireDevelopmentWork

Page 157: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

It is important tounderstand that theWebAudioAPI’seffectsnodesarebuildingblocks. Thismeansthatsomeoftheeffectsyouwanttoachievemightrequireadditionaldevelopmentworkonyourpart.Forexample, ifyouwant touseamultiband equalizer, youwon’t find a “multibandequalizernode”intheWebAudioAPIspecification.Instead,youmustbuildyourownmultibandequalizerusingacollectionofBiquadFilternodes.

SummaryInthischapter,youwereformallyintroducedtothenodegraphandhowtocreatecustomsignalchains using input sources and effects nodes. In the next few chapters, youwill build on thisknowledgeandexplorethespecificsofsomeoftheseeffectsnodes.

Page 158: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

15TheBiquadFilterNode

One of the most common ways to manipulate sound is by boosting or attenuating a range offrequencies using audio filters. A familiar example of this is the use of audio equalizers tobrightenormuffleasound.TheWebAudioAPIhasanodenamedBiquadFilterthatallowsyoutocreatedifferenttypesofaudiofiltersthatcanbeconnectedtogethertocreatevariousformsofequalizers. In thischapter,youwill learnhowtouse theBiquadFilter node, and in theprocess,youwillcreateaseven-bandgraphicequalizerandasingle-bandparametricequalizer.

UsingtheBiquadFilterNodeTo use the BiquadFilter node, you must first instantiate it using the createBiquadFilterfunctionandstorethereturnedobjectinavariable.varaudioContext=newAudioContext();varfilter=audioContext.createBiquadFilter();

Once you create the object, you can connect an input source to it. The following exampleconnectsanoscillatortotheobject.varaudioContext=newAudioContext();varosc=audioContext.createOscillator();varfilter=audioContext.createBiquadFilter();osc.connect(filter);//connectinputsourcetofilterosc.start(audioContext.currentTime);filter.connect(audioContext.destination);/*connectfiltertoaudioContext.destination*/

FilterTypesBiquadFilter contains a property named type that defines the type of filter the nodebehaveslike.Ifyoudonotexplicitlysetthetypeproperty,itsdefaultvalueislowpass.You

Page 159: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

canseethisintheconsole.log()outputinthefollowingcode:

varaudioContext=newAudioContext();varosc=audioContext.createOscillator();varfilter=audioContext.createBiquadFilter();filter.frequency.value=250;console.log(filter.type);//defaultislowpassosc.connect(filter);osc.start(audioContext.currentTime);filter.connect(audioContext.destination);

Toexplicitlysetthetypepropertytolowpass,youwritethefollowingcode:filter.type="lowpass";

In addition to the type property, BiquadFilter has a property namedfrequency.valuethatallowsyoutoassignaparticularfrequencytotheobject.Thevalueisinhertzandisrepresentedbyanumber.Thedefaultvalueis350.filter.frequency.value=1000;//1000Hzor1kHz

ThetypevalueofaBiquadFilternodedetermines if ithas twoadditionalproperties:gain and Q. The gain.value property allows you to boost or attenuatefrequency.value.TheQ.valuepropertyrepresentsthebandwidthofthefrequencyvalue.Bandwidth represents the reach by which neighboring frequencies are affected in relation tochanges made to the gain of the selected frequency. The following images demonstrate thedifference between a narrow bandwidth setting and a wide bandwidth setting of a 1 kHzfrequencyusingapeakingfilter.

The effect Q.value and gain.value have on frequency.value depends on thefilter’s type setting. The following chart lists the available filter types and describes therelationshipbetweentype,frequency,Q,andgainproperties.

Page 160: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()
Page 161: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

CreatinganEqualizerTwo of themost common types of equalizers are parametric and graphic.A graphic equalizerallowsyoutoboostorattenuateaseriesoffixedfrequenciesbutdoesnotincludetheabilitytomodifythebandwidthofthoseselectedfrequencies.Parametricequalizers,onthecontrary,allowyoutoselectaspecificfrequency,boostorattenuateit,andchangethebandwidthrange.YoucanuseBiquadFilternodestodesigneitheroftheseequalizers,andmanyothers.

GraphicEQThefollowingdiagramandcodeshowhowtocreateaseven-bandgraphicequalizer.Youdothisby chaining a series ofBiquadFilter nodes together and setting theirtype properties to

Page 162: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

peaking. Keep in mind that the only parameter the user of a graphic equalizer should beallowed to change is the gain of each filter. The input and output source for this example isabstractedusingafunctionnamedmultibandEQ.

varfilter1=audioContext.createBiquadFilter();filter1.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter1.gain.value=0;filter1.Q.value=1;/*___________Donotletusermodify.ThisisagraphicEQ!*/filter1.frequency.value=64;/*__Donotletusermodify.ThisisagraphicEQ!*/

varfilter2=audioContext.createBiquadFilter();filter2.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter2.gain.value=0;filter2.Q.value=1;/*___________Donotletusermodify.ThisisagraphicEQ!*/filter2.frequency.value=150;/*_Donotletusermodify.ThisisagraphicEQ!*/

varfilter3=audioContext.createBiquadFilter();filter3.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter3.gain.value=0;filter3.Q.value=1;/*___________Donotletusermodify.ThisisagraphicEQ!*/filter3.frequency.value=350;/*_Donotletusermodify.ThisisagraphicEQ!*/

varfilter4=audioContext.createBiquadFilter();filter4.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter4.gain.value=0;filter4.Q.value=1;/*___________Donotletusermodify.ThisisagraphicEQ!*/filter4.frequency.value=1000;/*Donotletusermodify.ThisisagraphicEQ!*/

varfilter5=audioContext.createBiquadFilter();filter5.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter5.gain.value=0;filter5.Q.value=1;/*___________Donotletusermodify.ThisisagraphicEQ!*/filter5.frequency.value=2000;/*Donotletusermodify.ThisisagraphicEQ!*/

varfilter6=audioContext.createBiquadFilter();filter6.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter6.gain.value=0;filter6.Q.value=1;/*___________Donotletusermodify.Thisisa

Page 163: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

graphicEQ!*/filter6.frequency.value=6000;/*Donotletusermodify.ThisisagraphicEQ!*/

varfilter7=audioContext.createBiquadFilter();filter7.type="peaking";/*______Donotletusermodify.ThisisagraphicEQ!*/filter7.gain.value=0;filter7.Q.value=1;/*___________Donotletusermodify.ThisisagraphicEQ!*/filter7.frequency.value=12000;/*Donotletusermodify.ThisisagraphicEQ!*/

functionmultibandEQ(inputConnection,outputConnection){

inputConnection.connect(filter1);filter1.connect(filter2);filter2.connect(filter3);filter3.connect(filter4);filter4.connect(filter5);filter5.connect(filter6);filter6.connect(filter7);filter7.connect(outputConnection);

}

Thecodefilesforthischapterincludeversionsofboththegraphicandparametricequalizerswithuser interfacecontrols.TheseapplicationsallowyoutotoggletheplaybackofasongandchangeparametersoftheBiquadFilternodesinrealtimebyusingtheinteractivesliders.

ParametricEQ

Page 164: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youcandesign aparametric equalizer in a similarway to thegraphic equalizer by chaining aseries ofBiquadFilter nodes together and setting their type properties topeaking. Theprimary difference of the parametric equalizer is that the frequency, gain, and bandwidth aremodifiableby theuser.Keep inmind thatwithmultibandparametric equalizers, the filter typemayhavemultipleoptionsavailable.Tokeepthecodesimpleandshort,thefollowingexampleshowshow to create a single-bandparametric equalizerwith type set to thevaluepeaking.TheinputandoutputsourceinthiscodeisabstractedusingafunctionnamedparametricEQ.varparametricEQ1=audioContext.createBiquadFilter();parametricEQ1.type="peaking";parametricEQ1.gain.value=0;//allowtheusertochangethisparametricEQ1.Q.value=1;//allowtheusertochangethisparametricEQ1.frequency.value=1000;functionparametricEQ(inputConnection,outputConnection){inputConnection.connect(parametricEQ1);parametricEQ1.connect(outputConnection);}

SummaryInthischapter,youlearnedabouttheBiquadFilternodeandhowtouseittocreatecustomequalizersandfilterarrangements.Keepinmindthattheexamplesherearekeptsimple,andlikethenodegraphitself,yourfilterarrangementscanbeascomplexasyouwanttomakethem.Inthenextchapter,youwilllearnaboutanothersignalprocessingnode:theconvolvernode.

Page 165: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

16TheConvolverNode

Inthischapter,youwilllearnhowtousetheconvolvernode.Theconvolverallowsyoutoapplyreverberation tonodegraph input sourcesby referencingaspecialkindofaudio filecalledanimpulseresponse.

ConvolutionReverbWhenanacousticsoundiscreated,itscharacteristicsareshapedbyitsimmediateenvironment.This isduetosoundwavesbouncingoffandaroundvariousobstacles.Theseobstaclescanbemadeofdifferentmaterialsthataffectthesoundindifferentways.Theresultofsoundemanatingfromasmallroomhasdifferentcharacteristicsthansoundemanatingfromalargeroom.Becausethehumanear canhear thesedifferences,when this information is transmitted to thebrain,weperceive these characteristics as room ambience. Modern advancements in digital audiotechnologyallowus to record theambienceofany real-worldenvironmentandapply it toanydigital audio signal directly. These recorded ambiences are stored as a special file called animpulse response. An impulse response file is made by recording a single sound burst in anenvironment, which could be white noise, a sine wave sweep, or even a balloon pop. Thisrecordingisthenrunthroughaspecialdigitalalgorithmtocreateasinglefilecalledanimpulseresponse.Thisimpulseresponsefileiscombinedorconvolvedwithanotherinputsourcetogivethetargetedsoundthespacialcharacteristicsoftheroomthattheimpulseismodeledfrom.

TheformatofimpulseresponsefilescanbeanyaudiofiletypeincludingWAV,MP3,AIFF,orOGG. However, to use them with the Web Audio API, impulse response files must be in abrowser-compatibleaudioformat.Forthischapter,weuseWAVfilesbecausetheyareofhigherqualitythanMP3files.Andbecauseimpulseresponsefilesaresmall,loadtimeisnotaconcern.

WheretoGetPre-RecordedImpulseResponseFiles

Page 166: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Therearemanyonlineresourceswhereyoucandownloadimpulseresponsefilesforfree,suchas:http://www.openairlib.net/.

UsingImpulseResponseFilesTouseimpulseresponsefiles,youmustfirstloadthem,decodethem,andstoretheminabuffer.varaudioContext=newAudioContext();varimpulseResponseBuffer;vargetSound=newXMLHttpRequest();getSound.open("get","sounds/impulse.js",true);//impulsefilegetSound.responseType="arraybuffer";

getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){impulseResponseBuffer=buffer;});};getSound.send();

Afterthefileisstoredinabuffer,thenextstepistowireupthenecessarynodestoapplytheeffecttoaninputsource.Tointegratetheimpulseresponseintothenodegraphconfiguration,youmustfirstcreateaconvolvernodeusingaudioContext.createConvolver()andstorethereturnedobjectinavariable.varconvolver=audioContext.createConvolver();

Youthenassigntheloadedimpulseresponsebuffertothebufferpropertyoftheobject.convolver.buffer=impulseResponseBuffer;

Next, you connect any input sourceyouwant to the convolver node.Here is an exampleofconnectinganoscillator.varosc=audioContext.createOscillator();varconvolver=audioContext.createConvolver();osc.type="sawtooth";convolver.buffer=impulseResponseBuffer;osc.connect(convolver);convolver.connect(audioContext.destination);osc.start(audioContext.currentTime);

The following HTML and JavaScript code combines the impulse file loader, node graphconnections,andJQueryDOMselectorstoallowyoutoplaytheoscillatorbyclickinganHTMLbuttonandholdingit.Thisallowsyoutohearthereverberationeffectmoreexplicitlybecausethereverb tail is audible after removing your finger from the mouse button and stopping theoscillator.

HTML

Page 167: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title></title><scripttype="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"></script><scriptsrc="js/app.js"></script></head><body><button>Oscillation</button></body></html>

JavaScript"usestrict";varaudioContext=newAudioContext();varimpulseResponseBuffer;vargetSound=newXMLHttpRequest();getSound.open("get","sounds/impulse.wav",true);getSound.responseType="arraybuffer";

getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){impulseResponseBuffer=buffer;});};

getSound.send();

/*___________________________________________BEGINplaybackfunctionality*/

varosc=audioContext.createOscillator();

functionplayback(){varconvolver=audioContext.createConvolver();osc=audioContext.createOscillator();osc.type="sawtooth";convolver.buffer=impulseResponseBuffer;osc.connect(convolver);convolver.connect(audioContext.destination);osc.start(audioContext.currentTime);}

$(function(){

$("button").on("mousedown",function(){playback();});

$("button").on("mouseup",function(){osc.stop();});});

Page 168: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

ControllingtheAmountofReverberationIn the previous code example, the amount of reverb applied to the oscillator is fixed at 100percent. Ifyouwant tomake theeffectvariable,whichallowsyou tocontrolhowmuchof theeffectisappliedtotheinputsource,youcandosobysplittingtheinputsourcewithagainnodeand routing one split to the convolver node prior to connecting it to the destination.You thenconnecttheothersplitdirectlytothedestination.Youusegain.valuetoblendtheamountoftheeffectyouwanttohear.

Thefollowingdiagramandnodegraphconfigurationcodedemonstratethesplittingoperation.

vargain=audioContext.createGain();varconvolver=audioContext.createConvolver();

osc=audioContext.createOscillator();osc.type="sawtooth";convolver.buffer=impulseResponseBuffer;osc.connect(convolver);convolver.connect(gain);gain.gain.value=0.2;gain.connect(audioContext.destination);osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

SummaryInthischapter,youlearnedhowtousetheconvolvernodetoapplyanimpulseresponsefiletoaninputsource.Youalsolearnedhowtousegainnodestocontroltheamountoftheeffectyouwanttohear.Inthenextchapter,youwilllearnhowtomodifythepanningofstereoinputsourcesandhowtocreatesophisticatedroutingschemesusingthechannelandmergernodes.

Page 169: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

17StereoPanning,ChannelSplitting,andMerging

TheWebAudioAPIincludesastereopannernodethatletsyoupaninputsourcestoanypartofthe stereo field. It also includes nodes that let you splitmultichannel audio files into separatechannels as well as merge multichannel input sources into a specified output channel. In thischapter,youwilllearnhowtousethesenodestomanipulatemultichannelinputsources.

TheStereoPannerNodeTo use the stereo panner node, you first invoke createStereoPanner() and store thereturnedobjectinavariable.varstereoPanner=audioContext.createStereoPanner();

Youcanthenconnectanyinputsourcetothenodeandusepan.valuetosetthelocationinthestereofieldwhereyouwanttoplacethesound.Thepan.valuepropertysettingisanumberbetween1 and−1,where1 represents a100percent pan to the right and−1 represents a 100percent pan to the left. In the following example, anoscillator is connected to a stereopannernodeandisset50percenttotheleft.varoscillator=audioContext.createOscillator();varstereoPanner=audioContext.createStereoPanner();stereoPanner.pan.value=-0.5;oscillator.connect(stereoPanner);stereoPanner.connect(audioContext.destination);oscillator.start(audioContext.currentTime);

ThestereoPanner()usesanequalpoweralgorithmtopaninputsources.Thismeansthatwhenastereoinputsourceispanned,theaudiocontentontheattenuatedsideissummedwiththeaudioontheamplifiedside.

Page 170: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheChannelSplitterIfyouwanttoisolatetheindividualchannelsofamultichannelinputsourceordonotwantyourstereo input sources to be subjected to an equal power algorithm, you must use the channelsplitter.Thisnodeisolatesanychannelofamultichannelinputsourceforfurtherprocessing.Thisappliestobothstereoandothermultichannelaudioinputsources,suchas5.1surroundfiles.Tocreateachannelsplitter,youinvokethecreateChannelSplitter()methodwithasingleargument and store the returned object in a variable. The argument value is the number ofchannelsoftheaudiosourcematerialthatyouintendtoconnecttothesplitter.Ifnoargumentisspecified,thedefaultis6.Inthefollowingexample,astereofileissplit,sotheargumentissetto2.varsplitter=audioContext.createChannelSplitter(2);

Tousethechannelsplitter,youconnectinputsourcestoitandthenconnectthesplittertoothernodes.When connecting the splitter to a destination node, you specify the channel of the inputsource to connect to in the second argument of theconnect() method. This argument is anumberthatrepresentsthechannelasanindexvalue.Thefollowingchartdisplaystheindexforeachchannelofasix-channelinputsource.

The following code shows the correspondence between the channel index argument and itsrespectivechanneltype.stereoInputSource.connect(splitter);splitter.connect(audioContext.destination,0);/*outputsleftside/channelofstereoinputsource*/splitter.connect(audioContext.destination,1);/*outputsrightside/channelofstereoinputsource*/

Thefollowingcodeshowshowtomodifythegainvalueofindividualleftandrightchannelsof a stereo input source. In otherwords, this configuration is the opposite of an equal powerpanningalgorithm.varsplitter=audioContext.createChannelSplitter(2);varpannerLeft=audioContext.createStereoPanner();varpannerRight=audioContext.createStereoPanner();varleft=audioContext.createGain();varright=audioContext.createGain();sound=audioContext.createBufferSource();sound.loop=true;

Page 171: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

sound.buffer=bufferSource;sound.connect(splitter);splitter.connect(left,0);//___connectleftchanneltogainnodesplitter.connect(right,1);//__connectrightchanneltogainnodeleft.gain.value=leftVal;/*_________independentleftchannelcontrol*/right.gain.value=rightVal;/*________independentrightchannelcontrol*/left.connect(pannerLeft);pannerLeft.pan.value=-1;pannerRight.pan.value=1;right.connect(pannerRight);pannerLeft.connect(audioContext.destination);pannerRight.connect(audioContext.destination);sound.start(audioContext.currentTime+time||audioContext.currentTime);

TheChannelMergerIfyouwanttocombinemultiplemonoinputsourcesandroutethemtoaspecificchannelinthestereo (or multichannel) spectrum, you use a channel merger. The function invocation for thechannel merger node takes one argument that determines how many input channels the objectaccepts.Ifnoargumentisgiven,thedefaultis6.varmerger=audioContext.createChannelMerger();

When connecting an input source to a channelmerger, youmust specify the output channelusingthethirdargumentoftheconnectmethod.inputSource.connect(merger,0,1);/*outputsallchannelsofinputSourcetorightchannel*/

MergingAllChannelsofaMultichannelFileintoaSingleMonoChannel

Tocombineamultichannel file into a singlemono output,which is placed at the center of thestereospectrum,yousetthechannelmergerinvocationargumentto1,andthenconnecttheinputsourcetothechannelmerger.varmultiChannelInputSource=audioContext.createBufferSource();varmerger=audioContext.createChannelMerger(1);/*Setnumberofchannels*/stereoInputSource.buffer=audioBuffer;stereoInputSource.connect(merger);merger.connect(audioContext.destination);

Page 172: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

UsingtheMergerandSplitterNodesTogetherThemergerandsplitternodescanbeusedinconjunctionwithoneanothertoroutespecificinputchannelstospecificoutputchannels.Thefollowingcodetakestheleftandrightsidesofastereoinputsourceandswapsthem.stereoInputSource.connect(splitter);splitter.connect(merger,0,1);//inputleftandoutputrightsplitter.connect(merger,1,0);//inputrightandoutputleftmerger.connect(audioContext.destination);

Ifyouconnectanaudioinputsource,suchasanaudiobuffersourcenode,directlytoachannelmergernode, there isnoreasontoset thesecondargumentof theconnectmethod toavalueotherthan0.Thisisbecausethemergernodehasasingleoutput.audioBufferSource.connect(merger,0,1);

If the inputof a channelmerger is a channel splitter, the secondargumentof theconnectmethodisthechanneloftheinputsourcesenttothemerger.varchannelSplitter=audioContext.createChannelSplitter();varchannelMerger=audioContext.createChannelMerger();varsound=audioContext.createBufferSource();sound.buffer=audioBuffer;sound.connect(channelSplitter);channelSplitter.connect(channelMerger,0,0);/*TheleftchannelofplaySoundisconnectedtothechannelmerger*/channelMerger.connect(audioContext.destination);

SummaryInthischapter,youlearnedhowtoapplystereopanningtoaudioinputsources.Youalsolearnedhow toworkwith the channel splitter and channelmerger nodes. In the next chapter, youwillexplorehowtocreatedelayeffectsusingthedelaynode.

Page 173: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

18TheDelayNode

Intheworldofcreativeaudio,delaysareacommonmethodusedtocreatetime-basedeffects.Inthischapter,youwilllearnhowtousethedelaynodetocreatethemostcommondelayeffects:echo,slapback,andping-pong.

TheDelayNodeThe delay node is used to adjust the time between when an input source plays and when itbecomes audible. The following example connects an audio buffer to a delay node. ThedelayTime.valuepropertydeterminesthedelaytimeinseconds.varsound=audioContext.createBufferSource();vardelay=audioContext.createDelay();delay.delayTime.value=1;//Onesecondsound.buffer=audioBuffer;sound.connect(delay);delay.connect(audioContext.destination);sound.start(audioContext.currentTime);

Ifyoulistentotheresultofthepreviousexample,youwillnoticethatitdoesnotprovidetherepetitiveechodelayeffectthatistypicalofaneffectsprocessor.Thisisbecausetheonlythingthe delay node does is pause the audio from playing for a set amount of time. If you want arepetitiveechoeffect,youmustcreateit.

CreatingEchoEffectsTocreateanechoeffect,youconfigureanodegraphschemethatsetsthedelayedsignaltofeedbackonitself.

Page 174: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thegain.valuepropertycontrols theamountof theeffectandthedelayTime.valuepropertycontrolsthelengthofthedelay.Thefollowingcodeappliestheeffecttoanaudiobuffer.varsound=audioContext.createBufferSource();vardelayAmount=audioContext.createGain();vardelay=audioContext.createDelay();sound.buffer=audioBuffer;delay.delayTime.value=0.5;delayAmount.gain.value=0.5;sound.connect(delay);delay.connect(delayAmount);delayAmount.connect(delay);delayAmount.connect(audioContext.destination);sound.connect(audioContext.destination);sound.start(audioContext.currentTime);

CreatingSlapBackEffectsAslapbackeffectisaquickdelayof40–140ms.Tocreatethistypeofeffect,yousplitaninputsource and connect one branch to the delay and the other branch to the destination. You alsoconnectthedelaynodetoagainnodetocontrolthevolumeoftheeffect.Thenodeconfigurationforaslapbackisshowninthefollowingexampleandfigure.

varsound=audioContext.createBufferSource();vardelayAmount=audioContext.createGain();vardelay=audioContext.createDelay();sound.buffer=audioBuffer;delay.delayTime.value=0.06;delayAmount.gain.value=0.5;sound.connect(delay);delay.connect(delayAmount);delayAmount.connect(audioContext.destination);sound.connect(audioContext.destination);sound.start(audioContext.currentTime);

CreatingaPing-PongDelay

Page 175: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Aping-pongeffectisanechodelaywheretheechotogglesbetweentheleftandrightsideofthestereospectrum.Thiseffectcanbecreatedbyspittinganinputsourcetotheleftandrightoutputs,runningeachofthoseoutputsthroughindependentdelayandgainnodes,andthenfeedingbackthesignalfromthegaintoitsowndelayaswellasthedelaybeingusedtoprocesstheothersideofthestereospectrum.

Thefollowingcodeimplementstheconfigurationshownintheabovefigure.//___________________________________________________BEGINsetup

varsound=audioContext.createBufferSource();sound.buffer=audioBuffer;

varmerger=audioContext.createChannelMerger(2);varsplitter=audioContext.createChannelSplitter(2);

varleftDelay=audioContext.createDelay();varrightDelay=audioContext.createDelay();

varleftFeedback=audioContext.createGain();varrightFeedback=audioContext.createGain();

//____________________________________________________ENDsetup

sound.connect(splitter);sound.connect(audioContext.destination);

splitter.connect(leftDelay,0);leftDelay.delayTime.value=0.5;

leftDelay.connect(leftFeedback);leftFeedback.gain.value=0.6;leftFeedback.connect(rightDelay);

splitter.connect(rightDelay,1);rightDelay.delayTime.value=0.5;rightFeedback.gain.value=0.6;

rightDelay.connect(rightFeedback);rightFeedback.connect(leftDelay);

leftFeedback.connect(merger,0,0);rightFeedback.connect(merger,0,1);

//___________________________________________BEGINoutput

merger.connect(audioContext.destination);

Page 176: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//___________________________________________ENDoutput

sound.start(audioContext.currentTime);

SummaryThe delay node by itself is not complicated or difficult to use, butwhen combinedwith othernodesitcanbeapowerful toolfor thecreationof interestingaudioeffects.In thenextchapter,youwillcontinueexploringthenodegraphandlearnhowtoapplydynamicrangecompressiontoaudioinputsources.

Page 177: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

19DynamicRangeCompression

In this chapter, youwill learn about the dynamics compressor node. This node allows you toapplydynamicrangecompressiontoaudioinputsources.

TheDynamicsCompressorNodeDynamicrangecompressionistheprocessofautomaticallyattenuatinganaudiosignalwhenitsdecibel level exceeds a specified threshold. This is analogous to manually turning down thevolumeknobonyourradiowhenapieceofmusicgetstooloudandthenturningitbackupduringaquieterpassage.Whenthisactionisdonewithadynamicrangecompressor,yougetthebenefitsofautomation,speed,andtheprecisionofacomputer.

TheWebAudio API comes with a built-in tool called the dynamics compressor node thatallowsyoutoapplydynamicrangecompressiontoaudioinputsources.Touseit,youmustfirstinvoke the createDynamicsCompressor() method and store the resulting object in avariable.varcompressor=audioContext.createDynamicsCompressor();

Theobjectprovidesyouwithacollectionoffivepropertiesthataffectthedynamicrangeofanaudioinputsource.Asixthpropertycalledreductionisalsoavailable,butitdoesnotaffectthe input source in anyway. The reduction property is used exclusively to output a reductionvalue. These properties are briefly described in the following chart. All properties exceptreduction take a number as their assignment. Thereduction property provides only areadoutvalue.

Page 178: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

The following code demonstrates how to apply the dynamics compressor node to an audioinput source. In this example, for every 12 dB the signal surpasses a threshold of −40 dB, itsoutputisincreasedby1dB.//___________________________________________________BEGINsetup

varsound=audioContext.createBufferSource();varcompressor=audioContext.createDynamicsCompressor();sound.buffer=audioBuffer;

//____________________________________________________ENDsetup

sound.connect(compressor);compressor.threshold.value=-40;compressor.ratio.value=12;

//___________________________________________BEGINoutputcompressor.connect(audioContext.destination);//___________________________________________ENDoutputsound.start(audioContext.currentTime);

Anyone familiarwith theworld of creative audiowill immediately be familiarwith everyproperty available to the dynamics compressor node except one: reduction. Thereductionproperty,specifictotheWebAudioAPI,outputsanumericvaluerepresentingtheamount of reduction the compressor is imposing on the input source.The following code usessetInterval()toallowyoutoseethechangeinreductionvalueasanaudioinputsourceiscompressed.//___________________________________________________BEGINsetupvarcompressor=audioContext.createDynamicsCompressor();

varsound=audioContext.createBufferSource();sound.buffer=audioBuffer;

Page 179: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//____________________________________________________ENDsetup

sound.connect(compressor);compressor.threshold.value=-40;compressor.ratio.value=12;

//___________________________________________BEGINoutputcompressor.connect(audioContext.destination);//___________________________________________ENDoutput

sound.start(audioContext.currentTime);

window.setInterval(function(){console.log(compressor.reduction.value);},50);

SummaryUsing the dynamics compressor node is not complicated. It contains all the basic parametersneededtomodifythedynamicrangeofanyinputsourceconnectedtoit.

InthenextchapteryouwilllearnhowtoworkwithtimeintheWebAudioAPI.

Page 180: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

20Time

Inthischapter,youwilllearnhowtoworkwithtimetoscheduleWebAudioAPIsoundplaybackpoints,howtocreateloops,andhowtoautomateparameterchanges.

TheTimingClockWhenyouinvokeanewinstanceoftheaudiocontext,theWebAudioAPI’sinternaltimingclockbegins to tick.This timing reference is in seconds and is expressed as a decimal number.Thetimingclockistiedtoyourcomputer’sinternalaudiohardwaresubsystem,givingitadegreeofprecisionthatcanalignwithsoundsatthesamplelevel.Ifyouwanttoseethecurrentvalueoftheaudioclock,youcanusethecurrentTimepropertyoftheaudiocontext.console.log(audioContext.currentTime);

Whenyouplayanaudioevent,theWebAudioAPIrequiresyoutoscheduleit.Rememberthatthe unit you use for time value scheduling is seconds. If you want to schedule an eventimmediately,youcanusethecurrentTimepropertyoftheaudiocontext.

You have already had some exposure to scheduling the playback of sounds in previouschapters,suchasinthefollowingexamplecode:sound.start(audioContext.currentTime);//Playimmediatelysound.start(audioContext.currentTime+2);/*Playaudiobuffertwosecondsintothefuture*/

ThestartMethodThestartmethodisusedtobeginasoundplaying.Thestartmethodtakesthreearguments.The first argument schedules when the sound plays, either immediately or in the future. Thesecond argument sets a start point that determineswhere to begin playback from in the audiobuffer.Thethirdargumentsetswhenasoundceasestoplay.Forareal-worldexample,imagine

Page 181: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

youwereplayingbacka4/4drumloopand0.5secondsintotheloopthedrummerhitthesnaredrum.Ifyouwanttostartplaybackfromthispoint,yousetthesecondargumentofstart() to0.5.sound.start(audioContext.currentTime,0.5);

Thethirdargumentsetshowmuchofthesoundwillplay.Ifyouhaveasoundthatis4secondslongandyouonlywanttohearthefirst2seconds,thenyousetthethirdargumentto2.sound.start(audioContext.currentTime,0,2);

LoopingSoundsToloopsounds,yousetthelooppropertyofanaudiobuffersourcenodetotrue.Tosetthestartpointofaloop,youusethepropertyloopStart.Tosettheendpointofaloop,youusethepropertyloopEnd.sound.loop=true;sound.loopStart=1;/*Setlooppointatonesecondafterbeginningofplayback*/sound.loopEnd=2;/*Setloopendpointattwosecondsafterbeginningofplayback*/

Sometimeswhentryingtodiscernplaybackandlooppoints,itisusefultoknowthelengthofan audio file. You can get this information using a property of the sound buffer namedduration.

varsound=audioContext.createBufferSource();sound.buffer=buffer;sound.buffer.duration;//lengthinsecondsofaudiofile

Includedinthecodeexamplesforthischapterisanapplicationthatallowsyoutomodifytheplaybackandlooppointsofanaudiofileinrealtimeusinginteractivesliders.

Page 182: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

UpdateYourAudioLoaderLibraryTheplay()methodofyouraudioloaderlibraryisnotdesignedtoaccessthesecondandthirdarguments of thestart method. You canmake these arguments availablewith the followingmodificationstoyourcode:soundObj.play=function(time,setStart,setDuration){playSound=audioContext.createBufferSource();playSound.buffer=soundObj.soundToPlay;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime+time||audioContext.currentTime,setStart||0,setDuration||soundObj.soundToPlay.duration);};

Thestartandendpointsettingsarenowavailable.sounds.snare.play(0,1,3);

ChangingAudioParametersoverTimeUp to thispointyouhavechangedaudioparametersbydirectly setting thevalueproperty to anumber.varosc=audioContext.createOscillator();osc.frequency.value=300;

TheWebAudioAPI comeswith a collection ofmethods that allow you to schedule audioparametervaluesimmediatelyoratsomepointinthefuture.Thefollowingcodeshowsalistofthesemethods.

Page 183: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

setValueAtTime(arg1,arg2)exponentialRampToValueAtTime(arg1,arg2)linearRampToValueAtTime(arg1,arg2)setTargetAtTime(arg1,arg2,arg3)setValueCurveAtTime(arg1,arg2,arg3)

Youcanusethesemethodsinplaceofsettingthevaluepropertyofanaudioparameter.osc.frequency.value=100;//Setvaluedirectlyosc.frequency.setValueAtTime(arg1,arg2);/*Setvaluewithaudioparametermethod*/

TheAudioParameterMethodsThesetValueAtTimeMethodThesetValueAtTimemethodallowsyoutocreateanabruptchangeofanaudioparameteratafutureperiodintime.Thefirstargumentisthevaluetheparameterwillbechangedto,andthesecondargumentisthetimethatitwilltaketochangetothatvalue.Inthefollowingexample,5secondsafterthecodeisrun,againnodeparametervalueisabruptlychangedfrom1to0.1.varosc=audioContext.createOscillator();varvolume=audioContext.createGain();osc.connect(volume);volume.gain.value=1;volume.gain.setValueAtTime(0.1,audioContext.currentTime+5);osc.start(audioContext.currentTime);volume.connect(audioContext.destination);

To use any of the other audio parameter methods that are described next, you must firstinitialize their settings usingsetValueAtTime(). This is shown in the code examples foreachmethod.

TheexponentialRampToValueAtTimeMethodTheexponentialRampToValueAtTime()methodallowsyoutocreateagradualchangeof the parameter value. Unlike the abrupt change of setValue AtTime(), this methodfollowsanexponentialcurve.Thefollowingcodedemonstratesthisbychanginganoscillator’sfrequencyfrom200Hzto3kHzoverthecourseof3seconds.varosc=audioContext.createOscillator();varvolume=audioContext.createGain();osc.frequency.value=200;osc.frequency.setValueAtTime(osc.frequency.value,audioContext.currentTime);//____Setinitialvalues!osc.frequency.exponentialRampToValueAtTime(3000,audioContext.currentTime+3);osc.start(audioContext.currentTime);osc.connect(audioContext.destination);

Page 184: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

ThelinearRampToValueAtTimeMethodThe linearRampToValueAtTime method is similar toexponentialRampToValueAtTime() but follows a gradual linear curve instead of anexponentialcurve.varosc=audioContext.createOscillator();varvolume=audioContext.createGain();osc.frequency.value=200;osc.frequency.setValueAtTime(osc.frequency.value,audioContext.currentTime);//Setinitialvaluesosc.frequency.linearRampToValueAtTime(3000,audioContext.currentTime+3);osc.start(audioContext.currentTime);osc.connect(audioContext.destination);

ThesetTargetAtTime()MethodThesetTargetAtTime()methodtakesthreearguments.Thefirstargumentisthefinalvalueof the audio parameter, the second argument is the time the change will begin, and the thirdargumentisatimeconstantthatdetermineshowlongthechangewilltaketocomplete.Thelargerthenumberofthethirdargument,thelongerthechangetakestocomplete.varosc=audioContext.createOscillator();varvolume=audioContext.createGain();osc.frequency.value=200;osc.frequency.setValueAtTime(osc.frequency.value,audioContext.currentTime);//Setinitialvaluesosc.frequency.setTargetAtTime(3000,audioContext.currentTime,2);osc.start(audioContext.currentTime);osc.connect(audioContext.destination);

ThesetValueCurveAtTime()MethodThesetValueCurveAtTime() method allows you to create a custom curve based on acollectionofaudioparametervaluesstoredinanarray.Thismethodtakesthreearguments.Thefirst argument is an array of values. The array used is a special kind of array called afloat32Array(), which is a typed array. Typed arrays are better performing thanconventional arrays and allow someWebAudioAPIs towork directlywith binary data. Thesyntaxforafloat32Array() requiresyou toexplicitlyset thenumberof indexvaluesandlookslikethefollowingcode:varwaveArray=newFloat32Array(10);//__SetnumberofindexvalueswaveArray[0]=20;waveArray[1]=200;waveArray[2]=20;waveArray[3]=200;waveArray[4]=20;waveArray[5]=200;

Page 185: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

waveArray[6]=20;waveArray[7]=200;waveArray[8]=20;waveArray[9]=200;

Thesecondargumentrepresentswhenyouwantthechangestobegin,andthethirdargumentisthetimespanyouwantthechangestotakeplacewithin.Thefollowingcodedemonstratesthisbytogglingthefrequencyofanoscillatorfrom100to500Hzandbackagainoverthecourseof3seconds.Thiscreatesawobbleeffect.varwaveArray=newFloat32Array(10);waveArray[0]=100;waveArray[1]=500;waveArray[2]=100;waveArray[3]=500;waveArray[4]=100;waveArray[5]=500;waveArray[6]=100;waveArray[7]=500;waveArray[8]=100;waveArray[9]=500;

varosc=audioContext.createOscillator();varvolume=audioContext.createGain();osc.frequency.value=500;osc.frequency.setValueAtTime(osc.frequency.value,audioContext.currentTime);//Setinitialvaluesosc.frequency.setValueCurveAtTime(waveArray,audioContext.currentTime+1,3);osc.start(audioContext.currentTime);osc.connect(audioContext.destination);

SummaryInthischapter,youlearnedthefundamentalsofworkingwithtime.Youlearnedhowtoloopandschedule sound playback, as well as how to schedule parameter value changes. In the nextchapter,youwilllearnhowtocreateaudiovisualizationsusingtheAnalysernode.

Page 186: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

21CreatingAudioVisualizations

Inthischapter,youwilllearnhowtousetheAnalysernodetocreateaspectrumanalyzerthatdisplaysreal-timeamplitudeinformationofaudiosignalsacrossacollectionoffrequencybands.TheWebAudioAPIincludesanodenamedAnalyser thatgivesyoureal-timefrequencyandtimedomaininformationaboutaudioinputsources.Thisinformationcanbeusedtocreatecustomvisual representationsof audio signals that include (but arenot limited to) spectrumanalyzers,phasescopes,andwaveformrenders.

ABriefWordonFourierAnalysisBeforeyougetstarted,youmustfirsthaveabasicconceptualunderstandingofFourieranalysis.Fourieranalysisisadifficulttopicinvolvingalotofimpressivemath,soapropercoverageofthe topic iswell beyond the scopeof thisbook.Themainpointyouneed tounderstand is thatFourieranalysisisawaytotakeamazinglycomplexthingslikesoundwavesandsimplifythem.Withthisapproach,asignal(referredtoasafunction)canbeeitherrepresentedorapproximatedby a combination of simpler periodic signals or functions, such as sine and cosine waves.Replicating a sound is also theoretically possible by combining an infinite number of thesewaveforms. In theory, a perfect replica (or perfect separation of constituent parts) is realizedfromthiscombination,butinpractice,humanbeingslackinfinitetimeandcomputingpower,soyouwillalwayshavetomakedowithanapproximation.

Some of the most common forms of Fourier analysis in audio processing are called fastFouriertransforms,ormorecommonlyFFTs.ThegoalofanFFTistoquicklygiveyouausefulapproximationwithoutdoingtoomuchcomputationalworkandslowingdownthesystem.

ABriefExplanationofBinary-CodedDecimalNumbers

Page 187: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TobetterunderstandhowtheWebAudioAPIgivesyouaccesstothetimeandfrequencydomainof audio input sources, youneed to understandhow to read binary-codeddecimal numbers.Abinary system is composed of a series ofon andoff values called bits.Bits are read in 8-bitgroupingscalledbytes,whichhaveanequivalentdecimalvalue.Bitsarereadfromrighttoleftandeachvalueiseitheranonvaluerepresentedbya1,oranoffvaluerepresentedbya0.Thedecimalequivalentofagroupingofbitsiscalculatedbyexponentiallycountingfromrighttoleftandaddingalloftheonvaluestogether.

Whenallbitsareon,abytehasavalueof255.Thisallowsfor256totalpossiblevalues(0–255).

TheSpectrumAnalyzerThe following program creates a basic frequency spectrum analyzer using an oscillator as itsinputsource.Therestofthischapterisdedicatedtoexplaininghowthiscodeworks.

JavaScript/JQuery"usestrict";$(function(){varaudioContext=newAudioContext();varanalyzer=audioContext.createAnalyser();varosc=audioContext.createOscillator();varfrequencyData=newUint8Array(analyzer.frequencyBinCount);//___Createarrayanalyzer.getByteFrequencyData(frequencyData);//______________________Storefrequencydataconsole.log(frequencyData.length);console.log(frequencyData);

varapp=$(".app");

Page 188: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varbars=undefined;

osc.frequency.value=120;osc.connect(analyzer);analyzer.connect(audioContext.destination);osc.start(audioContext.currentTime);analyzer.fftSize=2048;console.log(analyzer.frequencyBinCount);//1024

//________________________________BEGINVisualization

$(".bin-count-number").text(analyzer.fftSize/2);//____Bincount

for(vari=0;i<analyzer.frequencyBinCount;i++){

$(".app").append("<div></div><span>"+i+"</span>");}

bars=$(".app>div");

functionupdate(){requestAnimationFrame(update);

analyzer.getByteFrequencyData(frequencyData);

for(vari=0;i<bars.length;i+=1){

bars[i].style.height=frequencyData[i]+'px';

}

}

update();

//_______________________________ENDvisualization

});

HTML<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title></title><scripttype="text/javascript"src="js/jquery.js"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"type="text/css"></head><!--______________________________________________________BEGINAPP-->

<body><pclass="bin-count">Bincount:<bclass="bin-count-number"></b></p>

Page 189: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

<divclass="app"></div></body><!--______________________________________________________ENDAPP--></html>

CSS.app{

position:relative;margin:10px;

}

.app>div{width:0.1px;background-color:orange;display:inline-block;outline-style:solid;outline-color:orange;outline-width:0.1px;margin-left:8px;

}

span{display:inline-block;font-size:14px;color:rgba(128,128,128,0.5);margin:2px;

}

.bin-count{position:absolute;left:30%;float:right;font-size:2em;height:50px;

}

Theoutputoftheapplicationlookslikethefollowingfigure.

Page 190: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

WalkingthroughtheCodeThe first step to creating a spectrum analyzer is to invoke Analyser() and connect inputsources to the returned object. For this application, the only input source used is anoscillator and the output of the analyser variable is connected directly toaudioContext.destination.varanalyzer=audioContext.createAnalyser();varoscillator=audioContext.createOscillator90;oscillator.connect(analyzer);analyzer.connect(audioContext.destination);

TheAnalyserinterfaceenablesyoutoperformvariousFFTsontheaudiostream.TheFFTusedtocreateaspectrumanalyzertransformsthetimedomainoftheaudiosignalintonormalized(orlimited)frequency-domaindata.Thisisdonebychoppingtheoriginalaudiosignalintoparts,typicallycalledbins,andperformingananalysisandtransformationoneachpart.

The size of the FFT is stored in thefftSize property of theAnalyser node and thedefaultvalueis2048.Theallowedvaluesareanypowerof2between32and2048.Ifyousetitwrong,youwillgetanerror.ThenumberofbinsavailableisonehalfofthefftSizepropertyand is accessible by a read-only property of the Analyser node namedfrequencyBinCount.

Page 191: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

analyzer.fftSize=2048;console.log(analyzer.frequencyBinCount);//1024...orhalfoffftSize

Each bin is designated a range of frequencies called a band, and the following formuladeterminestherangeofeachband:

(SampleRate)/(FFTSize)=(BandSize)

Example:

44,100/2048=21.533203125

StoringtheFrequencyDatainanArrayThenextstep is tocreateanarray tostore thefrequencydata.Aspecialkindofarraycalledatypedarrayisrequiredforthistask.Atypedarrayisanarray-likeobjectspecificallydesignedforworkingwithbinarydata.//______________________CreatetypedarrayvarfrequencyData=newUint8Array(analyzer.frequencyBinCount);

//______________________Storefrequencydataanalyzer.getByteFrequencyData(frequencyData);

There are two kinds of typed arrays that the Analyser node is designed to work with:Float32Array andUint8Array. The index values of aFloat32Array are always adecimalnumberbetween0and1.TheindexvaluesofaUint8Arrayarelimitedto8bitsofinformationandwillalwaysbeanintegerbetween0and255.UsingaFloat32Arrayallowsforupto32bitsofinformationandgivesyoumoreprecisionbutismoreresourceintensive.Thisis in contrast to Uint8Array, which is more resource efficient but less precise. ThisapplicationusesaUint8Array.AFloat32ArrayorUint8Arraymustbecreatedusingthekeywordnew.

Inthefollowingcode,theUint8Arrayisinvokedwithasingleargumentthatdeterminesthenumberofindexesitwillhavebyusinganalyzer.frequencyBinCount.varfrequencyData=newUint8Array(analyzer.frequencyBinCount);console.log(frequencyData.length);//1024

YounowstorethefrequencydomaindatainthearrayusinggetByteFrequencyData().

analyzer.getByteFrequencyData(frequencyData);

IfthefrequencyDataarrayisaFloat32ArrayinsteadofaUint8Array,youusethegetFloatFrequencyData()methodandthecodelookslikethis:analyzer.getFloatFrequencyData(frequencyData);

Page 192: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HowtoThinkAboutthefrequencyDataArrayEach indexvalueof thefrequencyData arraycanbeanynumberbetween0and255.Thisvalue is correlated with the energy intensity of the frequency band that is designated by thatparticulararrayindex.Thefollowingdiagramscanhelptoclarifythis.

BuildingtheDisplayInterfaceThe following line of code renders the current number of bins to theDocumentObjectModel(DOM).$(".bin-count-number").text(analyzer.fftSize/2);//____Bincount

Page 193: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Thefollowingforloopcreatesadivforeachbin.Insideeachdiv,aspaniscreatedthatdisplaysanumberthatcorrespondstoeachbin.for(vari=0;i<analyzer.frequencyBinCount;i++){

$(".app").append("<div></div><span>"+i+"</span>");

}

Thebarsvariableselectsalldivelementsandisusedlaterinthecode.bars=$(".app>div");

ConnectingtheAnalyzertotheDOMToreadandusefrequencyData,theprogrammustcontinuouslycheckitscurrentstatesothatthe DOM can be updated with the new information. This can be done by placinganalyzer.getByteFrequencyData(frequencyData) in therequestAnimationFrame function.requestAnimationFrame is a method that tellsthe browser that you wish to perform an animation.When it is time to update the animation,requestAnimationFramecallsthefunctionthatyoupassedtoit.Theupdateratematchesthedisplayrefreshrateofthewebbrowser.functionupdate(){requestAnimationFrame(update);analyzer.getByteFrequencyData(frequencyData);}

update();

Tocreatetheverticalfrequencybars,thefor loopupdatestheCSSheightpropertyofeachdiv stored in thebar variable.Thevaluegiven toeachdiv is a pixel representationof thecurrentfrequencyDataarrayindex.Thisvalueisbetween0and255px.

Page 194: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

functionupdate(){requestAnimationFrame(update);analyzer.getByteFrequencyData(frequencyData);

for(vari=0;i<bars.length;i+=1){

bars[i].style.height=frequencyData[i]+'px';

}

}

update();

Theuserinterfaceofthespectrumanalyzerisdesignedtocreateadivforallbins.YoucanchangethesizeoftheFFTtolowerthebincount.analyzer.fftSize=64;

Theapplicationyoucreatedinthischapterworkswithfrequency-domaindata.Ifyouwanttoworkwithtime-domaindata,theAnalysernodehastwomethodsthatletyoucopyittoatypedarray. The first method is getByteTime DomainData () and is for use with aUint8Array(). The second method is getFloatTimeDomainData() and is for usewithFloat32Array().Tostore the timedomaindata inaUint8Array(),youwrite thefollowingcode:varfrequencyData=newUint8Array(analyzer.frequencyBinCount);analyzer.getByteTimeDomainData(frequencyData);

SummaryInthischapter,youlearnedabouttheAnalysernodeandcreatedafrequencyspectrumanalyzerapplication.

Page 195: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Upuntilnow,whenaddingnewnodesthataffectaudiobuffers,youhaveappliedthechangesto a single node graph that affectsall audio buffer input sources. In the next chapter, youwillupdatetheaudioloaderlibrarythatyoucreatedinChapter13toallowuserstocreatecustomizednodegraphsforindividualaudiobuffers.

Page 196: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

22AddingFlexibilitytotheAudioLoaderAbstraction

In this chapter, you will add flexibility to the audio loader abstraction and give usersindependently customizable nodegraphs for audio buffer input sources. In its current state, theaudio loader library you created in Chapter 13 only allows you to create one universal nodegraph configuration. So any files that you load have to conform to this configuration. This isundesirablefortworeasons.Thefirstisthatwhenyoucreatealibrary,youdon’twanttheusertohavetomodifyitsinternalstogetthefunctionalitytheywant.Thesecondreasonisthatitisusefultohave thechoice toapplycompletelydifferent effects todifferent audio input sources,whichrequiresnodeconfigurationsthatareindependentlycustomizable.

TheUpdatedInterfaceWhenyoucreateanylibraryorabstraction,itishelpfultofirstdefinewhattheinterfacewilllooklikeandthenworkbackwardtowarditscreation.Inthiscase,thefollowingexampleshowshowthe final interface will look. This is similar to the current library except that the object thataudioBatchLoadertakesasanargumenthasamethodthatdefinesacustomnodegraph.Thisnodegraphisappliedtoallaudiofilesreferencedaspropertiesinthecontainingobject."usestrict";

varsoundData={kick:"sounds/kick.mp3",snare:"sounds/snare.mp3",//________________________________________BEGINcustomnodegraphnodeGraph:functionnodeGraph(sound){vargain=audioContext.createGain();gain.gain.value=1;sound.connect(gain);gain.connect(audioContext.destination);}//________________________________________ENDcustomnodegraph}

Page 197: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varsound=audioBatchLoader(soundData);//Takestheobjectasargumentsound.kick.play();//Soundplaysusingcustomnodegraphsound.snare.play();//Soundplaysusingcustomnodegraph

Thisinterfaceallowsyoutoaddonemethodtotheobject;andthismethodthensetsthenodegraphconfigurationforallsoundfilesreferencedaspropertiesofthatobject.

ModifyingtheLibraryMakeacopyoftheemptytemplatefolderyoucreatedinChapter1andrenameittoChapter22.Inthejsfolder,placeacopyofthecompletedaudioloaderlibraryyoumodifiedinChapter20andreferenceitfromtheindex.htmlfile.<head><metacharset="UTF-8"><title>app</title><scriptsrc="js/audiolib.js"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head>

Next,createadirectorynamed“sounds”andplaceanMP3filenamed“snare”init(thisfileisavailableinthedownloadablecodeexamples).Copythefollowingcodeintotheapp.jsfile."usestrict";varsound=audioFileLoader("sounds/snare.mp3",function(sound){vargain=audioContext.createGain();gain.gain.value=0.2;sound.connect(gain);gain.connect(audioContext.destination);

});

window.addEventListener("mousedown",function(){sound.play();

});

window.addEventListener("mouseup",function(){sound.stop();

});

Ifyourunthepreviouscode,itwillnotwork.Intheaudiolib.jsfileyouwillnowmodifythefunctionnamedaudioFileLoadersothatthepreviouscodeworks.Thesemodificationswillletusersloadsinglefiles,eachofwhichhasauniquenodegraph.Oncethisworks,wewillgooverhowtomodifyaudioBatchLoadertoloadmultiplefiles.

Inyouraudiolib.jsfile,modifythecodetoincludeacallbackfunctionlikethefollowingexample:

Page 198: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

varaudioContext=newAudioContext();functionaudioFileLoader(fileDirectory,callback){varplaySound=undefined;varsoundObj={};

soundObj.fileDirectory=fileDirectory;vargetSound=newXMLHttpRequest();getSound.open("GET",soundObj.fileDirectory,true);getSound.responseType="arraybuffer";getSound.onload=function(){audioContext.decodeAudioData(getSound.response,function(buffer){soundObj.soundToPlay=buffer;

});}

getSound.send();

soundObj.play=function(time){playSound=audioContext.createBufferSource();playSound.buffer=soundObj.soundToPlay;playSound.connect(audioContext.destination);playSound.start(audioContext.currentTime+time||audioContext.currentTime,setStart||0,setDuration||soundObj.soundToPlay.duration);callback(playSound);

}

soundObj.stop=function(time){

playSound.stop(audioContext.currentTime+time||audioContext.currentTime);

}returnsoundObj;};

Inthepreviouscode,thecallbacknowfulfillstheroleofacustomizablenodegraphandthecodewillnowwork.However,thereisstilloneproblem:Iftheuserdoesnotuseacallback,thenanerrorresults.varsound=audioFileLoader("sounds/snare.mp3");//ERROR!

This error can be dealt with by simply using a conditional to check if the callback is afunction.Iftheconditionalreturnsfalse(becausetheuserdidn’tsetit),adefaultnodegraphissetinitsplace.

Todothis,modifythecodeasfollows:soundObj.play=function(time){playSound=audioContext.createBufferSource();playSound.buffer=soundObj.soundToPlay;playSound.start(audioContext.currentTime+time||audioContext.currentTime);

callback(playSound);if(typeofcallback==="function"){returncallback(playSound);

Page 199: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

}else{returnplaySound.connect(audioContext.destination);}

}

Thiscodenowworkswhetherthefunctionisinvokedwithacallbackornot.

ModifyingaudioBatchLoaderYouwillnowedittheaudioBatchLoaderfunctiontocheckifitsparameterobjectcontainsamethod, and if it does, themethod is set as the callback ofaudioFileLoader. This codeappliesacustomnodegraphtoagroupoffiles.functionaudioBatchLoader(obj){varcallback=undefined;varprop=undefined;

for(propinobj){if(typeofobj[prop]==="function"){callback=obj[prop];deleteobj[prop];}}

for(propinobj){

obj[prop]=audioFileLoader(obj[prop],callback);//___Placefunctionascallback

}returnobj;}

AnExplanationofthePreviousCodeEditIfamethodisfoundonobj,itisassignedtothevariablenamedcallback.Themethodisthendeleted from obj using the delete keyword. The deletion is necessary so that theaudioFileLoaderdoesnotattempttoreferenceitasanaudiofiledirectory.

Thefollowingcodeisanexampleofloadingacollectionoffileswithacustomnodegraph.Thiscodenowworks."usestrict";

varsound=audioBatchLoader({snare:"sounds/snare.mp3",kick:"sounds/kick.mp3",hihat:"sounds/hihat.mp3",nodes:function(sound){vargain=audioContext.createGain();

Page 200: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

sound.connect(gain);gain.gain.value=0.5;gain.connect(audioContext.destination);

}});

window.addEventListener("mousedown",function(){sound.snare.play();});

window.addEventListener("mouseup",function(){sound.snare.stop();});

OnethingyoushouldbeawareofisthattheobjectthattheaudioBatchLoadertakesasanargumentisintendedtohaveonlyonemethod.Ifithasmorethanonemethod,thenoneofthemisoverwritten.Whenusingafor-inloop,thepropertiesandmethodsofthetargetedobjectarenotreturned in any particular order. Because of this, you cannot knowwhichmethod is used andwhichoneisoverwrittenuntilthesoundisplayedback.Forthisreason,youmightwanttowriteanerrorchecktothrowanerrorforargumentobjectsthathavemorethanonemethod.Thisisleftuptoyoutoimplement.

SummaryIn thischapter,youaddedadditional flexibility toyouraudio loader libraryand in theprocessyou were exposed to a real-world example of how callback functions can be useful whendesigningalibrary.Inthenextchapteryouwilllearnhowtobuildaninteractivemusicsequencer.

Page 201: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

23BuildingaStepSequencer

Music applications, like sequencers and drummachines, allow users to record, edit, and playbacksoundsasacollectionoforganizednotearrangements.DuetothenatureoftheWebAudioAPIanditsrelationshiptotheDOM,musicsequencingapplicationsareachallengetocreate.Inthischapter,youwilllearnwhythisissoandhowtomeetthechallengebybuildingabasicdrumpatternstepsequencer.

TheProblemTheWebAudioAPIletsyouscheduleeventsimmediatelyorinthefuture.Aproblemwiththisapproach is that once an event is scheduled, it cannot be unscheduled. So for example, thefollowingcodeschedulesthreedrumsoundstoplayinan8thnotepatternforfourbars.varkick=audioFileLoader("sounds/kick.mp3");varsnare=audioFileLoader("sounds/snare.mp3");varhihat=audioFileLoader("sounds/hihat.mp3");

vartempo=120;//_____BPM(beatsperminute)vareighthNoteTime=(60/tempo)/2;functionplayDrums(){//Play4barsofthefollowing:for(varbar=0;bar<4;bar++){vartime=bar*8*eighthNoteTime;//Playthebass(kick)drumonbeats1,5kick.play(time);kick.play(time+4*eighthNoteTime);

//Playthesnaredrumonbeats3,7snare.play(time+2*eighthNoteTime);snare.play(time+6*eighthNoteTime);//Playthehi-hateveryeighthnote.for(vari=0;i<8;++i){hihat.play(time+i*eighthNoteTime);}}}

Page 202: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Ifyouwanttochangethetemporelationshipofthesesoundsinthemiddleofthefourbars,youcan’t. Instead, you have to wait until the sounds have completed playing. This is true of anyscheduled events that you might want to change during playback. And this restriction is notrelegatedtojusttempochanges.

CanIUsesetIntervalorsetTimeout?YoumightbewonderingifyoucanusesetIntervalorsetTimeouttosolvethisproblem.ThefollowingcodeusessetIntervaltoincrementacounterataspecifiedbeatsperminute(BPM), anddependingon the countervalue, aparticulardrumsound isplayed.This creates arhythmicpattern.varkick=audioFileLoader("sounds/kick.mp3");varsnare=audioFileLoader("sounds/snare.mp3");varhihat=audioFileLoader("sounds/hihat.mp3");

vartempo=120;//_____BPM(beatsperminute)varmilliseconds=1000;vareighthNoteTime=((60*milliseconds)/tempo)/2;

varcounter=1;window.setInterval(function(){if(counter===8){counter=1;}else{counter+=1;}if(counter){hihat.play();}if(counter===3||counter===7){snare.play();}if(counter===1||counter===5){kick.play();}

},eighthNoteTime);

TheproblemwiththisapproachisthatboththesetTimeoutandsetIntervalmethodshavetimingsthatareimpreciseandunstable.Therearetworeasonsforthis.Thefirstisthatthesmallest unit of time available to these methods is an integer of 1 millisecond, which is notpreciseenoughforaudiosample-levelvalueslike44.100kHz.TheotherproblemisthatunliketheWebAudioAPItimingclock,thesemethodscanbeinterruptedbyancillarybrowseractivitylikepagerenderingandredraws.AlthoughyoumightexpectsetIntervalorsetTimeouttorunateverynthmillisecond,dependingonfactorsoutsideyourcontrol,thevaluewilllikelybelargerandaudiblynoticeable.

Page 203: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheSolutionThesolutiontotheproblemistocreatearelationshipbetweentheWebAudioAPItimingclockand the browser’s internal setTimeout method to create a look-ahead mechanism thatrecursivelyloopsandchecksifeventswillbescheduledatsometimeinthefuture.Ifthisisthecase,theschedulinghappensandtheevent(s)takesplace.Thisgivesyouenoughleewaytocanceleventsatthelastmomentifneeded.

OnethingtokeepinmindisthatbecausesetTimeoutisinherentlyunstable,weknowthatthisrelationshipwillalwayshaveanunstableaspecttoit.Whetherornotthisapproachisstableenoughforyourapplicationsisforyoutodecide.OnethingwecanbecertainofisthatitismuchmoreaccuratethanusingsetIntervalorsetTimeoutonitsown.

HowItWorksThe basis for the relationship between the Web Audio API timing clock and the browser’sinternalsetTimeoutmethodisexpressedinthefollowingcode:

varaudioContext=newAudioContext();varfutureTickTime=audioContext.currentTime;functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){futureTickTime+=0.5;//____canbeanytimevalue.0.5happenstobeaquarternoteat120bpmconsole.log(futureTickTime);}window.setTimeout(scheduler,0);}scheduler();

Theway thepreviouscodeworks is that thesetTimeout function loops recursively, anduponeachiteration,aconditionalcheckswhether thevalueoffutureTickTime iswithinatenth of a second of the audioContext.currentTime. If this evaluates to true thenfutureTickTimeisincrementedby0.5,whichishalfasecond in“WebAudioTime.”ThefutureTickTimevariableremainssetatthisvalueuntilaudioContext.currentTime“catches up with it” once again. Then within a tenth of a second, futureTickTime isincrementedbyahalf-secondintothefuture.Thispatterncontinuesforaslongasthefunctionisallowedtorun.

Becauseahalf-secondtranslatestoaquarternoteat120beatsperminute,thefollowingcodeusesthisinformationtocreatea1/4thnotetimingcountthatisloggedtotheconsole.varfutureTickTime=audioContext.currentTime;varcounter=1;functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){console.log("Thisisbeat:"+counter);futureTickTime+=0.5;/*____canbeanytimevalue.0.5happenstobeaquarternoteat120bpm*/

Page 204: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

counter+=1;if(counter>4){counter=1;}}window.setTimeout(scheduler,0);}scheduler();

Thefollowingcodebuildsonthepreviousexampleandplaysanoscillatoroneachcount.Theoscillator is connected to a gainnodenamedmetronomeVolumewhich is connected to thedestination.Thegainnodeisaddedbecausethefinalapplicationinthischapterusesittotoggletheoscillatorvolumeonandoff.varfutureTickTime=audioContext.currentTime;varcounter=1;varosc=audioContext.createOscillator();varmetronomeVolume=audioContext.createGain();functionplayMetronome(time){osc=audioContext.createOscillator();osc.connect(metronomeVolume);metronomeVolume.connect(audioContext.destination);osc.start(time);osc.stop(time+0.1);

}

functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){

console.log("Thisisbeat:"+counter);playMetronome(futureTickTime);futureTickTime+=0.5;//____canbeanytimevalue.0.5happens//____________________________tobeaquarternoteat120bpm

counter+=1;

Page 205: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

if(counter>4){counter=1;}}window.setTimeout(scheduler,0);}scheduler();

ChangingTempoIfyouwant tochange the tempo,youhave tochange the timerelationshipbetweenevents.YoucandothisbyalteringwheneventsarescheduledtostartwiththefutureTickTimevariable.Thefollowingformulaisusefulforconvertingbeats(quarternotes)toseconds.vartempo=120.0;//tempo(inbeatsperminute);varsecondsPerBeat=(60.0/tempo);

Theapplicationyoubuildassumestheuseofa16thnotegrid.Youcandesignitwithanybeatdivision(s) you want, but for simplicity it is hard-coded with 16 notes. The following codeconvertsthefutureTickTimevariablefromatimevaluethatrepresentsaquarternotetoatimevaluethatrepresentsa16thnote.Theoscillatorisalsomodifiedtoplayadifferentfrequencyonthedownbeat.varfutureTickTime=audioContext.currentTime;varcounter=1;vartempo=120;varsecondsPerBeat=60/tempo;varcounterTimeValue=(secondsPerBeat/4);//___16thnotevarosc=audioContext.createOscillator();varmetronomeVolume=audioContext.createGain();

functionplayMetronome(time){osc=audioContext.createOscillator();osc.connect(metronomeVolume);metronomeVolume.connect(audioContext.destination);osc.frequency.value=500;osc.start(time);osc.stop(time+0.1);

}functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){

console.log("Thisis16this:"+counter);playMetronome(futureTickTime);futureTickTime+=counterTimeValue;

if(counter===1){osc.frequency.value=500;}else{osc.frequency.value=300;}

counter+=1;

Page 206: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

if(counter>16){counter=1;}}window.setTimeout(scheduler,0);}

scheduler();

Youcannowchangethetempobymodifyingthetempovariable.

BuildingtheSequencerYouarenowgoingtobuildthesequencerapplication.CreateacopyoftheWebAudiotemplatefolderyoucreatedinChapter1andrenameittosequencer.Intheindex.htmlfile,referenceboththeJQuerylibraryandtheaudiolib.js file thatyouupdated inChapter20. Inside thesequencerfolder,createafoldernamedsoundsandplacetheaudiofilesforthesequencerapplicationinit.

Copythefollowingcodetoapp.jsandsavethefile.Thiscoderefactorsthepreviouscodeyouhavewritten.Thisversionismorereadableandthemetronomeisgivenitsownfunction."usestrict";varaudioContext=newAudioContext();varfutureTickTime=audioContext.currentTime,counter=1,tempo=120,secondsPerBeat=60/tempo,counterTimeValue=(secondsPerBeat/4),osc=audioContext.createOscillator(),metronomeVolume=audioContext.createGain();

//_____________________________________________BEGINmetronomefunctionplayMetronome(time,playing){if(playing){osc=audioContext.createOscillator();osc.connect(metronomeVolume);metronomeVolume.connect(audioContext.destination);osc.frequency.value=500;if(counter===1){osc.frequency.value=500;}else{osc.frequency.value=300;}osc.start(time);osc.stop(time+0.1);}}

//______________________________________________ENDMetronomefunctionplayTick(){console.log("Thisis16thnote:"+counter);counter+=1;futureTickTime+=counterTimeValue;if(counter>16){counter=1;

Page 207: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

}}

functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){playMetronome(futureTickTime,true);playTick();}window.setTimeout(scheduler,0);}scheduler();

PlayingBackSoundsinSequenceYou will now create a series of arrays that represent music sequencer tracks. Each of thesearraysstorescountervalues.Oneachiterationofthecounter,aforlooprunstocheckifanyofthearraysholdsthecurrentcountervalue.Ifanyofthemdoes,thesoundassociatedwiththatarrayplays. The arrays are associated with the correct sound through a function namedscheduleSound().Thisfunctiontakesfourarguments:

■Thetrackarray

■Thesoundtoplay

■Thecurrentcountvalue

■Thetimetoschedulethesound

Thetrackarraysarepopulatedwithvaluessothatyoucanhearadrumsequenceimmediately.varfutureTickTime=audioContext.currentTime,counter=1,tempo=120,secondsPerBeat=60/tempo,counterTimeValue=(secondsPerBeat/4),osc=audioContext.createOscillator(),metronomeVolume=audioContext.createGain();

/*_____________________________________________BEGINloadsoundsamples*/

varkick=audioFileLoader("sounds/kick.mp3");varsnare=audioFileLoader("sounds/snare.mp3");varhihat=audioFileLoader("sounds/hihat.mp3");varshaker=audioFileLoader("sounds/shaker.mp3");

//_____________________________________________ENDloadsoundsamples

//_____________________________________________BEGINArrayTracks

varkickTrack=[1,9,11],snareTrack=[5,13],hiHatTrack=[13,14,15,16],shakerTrack=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

Page 208: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

//_____________________________________________ENDArrayTracks

functionscheduleSound(trackArray,sound,count,time){

for(vari=0;i<trackArray.length;i+=1){if(count===trackArray[i]){sound.play(time);}}}

//_____________________________________________BEGINmetronomefunctionplayMetronome(time,playing){

if(playing){osc=audioContext.createOscillator();osc.connect(audioContext.destination);osc.frequency.value=500;if(counter===1){osc.frequency.value=500;}else{osc.frequency.value=300;}osc.start(time);osc.stop(time+0.1);}}

//______________________________________________ENDMetronome

functionplayTick(){

console.log("Thisis16thnote:"+counter);counter+=1;futureTickTime+=counterTimeValue;if(counter>16){counter=1;}

}

functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){playMetronome(futureTickTime,true);

scheduleSound(kickTrack,kick,counter,futureTickTime-audioContext.currentTime);scheduleSound(snareTrack,snare,counter,futureTickTime-audioContext.currentTime);scheduleSound(hiHatTrack,hihat,counter,futureTickTime-audioContext.currentTime);scheduleSound(shakerTrack,shaker,counter,futureTickTime-audioContext.currentTime);

playTick();}window.setTimeout(scheduler,0);}

Page 209: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

scheduler();

Youmightbewonderingwhy thescheduleSound() function invocationsaresubtractingtheaudioContext.currentTimefromthefutureTickTime().

scheduleSound(kickTrack,kick,counter,futureTickTime-audioContext.currentTime);

This is done because the audio library you built in Chapter 13 is designed to referenceaudioContext.currentTimebydefaultandaddsanyadditionalnumericargumentstothisvalue.YousubtractaudioContext.currentTimefromfutureTickTimebecausethesevalueswillbecombinedwhentheplay()methodofyourlibraryisinvoked.

Whenscheduler() is invoked, thedrumsequencedoesnot start immediatelybecause ittakestimefortheaudiobuffersandfilestoload.Thisbehaviorcanbecorrectedbymodifyingthecodesothattheschedulerisinitiatedbyaplay/stopbutton.InyourHTMLcode,createabuttonwithaclassofplay-stop-buttonandgiveittextofplay/stop.<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title></title><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"></script><scriptsrc="js/audiolib.js"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head>

<!--___________________________________________BEGINAPP--><body>

<!--HTMLcode--><buttonclass="play-stop-button">Play/Stop</button>

</body><!--____________________________________________ENDAPP--></html>

YounowuseJQuerytointerfacewiththeDOMandhavetowrapyourcodeinadocument-readyfunction.Thefollowingcodedefinestheplay/stopbuttonfunctionality.$(function(){varfutureTickTime=audioContext.currentTime,counter=1,tempo=120,secondsPerBeat=60/tempo,counterTimeValue=(secondsPerBeat/4),osc=audioContext.createOscillator(),metronomeVolume=audioContext.createGain(),timerID=undefined,isPlaying=false;

Page 210: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

/*_____________________________________________BEGINloadsoundsamples*/

varkick=audioFileLoader("sounds/kick.mp3");varsnare=audioFileLoader("sounds/snare.mp3");varhihat=audioFileLoader("sounds/hihat.mp3");varshaker=audioFileLoader("sounds/shaker.mp3");

/*_____________________________________________ENDloadsoundsamples*/

//_____________________________________________BEGINArrayTracks

varkickTrack=[1,9,11],snareTrack=[5,13],hiHatTrack=[13,14,15,16],shakerTrack=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

//_____________________________________________ENDArrayTracks

functionscheduleSound(trackArray,sound,count,time){

for(vari=0;i<trackArray.length;i+=1){if(count===trackArray[i]){sound.play(time);}}

}

//_____________________________________________BEGINmetronome

functionplayMetronome(time,playing){

if(playing){osc=audioContext.createOscillator();osc.connect(metronomeVolume);metronomeVolume.connect(audioContext.destination);osc.frequency.value=500;if(counter===1){osc.frequency.value=500;}else{osc.frequency.value=300;}osc.start(time);osc.stop(time+0.1);}}

//______________________________________________ENDMetronome

functionplayTick(){console.log("Thisis16thnote:"+counter);counter+=1;futureTickTime+=counterTimeValue;if(counter>16){counter=1;}}

Page 211: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

functionscheduler(){if(futureTickTime<audioContext.currentTime+0.1){playMetronome(futureTickTime,true);scheduleSound(kickTrack,kick,counter,futureTickTime-audioContext.currentTime);scheduleSound(snareTrack,snare,counter,futureTickTime-audioContext.currentTime);scheduleSound(hiHatTrack,hihat,counter,futureTickTime-audioContext.currentTime);scheduleSound(shakerTrack,shaker,counter,futureTickTime-audioContext.currentTime);playTick();}

timerID=window.setTimeout(scheduler,0);}scheduler();functionplay(){isPlaying=!isPlaying;

if(isPlaying){counter=1;futureTickTime=audioContext.currentTime;scheduler();}else{window.clearTimeout(timerID);}}$(".play-stop-button").on("click",function(){play();});});

Ifyoulaunchthiscodefromyourserverandclicktheplay/startbutton,itwillstartandstoptheapplication.

CreatingtheUserInterfaceGridSo far you have built a working 16th note sequencer that plays back sound sequences via acollection of “array tracks” in code.You are nowgoing to create a user interface that allowsuserstocreatethesesequencesfromawebpage.

Todo this, you create four div elements positioned as rows, and eachof these contains 16childdivs.TheCSSdisplaysthesechilddivshorizontallyasacollectionofsmallsquares.Thefirstrowcontrolsplaybackofthekickdrum,thesecondrowthesnare,thethirdrowthehi-hat,andthefourthrowtheshaker.Thesequencerhasanadditionalbuttonthatturnsthemetronomeonandoffandaninputsliderthatcontrolsthetempo.

Page 212: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HTMLThefollowingcodeistheHTMLfortheapplication.<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>app</title><scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"></script><linkrel="stylesheet"href="css/app.css"><scriptsrc="js/audiolib.js"></script><scriptsrc="js/app.js"></script>

</head><!--_______________________________________________BEGINAPP--><body><divclass="app-grid"></div><buttonclass="play-stop-button">Play/Stop</button><buttonclass="metronome">Togglemetronome</button><divid="tempoBox">Tempo:<spanid="showTempo">120</span>BPM<inputid="tempo"type="range"min="30.0"max="160.0"step="1"value="120"></div></body><!--_______________________________________________ENDAPP--></html>

CSSThefollowingcodeistheCSSfortheapplication.

Page 213: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

body{background-color:red;font-size:25px;}

button{margin-bottom:5px;font-size:25px;}

.track-step{width:50px;height:50px;display:inline-block;background-color:orange;outline-style:solid;outline-width:1px;margin-left:5px;}

To create the div elements for the grid, you use a nested JavaScript for loop. Eachcollectionofgriditemshasaparentcontainer.functionplay(){isPlaying=!isPlaying;

if(isPlaying){counter=1;futureTickTime=audioContext.currentTime;scheduler();}else{window.clearTimeout(timerID);}}//__________________________________BEGINcreategridfor(vari=1;i<=4;i+=1){$(".app-grid").append("<divclass='track-"+i+"-container'</div>");for(varj=1;j<17;j+=1){$(“.track-”+i+“-container”).append(“<divclass=’grid-itemtrack-stepstep-"+j+"'</div>");}}//__________________________________ENDcreategrid

Thefollowingcodeallowsyoutotogglethemetronomeonandoff.$(".play-stop-button").on("click",function(){play();});//_________________________________________BEGINmetronometoggle$(".metronome").on("click",function(){if(metronomeVolume.gain.value){metronomeVolume.gain.value=0;}else{metronomeVolume.gain.value=1;}});//__________________________________________ENDmetronometoggle

Page 214: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Nextyouwritecodethat letsuserscontrol the tempofromtheHTMLinputrangeslideranddisplaysthecurrenttempoonthewebpage.First,modifytheplayTick()function:functionplayTick(){secondsPerBeat=60/tempo;counterTimeValue=(secondsPerBeat/4);console.log("Thisis16thnote:"+counter);counter+=1;futureTickTime+=counterTimeValue;if(counter>16){counter=1;}}

Thencreatetheeventlistenerusedtocontrolthetempofromtheslider:$(".metronome").on("click",function(){if(metronomeVolume.gain.value){metronomeVolume.gain.value=0;}else{metronomeVolume.gain.value=1;}});

$("#tempo").on("change",function(){tempo=this.value;$("#showTempo").html(tempo);});

YoucannowmodifythetempoofthesequencebymovingtheHTMLinputslider.

AddingInteractivitytotheGridElementsEachcollectionofelementswithaclassofgrid-itemhasaparent.Theparentelementsaredynamicallycreatedasshowninthefollowingcode:<divclass="track-1-container></div><divclass="track-2-container></div><divclass="track-3-container></div><divclass="track-4-container></div>

JQueryhasamethodnamedindex() that allowsyou to capture an element’s indexvaluerelativetoaparentelement.Inthecaseofthesequencerapplication,theindexvalueofthefirstgrid-itemofeachrowis0andthelastgrid-itemindexis15.Youcangivethisvalueanoffsetof+1sothat thefirst indexgrid-itemisreferencedas1andthelast isreferencedas16.Thisallowsforacorrelationbetweenthegrid-itemindexvaluesandthecountervalue.Youcancapture this informationbysettinganevent listener toallelementswithaclassofgrid-item. When the user clicks the grid-item, the offset index value is either pushed to orremoved fromacorresponding trackarraydependentonwhether thegrid-item isactiveornot.This iswhatdetermines ifasoundwillplayatacertainpoint in themusicsequence.The

Page 215: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

followingcodeimplementsthisfeatureandalsomodifiestheCSSbackground-colorofthegrid-itembasedonwhetheritisactiveornot.//__________________________________BEGINcreategridfor(vari=1;i<=4;i+=1){$(".app-grid").append("<divclass='track-"+i+"-container'</div>");for(varj=1;j<17;j+=1){$(".track-"+i+"-container").append("<divclass='grid-itemtrack-stepstep-"+j+"'</div>");}}//__________________________________ENDcreategrid

//______________________BEGINGridinteractivityfunctionsequenceGridToggler(domEle,arr){$(domEle).on("mousedown",".grid-item",function(){

vargridIndexValue=$(this).index();/*__________Getindexofgrid-item*/varoffset=gridIndexValue+1;/*_______________Add+1sovaluestartsat1insteadof0*/varindex=arr.indexOf(offset);/*_______________Checkifvalueexistsinarray*/

if(index>-1){/*______________________________Ifindexofitemexist.....*/

arr.splice(index,1);//_____________________thenremoveit....$(this).css("backgroundColor","");/*________andchangecolorofDOMelementtodefault*/}else{/*_______________________________________Ifitemdoesnotexist.....*/arr.push(offset);/*__________________________thenpushittotrackarray*/$(this).css("background-color","purple");/*_andchangecolorofDOMelementtopurple.*/

}});}

sequenceGridToggler(".track-1-container",kickTrack);sequenceGridToggler(".track-2-container",snareTrack);sequenceGridToggler(".track-3-container",hiHatTrack);sequenceGridToggler(".track-4-container",shakerTrack);//______________________ENDGridinteractivity

Nowsetthetrackarrayssothattheyareempty.varkickTrack=[1,9,11],snareTrack=[5,13],hiHatTrack=[13,14,15,16],shakerTrack=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

varkickTrack=[],snareTrack=[],hiHatTrack=[],shakerTrack=[];

Page 216: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Youcannowrunthesequencerandplaybacksoundsbyclickingthesquares.Thetempoalsochangeswhenthesliderismoved.

SummaryInthischapter,youlearnedhowtobuildabasicmusicsequencer.YounowunderstandthecoretechniquesneededtobuildWebAudioAPIapplicationsthatrelyoneventscheduling.

Page 217: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

24AJAXandJSON

Inthischapter,youaregoingtolearnhowtoquerydatausingwebAPIsandtocreateyourownweb API for accessing synth patch data to use in a web audio synthesizer. Third-party webservicescommonlyallowaportionoftheirdatatobeaccessibleviaawebAPI.Thisgivesyoutheabilitytoquerydataontheirserverandusetheirdatainyourapplications.AnexampleistheiTunespublicsearchAPIthat letsdeveloperssearchmedia titles in the iTunesstore.Tobegin,youmustfirstlearnabouttwotechnologies:AJAXandJSON.

AJAXAJAXisanacronymthatstandsforAsynchronousJavaScriptandXML.Thisisatechnologythatallows you to use JavaScript to access data asynchronously. You have already worked withAJAX in previous chapterswhen loading audio buffers using theXMLHttpRequest object.The X in AJAX refers to XML, which stands for Extensible Markup Language. This wasoriginally the data exchange format used with AJAX and is rarely used now. Inmodern webdevelopment,thedataexchangeformatyouuseisJSON.

JSONJSONstands forJavaScriptObjectNotation, and it is a data exchange format for transmittingand receiving data over theHTTP protocol whenworkingwithwebAPIs. JSON objects arenearly identical to JavaScript object literals, making them easy to work with. The differencebetweenaJSONobjectandaJavaScriptobjectliteralisthatJSONobjectsarenotassignedtoavariableandtheirkeysneedtobewrittenasstrings.JSONobjectsarestoredinJavaScriptfiles.ThefollowingcodeisanexampleofaJSONobject.{"buzzFunk":[{"type":"sawtooth",

Page 218: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

"frequency":65.25

},{"type":"triangle","frequency":65.25

},{

"type":"sawtooth","frequency":67.25

}]}

MakinganAJAXCalltotheiTunesSearchAPITodemonstratehowtointeractwithathird-partywebAPI,youarenowgoingtomakeaquerytotheiTunessearchAPI.

Makeacopyofthe“webaudiotemplate”folderyoucreatedinChapter1,renameitto“itunesapiexample”anddragittothesidebarinSublimeText.Next,referencetheJQuerylibraryfromtheindex.htmlfileandthencopythefollowingcodetotheapp.jsfile.$(function(){varapiURL="https://itunes.apple.com/search?term=funk&media=music&callback=?";$.getJSON(apiURL,function(data){console.log(data);

});});

GotoStartSublimeServerandinyourwebbrowsergotolocalhost:8080.Opentheconsoleandyouwillseeanobjectbeingreturned.

Ifyouclickthearrowandunfoldtheobject,youwillseealistofobjectsthateachcontainsdata.

Page 219: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

YouhavejustqueriedtheiTunessearchAPIforanymusicthat includesthekeyword“funk”andarenowinpossessionofaJavaScriptobjectthatcontainsthisdata.

HowtheCodeWorksJQuery has a collection of methods that abstract the XMLHttpRequest object and letsdevelopersmakeAJAX requestswith a simple syntax.Oneof thesemethods is$.getJSON.This method issues a request to a server that returns the queried data. The first argument of$.getJSON is a URL (commonly referred to as an endpoint). The endpoint is written as astring,andifyoulookcloselyyoucanseethesearchtermsembeddedinit.Thesearekey/valuepairssuchasterm=funkandmedia=music."https://itunes.apple.com/search?term=funk&media=music&callback=?";

Thepartoftheendpointafterthe“?”symboliscalledthequerystring.ThispartoftheURLcontainsthedatathatisbeingqueried.The“&”symbolseparatesthekey/valuepairs.

TheiTunesAPIsearchtermsareassignedtospecifickeysandinthepreviouscode,thesearetermandmedia.ThereisnostandardizationacrosswebAPIsforkey/valuenames,andtheyaredifferentforeachwebAPI.BecausetheURLstructureforallwebAPIsisdifferent,youwillneed to read the documentation for any that you areworkingwith. The documentation for theiTunes search API is here: https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/.

ThenextpartoftheURLstringletsyoutosetacallbacktorunoncethequerycompletes.Inthecode example, the callback of$.getJSON is used. If youwant tomake a call to the iTunessearchAPIonpageloadandinvokeafunctiononcompletion,itlookslikethefollowingcode:

Page 220: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

HTML<!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>app</title><scripttype=”text/javascript”src=”https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js”></script><scriptsrc=”js/app.js”></script><linkrel=”stylesheet”href=”css/app.css”></head><!--_______________________________________________BEGINAPP--><body></body><!--_______________________________________________ENDAPP--></html>

JavaScriptfunctionlogger(data){console.log(data);}

Inthepreviousexample,afunctionnamedloggerisrunwhenthequerycompletes.The$.getJSONmethodtakesacallbackasasecondargument.Thecallbackreturnsthedata

objectviaanargument.Inthefollowingcode,thisargumentisnameddata,butyoucannameitanythingyouwant.$.getJSON(apiURL,function(data){console.log(data);});

CreatingYourOwnWebAPItoReferenceSynthesizerPatchData

YouarenowgoingtocreateyourownwebAPI.ThegoalofthisexerciseistodemonstratehowtoreferenceaJSONobjectthatcontainssynthesizerpatchdata.Thedatayouwillcreateforyourweb API is a collection of settings for the oscillators of a synth. The user interface of theapplicationappearsasinthefigurebelow,andthecompletedcodeisavailableintheresourceexamplesforthischapter.

Page 221: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Make a new copy of the “web audio template” folder you created in Chapter 1, name thefolder “synthy_api”, and drag the folder to the sidebar in Sublime Text. Next, reference theJQuery library from the index.html file. Inside the “js” folder, create a new file nameddata.jsandcopythefollowingJSONobjecttoitandsavethefile.{"buzzFunk":[{"type":"sawtooth","frequency":65.25

},{

"type":"triangle","frequency":65.25

},{

"type":"sawtooth","frequency":67.25

}]}

Intheapp.jsfile,savethefollowingcode:$(function(){$.getJSON("js/data.js",function(data){console.log(data);});});

Go to Start Sublime Server and in yourweb browser go to localhost:8080. In theChromeconsole,youwillseetheJSONobject.

Page 222: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Ifyouunfoldtheobject,youwillseeitsinternals.

AJSONobjectisdifferentfromaregularJavaScriptobjectliteralbecauseitisnotassignedtoavariable.However, once thedata is returned, it is assigned to avariable and canbepassedaroundandassignedtoothervariables.$(function(){$.getJSON(“js/data.js”,function(data){varpatchParams=data;console.log(patchParams);//object});});

Page 223: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

TheDataStructureThe data structure of the JSONobject you areworkingwith contains a single object propertynamedbuzzFunk,which is an array containing three objects and each holds oscillator data.Whenthisdataisloadedintoyoursynth,all threeoscillatorscombinetocreateasinglesound.Eachobjecthastypeandfrequencysettingsfortheoscillatorthatreferencesit.

TheHTML andCSS codes for the keyboard interface used to play the synth that loads theJSON data are given below. Copy the HTML code to index.html and the CSS code toapp.css.

HTML<body><h1>SynthyAPI</h1><ulid="piano">

<li><divclass="white-keykey"id="c1"></div></li><li><divclass="black-keykey"id="c#1"></div></li><li><divclass="white-keykey"id="d1"></div></li><li><divclass="black-keykey"id="d#1"></div></li><li><divclass="white-keykey"id="e1"></div></li><li><divclass="white-keykey"id="f1"></div></li><li><divclass="black-keykey"id="f#1"></div></li><li><divclass="white-keykey"id="g1"></div></li><li><divclass="black-keykey"id="g#1"></div></li><li><divclass="white-keykey"id="a1"></div></li><li><divclass="black-keykey"id="b#1"></div></li><li><divclass="white-keykey"id="b1"></div></li><li><divclass="white-keykey"id="c2"></div></li><li><divclass="black-keykey"id="c#2"></div></li><li><divclass="white-keykey"id="d2"></div></li><li><divclass="black-keykey"id="d#2"></div></li><li><divclass="white-keykey"id="e2"></div></li><li><divclass="white-keykey"id="f2"></div></li><li><divclass="black-keykey"id="f#2"></div></li><li><divclass="white-keykey"id="g2"></div></li><li><divclass="black-keykey"id="g#2"></div></li><li><divclass="white-keykey"id="a2"></div></li><li><divclass="black-keykey"id="b#2"></div></li><li><divclass="white-keykey"id="b2"></div></li><li><divclass="white-keykey"id="c3"></div></li><li><divclass="black-keykey"id="c#3"></div></li><li><divclass="white-keykey"id="d3"></div></li><li><divclass="black-keykey"id="d#3"></div></li><li><divclass="white-keykey"id="e3"></div></li><li><divclass="white-keykey"id="f3"></div></li><li><divclass="black-keykey"id="f#3"></div></li><li><divclass="white-keykey"id="g3"></div></li><li><divclass="black-keykey"id="g#3"></div></li><li><divclass="white-keykey"id="a3"></div></li><li><divclass="black-keykey"id="b#3"></div></li><li><divclass="white-keykey"id="b3"></div></li></ul>

Page 224: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

</body>

CSSbody{background-color:purple;}

h1{font-family:"impact";color:rgb(228,208,230);margin-left:10%;font-size:70px;}

li{list-style:none;float:left;display:inline;width:40px;position:relative;}

.white-key{display:block;height:220px;background:#fff;border:1pxsolid#ddd;border-radius:003px3px;}

.black-key{display:inline-block;position:absolute;top:0px;left:-12px;width:25px;height:125px;background:#000;z-index:1;

}

The application uses a factory function to load the JSON data. This function takes twoarguments. The first argument is an endpoint that contains the JSON file, and the second is apropertyoftheJSONobjectthatcontainsthepatchyouwanttoload.Currently,theJSONfilehasonlyonepatchnamedbuzzFunk.ThefinalloadinginterfacefortheJSONdatalookslikethefollowingcode:varsynth=apiReader("js/data.js","buzzFunk");//loadpatchsynth.play(keyByDOMIndex);//playaspecificnoteonkeyboardsynth.stop();//stopplaying

Deleteanycodepresentinapp.jsandreplaceitwiththefollowingcode:

Page 225: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

"usestrict";varsynth=apiReader("js/data.js","buzzFunk");$(function(){$(".key").on("mouseover",function(){varindex=$(this).index('.key');synth.play(index);});$(".key").on("mouseout",function(){synth.stop();});});

Inthe“js”folder,createanewfilenamedmodule.jsandreferenceitintheindex.htmlfilebetweentheJQuerylibraryandapp.jsfile.

<head><metacharset="UTF-8"><title>app</title><scripttype="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.js"charset="utf-8"></script><scriptsrc="js/module.js"></script><scriptsrc="js/app.js"></script><linkrel="stylesheet"href="css/app.css"></head>

Inmodule.js,copyandsavethefollowingcode:"usestrict";varaudioContext=newAudioContext();

varapiReader=function(endpoint,patchProp){

$(function(){

$.getJSON(endpoint,function(data){app.patchParams=data[patchProp];})

});

varapp={

patchParams:undefined,oscillators:undefined,

play:function(id){

app.oscillators=app.patchParams.map(function(val){

varosc=audioContext.createOscillator();osc.type=val.type;osc.frequency.value=val.frequency;osc.detune.value=(val.frequency)+(id*100);osc.connect(audioContext.destination)osc.start(audioContext.currentTime)

returnosc;});

Page 226: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

},stop:function(){for(vari=0;i<app.oscillators.length;i+=1){app.oscillators[i].stop(audioContext.currentTime);

}}}

returnapp;

};

Launchtheindex.htmlfilefromSublimeServerandhoveryourmouseoverthesynthkeys.Youwillhear thesynthplayacollectionofoscillators that reference thesettings in the loadedpatchdata.

HowtheCodeWorksInthemodule.jsfile,thefactoryfunctionnamedapiReadertakestwoarguments.Thefirstargument is named endpoint and is the endpoint location of the JSON file. The secondargument isnamedpatchPropand is thepropertyof theJSONobject thatcontains thesynthpatchdata.Theendpointargumentvalueispassedtothe$.getJSONmethod.Inthebodyofthe$.getJSONcallback, thedesiredpatchof thereturnedobject is referencedandstored inapropertyoftheappobjectnamedapp.patchParams.

Thepurposeoftheappobjectistocontainthepropertiesandmethodsthatcreate,connect,start,andstoposcillatorsusingthesettingsthatarelistedintheJSONobjectproperty.Thefirstmethodoftheappobjectisnamedplay.It takesasingleargumentandistheindexvalueofaDOMelement that representsakey.When theplaymethod is invoked, themapmethod loopsthrougheachobjectintheapp.patchParamsarrayandcreatesanoscillatoroneachiteration.The type, frequency.value, and detune.value properties of each oscillator areassigned.Theoscillatoristhenconnectedtothenodegraphandsettostartplaying.app.oscillators=app.patchParams.map(function(val){varosc=audioContext.createOscillator();osc.type=val.type;osc.frequency.value=val.frequency;osc.detune.value=(val.frequency)+(id*100);osc.connect(audioContext.destination);osc.start(audioContext.currentTime);returnosc;});

ThefollowingcodeprovidestheindexvalueofaDOMelement(thekeyboardnotetheuserhoverstheirmouseover)multipliedby100.Theresultisaddedtotheoscillatorfrequencyandassigned to the detune.value property. This makes the oscillators play back at half-stepintervalsrelativetothekeyboardinterface.osc.detune.value=(val.frequency)+(id*100);

Page 227: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Eachoscillatoristhenreturnedandstoredinanarraynamedapp.oscillators.Thestop method is used to stop the oscillators from playing. Thismethod loops through

app.oscillatorsandinvokesaWebAudioAPIstopmethodoneachone.stop:function(){for(vari=0;i<app.oscillators.length;i+=1){app.oscillators[i].stop(audioContext.currentTime);}}

Inapp.js,theapiReaderfunctionisinvoked,whichreturnsanobjectnamedsynth.varsynth=apiReader("js/data.js","buzzFunk");

Theplayandstopmethodsareplacedintwoeventlistenerstostartandstoptheoscillatorsonmouseevents.$(".key").on("mouseover",function(){varindex=$(this).index('.key');synth.play(index);});$(".key").on("mouseout",function(){synth.stop();});

Whentheplaymethodisinvoked,thecurrentindexvalueofthedivelement(the“keyboardnote”)iscapturedandpassedtothefunction.varindex=$(this).index('.key');//__getindexvalueofkeysynth.play(index);//__________________passittoplaymethod

BuildingontheAPIThecodeinmodule.jsisdesignedtoloadonlythetypeandfrequencyofoscillators,butwhat if youwanted to load other custom settings such as volume?The following code adds avolumesettingtoeachoscillator.

data.js{"buzzFunk":[{"type":"sawtooth","frequency":65.25,"volume":1},{"type":"triangle","frequency":65.25,"volume":1},{"type":"sawtooth","frequency":67.25,

Page 228: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

"volume":0.3}]}

module.js"usestrict";varaudioContext=newAudioContext();varapiReader=function(endpoint,patchProp){

$(function(){

$.getJSON(endpoint,function(data){app.patchParams=data[patchProp];})

});varapp={patchParams:undefined,gainNodes:undefined,oscillators:undefined,

play:function(id){

app.gainNodes=app.patchParams.map(function(val){

vargain=audioContext.createGain();gain.gain.value=val.volume;returngain;

});app.oscillators=app.patchParams.map(function(val,i){

varosc=audioContext.createOscillator();osc.type=val.type;osc.frequency.value=val.frequency;osc.detune.value=(val.frequency)+(id*100);osc.connect(app.gainNodes[i]);app.gainNodes[i].connect(audioContext.destination);osc.connect(audioContext.destination);osc.start(audioContext.currentTime);

returnosc;});},stop:function(){for(vari=0;i<app.oscillators.length;i+=1){app.oscillators[i].stop(audioContext.currentTime);}}}returnapp};

Thesefilemodificationsgiveyourcodetheability tocreateagainnodeforeachoscillator.Theplaymethodoftheappobjectcontainsamapmethodthatcreatesthegainnodesandsets

Page 229: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

thegain.gain.value property of each one to the value of the current object’s volumeproperty.Allgainnodesareplacedinanarraythatisassignedtoapp.gainNodes.app.gainNodes=app.patchParams.map(function(val){vargain=audioContext.createGain();gain.gain.value=val.volume;returngain;});

Theoscillatorsarethenconnectedtothegainnodesinthesecondmapmethod.app.oscillators=app.patchParams.map(function(val,i){

varosc=audioContext.createOscillator();osc.type=val.type;osc.frequency.value=val.frequency;osc.detune.value=(val.frequency)+(id*100);osc.connect(app.gainNodes[i]);app.gainNodes[i].connect(audioContext.destination);osc.start(audioContext.currentTime);

returnosc;});

ExtendtheJSONObjectTheJSONobjecthasonlyone“patch.”Youcanextenditwithasmanypatchesasyoulike.Thefollowingcodeextendstheobjectwithaproperty(patch)namedgameSound.{"buzzFunk":[{"type":"sawtooth","frequency":65.25,"volume":1},{"type":"triangle","frequency":65.25,"volume":1},{

"type":"sawtooth","frequency":67.25,"volume":0.3}],"gameSound":[{"type":"square","frequency":100.25,"volume":1},{"type":"triangle","frequency":65.25,"volume":1},{

"type":"sawtooth",

Page 230: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

"frequency":67.25,"volume":0.3}]}

YouthenaccessthegameSoundsettingsbyloadingthemwithapiReader.

varsynth=apiReader("js/data.js","gameSound");

SummaryInthischapter,youlearnedhowtoquerythird-partywebAPIs,workwithJSONfiles,andcreateyourownwebAPItoloadpatchdataforasynthesizer.Theapplicationyoucreatedonlybeginstoexplore what is possible. For a challenge, try incorporating filters, LFOs, delays, and othersettings.Inthenextchapter,youwill learnaboutthefutureofJavaScriptandvariousresourcesforcontinuedlearning.

Page 231: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

25TheFutureofJavaScriptandtheWebAudioAPI

Inthisbook,youhavelearnedthecoreconceptsbehindtheJavaScriptprogramminglanguageandtheWebAudioAPI.To keep fromovercomplicating things, some parts of both the JavaScriptlanguageandtheWebAudioAPIhavebeenomitted.Thischapterpresentssomeoftheareasthatwereskippedandprovidesyouafewsuggestionsaboutwhatyoucanlearnnowtofuture-proofyournewskills.

TheWebAudioAPI1.0Asof thiswriting, theWebAudioAPIhasnot reachedversion1.0.Thismeans that there areparts of the API that are either changing or have changed but are not implemented in webbrowsers.Thefollowingtwosectionstalkmoreaboutthis.

3DSpacialPositioningInadditiontotheStereoPannernode,therearetwootherspacialpositioningnodes.Bothofthese nodes allow for 3D style panning. One is called Panner and the other is calledSpacialPanner.Panner has been recently deprecated. The replacement for Panner isSpacialPanner.Asofthiswriting,SpacialPannerhasnotbeenimplementedinanywebbrowsers.Thismakesitdifficulttowriteaboutitandchecktheaccuracyofcodesamples.Andfor this reason, we opted to omit a detailed explanation ofSpacialPanner and present ageneralsummaryhere.

Theideabehind3Dspacialpositioningisthatsoundismodifiedinrelationtotwoobjectsinathree-dimensionalspace.Thefirstobjectisasoundsourcethathasitsspacialpositioningmovedusing SpatialPanner. The other object is called SpatialListener that represents areal-worldhuman listener.Theutilityof thisapproach is that theSpatialListener object

Page 232: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

canbeprogrammedtoworkwithanavatarsuchasavideogamecharacter,wheresoundthatisgeneratedina“virtualworld”isperceivedfromafirst-personperspective.Volumechangestakeplaceautomaticallybasedonthevirtual“distance”betweentheSpatialListenerandanysound-generatingvirtualobjects.Foraddedrealism,filters,reverberation,andothereffectscanbeprogrammedtochangethecharacteristicsofsoundbasedontheperceivedpositionofvirtualobjects. You can read about SpatialPanner at the following URL:https://www.w3.org/TR/webaudio/#the-spatialpannernode-interface.

You can read about the SpatialListener at this URL:https://www.w3.org/TR/webaudio/#idl-def-SpatialListener.

RawModificationofAudioBufferDataTheWebAudioAPIallowsfortherawmodificationofaudiodata.Youdothisbyeithercreatingemptyaudiobuffersandpopulatingthemwithyourownprogrammeddataorbymodifyingbuffersthatalreadycontaindatasuchasaudiofileinformation.Thesemodificationscanbeusedtocreatecustomeffectsandotherusefulthingslikenoisegenerators.Thenodeinitiallyusedforthiswasnamed ScriptProcessor, but this been deprecated and replaced with a node namedAudioWorker. Unfortunately, as of this writing there are no web browsers that haveimplementedtheAudioWorkernode,soadetailedexplorationofithasbeenomittedfromthisbook. You can read about the AudioWorker node at this URL:https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API#Audio_Workers.

SuggestionsforContinuedLearningJavaScript6http://es6-features.org/(unofficial)

JavaScript6,technicallycalledECMAScript6orcommonlyreferredtoasES6,isthenewestversion of the JavaScript language and is currently being implemented in various JavaScriptenvironments. The material in this book is focused on the ECMAScript 5 standard and isreflective of the majority of JavaScript in use around the world at the time of this writing. Isuggest that you learn ES6 moving forward. ES6 has unique features such as block-scopedvariables that build on the ES5 specification. Everything you have learned about ES5 istransferabletoES6.

node.jshttps://nodejs.org

Page 233: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Node.jsisaserver-sideJavaScriptenvironmentbasedonV8,whichisthesameJavaScriptenginethatrunsGoogleChrome.InsteadofrunningJavaScriptfromawebbrowser,Node.jsallows you to run JavaScript from the terminal on your computer. It can be used to automatecomputertasks,runwebservers,andcommunicatewithdatabases.

TheWebMIDIAPIhttps://www.w3.org/TR/webmidi/

MIDI, which stands for Music Instrument Digital Interface, is a digital music instrumentprotocol created in 1982 byDaveSmith andChetWood.TheWebMIDIAPI allows users tocontrolandmanipulateMIDI-equippeddevicesusingwebbrowsers.

OpenSoundControlhttp://opensoundcontrol.org/

According to their website, Open Sound Control (OSC) is “a protocol for communicationamongcomputers,soundsynthesizers,andothermultimediadevicesthatisoptimizedformodernnetworking technology.” In other words, OSC is a protocol that facilitates the communicationbetweenhardwareandsoftwareoveranetwork.

SummaryIn this chapter, youwere presentedwith a list of options for continued learning. Even thoughJavaScripthasbeen taughthere in thecontextofworkingwithaudio, it is important tokeep inmindthatprogrammingisausefulcross-disciplinaryskillthatyoucanusetosolvemanydifferenttypesofproblems.

FurtherReading■JavaScript:TheDefinitiveGuidebyDavidFlanagan.

■UnderstandingECMAScript6byNicholasC.Zakas.

■ Programming JavaScriptApplications:RobustWebArchitecturewithNode,HTML5, andModernJSLibrariesbyEricElliott.

■YouDon’tKnowJSBookSeriesbyKyleSimpson.

■Node.jstheRightWay:Practical,Server-SideJavaScriptThatScalesbyJimR.Wilson.

■WebAudioAPIbyBorisSmus.

Page 234: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

BookWebsitehttp://www.javascriptforsoundartists.com

Page 235: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Index

3Dspacialpositioning,221–222

AAbstraction,129–135,185–189Additionassignment,24–25AJAX,3,207–209Algebrarules,18Ambience,151Analysernode,175–183ANDoperator,29Animation,107,182Anonymousfunctions,48–49;seealsoFunctionsAPI(applicationprogramminginterface),3–4;seealsoWebAudioAPIAppinterface,modifying,81–84Application,building,71–89,93–102Application,refactoring,108–110Arguments,16,43–44Arithmeticoperators,18,23–25;seealsoNumbersArrays

callbackfunctionsand,53–54forloopsand,36–37frequencydataarrays,180–182numbersand,21–22objectsand,60trackarrays,197–206

Assignmentoperators,11,23–25;seealsoOperatorsAsynchronouscodeexecution,118–120

Page 236: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

AsynchronousJavaScriptandXML(AJAX),3,207–209Attackproperty,166AudioBatchLoaderfunction,130–131,134–135,185–189AudioContext()method,65AudioFileLoaderfunction,131–134,186–192,198–200Audiofiles

abstracting,129–135asynchronouscodeexecution,118–120buffer,116–120,222compatibilityissues,118decoding,116,119getrequests,116–120importing,117–120impulseresponsefiles,151–154loading,115–120,129–135,185–192,198–200modifying,222playing,10,115–120,129–135prerequisitesfor,115–116synchronouscodeexecution,118–120XMLHttpRequest,116–120

Audioinputsources,137–142,155–167,175–179,183–185Audioloaderabstraction,185–189Audioloaderlibrary

creating,121,185flexibilityfor,185–189modifying,186–189updating,171,183,185

Audioparameters,140–141,171–174Audiovisualizations,creating,175–183

BBackgroundcolor,78–82,86–87,178,203–206,214Bangoperator,28Binary-codeddecimalnumbers,176Binarysystem,176Bincount,177–182Bindfunction,62–64Bins,179–182Biquadfilternode

Page 237: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

foraudiofiltering,140–142fordesigningequalizers,144–149typesof,144–147using,143–144

Bits,176Block-levelelement,75–76,84,87–89Booleandatatype,25–26Booleanvalues,25–29Border,84–85Boundobject,62–64Boxmodel,74Browsersetupview,6Bufferdata,modifying,222Buffer,processing,116–120Buffersourcenode,119–120Bulletpoints,86Bytes,176

CCallbackfunctions,52–54Caseinsensitivity,16CDN(contentdeliverynetwork),103–105Centeringelements,87–89Changeability,13Channelmergernodes,159–160Channelmerging,158–160Channelsplitting,158–160CharAt(),15–17Childselectors,80Chromedevelopertools,7–8,10,14,78Classes,121–122Classidentifier,81Cloningobjects,60Closures,49–52Code,10–12Codeabstraction,129–135Codeblock,36,79Codesnippets,6–7Colorselection,78–82,86–87,178,203–206,214

Page 238: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Comments,12,72,79Comparisonoperators,26–30;seealsoOperatorsCompatibilityissues,118Concat(),21–22Concatenation,14–15,20–22Conditionalstatements,31–35Console.log(),13–14Constructors,121,125–128Convolvernode,140,151–155Convolverreverb,151–155CSS(cascadingstylesheets)

appinterface,81–84block-levelelements,87–89border,84–85forbuildinguserinterface,77–89bulletpoints,86buttons,74–79checkingerrorsin,77–78childselectors,80codeblock,79colorselection,78–82,86–87,178,203–206,214comments,79datastructureof,214–216descendentselectors,80DOMprogramming,91–93,102elementselectors,79explanationof,2–3,74,77–78inlineelement,84withJQuery,106–108linkelement,77listelement,86margins,84–85,87–89methodchaining,107–108padding,84–85selectingelements,105sequencer,203–204sliders,74,76–78spectrumanalyzer,178

Page 239: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

DData.js,211–217,220Data,private,124–125,127Data,query,207–220Datatypes,11,57–58Decimalnumbers,19,169,176,180Delaynode,140,161–164Deletekeyword,188Descendentselectors,80Destination,9–10Detuneproperty,69Developertools,7–8,10,14,78Displayinterface,building,181–182Divelement,73,75–76Divisionassignment,25DocumentObjectModel(DOM),74DOMprogramming

APImethods,92buildingapplication,93–102CSSand,91–93,102eventlistener,99–100explanationof,74frequencyslider,96–99frequencyspectrumanalyzer,181–183HTMLand,74,91–102withJavaScript,74,91–102,181withJQuery,103–113nodes,96,100selectors,105–106,111–112,153setIntervalmethod,97–101simplifying,103–113start/stoptext,94–96triggeringoscillator,93–94

Drumsequence,191–206;seealsoSequencerDynamiccompressornode,165–167Dynamicobjectextension,123–124;seealsoObjectsDynamicrangecompression,140,165–167

E

Page 240: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Echoeffects,162Effects

buildingblocksfor,141–142echoeffects,162effectsbox,42–43exampleof,141nodesfor,139–142ping-pongeffects,163–164slapbackeffects,162–163typesof,139–142workingwith,137–142

Elementsblock-levelelements,75–76,84,87–89centering,87–89changing,106–107divelement,73,75–76formelement,73–74,76–78headingelement,73horizontalruleelement,73,76inlineelement,75–76,84inputelement,73–74,76–78,107–108,110linkelement,77listelement,73,86listitemelement,73,86paragraphelement,73parentelement,80,86–87,205selecting,79,105spanelement,73,75–76storing,105–106unorderedlistelement,73,81

Elementselectors,79,105Equalityoperator,26–27Equalizers,137,140,142–149Equaltooperator,27–28Eventlistener

audiobuffer,120DOMprogramming,99–100JQuery,107–111playback,135,217tempochanges,204–205

Page 241: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

ExponentialRampToValueAtTimemethod,172

FFactories,121–128FastFouriertransforms(FFTs),176,179–182Fileloader,115–120,129–135Filetypecompatibility,118Filter(),53Filtertypes,144–147Fontcolor,86–87Fontsize,86–87Fonttype,86–87Forinloop,59–60Forloop,35–37Formelement,73–74,76–78Fourieranalysis,175–176Frequency,changing,97–99FrequencyDataarray,180–182Frequencydata,storing,180–181Frequencyproperty,69Frequencyslider,96–99Frequencyspectrumanalyzer,176–183Functions

anonymousfunctions,48–49argumentsobject,43–44bindfunction,62–64callbackfunctions,52–54closures,49–52declaringvariables,46–50effectsbox,42–43exampleof,39–44explanationof,39expressionsfor,41hoisting,46–48oscillatorplayback,41–43partsof,40–41recursion,54–55scopeconcept,44–47

Page 242: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

GGainnodes,138–139,194Getrequests,116–120Getters,124–125Globalobject,63–64Globalreplace,16Globalscope,44–47,64Globalvariables,46–50,119GoogleChrome,4–7;seealsoChromedevelopertoolsGraphicequalizer,143,146–148;seealsoEqualizersGreaterthanoperator,27–28Groupingselectors,80

HHeadingelement,73“HelloSound”application,9–11Hoistingvariables,46–48Horizontalruleelement,73,76HTML(hypertextmarkuplanguage)

block-levelelements,75–76forbuildinguserinterface,71–77checkingerrorsin,72comments,72datastructure,213DOMprogramming,74,91–102elements,2,71–74explanationof,2–3,71–74formelement,76–78impulseresponsefiles,153inlineelement,75–76inputelement,76–78iTunesAPI,210JQueryand,105–108methodchaining,107–108selectingelements,105sequencer,202–203spectrumanalyzer,177–178tags,2,71–74templates,72–73

Page 243: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

thiskeyword,108treestructure,74–75typeattribute,76–77,107valueattribute,77

IIdentifiers,81ididentifier,81Ifstatement,32–33Immutability,13Impulseresponsefiles,151–154Inlineelement,75–76,84Inoperator,60Inputelement,73–74,76–78,107–108,110Inputsources,137–142,155–167,175–179,183–185iTunesAPI,208–210

JJavaScript

buildingapplication,93–102changingproperties,106–107classesand,121–122datatypes,11,57–58DOMprogramming,74,91–102,181explanationof,1–2futureof,221–223gettingstartedwith,9–22impulseresponsefiles,151–154methodchaining,107–108newkeyword,117,125–126object-orientedprogramming,121–122overviewof,1–8setupviewinbrowser,4–6spectrumanalyzer,176–177strictmodefor,5,63–64,93thiskeyword,61–62,108,126

JavaScript6,222JavaScriptObjectNotation,208;seealsoJSONobject

Page 244: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

JQueryCDNand,103–105changingproperties,106–107CSSand,106–109DOMprogramming,103–113eventlistener,107–111explanationof,103HTMLand,105–108methodchaining,107–108methods,106onOffin,112oscillatorwith,108–109refactoringapplication,108–110referencing,104selectingelements,105setIntervalin,111–112setup,103–104spectrumanalyzer,176–177storingelements,105–106thiskeyword,108using,105–113

JSONobjectdata.js,211–217,220datastructure,213–216explanationof,207–208extending,219–220iTunesAPI,208–210module.js,215–219patches,210–212,216,219–220playback,216–217forwebAPI,210–217

KKneeproperty,166

LLengthproperty,15,17Lessthanoperator,27–28

Page 245: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

LinearRampToValueAtTimemethod,173Linkelement,77Listbulletpoints,86Listelement,73,86Listitemelement,73,86Localscope,44–47LogicalANDoperator,29LogicalNOToperator,29–30Logicaloperators,28–30LogicalORoperator,29Loops

explanationof,31–32forloop,35–37forinloop,59–60loopingsounds,170–171loopproperty,170–171whileloop,37–38

Low-passfilter,141

MMacsetupview,6Map(),53–54Margins,84–85,87–89Math.abs(),20Math.ceil(),19Math.floor(),19Math.max(),19Mathmethods,18–20Math.min(),19Mathobject,18Math.random(),19–20Mergernodes,155,158–160Methodchaining,107–108Metronomefunction,194–205Mixingchannels,138Modificationnodes,139Module.js,215–219Moduloassignment,25

Page 246: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Monochannels,159–160Multibandequalizer,140,142;seealsoEqualizersMultichannelfiles,157–160Multiplicationassignment,25Musicsequencer,191–206;seealsoSequencerMutability,13

NNewkeyword,117,125–126Nodegraphs;seealsoNodes

buffernodesource,119–120effectsnodes,139–142exampleof,141explanationof,137–138gainnodes,138–139inputsources,138modificationnodes,139forWebAudioAPI,65–66,137–142

Node.js,223Nodes

analysernode,175–183biquadfilternode,140–149buffersourcenode,119–120channelmergernodes,159–160channelsplitting,158–160convolvernode,140,151–155delaynode,140,161–164dynamiccompressornode,140,165–167effectsnodes,139–142explanationof,138–139futureof,221–223gainnodes,138–139,194mergernodes,155,158–160modificationnodes,139nodegraphs,65–66,137–142placementof,138–139splitternodes,158–160stereopannernode,140,157–158forWebAudioAPI,65–66,137–142

Page 247: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Notequaltooperator,28NOToperator,29–30Null,12Numbers

algebrarules,18arithmeticoperators,18,23–25arraysand,21–22decimals,19,169,176,180mathmethods,18–20mathobject,18precedentexample,18–20precedentrules,18

Number-to-stringconversion,20

OObjectliterals,57–58,117,208,212Object-orientedprogramming,121–122Objects

arraysand,60boundobject,62–64classesand,122cloning,60–61datatypes,57–64dynamicobjectextension,123–124factoriesand,122–124globalobject,63–64literals,57–58,117,208,212loopingthrough,59–60methodfor,60programming,121–122propertyfor,60prototypalinheritance,61–62prototypeobject,126–128

Onendedproperty,67OnOffselector,93–101,112OpenSoundControl(OSC),223Operand,23Operators

additionassignment,24–25

Page 248: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

arithmeticoperators,18,23–25assignmentoperators,11,23–25bangoperator,28categoriesof,23–25comparisonoperators,26–30divisionassignment,25equalityoperator,26–27equaltooperator,27–28explanationof,23–24greaterthanoperator,27–28inoperator,60lessthanoperator,27–28logicaloperators,28–30moduloassignment,25multiplicationassignment,25notequaltooperator,28operand,23setIntervalmethod,24–25strictequalityoperator,27strictnotequaltooperator,28subtractionassignment,25

ORoperator,29Oscillators

creating,41–45,66–69,119–120detuneproperty,69frequencyproperty,69withJQuery,108–109methodsfor,66–67onendedproperty,67playback,9–10,32,41–43,66–67,93–94,108–109propertiesof,66–67refactoringapplication,108–110restarting,67–68start/stoptext,94–96stopmethod,67–68triggering,93–94typeproperty,68–69forvariables,12–13forWebAudioAPI,9–10,66–69

Page 249: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

PPadding,84–85Paragraphelement,73Parametricequalizers,143,146–149Parentelement,80,86–87,205Ping-pongdelay,163–164Playback

audiofiles,10,115–120,129–135audioparameters,171–174convolverreverb,153–154eventlistener,135,217explanationof,4forJSONobject,216–217loopingsounds,170–171oscillatorplayback,9–10,32,41–43,66–67,93–94,108–109forsequencer,192,197–202

Pop(),21–22Precedentexample,18–20Primitivedatatypes,57Privatedata,124–125,127Property

attackproperty,166changing,106–107detuneproperty,69explanationof,17frequencyproperty,69kneeproperty,166lengthproperty,15,17loopproperty,170–171onendedproperty,67prototypeproperty,126–128ratioproperty,166reductionproperty,165–167releaseproperty,166thresholdproperty,166typeproperty,68–69

Prototypalinheritance,61–62Prototypeobject,126–128Prototypeproperty,126–128

Page 250: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

Push(),21

QQuerystring,209–210

RRatioproperty,166Recursion,54–55Reductionproperty,165–167Regularexpressions,16Releaseproperty,166Replace(),16Resources,8,15,151–152,222–223Reverb,151–155

SScopeconcept,44–47Selectors

childselectors,80descendentselectors,80DOMselectors,105–106,111–112,153elementselectors,79,105grouping,80storing,105–106

Sequencerbuilding,191–206CSSfor,203–204gridelements,202–206HTMLfor,202–203interactivityfor,205–206metronome,194–205playback,192,197–202rhythmicpatterns,192–193tempochanges,192,195–206timingclock,193–204trackarrays,197–206userinterfacegrid,202–206

Page 251: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

SetIntervalmethodassignmentoperators,24–25DOMprogramming,97–101JQuery,111–112rhythmicpatterns,192–193

SetTargetAtTime()method,173Setters,124–125SetTimeoutmethod,192–197,199–201SetValueAtTimemethod,172SetValueCurveAtTime()method,173–174Shift(),21–22Single-bandequalizer,143,148;seealsoEqualizersSinglemonochannels,159–160Slapbackeffects,162–163Slice(),16–17Spacialplannernode,221–222Spanelement,73,75–76Spatiallistenernode,221–222Speakers,138Spectrumanalyzer,connecting,181–183Spectrumanalyzer,creating,176–183Splitternodes,158–160Startmethod,170–171Stepsequencer,191–206;seealsoSequencerStereopannernode,140,157–158,221–222Stopmethod,67–68Strictequalityoperator,27Strictmode,5,63–64,93Strictnotequaltooperator,28Strictstring,93–97,100,109Stringdatatypes,11,14–16Stringmethods,15–17Strings

caseinsensitivity,16datatypes,11,14–16globalreplace,16lengthproperty,15,17manipulating,14–17methods,15–17number-to-stringconversion,20

Page 252: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

regularexpressions,16resourcesfor,15valuesfor,16–17variablesand,14–17

SublimeText,4–6,115Subtractionassignment,25Switchstatement,33–34Synchronouscodeexecution,118–120Synthesizerpatchdata,210–212,216,219–220

TTemplatefolders,4–5Templates,72–73Tempo,changing,192,195–206Ternarystatement,34–35Textsize,86–87Third-partywebAPIs,207–220Thiskeyword,61–62,108,126Thresholdproperty,166Time

audioparametermethods,171–174loopingsounds,170–171startmethod,170–171timingclock,169–170,193–204workingwith,169–174

ToLowerCase(),15ToUpperCase(),15Trackarrays,197–206Troubleshootingtips,8–9Typeattribute,76–77Typeproperty,68–69Typestyle,86–87

UUnorderedlistelement,73,81Unshift(),21–22Userinterface(UI)

building,71–89

Page 253: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

CSSfor,77–89explanationof,71–72HTMLfor,71–77modifying,81–84

VValueattribute,77,106,108,110Values

assigning,11,13,23–26Booleanvalues,25–29forstrings,16–17

Variablesassigningvaluesto,11,13,23–26assignments,10–14changeabilityof,13concatenationof,14–15creating,10datatypeof,17–18declaring,46–50globalvariables,46–50,119hoisting,46–48immutabilityof,13mutabilityof,13names,13–14nullvalue,12oscillatorfor,12–13overwriting,13stringsand,14–17undefinedvalue,12understanding,10–11waveforms,10–14,17–18,21

Visualizations,creating,175–183Volumecontrol,138

WW3C(WorldWideWebConsortium),72,77Waveforms

changing,99–100outlinefor,101–102

Page 254: JavaScript for Sound Artists: Learn to Code with the Web Audio APIenglishonlineclub.com/pdf/JavaScript for Sound Artists... · 2019. 9. 21. · toUpperCase() toLowerCase() charAt()

selecting,99–102typesof,10–14,41–44,68–69,99–102variables,10–14,17–18,21

WebAudioAPIaudiooutput,9–10creating,210–212destination,9–10explanationof,3–4featuresof,65–66futureof,221–223gettingstartedwith,9–22“HelloSound”application,9–11nodesfor,65–66,137–142oscillators,9–10,66–69resourcesfor,8variables,10–11waveforms,11–14,17–18,21

WebMIDIAPI,223Whileloop,37–38Windowssetupview,6Workenvironment,4–6

XXML(ExtensibleMarkupLanguage),207;seealsoAJAXXMLHttpRequest,116–120,131–133,152–153,207–209

ZZero-basedindex,16,43