Search code examples
iosaudioobjective-c++soundtouch

iOS SoundTouch framework BPM Detection example


I have searched all over the web and cannot find a tutorial on how to use the SoundTouch library for beat detection.

(Note: I have no C++ experience prior to this. I do know C, Objective-C, and Java. So I could have messed some of this up, but it compiles.)

I added the framework to my project and managed to get the following to compile:

NSString *path = [[NSBundle mainBundle] pathForResource:@"song" ofType:@"wav"];

NSData *data = [NSData dataWithContentsOfFile:path];

player =[[AVAudioPlayer alloc] initWithData:data error:NULL];

player.volume = 1.0;

player.delegate = self;

[player prepareToPlay];
[player play];

NSUInteger len = [player.data length]; // Get the length of the data

soundtouch::SAMPLETYPE sampleBuffer[len]; // Create buffer array

[player.data getBytes:sampleBuffer length:len]; // Copy the bytes into the buffer

soundtouch::BPMDetect *BPM = new soundtouch::BPMDetect(player.numberOfChannels, [[player.settings valueForKey:@"AVSampleRateKey"] longValue]); // This is working (tested)

BPM->inputSamples(sampleBuffer, len); // Send the samples to the BPM class

NSLog(@"Beats Per Minute = %f", BPM->getBpm()); // Print out the BPM - currently returns 0.00 for errors per documentation

The inputSamples(*samples, numSamples) song byte information confuses me.

How do I get these pieces of information from a song file?

I tried using memcpy() but it doesn't seem to be working.

Anyone have any thoughts?


Solution

  • After hours and hours of debugging and reading the limited documentation on the web, I modified a few things before stumbling upon this: You need to divide numSamples by numberOfChannels in the inputSamples() function.

    My final code is like so:

    NSString *path = [[NSBundle mainBundle] pathForResource:@"song" ofType:@"wav"];
    
    NSData *data = [NSData dataWithContentsOfFile:path];
    
    player =[[AVAudioPlayer alloc] initWithData:data error:NULL];
    
    player.volume = 1.0;    // optional to play music
    
    player.delegate = self;
    
    [player prepareToPlay]; // optional to play music
    [player play];          // optional to play music
    
    NSUInteger len = [player.data length];
    
    soundtouch::SAMPLETYPE sampleBuffer[len];
    
    [player.data getBytes:sampleBuffer length:len];
    
    soundtouch::BPMDetect BPM(player.numberOfChannels, [[player.settings valueForKey:@"AVSampleRateKey"] longValue]);
    
    BPM.inputSamples(sampleBuffer, len/player.numberOfChannels);
    
    NSLog(@"Beats Per Minute = %f", BPM.getBpm());