从SoundTouch音频库转换short []进行播放(Converting a short[] from SoundTouch audio library for playback)

编程入门 行业动态 更新时间:2024-10-26 20:24:38
从SoundTouch音频库转换short []进行播放(Converting a short[] from SoundTouch audio library for playback)

我正在尝试将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); }

更多推荐

本文发布于:2023-07-25 10:47:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1260060.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:音频   short   SoundTouch   Converting   playback

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!