Making of: triqtraq

Der Software-Entwickler und KI-Experte Olaf van Zon hat triqtraq programmiert. Dabei musste er insbesondere für guten Klang sorgen – wegen der Rechenleistung des iPhones immer noch die größte  Herausforderung an einer Musik-App



.


Making-of

 

Audio-Applikationen verlangen vor allem eine starke Prozessorleistung: Um Audio in CD-Qualität zu erzeugen, benötigt man ein ausgehendes Signal von 44 100 Kilohertz mit einer Präzision von 16 Bit. Das bedeutet, dass die App ­je­de Sekunde 44 100 Abtastwerte (die kleinsten unterscheidbaren Teilchen im Audiobereich) in Stereo generieren muss. Bei triqtraq haben wir vier Kanäle, also die vierfache Rechenlast, dazu kommen die verschiedenen Algorithmen für Decay und Filter; zum Mixen und fürs Panning der Kanäle brauchen wir außerdem CPU-Leistung. Alles in allem mussten wir den Code also optimieren, damit keine Latenzen entstehen, und ich verrate hier ein paar Tricks dazu.

Zunächst suchte ich mir die Stellen im Code, bei denen es wirklich auf Geschwindigkeit ankommt, und konzentrierte mich auf die Soundverarbeitung. Zum Vergleich: Beim Interface spielt Geschwindigkeit eine eher unbedeutende Rolle, denn hier werden Nutzer eine Verzögerung von 50 Millisekunden kaum bemerken, beim Sound aber sehr wohl. In Apples Editor Xcode 4 findet man unter »Menu Open Developer Tool« ein Werkzeug namens ­Ins­truments, mit dem sich rechenintensive Stellen recht gut aufstöbern lassen: Es bietet einen Time Profiler, der abliest, welche Code-Zeile wie viel Verarbeitungszeit benö­tigt. Nachdem ich also wusste, welche Stellen ich optimieren musste, fing ich mit einfachen Maßnahmen an.


1. Werte in Variablen schreiben

Wird ein Wert öfter als einmal berechnet, ist es besser, ihn in eine Variable zu packen, statt ihn immer wieder neu zu berechnen. Das verringert die CPU-Auslastung auf Kosten von etwas Speicherkapazität. In einfachen Fällen achtet der Compiler auf solche Dinge, die komplexeren Angelegenheiten lassen sich damit aber nicht lösen. Zum Beispiel lassen sich die Code-Zeilen

float outputLeft = A1 * factor * maxVolume;
float outputRight = A2 * factor * maxVolume;

besser so notieren:

float volumeFactor = factor * maxVolume;
float outputLeft = A1 * volumeFactor;
float outputRight = A2 * volumeFactor;


2. Divisionen vermeiden

Da Floating Point Divisions – das Teilen von Gleitkommazahlen – auf dem iPhone ganz schlecht performen, sollte man sie im Audiocode so weit wie möglich vermeiden. Sollte man sie jedoch wirklich brauchen, kann man den Code auf so wenig Divisionen wie möglich reduzieren, etwa so: Der Abschnitt

float someValue = 7.0f;
for (int i = 0; i < 1024; i ++) {
    …
    float A = x / someValue;
    …
}

lässt sich ändern in:

float someValue = 7.0f;
float inverseOfSomeValue = 1 / someValue;
for (int i = 0; i < 1024; i ++) {
    …
    float A = x * inverseOfSomeValue;
    …
}


3. Methoden schneller abrufen

Objective-C kann für zeitkritische Anwendungen re­­la­tiv ineffizient sein, gerade wenn es um den Aufruf von Me­thoden geht. Will man eine ­Methode in einem zeitkriti­schen Code aufrufen, könnte man die Methode in eine C/C++-Funktion ändern, weil ihr Aufruf viel schneller ist. Objective-C und C/C++ lassen sich gut mischen – doch sollte man dabei Folgendes beachten: Wenn man C++-Code in eine Objective-C-Klasse schreibt, muss man die Datei­endung von ».m« in ».mm« ändern, damit der Compiler den C++-Code erkennt.

-(int)doB {
    …
    // do something in Objective-c here
    …
    return someValue;
}
-(void)doA {
    x = [self doB];
}

Wenn man doB als C-Funktion schreibt, lässt sie sich als
C-Funktion aufrufen:

int doB (){
    …
    // do something in C code here
    …
    return someValue;
}
-(void)doA {
    x = doB();
}
 


 

4. methodForSelector nutzen

Statt den Code in eine C/C++-Funktion zu program­mie­ren wie im vorherigen Beispiel, können Sie auf
die Objective-C-Methode auch mit einem Zei­ger verweisen und sie später mit ihm aufrufen. Das Tempo ist jetzt fast so hoch wie ein Auf­ruf in C/C++. Sie können den Code also wie folgt optimieren:

typedef int (*DoB_IMP)(id,SEL);
SEL doBSel;
DoB_IMP doBMethod;
-(int)doB {
    …
    // do something in Objective-C here
    …
    return someValue;
}
-(void)doA {
    doBMethod(self, doBSel);
}
-(void)init {
    // storing pointer to function
    doBSel = @selector(doB);
    doBMethod = (DoB_IMP)[self methodForSelector:doBSel];
}

Nun sind Sie an der Reihe, es selbst zu versuchen. Wenn es nicht auf Anhieb klappt, haben Sie Geduld – die Entwicklung von Apps erfordert viel Zeit und Konzentration, aber das Resultat kann sich durchaus lohnen.


(veröffentlicht in PAGE 12.2012)

 


Schlagworte: , , ,




Kommentieren

Einfach mit dem PAGE Account anmelden oder Formular ausfüllen

Name *

Email *

*Pflichtfeld

Ihr Kommentar *

 
 

Das könnte Sie auch interessieren