SuperCollider: drawing UGen graph

Many people find it useful to see graphically the network of unit generators in their SynthDefs. There is a Quark that will create a Graphviz .dot file from your SuperCollider code.

First, install Graphviz (of course). There are downloads for OSX, Linux, and others.

Then you need to install the rd_dot Quark. If you’ve never dealt with Quarks before, it is rather simple to install them. In your SuperCollider interpreter, type this:

Quarks.gui;

You will get a GUI window of all the available Quarks. The first time you run this the list will probably be empty. Press the Update Quark Listing button. Depending on your security settings, you may be prompted to accept their certificate. There will be a local listing written to your ~/Library/Application Support/SuperCollider/quarks directory. You might not get the listing refreshed immediately in your GUI windows after the process is finished. Simple kill the GUI and start it again.

Then, find the rd_dot quark. Click on the icon to the left of the name so it now reads +. Now press the Apply button in the “toolbar”. The rd_dot quark will be installed in your quarks directory.

Recompile your class library. It’s on the Language menu. Rebooting the interpreter will do it.

Try it out by changing the play method in your hacks to draw. Here’s a simple sine wave:

{SinOsc.ar()}.play;

Change play to draw:

{SinOsc.ar()}.draw;

When you interpret this now, you will get this displayed in Graphviz:

UGen graph

Possible glitch

If you have Word installed (I had a shotgun aimed at me), the file will open in Word since .dot files are associated with Word. The rd_dot quark writes a Graphviz .dot file to your tmp directory. An easy way to fix the association is to open any .dot file in the Finder inspector. Select it in Finder and press cmd-I. One of the sections in the inspector is Open With. Select SuperCollider from the option menu and apply to all.

If you want Word to remain associated with .dot files, you’ll have to hack the rd_dot code. It uses a simple call to open without any parameters, which is why Word is used. Change the open call to

open -a /Applications/SuperCollider/SuperCollider.app/
Posted in Computer Music, SuperCollider | Tagged , | Leave a comment

SuperCollider with Emacs on OSX

SuperCollider (Github) has a decent IDE these days. But perhaps you’d like to use an actual editor like Emacs.

Sam Aaron published an article on this, but it is badly outdated. It was also overly complicated including copying several core directories out of the app. He’s probably too busy doing his good work with Overtone to update it. You should check out Overtone, by the way.

You need to get the current source for scmode. There is no separate repo, so you need the whole SuperCollider repo. Once you clone the repo, the scmode code is under supercollider/editors/scel. The contents of the sc directory needs to be copied to the Extensions directory of your application support directory. You can discover the location of your application support directory by evaluating this in the SuperCollider interpreter:

Platform.userAppSupportDir;

On OSX that will be ~/Library/Application Support/SuperCollider, so copy scel to ~/Library/Application Support/SuperCollider/Extensions, creating the directory if it doesn’t already exist.

git clone https://github.com/supercollider/supercollider.git
cd supercollider/editors/scel
sudo mkdir ~/Library/Application\ Support/SuperCollider/Extensions
sudo cp -r sc ~/Library/Application\ Support/SuperCollider/Extensions

You need to add the contents of supercollider/editors/scel/el to your load path. You can just point to where you cloned the git repo, but I prefer to have my emacs lisp in a logical place. I copied the el directory to ~/.emacs.d/vendor/scel/el directory.

Add this to your init file:

(add-to-list 'load-path "~/.emacs.d/vendor/scel/el")
(require 'sclang)

You need to set your path within Emacs also. The sclang program is located in /Applications/SuperCollider/SuperCollider.app/Contents/Resources, so that needs to be in your path.
(For hacking in iTerm, I’ve also added it to my PATH in my bash startup file).

(setenv "PATH" (concat (getenv "PATH") ":/Applications/SuperCollider:/Applications/SuperCollider/SuperCollider.app/Contents/Resources"))
(setq exec-path (append exec-path '("/Applications/SuperCollider"  "/Applications/SuperCollider/SuperCollider.app/Contents/Resources" )))

Launch Emacs. When the dust settles, type

M-x sclang-start

The interpreter will start in a buffer named SCLang:PostBuffer and you will be presented with a new buffer named SCLang:Workspace.

Start the server in the workspace.

s = Server.local;
s.boot;

There will be a SCLang menu and you can execute commands from there. You’ll see the C-x C-f will evaluate the entire document. (Or type C-c C-p b to boot. Of course you can type C-h m to get the help for sclang mode).

Create a simple noisemaker.

{[SinOsc.ar(440, 0, 0.2), SinOsc.ar(442, 0, 0.2)]}.play;

C-c C-s will stop playing.

Have fun!

Posted in Computer Music, Emacs, SuperCollider | Tagged , | Leave a comment

JDK 8, OSX, and Netbeans

Have you installed an Early Access Release of JDK 8? You may want to still use JDK 7 for some projects. I have a JavaFX 2 project that needs JDK 7 since there will be API changes in JDK8.

I’ve previously covered using non Apple JDKs on Mountain Lion. Unfortunately, that doesn’t affect NetBeans default JDK.

When you look at the JDKs in NetBeans, you will see one is the “default”. There is no setting to change it to another JDK. So, if you just installed JDK 8, then that is your default now. You can go to individual project and set which JDK you need for that project. But if you want to set the default JDK, you have to change a NetBeans config file.

Edit this file:

/Applications/NetBeans/NetBeans 7.3.app/Contents/Resources/NetBeans/etc/netbeans.conf

You want to change the key netbeans_jdkhome like this:

netbeans_jdkhome=(/usr/libexec/java_home -v 1.7)

Nope, doesn’t work. That’s a shell command and we’re in just a properties file. So, this doesn’t work either:

netbeans_jdkhome=$JAVA_HOME

You need to be explicit.

netbeans_jdkhome="/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home"

You can still get the fully qualified path to a particular version of a JDK by typing this in a shell:

/usr/libexec/java_home -v 1.7
Posted in Java, NetBeans | Tagged , , | Leave a comment

JDK 7 and JavaFX 2

Some good news about JavaFX. It is now bundled with the JDK so you don’t need to download a separate installer.

Some bad news: the runtime is not on the classpath. (In Java 8, it will be on the classpath).

A simple fix is to do this:

cd /Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home/jre/lib
sudo cp jfxrt.jar ext
Posted in JavaFX | Tagged | Leave a comment

JDK 7 on OSX

You can download a dmg from Oracle’s download page. You might expect that you’d run the installer and you’d be ready to go. Not me.

I had previous versions of Java installed. In my startup file (.bash_profile) I had set this:

export JAVA_HOME=/Library/Java/Home/

With this set, java -version still reported 1.6.

I set it to this and things worked.

export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home

That’s a bit clunky. There is a better way.

export JAVA_HOME=$(/usr/libexec/java_home)

If you want to use another version, e.g. 1.6

export JAVA_HOME=$(/usr/libexec/java_home -v 1.6)
Posted in Java | Tagged , | 1 Response

jQuery UI 1.10 tabs

The release notes for jQuery UI 1.10.0 lists the API changes.

To handle a tab selection, you previously had to use the tab index and add a handler on the select event.

The select event is gone now. You use activate in the new API.

The index is gone too. Now you use the newPanel attribute on the tab parameter in your activate handler. You can use the newPanel’s selector attribute to determine which tabs was just selected. Oops. I mean activated.

function handleTabSelect(event, tab) {
         if (tab.newPanel.selector === "#tabone") {
...

Play with it at JSBin:

JS Bin

Here is a Gist if you prefer that.

Posted in Javascript, jQuery, jQuery UI | Leave a comment

Spring @MVC configuration without XML

XML is no longer hip. Actually, there is nothing as unhip as last year’s hip. That is until it becomes hip again 30 years later in failed irony.

Honestly, if you’ve been programming Java EE since the 90s, you know full well how error prone XML config files can be. A glance at an EJB XML config file – especially the CMP relationship config from version 2 – would make any sane person run screaming into the night. Tools were supposed to help, but they really didn’t.

Even the Spring Framework, a music major’s wildly successful solution to Java EE’s problems, has been inundated by XML config files. Until now.

Let’s see how we can configure a Spring @MVC web app with no XML.

Java EE update

Starting with the Servlet 3.0 specification, we can do away with the venerable WEB-INF/web.xml configuration file. In order to do this you must do the following:

  1. Write a class that implements javax.servlet.ServletContainerInitializer
  2. Create a file named META-INF/services/javax.servlet.ServletContainerInitializer which contains the fully qualified name of your implementation.

Spring

Beginning with release 3.1, Spring provides an implementation of the ServletContainerInitializer interface aptly named SpringServletContainerInitializer. Take a peek inside spring-web-[version 3.1 and above].jar and you’ll see the META-INF/services file mentioned above.

The SpringServletContainerInitializer class delegates to an implementation of
org.springframework.web.WebApplicationInitializer that you provide. There is just one method that you need to implement: WebApplicationInitializer#onStartup(ServletContext). You are handed the ServletContext that you need to initialize.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class WebAppInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext servletContext) {
      WebApplicationContext appContext = set up the context
 
      ServletRegistration.Dynamic dispatcher =
        servletContext.addServlet("dispatcher", new DispatcherServlet(appContext));
      dispatcher.setLoadOnStartup(1);
      dispatcher.addMapping("/");
    }
 
 }

Setting up the app contexts

Since we are avoiding writing XML config files, I suggest that instead of using the XmlWebApplicationContext class, use the AnnotationConfigWebApplicationContext which supports classpath scanning for Spring annotation based configuration. You can explicitly add configuration classes, or have the context scan for them.

To start up and shut down the context, we add a ContextLoaderListener.

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
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
 
   // Create the root appcontext
   AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
   rootContext.register(RootConfig.class);
   // since we registered RootConfig instead of passing it to the constructor
   rootContext.refresh(); 
 
   // Manage the lifecycle of the root appcontext
   servletContext.addListener(new ContextLoaderListener(rootContext));
   servletContext.setInitParameter("defaultHtmlEscape", "true");
 
   // now the config for the Dispatcher servlet
   AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
   mvcContext.register(WebMvcConfig.class);
 
   // The main Spring MVC servlet.
   ServletRegistration.Dynamic appServlet = servletContext.addServlet(
      "appServlet", new DispatcherServlet(mvcContext));
		appServlet.setLoadOnStartup(1);
   Set<String> mappingConflicts = appServlet.addMapping("/");
 
   if (!mappingConflicts.isEmpty()) {
      for (String s : mappingConflicts) {
         logger.error("Mapping conflict: " + s);
      }
      throw new IllegalStateException(
         "'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14");
   }
}

Java config files

The RootConfig Java class we specified in the previous example needs to use the @Configuration annotation. Essentially this class corresponds to the <beans> element in Spring XML config files. The <bean> elements are now methods with the @Bean annotation that return a bean instance. The <context:component-scan> element is now the class level annotation @ComponentScan.

1
2
3
4
5
6
7
8
9
10
@Configuration
@ComponentScan(basePackages = { "com.rockhoppertech.mvc.service",
		"com.rockhoppertech.mvc.repositories.internal" })
public class RootConfig {
 
   @Bean public SomeClass someClass() { 
      return someInstance;
   }
 
}

Filters

You can also create any Servlet Filters here. Here are a few Spring provided Filters.

In this example I set up the CharacterEncodingFilter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
 
...
 
   FilterRegistration.Dynamic fr = servletContext.addFilter("encodingFilter",  
      new CharacterEncodingFilter());
   fr.setInitParameter("encoding", "UTF-8");
   fr.setInitParameter("forceEncoding", "true");
   fr.addMappingForUrlPatterns(null, true, "/*");
...
 
}

@Enable*

XML namespaces are replaced by class level annotations that begin with @Enable.

  • @EnableWebMvc
  • @EnableAsync
  • @EnableScheduling
  • @EnableLoadTimeWeaving
  • @EnableTransactionManagement

Right now we configure MVC using the mvc: XML namespace, for example: <mvc:annotation:driven/>. The @EnableWebMvc annotation is the replacement.

Spring MVC configuration

Write a configuration class that contains the @EnableWebMvc annotation, which is defined by DelegatingWebMvcConfiguration. In addition, you will probably do a component scan for controllers here.

To customize the defaults, implement WebMvcConfigurer or extend WebMvcConfigurerAdapter. Any overridden method that does not return NULL will use that value instead of the default.

1
2
3
4
5
6
7
8
@Configuration
@EnableWebMvc
// scan for controllers
@ComponentScan(basePackages = { "com.rockhoppertech.mvc.web" })
public class WebMvcConfig extends WebMvcConfigurerAdapter {
   @Bean ViewResolver viewResolver() { ... }
   @Bean MessageSource messageSource() { ... }
etc.

Resources

Posted in Spring MVC | Tagged , | 2 Responses

Eclipse JavaScript Libraries Validation

I use several JavaScript libraries in my web apps. Just one of the many reasons I like Spring MVC over other web frameworks – like JSF – is that you can easily use current web technologies. HTML5? CSS3? jQuery? No problem!

Actually there is one problem, but it’s an Eclipse (or Spring STS) problem. When you add JavaScript to your project, Eclipse will validate the code. This is what I want when I am developing code! But I don’t want to debug or modify third party code. The Eclipse validator will almost always complain about minified versions of JavaScript files.

Project with JavaScript validation errors

Click to Enlarge

You can turn off validation. Problem solved. You can also remove squirrels from your backyard bird feeders with a bazooka.

A better solution

  • Open the project’s properties dialog. (right click, properties or Command-I)
  • Select JavaScript then Include Path from the tree on the left.
  • Select the Source tab in the property sheet.
  • Select the Excluded node from the project tree.
  • Press the Edit button.
  • In the modal dialog that pops up, add an Exclusion Pattern.

I put third party JavaScript in src/main/webapp/resources/js/libs and my own JavaScript in src/main/webapp/resources/js. So I add only src/main/webapp/resources/js/libs as an exclusion pattern. Then I no longer see jQuery, modernizr, or bootstrap errors, but I do see JavaScript errors in the code that I’m developing.

Eclipse JavaScript Validation

Click to Enlarge

Posted in Eclipse, jQuery, Spring MVC | Tagged , | Leave a comment

iOS Audio Unit Graph

Apple’s Core Audio API is very powerful. It is also not easy. With Great Power comes Great Heartburn when the documentation is out of date and/or scattered. Sometimes the needs of the few outweigh the needs of the many as in the case of conference talks. At WWDC 2011, session 411 was named “Music in iOS and Lion” (see the Resources). If you watch the presentation, you wil get a taste of what is possible. Unfortunately they were as stingy with code examples as Webern was with notes. (The goal of conference presentations is to show off, and not to educate the viewers. Not picking on these guys, but this has been true of every presentation I’ve ever seen).

So, here is a first step. It is a complete project that runs and produces sound. Many things are missing – on purpose – which will be added in subsequent blog posts. The point is to get the main point across in the simplest manner possible.

Core Audio is a C API. Currently there are no official Objective-C bindings. So, you need to mix your Objective-C code with C code. In more advanced code you will be using many Core Foundation types too, so get comfortable with this intermixing. You will also use classes such as AUGraph from the AudioToolbox framework. So, in your project setup, (under build phases in XCode 4+) you need to link to the AudioToolbox framework and the CoreAudio framework. You do not link to the AudioUnit framework here. If you do, you will get an error.

Most CA (Core Audio) API functions return an OSStatus value. This is a 32 bit integer.

OSStatus NewAUGraph ( AUGraph *outGraph );

The function to set up your graph is NewAUGraph. Here is one way to handle the result.

1
2
3
4
5
6
AUGraph outGraph;
OSStatus result = noErr;
result = NewAUGraph ( &outGraph );
if(result != noErr) {
   // handle it
}

Chris Adamson (see the Resources) wrote a function that many programmers use to display the status as a string if possible. If not he prints the digit. This is a bit like the old original Mac toaster that would pop up a dialog stating “Error -151 Occurred”. So, I’ve added a switch statement that checks the value against well known error constants.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void CheckError(OSStatus error, const char *operation) {
	if (error == noErr) return;
 
	char str[20];
	// see if it appears to be a 4-char-code
	*(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
	if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
		str[0] = str[5] = ''';
		str[6] = '';
	} else {
		// no, format it as an integer
		sprintf(str, "%d", (int)error);
	}
	fprintf(stderr, "Error: %s (%s)n", operation, str);
 
      switch(error) {
        case kAUGraphErr_NodeNotFound:
many more...

Using this utility function, your code will look like this instead.

CheckError(NewAUGraph(&outGraph),"NewAUGraph");

You will find some examples on the net that mix CA code into their View Controllers. I’d rather not. So, I created a regular class named GDSoundEngine that will contain all of the CA and Audio Unit frobs. The View Controller will simply tell the SoundEngine to do the things specified in its public interface, such as playNoteOn:velocity.

For example, this is how the view controller interacts with the sound engine. The note value is from the tag set on the UIButton from the storyboard.

- (IBAction)noteOn:(UIButton *)sender {
    UInt32 velocity = 100;
    [self.soundEngine playNoteOn:[sender tag] :velocity ];
}
- (IBAction)noteOff:(UIButton *)sender {
    [self.soundEngine playNoteOff:[sender tag] ];
}

Here is the setup in the View Controller.

1
2
3
4
5
6
7
8
9
10
11
12
13
@interface GDViewController ()
@property (strong) id soundEngine;
@end
 
@implementation GDViewController
@synthesize soundEngine = _soundEngine;
 
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.soundEngine = [[GDSoundEngine alloc] init];
}
etc.

The SoundEngine has a private interface with properties for the audio guts.

1
2
3
4
5
6
7
@interface GDSoundEngine()
@property (readwrite) AUGraph processingGraph;
@property (readwrite) AUNode samplerNode;
@property (readwrite) AUNode ioNode;
@property (readwrite) AudioUnit samplerUnit;
@property (readwrite) AudioUnit ioUnit;
@end

Notice that for each AUNode there is a corresponding AudioUnit. We will step through the details for each of these now.

Build an Audio Processing Graph

Here are the steps to build an Audio Unit Graph.

  1. Instantiate an AUGraph with the function NewAUGraph.
  2. Instantiate one or more AUNodes, each of which represents one audio unit in the graph. To create and add the nodes to the graph, use the function AUGraphAddNode.
    You first create an AudioComponentDescription to pass into this function.
  3. Open the graph and instantiate the audio units with the function AUGraphOpen.
  4. Obtain references to the audio units with the function AUGraphNodeInfo.

Step 1. The AUGraph is a property named processingGraph. In the implementation I use the underscore pattern for the instance variable. Then in the graph init method, the graph is created.

1
2
3
4
5
6
7
@synthesize processingGraph = _processingGraph;
...
- (BOOL) createAUGraph
{
    CheckError(NewAUGraph(&_processingGraph),
			   "NewAUGraph");
...

Here is an example of step 2. The AudioComponentDescription is set up first. The componentSubType field here is set to kAudioUnitSubType_Sampler. This AU was added in iOS 5. Then the AUNode is instantiated and added to the graph with AUGraphAddNode. Note that _samplerNode is the property’s instance variable.

1
2
3
4
5
6
7
8
9
    // create the sampler
    // for now, just have it play the default sine tone
    AudioComponentDescription cd;
    cd.componentType = kAudioUnitType_MusicDevice;
    cd.componentSubType = kAudioUnitSubType_Sampler;
    cd.componentManufacturer = kAudioUnitManufacturer_Apple;
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;
    CheckError(AUGraphAddNode(self.processingGraph, &cd, &_samplerNode), "AUGraphAddNode");

The RemoteIO AU is created in the same manner.

1
2
3
4
5
6
7
8
    // I/O unit
    AudioComponentDescription iOUnitDescription;
    iOUnitDescription.componentType          = kAudioUnitType_Output;
    iOUnitDescription.componentSubType       = kAudioUnitSubType_RemoteIO;
    iOUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
    iOUnitDescription.componentFlags         = 0;
    iOUnitDescription.componentFlagsMask     = 0;
    CheckError(AUGraphAddNode(self.processingGraph, &iOUnitDescription, &_ioNode), "AUGraphAddNode");

Now in step 3 we can instantiate the Audio Units from the AUNodes. The AUGraph needs to be open via AUGraphOpen for this to work.

1
2
3
4
5
6
7
8
    // The graph needs to be open before you call AUGraphNodeInfo
   CheckError(AUGraphOpen(self.processingGraph), "AUGraphOpen");
 
   CheckError(AUGraphNodeInfo(self.processingGraph, self.samplerNode, NULL, &_samplerUnit), 
               "AUGraphNodeInfo");
 
   CheckError(AUGraphNodeInfo(self.processingGraph, self.ioNode, NULL, &_ioUnit), 
               "AUGraphNodeInfo");

In step 4, we wire the Audio Units together with AUGraphConnectNodeInput.

1
2
3
4
5
6
7
 
    AudioUnitElement ioUnitOutputElement = 0;
    AudioUnitElement samplerOutputElement = 0;
    CheckError(AUGraphConnectNodeInput(self.processingGraph, 
                                       self.samplerNode, samplerOutputElement, // srcnode, inSourceOutputNumber
                                       self.ioNode, ioUnitOutputElement), // destnode, inDestInputNumber
               "AUGraphConnectNodeInput");

For debugging there is a function named CAShow that will display the current state of audio objects.

1
CAShow(self.processingGraph);

The completed graph setup method

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
- (BOOL) createAUGraph
{
    NSLog(@"Creating the graph");
 
    CheckError(NewAUGraph(&_processingGraph),
			   "NewAUGraph");
 
    // create the sampler
    // for now, just have it play the default sine tone
    AudioComponentDescription cd;
    cd.componentType = kAudioUnitType_MusicDevice;
    cd.componentSubType = kAudioUnitSubType_Sampler;
    cd.componentManufacturer = kAudioUnitManufacturer_Apple;
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;
    CheckError(AUGraphAddNode(self.processingGraph, &cd, &_samplerNode), "AUGraphAddNode");
 
 
    // I/O unit
    AudioComponentDescription iOUnitDescription;
    iOUnitDescription.componentType          = kAudioUnitType_Output;
    iOUnitDescription.componentSubType       = kAudioUnitSubType_RemoteIO;
    iOUnitDescription.componentManufacturer  = kAudioUnitManufacturer_Apple;
    iOUnitDescription.componentFlags         = 0;
    iOUnitDescription.componentFlagsMask     = 0;
    CheckError(AUGraphAddNode(self.processingGraph, &iOUnitDescription, &_ioNode), "AUGraphAddNode");
 
    // now do the wiring. The graph needs to be open before you call AUGraphNodeInfo
	CheckError(AUGraphOpen(self.processingGraph), "AUGraphOpen");
 
	CheckError(AUGraphNodeInfo(self.processingGraph, self.samplerNode, NULL, &_samplerUnit), 
               "AUGraphNodeInfo");
 
    CheckError(AUGraphNodeInfo(self.processingGraph, self.ioNode, NULL, &_ioUnit), 
               "AUGraphNodeInfo");
 
    AudioUnitElement ioUnitOutputElement = 0;
    AudioUnitElement samplerOutputElement = 0;
    CheckError(AUGraphConnectNodeInput(self.processingGraph, 
                                       self.samplerNode, samplerOutputElement, // srcnode, inSourceOutputNumber
                                       self.ioNode, ioUnitOutputElement), // destnode, inDestInputNumber
               "AUGraphConnectNodeInput");
 
 
	NSLog (@"AUGraph is configured");
	CAShow(self.processingGraph);
 
    return YES;
}

Starting the graph

Once the graph has been setup, you are ready to start processing by calling the function AUGraphInitialize. This calls the AudioUnitInitialize function of each Audio Unit in the graph. It also validates the graph’s connections and audio data stream formats. Finally, the graph is started with AUGraphStart.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void) startGraph
{
    if (self.processingGraph) {
        Boolean outIsInitialized;
        CheckError(AUGraphIsInitialized(self.processingGraph,
                                        &outIsInitialized), "AUGraphIsInitialized");
        if(!outIsInitialized)
            CheckError(AUGraphInitialize(self.processingGraph), "AUGraphInitialize");
 
        Boolean isRunning;
        CheckError(AUGraphIsRunning(self.processingGraph,
                                    &isRunning), "AUGraphIsRunning");
        if(!isRunning)
            CheckError(AUGraphStart(self.processingGraph), "AUGraphStart");
        self.playing = YES;
    }
}

Sending a note to the sampler

The final task is to define the public methods that are called by the View Controller. Here, the function MusicDeviceMIDIEvent sends a MIDI message to the sampler audio unit. For example, 0×90 is the MIDI note on message for channel 0.

1
2
3
4
5
6
7
8
9
10
11
12
- (void)playNoteOn:(UInt32)noteNum :(UInt32)velocity 
{
    UInt32 noteCommand = 0x90;
    NSLog(@"playNoteOn %lu %lu cmd %lx", noteNum, velocity, noteCommand);
    CheckError(MusicDeviceMIDIEvent(self.samplerUnit, noteCommand, noteNum, velocity, 0), "NoteOn");
}
 
- (void)playNoteOff:(UInt32)noteNum
{
    UInt32 noteCommand = 0x80;
    CheckError(MusicDeviceMIDIEvent(self.samplerUnit, noteCommand, noteNum, 0, 0), "NoteOff");
}

Summary

That’s it for now. The sound that you will hear is a beautiful sine wave. In the next blog post, I will show you how to set up the sample unit to use sounds from a DLS file or a SountFont2 file.

Resources

Posted in iOS | Tagged , | 2 Responses

Learning Clojure: Setting up the Emacs on OSX

I’ve been using the Emacs since my Lisp and AI course back in 1987. (My use of the definite article betrays that :) ) So, of course I wanted to learn Clojure using it. Unfortunately, there are either incomplete or conflicting posts in googlespace on how to go about doing this. You *can* grab the source with git and build etc., but let’s try the simplest thing possible.

xkd comic

There are two ways to have the Emacs interact with Clojure: inferior-lisp-mode and Slime. I will cover both here.

Initial setup

Clojure runs on the JVM (there are separate projects for the CLR and also ClojureScript), so you should have a JDK version 1.5 or later installed. If you have not set up Leiningen, or even know what that is, please read the first article in this series on setting that up.

Emacs

I was using Emacs 23. It is a bit more difficult setting it up and managing 23 since integration with the Emacs Lisp Package Archive isn’t baked in. So, just get Emacs 24.

For OSX, get the latest Emacs 24 pretest build. I – and many others – have been using it with no problems in spite of it not being a “release.”

Of course I had my Emacs init files. You may have either a ~/.emacs or ~/.emacs.d/init.el lying around. I renamed them (e.g. .emacs.d.bak) to start fresh and then launched Emacs. Just a reminder, if you have a ~/.emacs file, ~/.emacs.d/init.el will be ignored.

I edited my new ~/.emacs.d/init.el to include an additional elisp repository which hosts clojure-mode and paredit.

(require 'package)
(add-to-list 'package-archives
             '("marmalade" . "http://marmalade-repo.org/packages/") t)
(package-initialize)

Go ahead and evaluate the buffer (M-x eval-buffer).

The sequence of Emacs commands follows. You first refresh the local list of available packages and writes that list into a directory in your ~/.emacs.d. This will take bit of time. Then you install the clojure-mode package.

M-x package-refresh-contents
M-x package-install RET clojure-mode RET

If you want, you can run M-X package-list-packages to see what’s there, but I suggest that you don’t blindly add packages without first knowing if they play nicely together.

Inferior Lisp mode

Edit your ~/.emacs.d/init.el again and add these lines. If you’re not on OSX, ignore the third line which changes the Meta key from the Option key to the Command key.

(setq inferior-lisp-program "lein repl")
 
;; where is lein located? If it's not in a "standard path, add a line like this.
(add-to-list 'exec-path "/Users/gene/bin")
 
;; on OSX make the command key the meta key
(setq ns-command-modifier 'meta)

Now we can launch a REPL in a subprocess within the Emacs. This is Inferior Lisp Mode.
Open up a test clojure file (e.g. C-x f foo.clj), or navigate to a lein project you created in the first article in this series and edit or create one there.
Enter M-x run-lisp (or C-c C-z).
This will tell lein to start a REPL, since that is what you set the variable inferior-lisp-program to.
Now split the window by typing C-x 2. In one of the windows, navigate to your Clojure file.
Enter a simple sexp. Then after the final ), type C-x C-e to evaluate it. (clojure-mode binds this key sequence to lisp-eval-last-sexp, as well as C-c C-e so you don’t have to remember which!. As always, you can type M-x m for mode info.) You will see the result in the *inferior-lisp* REPL buffer.

(+ 2 2)

You can also go into the REPL buffer and type expressions there and they will be evaluated. Editing is fairly basic, but it may be all that you need. Indeed, if you’ve seen the screencasts by Rich Hickey,the creator of Clojure, you will see that he is using inferior Lisp mode.

Clojure mode key bindings.

C-c C-e evaluate expression to the left of the cursor
C-x C-e same thing
C-c C-r evaluate expression in region
C-c C-z run lisp
C-M-x evaluate defn
C-M-q indent
There are others. Type M-x m for more.

 

inferior-lisp

Slime

The Superior Lisp Interaction Mode for Emacs (Slime) has many more features, including a debugger, and code completion. It was written for other Lisps and is based on a client server model. Slime is the Emacs client and Swank is the “server”. That means you can run Clojure on a different machine if you’d like. For this article, we’ll stick with using it locally.

Swank

Since you already are using Leiningen, simply add the swank plugin. It will be downloaded to ~/.lein/plugins.

$ lein plugin install lein-swank 1.4.4
Including lein-swank-1.4.4.jar
Created lein-swank-1.4.4.jar
$

You can check current versions like this:

$ lein search lein-swank

Navigate to your project: using dired is easiest. Then do this:

M-x clojure-jack-in

This starts a Swank server, then uses Slime to connect to it from Emacs.
If you get an error stating that lein cannot be found, see OSX quirks.
Slime’s keybindings are a bit different from Inferior Lisp mode. I suggest that you type M-x m and scroll down to the Slime section or read the Swank Clojure Readme.

Since your are still learning Clojure, Slime’s inspector is quite handy. Place the cursor after a symbol or expression and type C-c I (I as in Inspector). The minibuffer will ask for confirmation and then display the result.
The other handy exploration function is slime-edit-definition. Place the cursor after a function, e.g. after the + in (+ 2 2), then type M-. (meta period). The source code for the definition of + will appear in a buffer.
Visit Slime’s home page for more information. There is a screencast there now showing it in action with Common Lisp.

slime

Alternatives

There are two alternative ways of specifying that you want to use Swank: through a project independent profile and inside a project.

For the global profile, add this to ~/.lein/profiles.clj

{:user {:plugins [ [lein-swank "1.4.4"] ]}}

Or add this to your project.clj if you want it inside your project. I prefer to not do this since other team members might be using another editor.

(defproject lein01 "1.0.0-SNAPSHOT"
  :description "test project"
  :plugins [[lein-swank "1.4.4"]]

OSX quirk

Here are a few of my OSX specific entries from .emacs.d/init.el. I prefer to use the command key as Emacs’ meta key. If you placed the lein script outside of “normal” paths, (e.g. ~/bin) you may have a problem with lein not being found inside Emacs. If that is the case, you can add your PATH that you set in .bash_profile to Emacs.

;; on OSX make the command key the meta key
(setq ns-command-modifier 'meta)
 
;; Read in PATH from .bash_profile
(if (not (getenv "TERM_PROGRAM"))
     (setenv "PATH"
            (shell-command-to-string "source $HOME/.bash_profile &amp;&amp; printf $PATH")))

Emacs Starter Kit

I suggest that you also install Phil Hagelberg’s Emacs Starter Kit. It includes a good set of defaults, as well as ido-mode and paredit.

M-x package-install RET starter-kit RET

If you don’t want the starter kit, at least install paredit.

M-x package-install RET paredit RET

Then add this to your ~/.emacs.d/init.el

(autoload 'paredit-mode "paredit"
      "Minor mode for pseudo-structurally editing Lisp code." t)
(add-hook 'emacs-lisp-mode-hook    (lambda () (paredit-mode +1)))
(add-hook 'clojure-mode-hook       (lambda () (paredit-mode +1)))

Of course the starter kit does this for you. Read the documentation at the Emacs Wiki on how to use paredit mode.

Have fun.

Resources

Books

Posted in Clojure, IDE | Tagged , , , , | 2 Responses