Question

I'm trying to build iOS app for my inner work. This app is simple step midi sequencer. All what this app doing now is sending simple midi messages to the "network session" on same iPad - this session people call "Virtual Midi", sorry I don't know what the correct name is - but this is not matter, this part works fine for me and background apps (like animoog, ThumbJam, etc.) receive this messages fine...

The only main problem is that I faced with issue. When I'm sending midi notes in the LOOP (about 1/8, 1/16, no matter) and when application going to background (when I press home button) and I'm traveling in other apps, like Mail, Safari, or doing something in animoog, then it's lug/buggy/ each time., works with delay. For example "Genome Midi Sequencer" - not lugging when I'm traveling and doing something in Mail, Safari, or other apps - in other words even if any current application takes all resources in CPU - Genome Midi sequencer still sending midi messages without any delay. Why?

How I can build the same Ultra high priority NSThread?, which will be work without any delay even if I opened other app and it's load CPU? I noticed that when "Genome" app sending midi and I'm scrolling or touching inbox letters, then Mail app lugging - which is correct, because iOS give top priority for the Genome. I want the same.

Here is how I'm sending midi messages:

I'm sending Midi notes in the loop. So it's sound like Dm, Dm, Dm, Dm.....each 1/8. And it is important that between them there was no gap/delay in time. But it's buggy with delay some time.

  1. Main High priority NSThread

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(midiTimerTickTick) object:nil];
            [thread setThreadPriority:1];
            [thread start];
            [thread release];
    
  2. Method for the created thread

    -(void) midiTimerTickTick{
        uint64_t nextTime = mach_absolute_time();
        uint64_t timerInterval = 1000*1000*8;
        while (true){
            if(mach_absolute_time() >= nextTime)
            {
                //do work
                [self sendMidiMessage]; //Here piano playing
    
                //++
                nextTime+=timerInterval;
            }
        }        
    }
    
  3. In the AppDelegate.m file

    - (void)applicationDidEnterBackground:(UIApplication *)application
    {
        bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
            [application endBackgroundTask:bgTask]; //Tell the system that we are done with the tasks
            bgTask = UIBackgroundTaskInvalid; //Set the task to be invalid
            //System will be shutting down the app at any point in time now
        }];
    }
    
Was it helpful?

Solution

To start with, I would check the A Tasty Pixel blog by Michael Tyson for some basic timing information. Your current method is very inefficient and will use many many cpu cycles for no reason in particular. Essentially the CPU is constantly doing a comparison on the high priority thread, not a great idea.

The best way to solve your problem is to delve into Core Audio. This will allow you to schedule your samples in real time if your app is in the foreground or background, however, it does take some time to learn. A great way to get going quick for what you want to do is to run the Amazing Audio Engine which is also built by Michael, but has great support for quickly getting core audio up and running.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top