iOS SoundTouch framework BPM Detection example

匿名 (未验证) 提交于 2019-12-03 01:58:03

问题:

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?

回答1:

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()); 


回答2:

I've tried this solution to read the BPM from mp3 files (using the TSLibraryImport class to convert to wav) inside the iOS Music Library:

                                MPMediaItem *item = [collection representativeItem];                                   NSURL *urlStr = [item valueForProperty:MPMediaItemPropertyAssetURL];                                   TSLibraryImport* import = [[TSLibraryImport alloc] init];                                   NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);                                  NSString *documentsDirectory = [paths objectAtIndex:0];                                   NSURL* destinationURL = [NSURL fileURLWithPath:[documentsDirectory stringByAppendingPathComponent:@"temp_data"]];                                  [[NSFileManager defaultManager] removeItemAtURL:destinationURL error:nil];                                   [import importAsset:urlStr toURL:destinationURL completionBlock:^(TSLibraryImport* import) {                                       NSString *outPath = [documentsDirectory stringByAppendingPathComponent:@"temp_data"];                                        NSData *data = [NSData dataWithContentsOfFile:outPath];                                      AVAudioPlayer *player =[[AVAudioPlayer alloc] initWithData:data error:NULL];                                       NSUInteger len = [player.data length];                                      int numChannels = player.numberOfChannels;                                       soundtouch::SAMPLETYPE sampleBuffer[1024];                                       soundtouch::BPMDetect *BPM = new soundtouch::BPMDetect(player.numberOfChannels, [[player.settings valueForKey:@"AVSampleRateKey"] longValue]);                                        for (NSUInteger i = 0; i inputSamples(sampleBuffer, samples); // Send the samples to the BPM class                                       }                                       NSLog(@"Beats Per Minute = %f", BPM->getBpm());                                    }]; 

The strangeness is that the calculated BMP is always the same value:

2013-10-02 03:05:36.725 AppTestAudio[1464:1803]  Beats Per Minute = 117.453835 

No matter which track was i.e. number of frames or the buffer size (here I used 2K buffer size as for the SoundTouch example in the source code of the library).



回答3:

For Swift 3:

https://github.com/Luccifer/BPM-Analyser

And use it like:

guard let filePath = Bundle.main.path(forResource: "TestMusic", ofType: "m4a"), let url = URL(string: filePath) else {return "error occured, check fileURL"}  BPMAnalyzer.core.getBpmFrom(url, completion: nil) 

Feel free to comment!



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!