making musical apps (excerpt: how to build a music app for ios)

Upload: create-digital-music-motion-noise

Post on 16-Jul-2015

31.676 views

Category:

Documents


0 download

DESCRIPTION

Making Musical Apps: Real-time audio synthesis on Android and iOS (O'Reilly)by Peter BrinkmannExclusive createdigitalmusic.com excerpt:How to make a music app for iOS

TRANSCRIPT

Setting Up the Development EnvironmentVe will limit oui uiscussion ol iOS uevelopment to the latest veision ol Apple`s inte-giateu uevelopment enviionment, Xcoue +.2. Even though Xcoue +.2 has Luilt-in sup-poit loi Git, it will not sullice loi oui puiposes Lecause ol its limiteu suppoit loi suL-mouules.InoiueitouownloauacopyoltheiOSLiancholliLpu,openateiminal(App|ications/Uti|itics/Tcrnina|.app), change into the uiiectoiy wheie you want to keepyoui installation ol liLpu, anu entei the lollowing commanus:$ git clone git://github.com/libpd/pd-for-ios.git$ cd pd-for-ios$ git submodule init$ git submodule updateThis will install liLpu anu its auuio glue loi iOS as well as utilities anu a lew sampleapps. It is goou piactice to keep youi copy ol liLpu up to uate. In oiuei to uo that, youshoulu iegulaily issue the lollowing commanus in youi pd-jor-ios uiiectoiy:$ git pull$ git submodule updateYoushoulutiythesampleappsnowinoiueitomakesuiethatyouiinstallationiswoiking. In oiuei to test a sample pioject, just open its .xcodcproj lile.Vhen you open a pioject loi the liist time, select the menu item Piouuct ManageSchemes.. You shoulu see two schemes, one loi the cuiient pioject anu one loi liLpu,laLeleulibpd-ios(Figuie6-1).Xcouesometimesgetsconluseuwhenautocieatingschemes, though, anu il you`ve Leen using liLpu since Leloie the move to GitHuL, thenyou may enu up with a spuiious seconu scheme loi liLpu, laLeleu libpd, which you cansalely uelete.Iigurc -1. Managing schcncs in Xcodc 1.2. WavcTab|cs is onc oj thc sanp|c apps inc|udcd with thc|ibpd distribution.86 | Chapter 6:Pd for iOSThis is an excerpt from Chapter 6: Pd for iOS. To order the book visit:http://shop.oreilly.com/product/0636920022503.doIl you tiy to iun a sample app anu nothing happens, check the active scheme in theuppei iighthanu coinei ol Xcoue (Figuie 6-2). It shoulu uisplay the name ol the cuiientpioject, not libpd-ios. Il it uoesn`t, open the Scheme pop-up menu anu select the mainscheme ol the pioject.Iigurc -2. Chcc|ing thc activc schcncNone ol the sample piojects aie teiiiLly exciting, Lut that`s intentional. They aie sup-poseu to illustiate key points aLout liLpu uevelopment loi iOS; any visual oi musicaluazzle woulu uistiact liom theii main puipose.Creating a Musical App: Part IAs in Chaptei 5, we`ll cieate a guitai tunei app. Oui liist veision will Le just a uigitaltuning loik, emitting ieleience tones on uemanu. Think ol it as Hc||o Wor|d! loi liLpu.In oiuei to use liLpu in an app, you neeu to impoit the liLpu Xcoue pioject into youipioject anu wiie it up so that the euitoi, compilei, anu linkei can linu the necessaiyiesouices. Xcoue +.2 makes this initial setup iathei haiu, anu it is lieguently easiei tocopy a sample pioject anu mouily it loi youi puiposes. Neveitheless, we`ll ignoie thesample piojects loi now anu Luilu oui guitai tunei app liom sciatch.In Xcoue, select File New New Pioject anu ask the new pioject wizaiu to cieatethe scalloluing ol a Single View Application (Figuie 6-3).Now Xcoue piesents a numLei ol options loi oui app (Figuie 6-+). Ve neeu to choosea name loi oui app, e.g., GuitarTuner, a company iuentiliei, anu a pielix, e.g., GT, thatthe new pioject wizaiu will piepenu to the classes that it geneiates. In oiuei to stieam-linetheexposition,we`lllimitouiselvestoiPhoneappsloinow,Luteveiythingweuiscuss in this chaptei applies to iPau apps as well. Ve won`t neeu stoiyLoaius in ouisingle-view app, Lut we will use automatic ieleience counting (ARC) Lecause that`swhat Apple iecommenus loi new uevelopment.Importing libpdClickonthemenuitemFileAuuFilesto"GuitaiTunei".anuauuthelile|ibpd.xcodcproj. Now liLpu shoulu show up as a suLpioject ol youi pioject (Figuie 6-5).Creating a Musical App: Part I | 87Iigurc -3. Projcct crcation in Xcodc 1.2Iigurc -1. Projcct crcation options in Xcodc 1.288 | Chapter 6:Pd for iOSIigurc -5. |ibpd in Xcodc 1.2Click on GuitarTuner in the Pioject Navigatoi to get to the main pioject settings anucheck that GuitarTuner is selecteu unuei Taigets. The settings will open on the Sum-maiy taL (Figuie 6-6). Take this oppoitunity to ueselect all scieen oiientations exceptpoitiait. Latei, when you have a sense ol how the auuio components inteiact with theiest ol the app, you may want to ievisit the guestion ol which scieen oiientations tosuppoit. Foi now, oiientation changes aie just one moie potential point ol lailuie anuso we`ll uisallow them, the lastei to get oui app oll the giounu.Iigurc -. Projcct scttingsNow select the Builu Settings taL. In the seconu Lai liom the top, select All anu Com-Lineu,thenenteitheseaichteimuser header.FinutheiowlaLeleuUseiHeaueiSeaichPathsanuuouLle-clickintheiightcolumn,theonecoiiesponuingtoyouicuiient taiget. A little uialog winuow will pop up. Now click on -, then select the LoxlaLeleu recursive, anu linally entei the path to youi liLpu installation (Figuie 6-7). Ilyou`ve placeu Loth youi new pioject anu youi copy ol Pu loi iOS in youi Docuncntsloluei, then the path S(SRCROOT)/../../pd-jor-ios/|ibpd shoulu woik.Creating a Musical App: Part I | 89Vhile the entiie setup is teuious, the heauei seaich path is the only paitthat`s eiioi-pione. Il you encountei Luilu pioLlems latei on, you shoululiist check whethei youi seaich path is coiiect.Configuring for PortabilityIl you`ie going to shaie youi coue with othei uevelopeis, then you neeu to take specialcaie to make youi pioject poitaLle. The Lest solution is pioLaLly the appioach ol Puloi iOS, using git suLmouules.Cieate one loluei that will holu Loth youi pioject loluei anu a copy ol liLpu, packageuas a git suLmouule (just liLpu, cloneu uiiectly liom git://github.con/|ibpd/|ibpd.git, notPuloiiOS).Viththissetup,youcanuseasimpleielativepath,S(SRCROOT)/../../|ibpd, anu youi heauei seaich path will Le poitaLle.An auueu Lenelit ol packaging liLpu as a git suLmouule is that it avoius veision conllictsuown the ioau. The suLmouule ol youi pioject will specily the veision ol liLpu to use,anuuseisolyouicouewillautomaticallyieceivethisveisionwhentheycloneyouipioject. Vhen you choose to upgiaue to a new veision ol liLpu, useis ol youi coue willieceive the same upgiaue when they upuate theii local copy.Select the Builu Phases taL, open the Taiget Depenuencies section anu click on -, thenauu libpd-ios as a uepenuency. Finally, open the Link Binaiies Vith LiLiaiies sectionanuauu|ibpd-ios.a,AudioToo|box.jrancwor|,anuA\Ioundation.jrancwor|(Fig-uie 6-S). Don`t woiiy il Xcoue ienueis the entiy loi |ibpd-ios.a in ieu; it`s a known Lugol Xcoue that won`t cause any tiouLle.Iigurc -7. Hcadcr path scttings90 | Chapter 6:Pd for iOSUnloitunately, Xcoue uoes not know that the static liLiaiy |ibpd-ios.aanu the heauei seaich path aie ielateu. Il you keep moie than one copyol liLpu aiounu, then it is easy to get conluseu anu impoit a Linaiy liomone anu heauei liles liom anothei, potentially leauing to haiu-to-tiackLuilu lailuies wheie the compilei succeeus Lut the linkei lails.This completes oui initial setup ol a new pioject with liLpu. Vhew! It was a lot ol woik,Lut it`s uone now.Configuring libpdLet`s auu a Pu patch to oui app. As in Chaptei 5, we use a stiaightloiwaiu mouilicationol oui synthesizei patch liom Chaptei 2 (Figuie 6-9). Click on the menu item File Auu File to "GuitaiTunei". anu select the loluei containing youi patch. Xcoue olleisanumLeiolwaysolimpoitinglolueis;makesuietoselectCieategioupsloianyauueu lolueis Leloie clicking on Auu (Figuie 6-10).NowwesetupthecomponentsolliLpuasuiscusseuinLaunchSe-guence on page 57. Fiist, we neeu to conliguie the auuio components ol liLpu, usingan instance ol the PdAudioController class uiscusseu in Chaptei +. The auuio contiolleiis a gloLal oLject, potentially ielevant to all paits ol the app, anu so we have the appli-cation uelegate manage it anu make it availaLle thiough an accessoi methou.The appIication deIegate interface GTAppDeIegate.h. #import #import "PdAudioController.h"@class GTViewController;@interface GTAppDelegate : UIResponder Iigurc -8. Conjiguring bui|d phascsCreating a Musical App: Part I | 91@property (strong, nonatomic) UIWindow *window;@property (strong, nonatomic) GTViewController *viewController;@property (strong, nonatomic, readonly) PdAudioController *audioController;@endIigurc -9. Guitar tuncr patch (jirst vcrsion)Vhen uesigning a musical app with liLpu, one ol the Lasic uecisions is how to managethe lile ol the auuio thieau. In this simple example, we`ll take the most stiaightloiwaiuappioach anu tie the lile ol the auuio thieau to the active lile ol the app. In othei woius,the auuio thieau will Le active whenevei oui app is active.Tyingthelilecycleoltheauuiothieautothelilecycleoltheappisaguick anu convenient way to get a new auuio pioject oll the giounu. Istait most new piojects that way. Il necessaiy, I ievisit the managementol the auuio thieau latei, altei I`ve implementeu enough ol the auuiolunctionality to allow loi meaninglul testing.Thenextcoueexampleshowsanimplementationolthisappioach.Vecieateanuconliguie the auuio contiollei on launch, anu we check the ietuin value in case some-thinggoeswiong.Inthissimpleexample,wejustlogawaininganugiveupiltheuesiieu conliguiation is not availaLle. In ieal-woilu coue, you will neeu to implementsome giacelul way ol hanuling conliguiation lailuies, anu you may want to tiy a numLeiol uilleient conliguiations until you linu one that woiks. In any case, the conliguiationthat we aie ieguesting heie, two output channels at CD sample iate with an amLientauuio session categoiy, is common anu will pioLaLly Le availaLle.92 | Chapter 6:Pd for iOSThe appIication deIegate impIementation GTAppDeIegate.m. #import "GTAppDelegate.h"#import "GTViewController.h"@implementation GTAppDelegate@synthesize window = _window;@synthesize viewController = _viewController;@synthesize audioController = _audioController;-(BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {_audioController = [[PdAudioController alloc] init];if ([self.audioController configureAmbientWithSampleRate:44100numberChannels:2 mixingEnabled:YES] != PdAudioOK) {NSLog(@"failed to initialize audio components");}self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];self.viewController = [[GTViewController alloc]initWithNibName:@"GTViewController" bundle:nil];self.window.rootViewController = self.viewController;[self.window makeKeyAndVisible];return YES;}Iigurc -10. |nporting thc patch into XcodcCreating a Musical App: Part I | 93// Without ARC, we would need to implement a dealloc method that// releases _audioController.-(void)applicationDidBecomeActive:(UIApplication *)application {self.audioController.active = YES;}-(void)applicationWillResignActive:(UIApplication *)application {self.audioController.active = NO;}- (void)applicationDidEnterBackground:(UIApplication *)application { }- (void)applicationWillEnterForeground:(UIApplication *)application { }- (void)applicationWillTerminate:(UIApplication *)application { }@endThe OLjective-C components ol liLpu pioviue line-giaineu suppoit loimanaging auuio conliguiations. You can choose to allow amLient auuioas well as mixing, anu the contiollei class will automatically choose theappiopiiate auuio session categoiy. You can also ieconliguie the auuiocomponents on the lly.Moieovei,theauuiocontiolleiclassimplementstheAVAudioSessionDelegate piotocol. An instance ol PdAudiocontroller will iegistei itsellas the auuio session uelegate, anu it will automatically suspenu playLackwhen a phone call comes in. Il this is not the uesiieu Lehavioi, oi il youwant to implement auuitional lunctionality (such as having the auuiolaue in anu out insteau ol just tuining it on anu oll), then you can simplycieate a suLclass ol PdAudioController anu oveiiiue the methous whoseLehavioi you`u like to change.Now we iegistei a uispatchei oLject with liLpu. Vhile we uon`t expect to ieceive anymessages liom Pu loi the time Leing, the uispatchei may still come in hanuy Lecauseit will log status messages that Pu piints to the console.Ve neeu to ueciue which pait ol oui app shoulu Le iesponsiLle loi managing the uis-patchei. Since the main puipose ol uispatchei is to ieceive messages liom Pu, anu sincethose messages will typically allect the usei inteilace, we`ll put the view contiollei inchaige ol managing the uispatchei.Altei iegisteiing the ieceivei, we open oui patch, also in the view contiollei. In oiueito open a patch, we neeu to specily the name ol the lile anu the path to the loluei thatcontains it. Because ol the way we packageu the patch, we can simply invoke [[NSBundlemainBundle] resourcePath] in oiuei to get the path.94 | Chapter 6:Pd for iOSThe view controIIer interface GTViewControIIer.h. #import #import "PdDispatcher.h"@interface GTViewController : UIViewController {PdDispatcher *dispatcher;void *patch;}@endThe view controIIer impIementation GTViewControIIer.m. #import "GTViewController.h"@implementation GTViewController#pragma mark - View lifecycle-(void)viewDidLoad {[super viewDidLoad];dispatcher = [[PdDispatcher alloc] init];[PdBase setDelegate:dispatcher];patch = [PdBase openFile:@"tuner.pd"path:[[NSBundle mainBundle] resourcePath]];if (!patch) {NSLog(@"Failed to open patch!");// Gracefully handle failure...}}-(void)viewDidUnload {[super viewDidUnload];[PdBase closeFile:patch];[PdBase setDelegate:nil];}// Omitting the remaining view controller methods...@endThe cleanup in the viewDidUnload methou is not stiictly necessaiy in this simple app,Lut it is goou piactice to iemain awaie ol the iesouices that we aie consuming anu toielease them as soon as possiLle. Even with ARC, theie aie some iesouices that willnot Le automatically ieleaseu, such as Pu patches anu the uelegate ol PdBase.Inpiinciple,wealieauyhaveamusicalapp.Alltheciucialpiecesaiepiesentanuwoiking; il you launch the app, it will loau a patch, stait an auuio thieau anu ienueisamples. A uispatchei is installeu anu ieauy to ieceive messages liom Pu. Il you watchthe log messages when launching the app, you`ll see that the auuio components aieLeing conliguieu anu staiteu. Ve just uon`t heai anything yet Lecause the app uoesn`tyet tiiggei any sounus. Ve`ll iemeuy that next.Creating a Musical App: Part I | 95Connecting the User InterfaceIn oiuei to have oui patch make sounus, we will auu a lew Luttons to oui usei inteilace.Each will tiiggei a note coiiesponuing to a stiing on the guitai. The liist step is to auuthe necessaiy callLack lunctions to oui view contiollei (see the next coue example).The view controIIer interface (GTViewControIIer.h) with caIIback methods. #import #import "PdDispatcher.h"@interface GTViewController : UIViewController {PdDispatcher *dispatcher;void *patch;}-(IBAction)playE:(id)sender;-(IBAction)playA:(id)sender;-(IBAction)playD:(id)sender;-(IBAction)playG:(id)sender;-(IBAction)playB:(id)sender;-(IBAction)playE2:(id)sender;@endThis is just the stanuaiu Loileiplate loi connecting UI elements to youi coue. The mostinteiesting pait is oui implementation ol the callLack methous (see the coue exampleLelow). Each callLack senus a MIDI note value to the patch (+0 loi the low E-stiing,+5 loi the A-stiing, etc.) anu tiiggeis a sounu.TheviewcontroIIerimpIementation(GTViewControIIer.m)withcaIIbackmethods. #pragma mark - button callbacks-(void)playNote:(int)n {[PdBase sendFloat:n toReceiver:@"midinote"];[PdBase sendBangToReceiver:@"trigger"];}-(IBAction)playE:(id)sender {NSLog(@"Playing E");[self playNote:40];}-(IBAction)playA:(id)sender {NSLog(@"Playing A");[self playNote:45];}-(IBAction)playD:(id)sender {NSLog(@"Playing D");[self playNote:50];96 | Chapter 6:Pd for iOS}-(IBAction)playG:(id)sender {NSLog(@"Playing G");[self playNote:55];}-(IBAction)playB:(id)sender {NSLog(@"Playing B");[self playNote:59];}-(IBAction)playE2:(id)sender {NSLog(@"Playing E2");[self playNote:64];}Finally, we cieate some Luttons in the usei inteilace anu connect them to oui callLackmethous. Open GT\icwContro||cr.xib in the Inteilace Builuei anu auu six Luttons totheview,oneloieachstiingontheguitai.YoucanassignappiopiiatetitlesintheAttiiLute Inspectoi taL on the iight. Il you select Ii|c`s Owncr in the column on the leltanuopentheconnectionstaLontheiight,youwillseeouinewlycieateucallLackmethous. Connect each methou to the appiopiiate Lutton event (Figuie 6-11).Inthisexample,Ihavechosentotiiggeisounuswhentheuseiliisttouches a Lutton. This is slightly unusual; the stanuaiu Lehavioi ol Lut-tons is to tiiggei actions on ielease. Still, I Lelieve that this is the coiiectchoice loi musical apps. Altei all, you will heai a sounu the momentyou piess a key on a piano, not when you ielease it.Ilyoulaunchyouiappnow,youcanpushtheLuttonsanuheaithecoiiesponuingsounus. You may neeu to plug in heauphones il youi Luilt-in speakeis aie unaLle toienuei low lieguencies.This simple example goes a long way towaius Luiluing musical apps. Most ol the majoipieces aie alieauy in place. Cleaily, oui app has lots ol ioom loi impiovement, Lut itseives its puipose: It shows the anatomy ol a simple liLpu-Laseu app with a minimumol coue. As an exeicise, you may want to tiy anu impiove this app. Heie aie a lew topicsto think aLout: Senuing a lloat anu a Lang when playing a sounu is somewhat ieuunuant. Howcan you ievise the patch so that a miui note message also acts as a tiiggei? (Hint:Look up tiiggeis in Pu.) The sounu is guite Loiing. Can you ieplace theosc~ oLject with anothei sounuthat sounus moie inteiesting? (Hint: Look up the phasor~ oLject loi a guick anuuiitychange,oiieauuponsynthesistechniguesanutiysomethingmoiesophisticateu.)Creating a Musical App: Part I | 97Creating a Musical App: Part IIAs in Chaptei 5, we mouily oui patch Ly auuing a fiddle~ oLject that peiloims pitchanalysisonthemiciophoneinput.ThepatchwillsenulloatvaluestothesymLolpitch when fiddle~ uetects a staLle pitch (Figuie 6-12).Make suie to upuate the copy ol the patch in youi Xcoue pioject. Also, since the newveisionolouipatchieguiiesauuioinput,weneeutoieguestinputchannelswhenconliguiing the auuio components:-(BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions {_audioController = [[PdAudioController alloc] init];if ([self.audioController configurePlaybackWithSampleRate:44100numberChannels:2 inputEnabled:YES mixingEnabled:NO] != PdAudioOK) {NSLog(@"failed to initialize audio components");}self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];self.viewController = [[GTViewController alloc] initWithNibName:@"GTViewController" bundle:nil];Iigurc -11. Connccting buttons in |ntcrjacc Bui|dcr98 | Chapter 6:Pd for iOSWant to see more? Get your copy at oreilly.comhttp://shop.oreilly.com/product/0636920022503.do