// This is called periodically by the media server. static bool audioProcessing(void *clientdata, short int *audioInputOutput, int numberOfSamples, int samplerate) { SuperpoweredShortIntToFloat(audioInputOutput, inputBufferFloat, numberOfSamples); // Converting the 16-bit integer samples to 32-bit floating point. frequencyDomain->addInput(inputBufferFloat, numberOfSamples); // Input goes to the frequency domain. // In the frequency domain we are working with 1024 magnitudes and phases for every channel (left, right), if the fft size is 2048. while (frequencyDomain->timeDomainToFrequencyDomain(magnitudeLeft, magnitudeRight, phaseLeft, phaseRight)) { // You can work with frequency domain data from this point. // This is just a quick example: we remove the magnitude of the first 20 bins, meaning total bass cut between 0-430 Hz. memset(magnitudeLeft, 0, 80); memset(magnitudeRight, 0, 80); // We are done working with frequency domain data. Let's go back to the time domain. // Check if we have enough room in the fifo buffer for the output. If not, move the existing audio data back to the buffer's beginning. if (fifoOutputLastSample + stepSize >= fifoCapacity) { // This will be true for every 100th iteration only, so we save precious memory bandwidth. int samplesInFifo = fifoOutputLastSample - fifoOutputFirstSample; if (samplesInFifo > 0) memmove(fifoOutput, fifoOutput + fifoOutputFirstSample * 2, samplesInFifo * sizeof(float) * 2); fifoOutputFirstSample = 0; fifoOutputLastSample = samplesInFifo; }; // Transforming back to the time domain. frequencyDomain->frequencyDomainToTimeDomain(magnitudeLeft, magnitudeRight, phaseLeft, phaseRight, fifoOutput + fifoOutputLastSample * 2); frequencyDomain->advance(); fifoOutputLastSample += stepSize; }; // If we have enough samples in the fifo output buffer, pass them to the audio output. if (fifoOutputLastSample - fifoOutputFirstSample >= numberOfSamples) { SuperpoweredFloatToShortInt(fifoOutput + fifoOutputFirstSample * 2, audioInputOutput, numberOfSamples); fifoOutputFirstSample += numberOfSamples; return true; } else return false; }
extern "C" JNIEXPORT jdouble Java_com_juztoss_rhythmo_audio_BpmDetector_detect(JNIEnv *env, jobject instance, jstring source ) { const char *path = env->GetStringUTFChars(source, JNI_FALSE); SuperpoweredDecoder *decoder = new SuperpoweredDecoder(); const char *openError = decoder->open(path, false, 0, 0); if (openError) { __android_log_print(ANDROID_LOG_ERROR, __func__, " Decoder error, path %s, error: %s", path, openError); delete decoder; env->ReleaseStringUTFChars(source, path); return -1; }; env->ReleaseStringUTFChars(source, path); const int samplesToDetect = 2097152; //The pow of 2 in case the fourier transform inside of the detector need it int64_t duration = decoder->durationSamples; int64_t start = duration / 2 - samplesToDetect / 2; int64_t end = start + samplesToDetect; if(start <= 0) { start = 0; end = decoder->durationSamples; } decoder->seek(start, false); SuperpoweredOfflineAnalyzer * analyzer = new SuperpoweredOfflineAnalyzer(decoder->samplerate, 0, decoder->durationSeconds); // Create a buffer for the 16-bit integer samples coming from the decoder. short int *intBuffer = (short int *)malloc(decoder->samplesPerFrame * 2 * sizeof(short int) + 16384); // Create a buffer for the 32-bit floating point samples required by the effect. float *floatBuffer = (float *)malloc(decoder->samplesPerFrame * 2 * sizeof(float) + 1024); // Processing. while (decoder->samplePosition <= end) { // Decode one frame. samplesDecoded will be overwritten with the actual decoded number of samples. unsigned int samplesDecoded = decoder->samplesPerFrame; if (decoder->decode(intBuffer, &samplesDecoded) == SUPERPOWEREDDECODER_ERROR) break; if (samplesDecoded < 1) break; // Convert the decoded PCM samples from 16-bit integer to 32-bit floating point. SuperpoweredShortIntToFloat(intBuffer, floatBuffer, samplesDecoded); // Submit samples to the analyzer. analyzer->process(floatBuffer, samplesDecoded); }; // Get the result. float bpm; analyzer->getresults(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &bpm, NULL, NULL); // Cleanup. delete decoder; delete analyzer; free(intBuffer); free(floatBuffer); return bpm; }