resetear - Ejemplo de detección de BPM en el marco de SoundTouch de iOS
como resetear bose soundtouch 20 (3)
Después de horas y horas de depurar y leer la documentación limitada en la web, modifiqué algunas cosas antes de tropezar con esto: necesita dividir numSamples
por numberOfChannels
en la función inputSamples()
.
Mi código final es así:
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());
He buscado en toda la web y no puedo encontrar un tutorial sobre cómo usar la biblioteca SoundTouch para la detección de tiempos.
(Nota: no tengo experiencia en C ++ antes de esto. Conozco C, Objective-C y Java. Así que podría haber estropeado algo de esto, pero se compila).
Agregué el marco a mi proyecto y logré obtener lo siguiente para compilar:
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
La información del byte de la canción inputSamples(*samples, numSamples)
me confunde.
¿Cómo obtengo esta información de un archivo de canción?
Intenté usar memcpy()
pero parece que no funciona.
Alguien tiene alguna idea?
He intentado esta solución para leer el BPM desde archivos mp3 (usando la clase TSLibraryImport para convertir a wav) dentro de la biblioteca de música de iOS:
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());
}];
Lo extraño es que el BMP calculado siempre tiene el mismo valor:
2013-10-02 03:05:36.725 AppTestAudio[1464:1803] Beats Per Minute = 117.453835
No importa qué pista sea, es decir, el número de fotogramas o el tamaño del búfer (aquí utilicé el tamaño del búfer 2K como para el ejemplo de SoundTouch en el código fuente de la biblioteca).
Para Swift 3:
https://github.com/Luccifer/BPM-Analyser
Y úsalo como:
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)
¡Siéntete libre de comentar!