an open-source digital signal processing and sound synthesis language
about · links · contact

iRTcmix Tutorials - Hello iRTcmix

Welcome to the wonderful world of iOS programming using iRTcmix! This tutorial is intended as a basic introduction to building an iOS application with iRTcmix. We will be using the code in the simple "Hello iRTcmix" application included in the "iRTcmix Basics" demo distribution on the iRTcmix page.

Although the "Hello iRTcmix" app is fully-coded in the distribution, we will take you through the steps we used to create the application, including how we use the RTcmixPlayer and RTcmixScore classes to start the RTcmix engine and parse the RTcmix score. Essentially we will be guiding you through the software coding involved to build the working "Hello iRTcmix" app. We will be starting from the basic set-up of the XCode project, with all the appropriate files and settings.

This tutorial is intended to be useful to programmers of all skill levels. However, some familiarity with XCode, the iOS SDK, and the Objective-C programming language is necessary. If you have yet to dabble in iOS programming you should head to your friendly neighborhood (or internet) bookstore and get a beginners guide to iOS programming. You don't need to master the SDK to get started with iRTcmix, but it will help to have a basic understanding of the principles of iOS programming. We also assume familiarity with RTcmix and digital music synthesis/processing in general.

Also, you will need to register with the Apple Developer Program in order to get started programming for iOS. Registration is free, but in order to test your programs on a device, you will need to subscribe to the $99/year program. Until then, you are limited to testing in the simulator that runs on the Mac.

Setting up an Xcode Project

The first thing you need to do is set up an Xcode project that has all the necessary files and settings. Instructions can be found on the iRTcmix Xcode Project Setup Guide page. After you have followed the instructions there to set up a blank project you will be ready to follow the tutorial below.

Configuring the ViewController

We are adopting the model-view-controller approach to programming an app, and we want to keep the logic and data for the program concentrated in one place. The iRTcmix-provided RTcmixPlayer and RTcmixScore classes already have the logic and data for audio production and score-parsing built into them. We'll trace the flow of control from a user-initiated event to the parsing/sending of a score to the RTcmix engine for audio realization. Two different methods for reading an RTcmix score are included in this demo.

When XCode builds a simple 'Single View Application' the ViewController class will look something like this:

ViewController.h:

	#import <UIKit/UIKit.h>

	@interface ViewController : UIViewController

	@end
ViewController.m:
	#import "ViewController.h"

	@implementation ViewController

	... followed by several methods for potential use in our app ...
First of all, let's add the code to allow the ViewController to address the RTcmixPlayer and RTcmixScore classes. We will be using these to control our audio system and manage our RTcmix score data. In the ViewController.h file, we make the following modifications:
	#import <UIKit/UIKit.h>
	#import "RTcmixPlayer.h"
	#import "RTcmixScore.h"

	@interface ViewController : UIViewController

	@property (nonatomic, strong)	RTcmixPlayer	*rtcmixManager;
	@property (nonatomic, strong)	RTcmixScore	*beepScore;
The
	#import "RTcmixPlayer.h"
	#import "RTcmixScore.h"
statements bring in the header files so that the ViewController "knows" about the actions possible with the RTcmixPlayer and RTcmixScore classes. We then declare two properties to access those classes (*rtcmixManager and *beepScore).

While we're at it, we'll add three method declarations that we will use for connecting to buttons on the interface (using the Interface Builder). These are declared as IBAction methods -- that's how XCode determines that they can be used for interface events:

	-(IBAction)goPlingScore; // executes an RTcmix score
	-(IBAction)goBeepScore; // executes an RTcmix score
	-(IBAction)flush; // clears all running scores
Our finished ViewController.h file now looks like this:
	#import <UIKit/UIKit.h>
	#import "RTcmixPlayer.h"
	#import "RTcmixScore.h"

	@interface ViewController : UIViewController

	@property (nonatomic, strong)	RTcmixPlayer	*rtcmixManager;
	@property (nonatomic, strong)	RTcmixScore	*beepScore;

	-(IBAction)goPlingScore; // executes an RTcmix score
	-(IBAction)goBeepScore; // executes an RTcmix score
	-(IBAction)flush; // clears all running scores

	@end
In the corresponding ViewController.m file, we modify the code to look like this:
	#import "ViewController.h"

	@interface ViewController ()

	@end

	@implementation ViewController

	-(IBAction)goPlingScore {
		// method 1 to play a score - parseScoreWithRTcmixScore:
		[self.rtcmixManager parseScoreWithRTcmixScore:self.beepScore];
	}

	-(IBAction)goBeepScore {
		// method 2 to play a score - parseScoreWithNSString:
		[self.rtcmixManager parseScoreWithNSString:@"WAVETABLE(0, 5, 24000, 440, .5)"];
	}

	-(IBAction)flush {
		// stop all running scores
		[self.rtcmixManager flushAllScripts];
	}
This codes the IBaction method calls (-goPlingScore, -goBeepScore and -flush) that we have added to our ViewController class.

Using the RTcmixPlayer and RTcmixScore Classes

In order to use the rtcmixManager property in our ViewController class, we need to set it up and make any necessary initializations and variable assignments. We do this by adding functionality to the XCode-generated -viewDidLoad method. This method gets called right after the application interface is loaded onto the iDevice, so it is appropriate that we use it to instantiate and start our RTcmix capabilities.

The -viewDidLoad method generated by XCode looks like this:

	- (void)viewDidLoad
	{
		[super viewDidLoad];
		// Do any additional setup after loading the view, typically from a nib.
	}
Our modified -viewDidLoad is this:
	- (void)viewDidLoad
	{
		[super viewDidLoad];

		// initialize the RTcmixPlayer and start audio.
		self.rtcmixManager = [RTcmixPlayer sharedManager];
		[self.rtcmixManager startAudio];

		// load the score from the file HelloiRTcmix.sco and assign it to beepScore
		NSString *scorePath = [[NSBundle mainBundle] pathForResource:@"HelloiRTcmix" ofType:@"sco"];
		NSString *scoreText = [NSString stringWithContentsOfFile:scorePath encoding:NSUTF8StringEncoding error:nil];
		[self.rtcmixManager addScore:@"helloScore" withString:scoreText];
	
		self.beepScore = [self.rtcmixManager.scoreDict objectForKey:@"helloScore"];
	}
The initial
	[super viewDidLoad];
statement invokes all the functionality of the "superclass" (in this case a 'UIViewController') to do all the actions necessary for iOS to run our application. We then add the following two lines:
	self.rtcmixManager = [RTcmixPlayer sharedManager];
	[self.rtcmixManager startAudio];
which assigns an instance of the RTcmixPlayer class to the property we declared (rtcmixManager). It initialized this using the -sharedManager method, which uses the singleton design pattern to ensure that that only one instance of the RTcmixPlayer class will be created in our application. This can be important in more complex RTcmix applications.

Once rtcmixManager has been assigned, we use the -startAudio method available from the RTcmixPlayer class to, well, start the audio.

The next three lines of code:

	NSString *scorePath = [[NSBundle mainBundle] pathForResource:@"HelloiRTcmix" ofType:@"sco"];
	NSString *scoreText = [NSString stringWithContentsOfFile:scorePath encoding:NSUTF8StringEncoding error:nil];
	[self.rtcmixManager addScore:@"helloScore" withString:scoreText];
are used to load and set up an RTcmix scorefile from the disk. In the Supporting Files folder of the "Hello iRTcmix" XCode project, there is a file called HelloiRTcmix.sco containing the following RTcmix score:
	pitches = { 7.00, 7.02, 7.05, 7.07, 7.10, 8.00, 8.07 }
	pitchArraySize = len(pitches)

	for (time = 0; time < 5; time = time+0.12) 
	{
		index = trand(0, pitchArraySize)
		note = pitches[index]
		STRUM2(time, .36, 16000, note, 1, 1.0, random())
	}	
You should copy this file into your project by dragging it from the "Hello iRTcmix" project into the "Supporting Files" group of your project. Make sure to check the box to "Copy items into destination group's folder (if needed)".

This is a fairly simple algorithmic RTcmix scorefile. We invoke it with our -goPlingScore method. To access the score, however, we need to find it in the Application bundle (on the "disk") and load it into memory. The

	NSString *scorePath = [[NSBundle mainBundle] pathForResource:@"HelloiRTcmix" ofType:@"sco"];
sets the *scorePath property to reference the "HelloiRTcmix.sco" in the Application bundle. The next line of code:
	NSString *scoreText = [NSString stringWithContentsOfFile:scorePath encoding:NSUTF8StringEncoding error:nil];
loads the text of the HelloiRTcmix.sco file into memory and sets the *scoreText property to reference it. We then add this text to our main rtcmixManager variable:
	[self.rtcmixManager addScore:@"helloScore" withString:scoreText];
which then allows us to reference the score via an RTcmixScore object that we have designated as our beepScore variable:
	self.beepScore = [self.rtcmixManager.scoreDict objectForKey:@"helloScore"];
Why do we have this complexity for scorefile loading? For very simple scores, we don't really need to do this score-loading and score-reencoding and score-adding operation (see the -goBeepScore method, discussed below). However, the RTcmixScore class has added functionality for RTcmix scores that use data coming from the application itself; i.e. 'outside' RTcmix. Several of the other demos included in the "iRTcmix_Demos" distribution show these capabilities.

Our final -viewDidLoad method then looks like this:

	- (void)viewDidLoad
	{
		[super viewDidLoad];

		// initialize the RTcmixPlayer and start audio.
		self.rtcmixManager = [RTcmixPlayer sharedManager];
		[self.rtcmixManager startAudio];

		// load the score from the file HelloiRTcmix.sco and assign it to beepScore
		NSString *scorePath = [[NSBundle mainBundle] pathForResource:@"HelloiRTcmix" ofType:@"sco"];
		NSString *scoreText = [NSString stringWithContentsOfFile:scorePath encoding:NSUTF8StringEncoding error:nil];
		[self.rtcmixManager addScore:@"helloScore" withString:scoreText];
	
		self.beepScore = [self.rtcmixManager.scoreDict objectForKey:@"helloScore"];
	}
Once the initializations are done in the -viewDidLoad method, using them from our interface is quite easy. The IBAction methods we coded are almost self-explanatory:
	-(IBAction)goPlingScore {
		// method 1 to play a score - parseScoreWithRTcmixScore:
		[self.rtcmixManager parseScoreWithRTcmixScore:self.beepScore];
	}
Invoking the -goPlingScore method calls the -parseScoreWithRTcmixScore method on our rtcmixManager, which both parses the score and then sends it to the RTcmix engine for realization into audio. This will happen every time this method is called. The -goBeepScore method is even simpler:
	-(IBAction)goBeepScore {
		// method 2 to play a score - parseScoreWithNSString:
		[self.rtcmixManager parseScoreWithNSString:@"WAVETABLE(0, 5, 24000, 440, .5)"];
	}
as it shows how to use an RTcmix score directly as text in the application.

The -flush IBAction method calls the -flushAllScripts method on the rtcmixManager:

	-(IBAction)flush {
		// stop all running scores
		[self.rtcmixManager flushAllScripts];
	}
which removes all currently-scheduled RTcmix events from the audio processing queue.

How do you then call our ViewController interface methods? That's when XCode is actually fun -- click on the ViewController.xib file and connect the actions of the interface elements to the appropriate ViewController interface method. So easy!

Build and Run, and it should just go!