我正在尝试将SoundTouch C ++库用于Android应用中的音频速度和音高变化。 我已经成功地将Java byte []数组(从.wav)推送到JNI,返回它,然后用AudioTrack播放它。
下一步是尝试通过SoundTouch管道推送样本byte []。 我已经剖析了库中包含的SoundStretch控制台程序的来源,并试图对其进行调整。 我正在使用立体声16位源进行测试。
使用我当前的临时设置,我忽略了RIFF标头并将其与.wav数据一起转换,因为Java AudioTrack对象不需要读取标头,它只播放原始PCM。 播放原始字节[]而不通过SoundTouch发送只会导致标题所在的小点击。
通过SoundTouch管道发送后,我正在回放音频开头的白噪声。 我假设我在write()函数结束时遇到了问题,我write() short简化为signed char。 这里,控制台应用程序正在写入文件,而不是推送到向量:
int res = (int)fwrite(temp, 1, numBytes, fptr);我已经阅读了fwrite的文档,但是我不知道有关bit twiddling或音频处理的知识,知道如何在char []中正确获取此信息而不是写入文件。 我知道我正在向演员丢失信息,但我不确定如何纠正它。
如果有人有额外的动机,可以在这里找到SoundStretch源: http : //www.surina.net/soundtouch/sourcecode.html
extern "C" DLL_PUBLIC jbyteArray Java_net_surina_soundtouch_SoundTouch_getMutatedBytes (JNIEnv *env, jobject thiz, jbyteArray input, jint length) { const int BUFF_SIZE = 2048000; SoundTouch soundTouch; jboolean isCopy; jbyte* ar = env->GetByteArrayElements(input, &isCopy); signed char* cBufferIn = (signed char*)ar; SAMPLETYPE* fBufferIn = new SAMPLETYPE[length]; vector<signed char> fBufferOut; //converts the chars to floats per the SoundTouch console app. convertInput16(cBufferIn, fBufferIn, length); //channels, sampling rate, speed, pitch change setup(&soundTouch, 2, 44100, 1.0, 0); //transform floats from fBufferIn to fBufferout process(&soundTouch, fBufferIn, fBufferOut, BUFF_SIZE); signed char* res = &fBufferOut[0]; jbyteArray result = env->NewByteArray(length); env->SetByteArrayRegion(result, 0, fBufferOut.size(), res); LOGV("fBufferOut Size: %d", fBufferOut.size()); delete[] fBufferIn; return result; }处理():
static void process(SoundTouch* soundTouch, SAMPLETYPE* fBufferIn, vector<signed char>& fBufferOut, int BUFF_SIZE) { int nSamples = BUFF_SIZE / 2; //2 bytes per sample, using 16 bit sample for testing int buffSizeSamples = BUFF_SIZE / 2; //2 channel stereo soundTouch->putSamples(fBufferIn, nSamples); do { nSamples = soundTouch->receiveSamples(fBufferIn, buffSizeSamples); write(fBufferIn, fBufferOut, nSamples / 2); //2 channels } while (nSamples != 0); soundTouch->flush(); do { nSamples = soundTouch->receiveSamples(fBufferIn, buffSizeSamples); write(fBufferIn, fBufferOut, nSamples / 2); LOGV("NUMBER OF SAMPLES: %d", nSamples); } while (nSamples != 0); }写():
static void write(const float *bufferIn, vector<signed char>& bufferOut, int numElems) { int numBytes; int bytesPerSample; if (numElems == 0) return; bytesPerSample = 16 / 8; //16 bit test sample / bits in a byte numBytes = numElems * bytesPerSample; short *temp = (short*)getConvBuffer(numBytes); switch (bytesPerSample) { case 2: //16 bit encoding per the SoundStretch console app { short *temp2 = (short *)temp; for (int i = 0; i < numElems; i++) { short value = (short)saturate(bufferIn[i] * 32768.0f, -32768.0f, 32767.0f); //magic to me temp2[i] = value; //works for little endian only. } break; } default: assert(false); } for (int i = 0; i < numElems; ++i) { bufferOut.push_back((signed char)temp[i]); //I think my problem is here. } delete[] temp; //bytesWritten += numBytes; }I'm attempting to use the SoundTouch C++ library for audio speed and pitch changes in an Android app. I have successfully pushed a Java byte[] array (from a .wav) through JNI, returned it, and played it back with an AudioTrack.
The next step is attempting to push a sample byte[] through the SoundTouch pipeline. I have dissected the source of the SoundStretch console program included with the library and have attempted to adapt it. I am using a stereo, 16-bit source for testing purposes.
With my current temporary setup I am ignoring the RIFF header and converting it along with the .wav data because the Java AudioTrack object does not need to read the header, it just plays raw PCM. Playing the raw byte[] without sending through SoundTouch just results in a small click where the header is.
After sending through the SoundTouch pipeline, I am playing back white noise where the beginning of the audio is supposed to be. I assume I am having a problem at the end of my write() function, where I am casting short's to signed chars. Here, the console app is writing to a file, instead of pushing to a vector:
int res = (int)fwrite(temp, 1, numBytes, fptr);I have read the documentation for fwrite but I don't know enough about bit twiddling or audio processing to know what to do here to correctly get this information in a char[] instead of writing to a file. I know I am loosing information with the cast, but I am unsure of how to correct it.
In case anyone is extra motivated, the SoundStretch source can be found here: http://www.surina.net/soundtouch/sourcecode.html
extern "C" DLL_PUBLIC jbyteArray Java_net_surina_soundtouch_SoundTouch_getMutatedBytes (JNIEnv *env, jobject thiz, jbyteArray input, jint length) { const int BUFF_SIZE = 2048000; SoundTouch soundTouch; jboolean isCopy; jbyte* ar = env->GetByteArrayElements(input, &isCopy); signed char* cBufferIn = (signed char*)ar; SAMPLETYPE* fBufferIn = new SAMPLETYPE[length]; vector<signed char> fBufferOut; //converts the chars to floats per the SoundTouch console app. convertInput16(cBufferIn, fBufferIn, length); //channels, sampling rate, speed, pitch change setup(&soundTouch, 2, 44100, 1.0, 0); //transform floats from fBufferIn to fBufferout process(&soundTouch, fBufferIn, fBufferOut, BUFF_SIZE); signed char* res = &fBufferOut[0]; jbyteArray result = env->NewByteArray(length); env->SetByteArrayRegion(result, 0, fBufferOut.size(), res); LOGV("fBufferOut Size: %d", fBufferOut.size()); delete[] fBufferIn; return result; }process():
static void process(SoundTouch* soundTouch, SAMPLETYPE* fBufferIn, vector<signed char>& fBufferOut, int BUFF_SIZE) { int nSamples = BUFF_SIZE / 2; //2 bytes per sample, using 16 bit sample for testing int buffSizeSamples = BUFF_SIZE / 2; //2 channel stereo soundTouch->putSamples(fBufferIn, nSamples); do { nSamples = soundTouch->receiveSamples(fBufferIn, buffSizeSamples); write(fBufferIn, fBufferOut, nSamples / 2); //2 channels } while (nSamples != 0); soundTouch->flush(); do { nSamples = soundTouch->receiveSamples(fBufferIn, buffSizeSamples); write(fBufferIn, fBufferOut, nSamples / 2); LOGV("NUMBER OF SAMPLES: %d", nSamples); } while (nSamples != 0); }write():
static void write(const float *bufferIn, vector<signed char>& bufferOut, int numElems) { int numBytes; int bytesPerSample; if (numElems == 0) return; bytesPerSample = 16 / 8; //16 bit test sample / bits in a byte numBytes = numElems * bytesPerSample; short *temp = (short*)getConvBuffer(numBytes); switch (bytesPerSample) { case 2: //16 bit encoding per the SoundStretch console app { short *temp2 = (short *)temp; for (int i = 0; i < numElems; i++) { short value = (short)saturate(bufferIn[i] * 32768.0f, -32768.0f, 32767.0f); //magic to me temp2[i] = value; //works for little endian only. } break; } default: assert(false); } for (int i = 0; i < numElems; ++i) { bufferOut.push_back((signed char)temp[i]); //I think my problem is here. } delete[] temp; //bytesWritten += numBytes; }最满意答案
我只需要获取char []中的所有位:
for (int i = 0; i < numElems; ++i) { bufferOut.push_back(temp[i] & 0xff); bufferOut.push_back((temp[i] >> 8) & 0xff); }I just needed to get all the bits in char[]:
for (int i = 0; i < numElems; ++i) { bufferOut.push_back(temp[i] & 0xff); bufferOut.push_back((temp[i] >> 8) & 0xff); }更多推荐
发布评论