【问题标题】:iOS SoundTouch framework BPM Detection exampleiOS SoundTouch 框架 BPM 检测示例
【发布时间】:2013-07-20 02:08:30
【问题描述】:

我搜索了整个网络,但找不到有关如何使用SoundTouch library 进行节拍检测的教程。

(注意:在此之前我没有 C++ 经验。我知道 C、Objective-C 和 Java。所以我可能会搞砸一些,但它可以编译。)

我将framework 添加到我的项目中并设法编译以下内容:

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

inputSamples(*samples, numSamples) 歌曲字节信息让我感到困惑。

如何从歌曲文件中获取这些信息?

我尝试使用memcpy(),但它似乎不起作用。

有人有什么想法吗?

【问题讨论】:

    标签: ios audio objective-c++ soundtouch


    【解决方案1】:

    经过数小时的调试和阅读网络上有限的文档后,我在偶然发现之前修改了一些内容:您需要在 inputSamples() 函数中将 numSamples 除以 numberOfChannels

    我的最终代码是这样的:

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

    【讨论】:

    • 很酷,你能告诉你是如何将 SoundTouch 库添加到 xcode 项目中的吗?
    • 您只需下载框架并将其导入您的项目。
    • 好的,我已经设法将它包含到 xcode 项目中,上面的代码不起作用,有时应用程序崩溃,我尝试了 wav 和 mp3 文件,我什至使用了 soundtouch 中的 orig 音频样本网站,它给了我一个崩溃问题,或 nan 结果(使用原始示例音频时)
    • 我能够集成 SoundTouch。无论如何,BMP 总是返回 0.0f。不理解评论 // 打印 BPM - 当前每个文档的错误返回 0.00
    • @MrHappyAsthma 我已经尝试过你所说的检测 BPM,但 SoundTouchLibrary 似乎不支持 armv7。你能给我使用 SoundTouch 检测 BPM 的示例代码吗?
    【解决方案2】:

    我已尝试使用此解决方案从 iOS 音乐库中的 mp3 文件(使用 TSLibraryImport 类转换为 wav)读取 BPM:

                                    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 <= len - 1024; i = i + 1024) {
    
                                             NSRange r = NSMakeRange(i, 1024);
                                             //NSData *temp = [player.data subdataWithRange:r];
                                             [player.data getBytes:sampleBuffer range:r];
    
                                             int samples = sizeof(sampleBuffer) / numChannels;
    
                                             BPM->inputSamples(sampleBuffer, samples); // Send the samples to the BPM class
    
                                         }
    
                                         NSLog(@"Beats Per Minute = %f", BPM->getBpm());
    
    
                                     }];
    

    奇怪的是计算出来的BMP总是一样的值:

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

    无论是哪个轨道,即帧数或缓冲区大小(这里我使用 2K 缓冲区大小作为库源代码中的 SoundTouch 示例)。

    【讨论】:

      【解决方案3】:

      对于 Swift 3:

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

      并像这样使用它:

      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)
      

      欢迎评论!

      【讨论】:

        猜你喜欢
        • 2014-07-16
        • 1970-01-01
        • 1970-01-01
        • 2011-07-19
        • 1970-01-01
        • 1970-01-01
        • 2014-08-09
        • 1970-01-01
        • 2010-10-03
        相关资源
        最近更新 更多