iOS SDK Spela toner med ljudverktyget

Välkommen till den sjunde avbetalningen i vår serie om hur man både designar och bygger en 1980-version av IOS? Telefonen? app. I denna handledning demonstrerar jag hur du spelar en lämplig ljudton för varje nummer på telefonens knappsats.

Final App Preview

Detta är en snapshot av vad vi kommer att bygga under denna serie:

Innan du börjar?

Detta är en serie med flera delar som är utformad för att lära ut mellanliggande iOS SDK-ämnen. Innehållet blir alltmer komplicerat när serien går vidare. Om du vid någon tidpunkt hittar dig förlorad i att följa den här serien kan du behöva ta ett steg tillbaka och arbeta dig igenom vår Learn Objective-C-serie eller vår början iOS SDK Development-serie.

I den sista handledningen i denna serie visade jag hur man faktiskt skulle initiera ett iPhone-samtal efter att ha ringt ett nummer på knappsatsen och också hur man formaterar numrervisningen när en användare kränger en siffra. I den här handledningen lägger vi till de utlovade touchtonerna till var och en av knapparna 0-9.

iOS-ljudöversikt

IOS SDK levereras med flera ramar som tillhandahåller olika metoder för att spela ljudklipp och till och med generera ljud på flykt. Apples Multimedia Programmeringsguide beskriver syftet med varje tillgänglig ljudram enligt följande:

  • Använd Media Player Framework att spela låtar, ljudböcker eller ljudpodcast från en användares iPod-bibliotek?
  • Använd AV-stiftelsens ramverk att spela och spela in ljud med ett enkelt objektiv-C-gränssnitt?
  • Använd Ljudverktygslåda ram för att spela ljud med synkroniseringsfunktioner, åtkomstpaket med inkommande ljud, parsa ljudflöden, konvertera ljudformat och spela in ljud med tillgång till enskilda paket?
  • Använd Ljudenhetens ramverk att ansluta till och använda plugins för ljudbehandling?
  • Använd OpenAL-ramverket för att ge positionell ljuduppspelning i spel och andra applikationer. IOS stöder OpenAL 1.1?

-Multimedia Programmeringsguide: Använda ljud

En hel serie av handledningar kan vara tillägnad varje ram i ovanstående lista, men tillräckligt för att säga att för denna handledning ska vi använda Audio Toolbox-ramen på grund av ett unikt erbjudande: Systemljudtjänster. Systemljudtjänster är ett C-nivågränssnitt som är avsett för att spela korta användargränssnittsljud och andra små ljudklipp med 30 sekunder eller mindre.

Processen för att spela ett ljudklipp med System Sound Services omfattar tre steg:

  1. Registrera en ljudklipp med System Sound Services för uppspelning i framtiden (inte så långt)
  2. Ta emot ett systemljud-ID (SSID) som unikt identifierar ljudklippet som är registrerat hos systemljudservern.
  3. Ring systemljudservern med lämplig SSID för att starta uppspelningen.

Resten av denna handledning kommer att implementera denna process för att spela inspelade DTMF-toner för knappsatsen siffror 0-9.

Varför använder vi förinspelade toner istället för att generera lämplig frekvens på flyget? I huvudsak för att spara tid och för att hålla denna handledning mer tillgänglig genom att undvika matematik som är involverad i sinusformiga funktioner och frekvensgenerering. Om du vill gå den vägen istället hittar du troligtvis följande artiklar:

  • Dual-Tone Multi-Frequency Signalering
  • Tryck på Tone-knappsatsen
  • Sinusvåg
  • iPhone Dev SDK Forums: Skapa en pip

Vill du verkligen veta hur man genererar ljud på flyget? Om det här inlägget får minst 10 kommentarer som begär en handledning om hur man skapar ljud från början den 1 maj 2011 ska jag göra en avancerad iOS SDK-serie om det här ämnet. Inga löften att det kommer att innebära DTMF-toner specifikt, men det kommer definitivt att bli något häftigt.

Med den teoretiska kunskapen ur vägen, låt oss dyka in i koden och få den här funktionen klar!

Steg 1: Importera AudioToolbox Framework

Vi måste börja med att importera Audio Toolbox-ramverket till vår applikation för att göra Systemljudtjänsten tillgänglig för vår kod. För att göra det, välj "PhoneAppSkin" -projektet i rutan Projekt Navigator i Xcode, välj sedan "PhoneAppSkin" under "TARGETS" och välj slutligen fliken "Byggfaser". Därefter ska din skärm se ut så här:

Därefter, klicka på länken "Länka binära med bibliotek" och klicka på "+" -symbolen för att lägga till en ny ram för projektets länkfas.

Slutligen hitta "AudioToolbox" -ramen i popup-fönstret och klicka sedan på "Lägg till".

Öppna sedan upp PhoneViewController.h fil och lägg till den rad som behövs för att faktiskt importera Audio Toolbox-ramverket till din klass:

 #importera  #importera 

Funktionerna för ljudverktygslådan ska nu vara tillgängliga för din klass!

Steg 2: Importera WAV-filer i Touch Tone

Hämta och öppna källkoden som bifogas denna Mobiletuts + post och hitta mappen med titeln "Audio". Dra hela den här mappen till mappen "Resurser" i Xcode Project Navigator, se till att du väljer "Kopiera" när du blir ombedd. Du borde sluta med en skärm så här:

Steg 3: Skapa en array för SSID-referenser

I PhoneViewController.h, lägg till följande C-format array deklaration:

 @interface PhoneViewController: UIViewController SystemSoundID toneSSIDs [10]; 

Linje 13 förklarar en typ av C-typ av typ SystemSoundID med en maximal kapacitet på 10.

Lagring av systemljud-ID i denna array gör det möjligt för oss att snabbt hänvisa till lämpligt ljudklipp i numberButtonPressed: metod senare.

Steg 4: Registrera tonljudet

Öppna PhoneViewController.m och hoppa till initWithCoder metod på linje 17. När PhoneViewController initialiseras först och initWithCoder Metoden heter, vi vill registrera systemljud för varje ton som ska användas på knappsatsen med iOS-systemljudservern. När ett ljudklipp är registrerat hos ljudservern kan vi instruera servern att spela upp ljudfilen senare när knappsatsen trycks ned.

För att registrera knapparna 0-9, lägg till följande kod:

 -(id) initWithCoder: (NSCoder *) aDecoder self = [super initWithCoder: aDecoder]; om (själv) phoneNumberString = [[NSString alloc] init]; för (int count = 0; count < 10; count++) NSString *toneFilename = [NSString stringWithFormat:@"DTMF_%02d", count]; NSURL *toneURLRef = [[NSBundle mainBundle] URLForResource:toneFilename withExtension:@"wav"]; SystemSoundID toneSSID = 0; AudioServicesCreateSystemSoundID( (CFURLRef) toneURLRef, &toneSSID ); toneSSIDs[count] = toneSSID;   return self; 

rad 24, en för loop som kommer att iterera 10 gånger börjar. Syftet med detta för loop är att lägga till ett nytt systemljud ID till toneSSIDs array för var och en av de beräkningstoner som är associerade med tangenterna 0-9.

linje 25, en förekomst av NSString är instansierad som håller filnamnet för den relevanta DTMF-tonen. En intressant anteckning på denna rad är stringWithFormat: metodsamtal och % 02d format specifier. Detta format specifier omvandlar alla siffror till en nollpolstret siffra med 2 tecken i längd. Så blir till exempel 0 '00', blir 1 '01', 2 blir '02', etc.

linje 27, de NSBundle klassen används för att generera en filsystemväg till filnamnet som genereras på rad 25 med en förlängning av "wav" bifogad. NSLog Detta värde om du vill se hela sökvägen för dig själv.

Linje 29 skapar en variabel för att hålla SystemSoundID som kommer att genereras av iOS-systemljudservern nästa.

Som en sidnot, SystemSoundID är bara en typedef för Mac Type uint32, vilket är själv en typedef för unsigned long. Följaktligen kunde vi ha förklarat variabeln på denna typ av typ unsigned long, men det skulle vara dålig övning eftersom framtida iOS-utgåvor kan ändra SystemSoundID skriv, vilket orsakar att koden bryts. Det är dock bra att komma ihåg detta när du arbetar med SystemSoundIDs eftersom kompilatorn ibland kommer att varna om inkompatibla unsigned long typer.

Linjer 31 - 34 är ett c-stilfunktionssamtal till AudioServicesCreateSystemSoundID, som tar a CFURL (Core Foundation URL) för ljudfilbanan för att skapa ett Systemljud ID för och en SystemSoundID-referens som används för att lagra SSID-filen efter att den har skapats. Lägg märke till hur ampersandkaraktären (dvs '&') visas före toneSSID variabel på rad 33? Detta är ett unary prefix operatör som konverterar toneSSID parametern i variabelns minnesadress istället för det värde som lagras i minnet för den variabeln. Detta är gjort så att AudioServicesCreateSystemSoundID funktionen kan lagra det genererade SSID numret direkt i toneSSID minnesadressen, så att funktionsanroparen (dvs. vår metod) åtkomst till det genererade SSID utan att egentligen överföra SSID tillbaka från funktionen.

Låter lite förvirrande? Det kommer förmodligen inte om du redan har erfarenhet av programmering på ett språk som C, C ++ eller Go. Eftersom Objective-C är en strikt superset av C-språket, är iOS SDK ibland beroende av bibliotek som är skrivna i procedur C. Om C-syntaxen inte är meningsfull för dig, oroa dig inte för det för mycket just nu, men ta det som en utmaning att komplettera din iOS SDK-kunskap med grunden för C-språket i framtiden!

ledning 35, indexet för toneSSIDs c-stil array betecknad av strömmen räkna värdet tilldelas det värde som skapas av AudioServicesCreateSystemSoundID fungera. Detta SSID-värde kommer att refereras senare för att spela rätt ton när användaren tappar på knappsatsens nummer.

Steg 5: Spela toner på Tryck

De numberButtonPressed: Metoden heter varje gång touchUpInside händelse bränder för knapparna 0 - 9. Eftersom index 0-9 av toneSSIDs array innehåller nu den motsvarande tonen för varje knapp, är följande tre streckkod tillräckligt för att spela den lämpliga tonen:

 -(IBAction) numberButtonPressed: (UIButton *) pressedButton int toneIndex = [pressedButton.titleLabel.text intValue]; SystemSoundID toneSSID = toneSSIDs [toneIndex]; AudioServicesPlaySystemSound (toneSSID); self.phoneNumberString = [self.phoneNumberString stringByAppendingString: pressedButton.titleLabel.text]; [self displayPhoneNumber]; 

Linje 96 konverterar textvärdet av den pressade UIButton titel till ett heltal från en sträng.

Med den uppringda siffran som erhållits, rad 97 hämtar a SystemSoundID från toneSSIDs array.

rad 98, de AudioServicesPlaySystemSound funktionen heter med SSID bara hämtad för att starta uppspelning av beredningstangenten.

Det är allt! Gå vidare och spara och bygga projektet nu, och du bör upptäcka att knappsatsen har ljudeffekter!

Steg 6: Göra det Snappy

Det finns ett litet problem med den nuvarande lösningen. Märker du förseningen mellan att trycka på knappen och den genererade tonen? I del 6 i denna serie var knappsatsens knappar inställda för att utlösa touchUpInside verkan. Den här åtgärden brinner när användaren tar bort fingret från knappen. Tonen ska dock spelas så fort användaren knackar på knappen, inte efter att ha tagit bort fingret. För att åtgärda detta, öppna PhoneView.xib, ta bort touchUpInside IBAction referenser för alla knappar och bind sedan varje knapps landning åtgärd till numberButtonPressed: metod.

Om du behöver hjälp att ta reda på hur du gör det här steget, hänvisar du bara till del 6, steg 1 i den här serien.

Sammanfatta

Denna handledning har varit en virvelvindsturnering i Audio Toolbox Framework och System Sound Services. Om du har frågor, var god att lämna dem i kommentarerna nedan och jag gör mitt bästa för att svara. Självklart finns det inte tillräckligt med timmar på dagen för mig att kolla alla mina tidigare inlägg för nya kommentarer varje dag, så som månaderna bär på dig kan ha bättre lycka kontakta mig via Twitter: @markhammonds.