我已成功将Superpowered SDK CrossExample项目导入android studio并在三星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指针后发生此错误,所以我相信在成功设置录制路径后,此错误将消失。
SuperpoweredRecorder.h文档的链接:http://superpowered.com/docs/class_superpowered_recorder.html
在查看文档时,我还需要添加哪些代码才能使用tempPath
和destinationPath
变量?
我自己添加的代码是正向双斜线。
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
#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
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");
}
}
答案 0 :(得分:2)
如果您遇到细分错误,您的应用可能不会声明WRITE_EXTERNAL_STORAGE
权限(CrossExample
不会,因为它没有写任何东西)。如果它仍然存在,则包含目录可能不存在 - 例如&#34; / SD卡/不存在的输入/输出&#34;
答案 1 :(得分:1)
我意识到这已经很晚了,但如果它有用,我相信moe是正确的;但是,从API 23开始,仅在清单中包含WRITE_EXTERNAL_STORAGE权限是不够的。由于新的权限模型,您还需要明确检查并请求此权限。在开发过程中,您还可以转到应用的应用信息 - >权限页面,并在那里手动启用权限(假设它在您的清单中)。
我有一个段错误,直到我采取了最后一步,它现在不再发生了。
我希望这可以帮助像我一样困惑的人。