/
csound_ios_manual.tex
542 lines (382 loc) · 32.2 KB
/
csound_ios_manual.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
\documentclass[11pt]{article}
\usepackage{hyperref}
\usepackage{listings}
\usepackage{color}
\usepackage{xcolor}
\usepackage{caption}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage{graphicx}
\usepackage{comment}
%\DeclareCaptionFont{white}{\color{white}}
%\DeclareCaptionFormat{listing}{\colorbox{gray}{\parbox{\textwidth}{#1#2#3}}}
%\captionsetup[lstlisting]{format=listing,labelfont=white,textfont=white}
\DeclareCaptionFont{white}{\color{white}}
\DeclareCaptionFormat{listing}{\colorbox[cmyk]{0.43, 0.35, 0.35,0.01}{\parbox{\textwidth}{\hspace{15pt}#1#2#3}}}
\captionsetup[lstlisting]{format=listing,labelfont=white,textfont=white, singlelinecheck=false, margin=0pt, font={bf,footnotesize}}
\lstset{ %
language=[Objective]C,
%breakindent=40pt,
basicstyle=\ttfamily\footnotesize, % the size of the fonts that are used for the code
%numbers=left, % where to put the line-numbers
numberstyle=\ttfamily\footnotesize, % the size of the fonts that are used for the line-numbers
%stepnumber=1, % the step between two line-numbers. If it is 1 each line will be numbered
numbersep=5pt, % how far the line-numbers are from the code
backgroundcolor=\color{white}, % choose the background color. You must add \usepackage{color}
showspaces=false, % show spaces adding particular underscores
showstringspaces=false, % underline spaces within strings
showtabs=false, % show tabs within strings adding particular underscores
%frame=single, % adds a frame around the code
%frame=shadowbox,
%frame=tb,
tabsize=2, % sets default tabsize to 2 spaces
%captionpos=b, % sets the caption-position to bottom
breaklines=true, % sets automatic line breaking
breakatwhitespace=false, % sets if automatic breaks should only happen at whitespace
escapeinside={\%*}{*)}, % if you want to add a comment within your code
%stringstyle=\color{white}\ttfamily,
xleftmargin=17pt,
framexleftmargin=17pt,
framexrightmargin=5pt,
framexbottommargin=4pt
}
\author{\textbf{Victor Lazzarini, Steven Yi, and Richard Boulanger}}
%\date{2011.11.xx}
\date{\today}
\title{\textbf{Csound for iOS}}
\begin{document}
\maketitle
\section{Introduction}
Welcome to Csound for iOS! This document will discuss the details about using Csound for iOS. For those with knowledge of Csound, hopefully you will see that the value of your knowledge is only enhanced by offering a new platform on which to create musical software and works.
\subsection{Regarding the Csound for iOS Examples Project}
This documentation covers discussion of the Csound for iOS API. Users interested in diving in to see how the API is used may want to download the Csound for iOS Examples Projects which contains a set of examples, in both Objective-C and in Swift, that cover different use cases of the API. The code for each example may be useful in getting you a jump-start into building your own applications.
\subsection{Regarding the LGPL License}
The Csound for iOS includes Csound and \href{http://mega-nerd.com/libsndfile/}{libsndfile}. These are distributed as static libraries. Users of the Csound for iOS API must comply with the licensing requirements of the GNU Lesser General Public License v2.1, which both libraries use. Please carefully review the license files that accompany each project (you can view a generic version of the LGPL v2.1 license at \href{http://www.gnu.org/licenses/lgpl-2.1.html}{http://www.gnu.org/licenses/lgpl-2.1.html}).
%======
\section{Getting and Using the Csound for iOS API}
You can locate and download the latest version of The Csound for iOS library in the Mobile and Web section of the Download page (\url{http://csound.github.io/download.html}) at the Csound Website on GitHub (\url{http://csound.github.io/}).
\subsection{The Zip archive includes}
\begin{itemize}
\item Statically compiled libcsound.a and libsndfile.a, compiled as universal binaries for armv6, armv7, armv7f, arm64 and i386 CPU architectures (to work with both iOS devices and simulators)
\item C Headers for the Csound C API
\item CsoundObj Objective-C API Source
\item Documentation
\item The Csound for iOS Obj-C Examples
\item The Csound for iOS Swift Examples
\end{itemize}
\subsection{Getting Started with the Examples}
Csound for iOS was chosen to be delivered as pre-compiled libraries and headers for easy inclusion into projects.
To launch Xcode and get started with the Csound for iOS examples, double-click on the file \textit{Csound iOS Examples.xcodeproj}. Once Xcode is running, choose an appropriate iOS Simulator, or choose your connected iPhone or iPad to run the examples on your hardware. In the Project Navigator section of the Xcode IDE, select either of the Csound iOS Examples folders (Obj-C or Swift). In the Main Editor, select the General Tab, and under the Signing section select "automatically manage signing", and set the team appropriately (typically your Apple ID). To run the examples under the scheme you have chosen above, click on the Run Button in the upper left corner of the Xcode IDE. This will Build and run the examples project. Now that they are running on the simulator or your hardware, you can select from the list of examples in the sidebar to explore some of the ways you can use Csound. To see how each example is realized, expand the project and then the ViewControllers folder in the project navigator. In this folder, you will find the sources for each example.
\subsection{Getting Started with Your Own Project}
To get started using the Csound for iOS API in a project of your own, you need to:
\begin{enumerate}
\item Launch Xcode
\item From the welcome screen, click on \textit{Create a New Xcode project}
\item Select a \textit{Single View Application}
\item Give your project a name and set Language to \textit{Objective-C}
\item Choose where to save the project
\item Then select "Create" and Xcode will set everything up for you and create a working empty project that you can build and run.
\item To make this a Csound for iOS project, you need to Right-click your project folder in the Project Navigator, and from the context menu choose ``Add Files to [project name]''
\item In the file dialog that opens, navigate to the folder containing the csound-iOS folder and select the csound-iOS folder. Keep the default settings of ``Create groups for any added folders''. You will want to select ``Copy items into destination group's folder (if needed)'' so that all the files you are using are contained in this project.
\item Make sure that csound-iOS is added to all of your targets for your project.
\item If working in Swift, you must include a 'Bridging' Header that contains your Objective-C \#import statements. This is as simple as adding a .h file to your project, filling in the import statements, and then identifying it as your Bridging header in the project build settings.
\end{enumerate}
After selecting ``Add files'', the csound-iOS folders should now be a part of your project. You will now be able to reference both the standard Csound C API as well as the Objective-C CsoundObj API from your project code.
%======
\section{Introduction to the API}
\subsection{The Csound and CsoundObj API}
Csound for iOS is released with the standard Csound C API as well as a custom Objective-C CsoundObj API that has been designed to streamline and simplify developing on iOS. The CsoundObj API includes methods for binding widgets to channels (used to communicate to and from Csound), mapping hardware MIDI to widgets, enabling hardware sensors, and more. For further detail, please consult the \textit{CsoundObj.h} and \textit{CsoundObj.m} files.
While the CsoundObj API has been designed to ease things for iOS development and to follow conventions of Objective-C, the decision was made not to wrap "everything" in the Csound C API. As C coding is commonly found to be used within iOS development, we felt it was better to try to cover the important things that are normally done in Objective-C in CsoundObj, while delegating the user to the C API for parts of Csound that may not be used as often. The \textbf{CSOUND*} struct pointer that a CsoundObj class holds can be accessed via the \textbf{getCsound} method in CsoundObj. For more information about the Csound C API, consult the \textit{csound.h} header file within the csound-iOS/headers folder.
\section{Using the CsoundObj API}
The CsoundObj API revolves around the Objective-C CsoundObj class. This class contains a \textbf{CSOUND*} struct pointer and has methods for running Csound, as well as convenience methods to help aid developers in connecting elements to Csound. By itself, CsoundObj can take in a CSD file and render it. By using CsoundBindings, objects can interact to read values from and write values to Csound. Beyond that, extended features can be accessed by using the Csound C API together with the CSOUND* struct.
\subsection{Designing Csound CSD projects to work with Hosts}
To communicate to and from a host program with Csound, you will most likely use the \textbf{chnset} and \textbf{chnget} opcodes. These opcodes will allow you to read from and write values to a named channel. Your host program will also be writing to and reading from these same channels. As a byproduct of using named channels, your CSD will be portable and will work on other platforms (Desktop, Android); thus, porting over apps to/from iOS will only involve redoing the application and code, while your audio engine (Csound) should ``just work.''
\subsubsection{CsOptions}
Csound will use the CsOptions you provide, and it will default to \textit{-o dac} for realtime audio output. In the past, a standard set of flags were ``{\tt -odac -dm0}''. These told Csound to play to dac in realtime, turn off displays and use message level 0. This minimized messages going out to the console or to your message handler if you set one. In many cases, you will not need to specify any commandline options to get the project to render audio on your device; but if you want to use \textbf{MIDI} hardware, or if you want to use the \textbf{Microphone}, you will need to set the appropriate CsOptions to enable these devices.
If the CSD in your app responds to MIDI messages from keyboard or other controller (such as the Arturia MINIlab mkII or the Korg NanoKontrol), you will need to set the {\tt -M0} flag.
If the CSD in your app processes audio input, you will need to set the ``{\tt -iadc}'' flag, as well as the useAudioInput property of your CsoundObj instance to be 'true' (or 'YES' in Objective-C). And when you do use the microphone, Apple requires you to modify the \textit{Info.plist} file and include the "Privacy - Microphone Usage Description" key-value pair as described in this technical document: \url{https://developer.apple.com/library/content/qa/qa1937/}
\subsection{CsoundBinding for Communicating with Csound}
The CsoundObj API has been created to ease communication with Csound by using objects that implement the CsoundBinding protocol. The protocol definition is as follows:
\begin{lstlisting}[caption=CsoundBinding Protocol Definition]
@protocol CsoundBinding <NSObject>
- (void)setup:(CsoundObj*)csoundObj;
@optional
- (void)cleanup;
- (void)updateValuesFromCsound;
- (void)updateValuesToCsound;
@end
\end{lstlisting}
CsoundBindings are used to both read values from Csound as well as write values to Csound. The lifecycle of CsoundBindings is as follows:
\begin{itemize}
\item \textbf{setup} - this method is called after Csound's compile call but before the main performance loop. CsoundBindings should use this method to create any channel pointers and any other values they will need during performance.
\item \textbf{updateValuesToCsound} and \textbf{updateValuesFromCsound} - these methods are called during the Csound performance loop. \textbf{updateValuesToCsound} is called before each call to csoundPerformKsmps, while \textbf{updateValuesFromCsound} is called after each call.
\item \textbf{cleanup} - this method is called after Csound has completed its run and should be used by CsoundBindings to free up any allocated data and remove references to channel pointers.
\end{itemize}
By using CsoundBindings, CsoundObj functionality can be extended to communicate with as many items as you would like. Included with Csound for iOS is the CsoundUI which contains pre-made wrapper classes for common UI classes (UILabel, UIButton, UISlider, UISwitch) and similarly, CsoundMotion provides wrapper for hardware sensors (Accelerometer, Attitude, Gyroscope). CsoundObj has helper methods for the CsoundBindings that come with the CsoundObj API, as well as the generic \textbf{addBinding} and \textbf{removeBinding} methods for adding custom CsoundBindings. Please consult these classes as well as their use in context within the Csound for iOS Examples project.
%======
\section{Common CsoundObj API Methods}
\subsection{Binding Widgets to CsoundObj}
The CsoundUI API contains the following methods for binding widgets:
\begin{lstlisting}[caption=Methods for Widget Binding]
- (void)addLabel:(UILabel *)uiLabel forChannelName:(NSString *)channelName;
- (void)addButton:(UIButton *)uiButton forChannelName:(NSString *)channelName;
- (void)addSlider:(UISlider*)uiSlider forChannelName:(NSString *)channelName;
- (void)addSwitch:(UISwitch *)uiSwitch forChannelName:(NSString *)channelName;
- (void)addMomentaryButton:(UIButton *)uiButton forChannelName:(NSString *)channelName;
\end{lstlisting}
These methods allow for easy binding of UILabels, UISliders, UISwitches, and UIButtons (two different types of buttons), and return the CsoundBinding that was created to wrap the widget. If the design of your app requires that you remove a widget from being used with CsoundObj, you can use the returned CsoundBinding and pass it to the removeBinding method. To bind your own custom widgets, you will need to create your own CsoundBinding. There are examples of both using the convenience widget binding methods as well as custom CsoundBinding in the Csound for iOS Examples project.
%======
\section{Interfacing with Hardware}
\subsection{Audio Input and Output}
CsoundObj has been designed to connect everything necessary for audio input and output from Csound to CoreAudio. Enabling input and output depends on what commandline arguments are given when running Csound. The commandline arguments should be supplied as part of the CSD \textbf{CsOptions} section. To enable audio output, use \textbf{-o dac} and to enable audio input, use \textbf{-i adc} as well as your CsoundObj's useAudioInput value to true or YES. (Note that by default, Csound assumes -o dac and it does not need to be specified explicitly, whereas if you plan to use the microphone or audio input, you do need to specify -i adc.)
\subsection{MIDI Hardware Input}
MIDI input is supported in two ways: directly to Csound, or indirectly via Widgets.
\subsubsection{Direct MIDI input to Csound}
CsoundObj has a property called \textbf{midiInEnabled}. By default this value is set to NO; setting it to YES will enable MIDI input from CoreMIDI directly into Csound. This will allow using Csound's MIDI handling and opcodes to respond to note and controller data from hardware MIDI devices connected to your device. The Csound for iOS Examples project contains an example called \emph{Hardware MIDI Controller} that demonstrates a project setup to handle MIDI coming from a hardware keyboard. (Your hardware controller must be plugged into the iOS device prior to starting the App or it will not be recognized by the software.)
Note that this flag is read when CsoundObj begins a Csound run. Setting this to YES while CsoundObj is currently rendering will have no effect.
\subsubsection{Using MidiWidgetsManager to Control Widgets}
For MIDI controller data, rather than handle it directly in Csound, you can use the MidiWidgetsManager to map data from channels to UI Widgets. The MidiWidgetsManager uses \textbf{MidiWidgetWrappers} to handle mapping of controller data and setting values on widgets. Currently, the MidiWidgetsManager only has one built-in MidiWidgetWrapper for UISlider. To map values to custom widgets, you will need to create your own implementations of MidiWidgetWrappers.
This alternative to direct MIDI input to Csound allows for MIDI mapping without a CsoundObj instance actively rendering. In terms of architecture, MIDI values will map to Widgets, and the values within the Widgets are what will be connected with Csound. By using this design, the values in the widget will be the primary source of values across the system and no synchronization of values is required, whether modified by MIDI or touch input.
\subsection{Accelerometer, Gyroscope, Attitude}
CsoundMotion has built-in support for three of the more commonly used hardware sensors on iOS devices: Accelerometer, Gyroscope, and Attitude. CsoundMotion has the following methods to enable these features:
\begin{lstlisting}[caption=CsoundMotion Hardware Sensor Methods]
-(id<CsoundBinding>)enableAccelerometer;
-(id<CsoundBinding>)enableGyroscope;
-(id<CsoundBinding>)enableAttitude;
\end{lstlisting}
When these features are enabled, CsoundBindings that wrap the sensors will send values into Csound via hardcoded channels:
\begin{itemize}
\item Acclerometer
\begin{itemize}
\item accelerometerX
\item accelerometerY
\item accelerometerZ
\end{itemize}
\item Gyroscope
\begin{itemize}
\item gyroX
\item gyroY
\item gyroZ
\end{itemize}
\item Attitude
\begin{itemize}
\item attitudeRoll
\item attitudePitch
\item attitudeYaw
\end{itemize}
\end{itemize}
Once a sensor has been enabled, you can access those values in Csound using \textbf{chnget}. For further study, please see the \emph{Motion Control} example in the Examples project.
%======
\section{The Csound for iOS Examples}
The Examples \textit{xcodeproj} contains a number of simple examples that illustrate different aspects of working with Csound for iOS. The following is a brief description of each of the sixteen examples currently featured.
\subsection{Simple Test 1}
\emph{Simple Test 1} is an example that plays ascending notes. The pitch of the notes can be altered by using the slider. Also, a UISwitch is used to turn on/off the rendering of Csound. In the code, you'll find that the callback that is connected to the UISwitch shows the basic usage of CsoundObj to render a CSD that is included as a resource for the project:
\begin{lstlisting}[caption=Example code showing configuring and starting a CsoundObj in Objective-C]
-(IBAction) toggleOnOff:(UISwitch *)sender {
NSLog(@"Status: %d", [sender isOn]);
if(sender.on) {
NSString *csdFile = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"csd"];
NSLog(@"FILE PATH: %@", csdFile);
[self.csound stop];
self.csound = [[CsoundObj alloc] init];
[self.csound addListener:self];
CsoundUI *csoundUI = [[CsoundUI alloc] initWithCsoundObj:self.csound];
csoundUI.labelPrecision = 2;
[csoundUI addSlider:mSlider forChannelName:@"slider"];
[self.csound play:csdFile];
} else {
[self.csound stop];
}
}
\end{lstlisting}
\pagebreak
\begin{lstlisting}[caption=Example code showing configuring and starting a CsoundObj in Swift 3]
@IBAction func toggleOnOff(_ sender: UISwitch) {
print("Status: \(sender.isOn)")
if sender.isOn {
let csdFile = Bundle.main.path(forResource: "test", ofType: "csd")
csound = CsoundObj()
csound.add(self)
let csoundUI = CsoundUI(csoundObj: csound)
csoundUI?.labelPrecision = 2
csoundUI?.add(uiLabel, forChannelName: "slider")
csoundUI?.add(uiSlider, forChannelName: "slider")
csound.play(csdFile)
} else {
csound.stop()
}
}
\end{lstlisting}
\subsection{Simple Test 2}
\emph{Simple Test 2} is a generative music example that contains a number of sliders that affect the rate of notes generated, the duration of notes generated, and the ADSR envelope for each note generated.
\subsection{Button Test}
\emph{Button Test} uses a CSD based on Simple Test 2, but the user needs to press a button to trigger each note. Of interest to the developer is the fact that the two buttons in this example show two different ways in which to integrate buttons with CsoundObj:
\begin{enumerate}
\item Using CsoundObj's \textbf{addMomentaryButton:forChannelName:} method, which will setup a k-rate channel for Csound. The value will be 0 when the button is not pressed, and will be 1 for one ksmps period when a button is pressed (it returns to 0 the following ksmps period).
\item Using a standard button callback, the callback will create a string score and send that to Csound using CsoundObj's \textbf{sendScore} method. (See code below.)
\end{enumerate}
\begin{lstlisting}[caption=Example code showing sending score text to CsoundObj]
-(IBAction) eventButtonHit:(id)sender {
NSString* score = [NSString stringWithFormat:@"i2 0 %f", [mDurationSlider value]];
[mCsound sendScore:score];
}
\end{lstlisting}
\begin{lstlisting}[caption=Equivalent example in Swift 3]
@IBAction func eventButtonHit(_ sender: UIButton) {
let score = "i2 0 \(mDurationSlider.value)"
csound.sendScore(score)
}
\end{lstlisting}
Note that the second method will read the value from the duration slider when creating the note, while the first method handles reading the duration from the channel within the CSD code.
\subsection{Play: Haiku IV}
\emph{Play: Haiku IV} is the fourth movement from a suite of nine generative Csound pieces by Iain McCurdy. Csound begins rendering the work when the view appears and stops when the view unloads and the CsoundObj is de-allocated.
\subsection{Render: Trapped in Convert}
\emph{Render: Trapped in Convert} demonstrates how to render a CSD to disk as an audio file and how to use AVFoundation to access and play the rendered audio.
\subsection{Render: Console Output}
\emph{Render: Console Output} shows how to use an Objective-C selector as a message callback for Csound through the CsoundObj. In the example's \textbf{run} method, the call to CsoundObj's \textbf{setMessageCallback} with both the selector to call and the target object is used to route Csound's messages to the example's UITextView:
\begin{lstlisting}[caption=Example of setting message callback]
[self.csound setMessageCallback:@selector(messageCallback:) withListener:self];
\end{lstlisting}
\begin{lstlisting}[caption=Equivalent example in Swift 3]
csound.setMessageCallback(#selector(messageCallback(_:)), withListener: self)
\end{lstlisting}
The message callback selector handles formatting the Csound message using typical C code (or Swift equivalents/wrappers) one will find when using message callbacks with Csound:
\begin{lstlisting}[caption=Message Callback Selector Code]
- (void)messageCallback:(NSValue *)infoObj
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
Message info;
[infoObj getValue:&info];
char message[1024];
vsnprintf(message, 1024, info.format, info.valist);
NSString *messageStr = [NSString stringWithFormat:@"%s", message];
[self performSelectorOnMainThread:@selector(updateUIWithNewMessage:)
withObject:messageStr
waitUntilDone:NO];
[pool drain];
}
\end{lstlisting}
\begin{lstlisting}[caption=Message Callback Selector Code in Swift 3]
func messageCallback(_ infoObj: NSValue) {
var info = Message()
infoObj.getValue(&info)
let message = UnsafeMutablePointer<Int8>.allocate(capacity: 1024)
let va_ptr: CVaListPointer = CVaListPointer(_fromUnsafeMutablePointer: &(info.valist))
vsnprintf(message, 1024, info.format, va_ptr)
let output = String(cString: message)
DispatchQueue.main.async { [unowned self] in
self.updateUIWithNewMessage(output)
}
}
\end{lstlisting}
Note: after the message is formatted and converted into an Objective-C NSString from a C char*, a \textbf{performSelectorOnMainThread} or a closure dispatched on the main thread is used to update the UI with the message text. The callback from Csound will not be on the main thread. This step is therefore required as all modifications to the user interface must be done on the main thread.
\subsection{Instrument Tweaker}
\emph{Instrument Tweaker} allows the user to modify the CSD on the fly using the \textbf{updateOrchestra} method from CsoundObj.
\subsection{F-table Viewer}
\emph{F-table Viewer} demonstrates using a CsoundBinding to read an f-table from Csound and display that table. Note that the WaveView's code is doing some optimization to check if it has already loaded. It is also checking that the table itself has completed loading before trying to grab any values for the table.
\begin{lstlisting}[caption=Waveview code demonstrating reading f-tables from Csound]
- (void)updateValuesFromCsound
{
if (!tableLoaded) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CSOUND *cs = [csObj getCsound];
sr = csoundGetSr(cs);
ksmps = csoundGetKsmps(cs);
if ((tableLength = csoundTableLength(cs, 1)) > 0) {
table = malloc(tableLength * sizeof(MYFLT));
csoundGetTable(cs, &table, 1);
tableLoaded = YES;
[self performSelectorInBackground:@selector(updataDisplayData) withObject:nil];
}
[pool release];
}
}
\end{lstlisting}
\pagebreak
\begin{lstlisting}[caption=Equivalent example in Swift 3]
func updateValuesFromCsound() {
if !tableLoaded {
let cs = csObj.getCsound()
tableLength = Int(csoundTableLength(cs, Int32(fTableNumber)))
if tableLength > 0 {
table = UnsafeMutablePointer<Float>.allocate(capacity: tableLength)
csoundGetTable(cs, &table, Int32(fTableNumber))
tableLoaded = true
}
DispatchQueue.global(qos: .background).async { [unowned self] in
self.updateDisplayData()
}
}
}
\end{lstlisting}
This example shows how to off-loads calculations in a background thread using \textbf{performSelectorInBackground} or a closure dispatched in the background, then posts to the main thread to update the user interface.
\subsection{Soundfile: Pitch Shifter}
\emph{Soundfile: Pitch Shifter} demonstrates a technique of finding the URL of a bundled AIFF file playing it with Csound. This code finds the path for the \emph{audiofiletest.aif} file that is included with the project, and uses that value to construct a score statement to send to Csound. The example sets up an instance of CsoundObj in its \textbf{viewDidLoad} method, as well as binds a custom UIKnob widget for controlling the playback pitch of the audio file:
\begin{lstlisting}[caption=CsoundObj setup code]
- (void)viewDidLoad
{
[super viewDidLoad];
self.csound = [[CsoundObj alloc] init];
NSString *csdPath = [[NSBundle mainBundle] pathForResource:@"audiofiletest" ofType:@"csd"];
[self.pitchKnob setMinimumValue:0.5f];
[self.pitchKnob setMaximumValue:2.0f];
[self.pitchKnob setValue:1.0f];
[self.csound addBinding:self.pitchKnob];
[self.csound play:csdPath];
}
\end{lstlisting}
\begin{lstlisting}[caption=CsoundObj Swift 3 setup code]
override func viewDidLoad() {
super.viewDidLoad()
title = "10. Soundfile: Pitch Shifter"
csound = CsoundObj()
let csdPath = Bundle.main.path(forResource: "audiofiletest", ofType: "csd")
pitchKnob.minimumValue = 0.5
pitchKnob.maximumValue = 2.0
pitchKnob.value = 1.0
csound.addBinding(self.pitchKnob)
csound.play(csdPath)
}
\end{lstlisting}
The ControlKnob widget is custom UIView that is also a CsoundBinding. It uses a hardcoded Csound channel called "pitch". After the CsoundObj object is setup and started, performance of the audio file is done in the callback to the Play button press:
\begin{lstlisting}[caption=Play button callback code]
- (IBAction)play:(UIButton *)sender
{
NSString *audioFilePath = [[NSBundle mainBundle] pathForResource:@"audiofiletest" ofType:@"aif"];
NSString *score = [NSString stringWithFormat:@"i1 0 1 \"%@\"", audioFilePath];
[self.csound sendScore:score];
}
\end{lstlisting}
\begin{lstlisting}[caption=Play button Swift 3 callback code]
@IBAction func play(_ sender: UIButton) {
let audioFilePath = Bundle.main.path(forResource: "testAudioFile", ofType: "aif")
if audioFilePath != nil {
let score = "i1 0 1 \"\(audioFilePath!)\""
csound.sendScore(score)
}
}
\end{lstlisting}
\subsection{Mic: Stereo Delay}
\emph{Mic: Stereo Delay} shows how to process audio in realtime, with independent delay and feedback settings for each channel. The use of audio input is controlled by the standard Csound flag \textbf{-i adc} that is found in the CSD's \textbf{CsOptions} section.
\subsection{Mic: Harmonizer}
\emph{Mic: Harmonizer} using Csound's streaming Phase Vocoder to create a harmonizer effect and the user can control the balance between the original and harmonized sound.
\subsection{Mic: Recording}
\emph{Mic: Recording} demonstrates the recording feature of CsoundObj. It also includes a custom metering widget that implements \textbf{CsoundBinding} to read values from Csound. Note that the \textbf{updateValuesFromCsound} reads the minimum necessary values from Csound and then continues further calculations off the audio callback thread where \textbf{updateValuesFromCsound} is called. It is important to minimize the amount of processing done in the audio callback thread and to push all processing to another thread. This can be done using the standard \textbf{performSelector} method; upon completing calculations, updates to the UI will need to be done on the main thread, which is done here using \textbf{performSelectorOnMainThread}. This pattern is common in audio processing applications.
\subsection{Hardware: MIDI Controller}
\emph{Hardware: MIDI Controller} shows how to use an external device to send MIDI Note and Controller Messages to Csound and also demonstrates an on-screen virtual MIDI keyboard class.
\begin{enumerate}
\item In the \textbf{viewDidLoad}, a \textbf{MidiWidgetsManager} is created and used to map MIDI controller values to sliders.
\item MIDI keyboard and controller input is also routed to Csound using CsoundObj's \textbf{setMidiInEnabled} method. This allows using standard Csound MIDI programming within the context of a Csound for iOS project. (This has been tested on iPad 1 and 2, using a Korg NanoKey connected via Apple USB Camera Connection kit, as well as with MIDI keyboards hooked up to an Alesis I/O Dock.)
\item A custom multi-touch virtual keyboard widget demonstrates how to track the different touches, map them to keyboard keys, and use \textbf{sendScore} to turn on and off notes.
\end{enumerate}
For those interested in making virtual instruments, this example may be useful to use as a starting point for your own projects.
\subsection{Hardware: Motion Control}
\emph{Hardware: Motion Control} shows how to use the device's motion sensor data as a set of controllers for Csound, and also displays this data in a set of UILabels. Accelerometer X controls oscillator frequency, Attitude: Yaw controls filter cutoff, Attitude: Pitch controls amplitude, and Attitude: Roll controls filter resonance.
\subsection{XY Pad: Multitouch}
\emph{XY Pad: Multitouch} demonstrates a multitouch performance surface. The multitouch code maps each touch down and up to a note on and off. It also sends continuous X and Y values to Csound. Each touch is dynamically assigned and mapped to a unique instance of the Csound instrument in the CSD.
\subsection{XY Pad: Mic PitchShift+Mix}
\emph{XY Pad: Mic PitchShift+Mix} uses Csound's 'PVS' realtime streaming spectral opcodes to perform pitch shifting on a signal coming in from the microphone. It uses a custom ControlXYGrid widget that allows controlling the mix of the wet and dry signal along the X-axis and the amount of pitch shifting along the Y-axis.
%======
\section{Conclusion}
We hope that this document has helped you to become familiar with the design and usage of the Csound for iOS API. The example Objective-C, Swift, and Csound CSD code should hopefully give you a good starting point for your own musical projects, and we encourage you to take these examples and run with it. We look forward to hearing your questions and feedback on this API, and most of all, we look forward to seeing and using your Apps, and hearing the music and sounds that you create with them.
\end{document}