Superpowered SDK:实现SuperpoweredRecorder.h并设置记录路径 [英] Superpowered SDK: Implementing SuperpoweredRecorder.h and setting up recording paths

查看:194
本文介绍了Superpowered SDK:实现SuperpoweredRecorder.h并设置记录路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已成功将Superpowered SDK CrossExample项目导入android studio,并在Samsung galaxy S3和模拟器上对其进行了测试.现在,我正在实现一个记录选项,以使用SuperpoweredRecorder.h记录应用播放的音频.我将需要有关如何正确设置*tempPath*destinationPath变量以成功保存记录的帮助. 该项目的构建正常,但是当我尝试在Galaxy S3或模拟器上运行该应用程序时,出现以下错误消息: 19565-19565/com.superpowered.crossexample A/libc﹕ Fatal signal 11 (SIGSEGV) at 0x006f0070 (code=1), thread 19565 (ed.crossexample) 添加* tempPath和* destinationPath指针后发生此错误,因此我相信在成功设置记录路径后,该错误将消失.

I have successfully imported Superpowered SDK CrossExample project into android studio and tested it on Samsung galaxy S3 and emulator. Now I’m implementing a record option to record audio played by the app using SuperpoweredRecorder.h. I will need help for how to correctly set *tempPath and *destinationPath variables to successfully save the recording. The project builds OK, but when I’m trying to run the app on the Galaxy S3 or on the emulator I’m getting the following error message: 19565-19565/com.superpowered.crossexample A/libc﹕ Fatal signal 11 (SIGSEGV) at 0x006f0070 (code=1), thread 19565 (ed.crossexample) This error occurred after adding *tempPath and *destinationPath pointers so I believe after successful setting up the recording paths this error will be gone.

SuperpoweredRecorder.h文档的链接: http://superpowered.com/docs/class_superpowered_recorder.html 在查看文档时,我还需要在代码中添加什么才能使用tempPathdestinationPath变量?

The link to SuperpoweredRecorder.h documentation: http://superpowered.com/docs/class_superpowered_recorder.html When looking at the documentation what else do I have to add to the code to use tempPath and destinationPath variables?

我自己添加的代码在正斜杠之间.

The code added myself is between forward double slashes.

SuperpoweredExample.h

SuperpoweredExample.h

#ifndef Header_SuperpoweredExample
#define Header_SuperpoweredExample

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <math.h>
#include <pthread.h>

#include "SuperpoweredExample.h"
#include "SuperpoweredAdvancedAudioPlayer.h"
#include "SuperpoweredFilter.h"
#include "SuperpoweredRoll.h"
#include "SuperpoweredFlanger.h"
#include "SuperpoweredMixer.h"
#include "SuperpoweredRecorder.h"

#define NUM_BUFFERS 2
#define HEADROOM_DECIBEL 3.0f
static const float headroom = powf(10.0f, -HEADROOM_DECIBEL * 0.025);

class SuperpoweredExample {
public:

SuperpoweredExample(const char *path, int *params);
~SuperpoweredExample();

void process(SLAndroidSimpleBufferQueueItf caller);
void onPlayPause(bool play);
void onCrossfader(int value);
void onFxSelect(int value);
void onFxOff();
void onFxValue(int value);
//Added function declaration
void onRecord(bool record);
//
private:
SLObjectItf openSLEngine, outputMix, bufferPlayer;
SLAndroidSimpleBufferQueueItf bufferQueue;

SuperpoweredAdvancedAudioPlayer *playerA, *playerB;
SuperpoweredRoll *roll;
SuperpoweredFilter *filter;
SuperpoweredFlanger *flanger;
SuperpoweredStereoMixer *mixer;
SuperpoweredRecorder *recorder;
//added object variables
const char *tempPath;
const char *destinationPath;
//
unsigned char activeFx;
float crossValue, volA, volB;
pthread_mutex_t mutex;

float *outputBuffer[NUM_BUFFERS];
int currentBuffer, buffersize;
};

#endif

SuperpoweredExample.cpp

SuperpoweredExample.cpp

#include "SuperpoweredExample.h"
#include <jni.h>
#include <stdlib.h>
#include <stdio.h>
#include <android/log.h>

static void playerEventCallbackA(void *clientData,         SuperpoweredAdvancedAudioPlayerEvent event, void *value) {
if (event == SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess) {
    SuperpoweredAdvancedAudioPlayer *playerA = *     ((SuperpoweredAdvancedAudioPlayer **)clientData);
    playerA->setBpm(126.0f);
    playerA->setFirstBeatMs(353);
    playerA->setPosition(playerA->firstBeatMs, false, false);
};
}

static void playerEventCallbackB(void *clientData,     SuperpoweredAdvancedAudioPlayerEvent event, void *value) {
if (event == SuperpoweredAdvancedAudioPlayerEvent_LoadSuccess) {
    SuperpoweredAdvancedAudioPlayer *playerB = *((SuperpoweredAdvancedAudioPlayer **)clientData);
    playerB->setBpm(123.0f);
    playerB->setFirstBeatMs(40);
    playerB->setPosition(playerB->firstBeatMs, false, false);
};
}

static void openSLESCallback(SLAndroidSimpleBufferQueueItf caller, void         *pContext) {
((SuperpoweredExample *)pContext)->process(caller);}

static const SLboolean requireds[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };

SuperpoweredExample::SuperpoweredExample(const char *path, int *params) :     currentBuffer(0), buffersize(params[5]), activeFx(0), crossValue(0.0f),     volB(0.0f), volA(1.0f * headroom) {
pthread_mutex_init(&mutex, NULL); // This will keep our player volumes and     playback states in sync.

for (int n = 0; n < NUM_BUFFERS; n++) outputBuffer[n] = (float     *)memalign(16, (buffersize + 16) * sizeof(float) * 2);

unsigned int samplerate = params[4];

playerA = new SuperpoweredAdvancedAudioPlayer(&playerA ,     playerEventCallbackA, samplerate, 0);
playerA->open(path, params[0], params[1]);
playerB = new SuperpoweredAdvancedAudioPlayer(&playerB,     playerEventCallbackB, samplerate, 0);
playerB->open(path, params[2], params[3]);

playerA->syncMode = playerB->syncMode =     SuperpoweredAdvancedAudioPlayerSyncMode_TempoAndBeat;

roll = new SuperpoweredRoll(samplerate);
filter = new SuperpoweredFilter(SuperpoweredFilter_Resonant_Lowpass,     samplerate);
flanger = new SuperpoweredFlanger(samplerate);

mixer = new SuperpoweredStereoMixer();

//Create SuperpoweredRecorder and allocate memory for it
recorder = new SuperpoweredRecorder(tempPath, samplerate);
//

// Create the OpenSL ES engine.
slCreateEngine(&openSLEngine, 0, NULL, 0, NULL, NULL);
(*openSLEngine)->Realize(openSLEngine, SL_BOOLEAN_FALSE);
SLEngineItf openSLEngineInterface = NULL;
(*openSLEngine)->GetInterface(openSLEngine, SL_IID_ENGINE,     &openSLEngineInterface);
// Create the output mix.
(*openSLEngineInterface)->CreateOutputMix(openSLEngineInterface, &outputMix,     0, NULL, NULL);
(*outputMix)->Realize(outputMix, SL_BOOLEAN_FALSE);
SLDataLocator_OutputMix outputMixLocator = { SL_DATALOCATOR_OUTPUTMIX,     outputMix };

// Create the buffer queue player.
SLDataLocator_AndroidSimpleBufferQueue bufferPlayerLocator = {     SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, NUM_BUFFERS };
SLDataFormat_PCM bufferPlayerFormat = { SL_DATAFORMAT_PCM, 2, samplerate *     1000, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,     SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN };
SLDataSource bufferPlayerSource = { &bufferPlayerLocator,     &bufferPlayerFormat };
const SLInterfaceID bufferPlayerInterfaces[1] = { SL_IID_BUFFERQUEUE };
SLDataSink bufferPlayerOutput = { &outputMixLocator, NULL };
(*openSLEngineInterface)->CreateAudioPlayer(openSLEngineInterface,     &bufferPlayer, &bufferPlayerSource, &bufferPlayerOutput, 1,     bufferPlayerInterfaces, requireds);
(*bufferPlayer)->Realize(bufferPlayer, SL_BOOLEAN_FALSE);

// Initialize and start the buffer queue.
(*bufferPlayer)->GetInterface(bufferPlayer, SL_IID_BUFFERQUEUE,     &bufferQueue);
(*bufferQueue)->RegisterCallback(bufferQueue, openSLESCallback, this);
memset(outputBuffer[0], 0, buffersize * 4);
memset(outputBuffer[1], 0, buffersize * 4);
(*bufferQueue)->Enqueue(bufferQueue, outputBuffer[0], buffersize * 4);
(*bufferQueue)->Enqueue(bufferQueue, outputBuffer[1], buffersize * 4);
SLPlayItf bufferPlayerPlayInterface;
(*bufferPlayer)->GetInterface(bufferPlayer, SL_IID_PLAY, &bufferPlayerPlayInterface);
(*bufferPlayerPlayInterface)->SetPlayState(bufferPlayerPlayInterface,     SL_PLAYSTATE_PLAYING);
}

SuperpoweredExample::~SuperpoweredExample() {
for (int n = 0; n < NUM_BUFFERS; n++) free(outputBuffer[n]);
delete playerA;
delete playerB;
delete mixer;
pthread_mutex_destroy(&mutex);
}

void SuperpoweredExample::onPlayPause(bool play) {
pthread_mutex_lock(&mutex);
if (!play) {
    playerA->pause();
    playerB->pause();
} else {
    bool masterIsA = (crossValue <= 0.5f);
    playerA->play(!masterIsA);
    playerB->play(masterIsA);
};
pthread_mutex_unlock(&mutex);
}
//onRecord function
void SuperpoweredExample::onRecord(bool record) {
pthread_mutex_lock(&mutex);
if (!record) {
    recorder->stop();
} else {
    recorder->start(destinationPath);
};
pthread_mutex_unlock(&mutex);
}
//

void SuperpoweredExample::onCrossfader(int value) {
pthread_mutex_lock(&mutex);
crossValue = float(value) * 0.01f;
if (crossValue < 0.01f) {
    volA = 1.0f * headroom;
    volB = 0.0f;
} else if (crossValue > 0.99f) {
    volA = 0.0f;
    volB = 1.0f * headroom;
} else { // constant power curve
    volA = cosf(M_PI_2 * crossValue) * headroom;
    volB = cosf(M_PI_2 * (1.0f - crossValue)) * headroom;
};
pthread_mutex_unlock(&mutex);
}

void SuperpoweredExample::onFxSelect(int value) {
__android_log_print(ANDROID_LOG_VERBOSE, "SuperpoweredExample", "FXSEL %i",     value);
activeFx = value;
}

void SuperpoweredExample::onFxOff() {
filter->enable(false);
roll->enable(false);
flanger->enable(false);
}

#define MINFREQ 60.0f
#define MAXFREQ 20000.0f

static inline float floatToFrequency(float value) {
if (value > 0.97f) return MAXFREQ;
if (value < 0.03f) return MINFREQ;
value = powf(10.0f, (value + ((0.4f - fabsf(value - 0.4f)) * 0.3f)) *     log10f(MAXFREQ - MINFREQ)) + MINFREQ;
return value < MAXFREQ ? value : MAXFREQ;
}

void SuperpoweredExample::onFxValue(int ivalue) {
float value = float(ivalue) * 0.01f;
switch (activeFx) {
    case 1:
        filter->setResonantParameters(floatToFrequency(1.0f - value), 0.2f);
        filter->enable(true);
        flanger->enable(false);
        roll->enable(false);
        break;
    case 2:
        if (value > 0.8f) roll->beats = 0.0625f;
        else if (value > 0.6f) roll->beats = 0.125f;
        else if (value > 0.4f) roll->beats = 0.25f;
        else if (value > 0.2f) roll->beats = 0.5f;
        else roll->beats = 1.0f;
        roll->enable(true);
        filter->enable(false);
        flanger->enable(false);
        break;
    default:
        flanger->setWet(value);
        flanger->enable(true);
        filter->enable(false);
        roll->enable(false);
};
}

void SuperpoweredExample::process(SLAndroidSimpleBufferQueueItf caller) {
pthread_mutex_lock(&mutex);
float *stereoBuffer = outputBuffer[currentBuffer];

bool masterIsA = (crossValue <= 0.5f);
float masterBpm = masterIsA ? playerA->currentBpm : playerB->currentBpm;
double msElapsedSinceLastBeatA = playerA->msElapsedSinceLastBeat; // When playerB needs it, playerA has already stepped this value, so save it now.

bool silence = !playerA->process(stereoBuffer, false, buffersize, volA, masterBpm, playerB->msElapsedSinceLastBeat);
if (playerB->process(stereoBuffer, !silence, buffersize, volB, masterBpm, msElapsedSinceLastBeatA)) silence = false;

roll->bpm = flanger->bpm = masterBpm; // Syncing fx is one line.

if (roll->process(silence ? NULL : stereoBuffer, stereoBuffer, buffersize) && silence) silence = false;
if (!silence) {
    filter->process(stereoBuffer, stereoBuffer, buffersize);
    flanger->process(stereoBuffer, stereoBuffer, buffersize);
    //adding buffer to process function
    recorder->process(stereoBuffer, 0, buffersize);
    //
};


pthread_mutex_unlock(&mutex);

// The stereoBuffer is ready now, let's put the finished audio into the requested buffers.
if (silence) memset(stereoBuffer, 0, buffersize * 4); else SuperpoweredStereoMixer::floatToShortInt(stereoBuffer, (short int *)stereoBuffer, buffersize);

(*caller)->Enqueue(caller, stereoBuffer, buffersize * 4);
if (currentBuffer < NUM_BUFFERS - 1) currentBuffer++; else currentBuffer = 0;
}

extern "C" {
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_SuperpoweredExample(JNIEnv *javaEnvironment, jobject self, jstring apkPath, jlongArray offsetAndLength);
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onPlayPause(JNIEnv *javaEnvironment, jobject self, jboolean play);
//connect onRecord with java
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onRecord(JNIEnv *javaEnvironment, jobject self, jboolean record);
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onCrossfader(JNIEnv *javaEnvironment, jobject self, jint value);
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onFxSelect(JNIEnv *javaEnvironment, jobject self, jint value);
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onFxOff(JNIEnv *javaEnvironment, jobject self);
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onFxValue(JNIEnv *javaEnvironment, jobject self, jint value);
}

static SuperpoweredExample *example = NULL;

// Android is not passing more than 2 custom parameters, so we had to pack file offsets and lengths into an array.
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_SuperpoweredExample(JNIEnv *javaEnvironment, jobject self, jstring apkPath, jlongArray params) {
// Convert the input jlong array to a regular int array.
jlong *longParams = javaEnvironment->GetLongArrayElements(params, JNI_FALSE);
int arr[6];
for (int n = 0; n < 6; n++) arr[n] = longParams[n];
javaEnvironment->ReleaseLongArrayElements(params, longParams, JNI_ABORT);

const char *path = javaEnvironment->GetStringUTFChars(apkPath, JNI_FALSE);
example = new SuperpoweredExample(path, arr);
javaEnvironment->ReleaseStringUTFChars(apkPath, path);

}

JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onPlayPause(JNIEnv *javaEnvironment, jobject self, jboolean play) {
example->onPlayPause(play);
}
//connect onRecord with java code
JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onRecord(JNIEnv *javaEnvironment, jobject self, jboolean record) {
example->onRecord(record);
}
//

JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onCrossfader(JNIEnv *javaEnvironment, jobject self, jint value) {
example->onCrossfader(value);
}

JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onFxSelect(JNIEnv *javaEnvironment, jobject self, jint value) {
example->onFxSelect(value);
}

JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onFxOff(JNIEnv *javaEnvironment, jobject self) {
example->onFxOff();
}

JNIEXPORT void Java_com_superpowered_crossexample_MainActivity_onFxValue(JNIEnv *javaEnvironment, jobject self, jint value) {
example->onFxValue(value);
}

MainActivity.java

MainActivity.java

package com.superpowered.crossexample;

import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

import java.io.IOException;

public class MainActivity extends ActionBarActivity {
boolean playing = false;
//Added variable
boolean recording = false;
//

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Get the device's sample rate and buffer size to enable low-latency Android audio output, if available.
    String samplerateString = null, buffersizeString = null;
    if (Build.VERSION.SDK_INT >= 17) {
        AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
        samplerateString = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
        buffersizeString = audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
    }
    if (samplerateString == null) samplerateString = "44100";
    if (buffersizeString == null) buffersizeString = "512";

    // Files under res/raw are not compressed, just copied into the APK. Get the offset and length to know where our files are located.
    AssetFileDescriptor fd0 = getResources().openRawResourceFd(R.raw.lycka), fd1 = getResources().openRawResourceFd(R.raw.nuyorica);
    long[] params = {
            fd0.getStartOffset(),
            fd0.getLength(),
            fd1.getStartOffset(),
            fd1.getLength(),
            Integer.parseInt(samplerateString),
            Integer.parseInt(buffersizeString)
    };
    try {
        fd0.getParcelFileDescriptor().close();
        fd1.getParcelFileDescriptor().close();
    } catch (IOException e) {}

    // Arguments: path to the APK file, offset and length of the two resource files, sample rate, audio buffer size.
    SuperpoweredExample(getPackageResourcePath(), params);

    // crossfader events
    final SeekBar crossfader = (SeekBar)findViewById(R.id.crossFader);
    crossfader.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            onCrossfader(progress);
        }

        public void onStartTrackingTouch(SeekBar seekBar) {}
        public void onStopTrackingTouch(SeekBar seekBar) {}
    });

    // fx fader events
    final SeekBar fxfader = (SeekBar)findViewById(R.id.fxFader);
    fxfader.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            onFxValue(progress);
        }

        public void onStartTrackingTouch(SeekBar seekBar) {
            onFxValue(seekBar.getProgress());
        }

        public void onStopTrackingTouch(SeekBar seekBar) {
            onFxOff();
        }
    });

    // fx select event
    final RadioGroup group = (RadioGroup)findViewById(R.id.radioGroup1);
    group.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
            RadioButton checkedRadioButton = (RadioButton)radioGroup.findViewById(checkedId);
            onFxSelect(radioGroup.indexOfChild(checkedRadioButton));
        }
    });
}

public void SuperpoweredExample_PlayPause(View button) {  // Play/pause.
    playing = !playing;
    onPlayPause(playing);
    Button b = (Button) findViewById(R.id.playPause);
    b.setText(playing ? "Pause" : "Play");
}
//Added the following Record method
public void SuperpoweredExample_Record(View button) {  // Record/Stop Recording.
    recording = !recording;
    onRecord(recording);
    Button r = (Button) findViewById(R.id.rec);
    r.setText(recording ? "Start Recording" : "Stop Recording");
}
//
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

private native void SuperpoweredExample(String apkPath, long[] offsetAndLength);
private native void onPlayPause(boolean play);
private native void onCrossfader(int value);
private native void onFxSelect(int value);
private native void onFxOff();
private native void onFxValue(int value);
//Added the following line
private native void onRecord(boolean record);
//

static {
    System.loadLibrary("SuperpoweredExample");
}
}

推荐答案

如果遇到分段错误,则可能是您的应用程序未声明WRITE_EXTERNAL_STORAGE权限(CrossExample并未声明).它没有写任何东西).如果仍然存在,则包含的目录可能不存在-例如"/sdcard/不存在/退出".

If you're getting a segmentation fault, it's likely that your application doesn't declare the WRITE_EXTERNAL_STORAGE permission (which CrossExample doesn't, as it's not writing anything). If it persists, the containing directory may not exist - e.g. "/sdcard/nonexistent/out".

这篇关于Superpowered SDK:实现SuperpoweredRecorder.h并设置记录路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆