2014-01-05 5 views
0

Android 앱에서 오디오 속도 및 피치 변경에 SoundTouch C++ 라이브러리를 사용하려고합니다. Java 바이트 [] 배열 (.wav)을 JNI를 통해 성공적으로 푸시 한 다음 반환하고 AudioTrack을 사용하여 재생했습니다.재생을 위해 SoundTouch 오디오 라이브러리에서 짧은 []을 변환합니다.

다음 단계는 SoundTouch 파이프 라인을 통해 샘플 바이트 []를 푸시하려고 시도하는 것입니다. 라이브러리에 포함 된 SoundStretch 콘솔 프로그램의 소스를 해부하고이를 적용하려고했습니다. 테스트 목적으로 스테레오 16 비트 소스를 사용하고 있습니다.

Java AudioTrack 개체가 헤더를 읽을 필요가 없기 때문에 현재 임시 설치로 RIFF 헤더를 무시하고 .wav 데이터와 함께 변환합니다. 원시 PCM 만 재생합니다. SoundTouch를 보내지 않고 원시 바이트 []를 재생하면 헤더가있는 작은 클릭이 발생합니다.

SoundTouch 파이프 라인을 통해 전송 한 후 오디오 시작 부분에 흰색 노이즈가 재생됩니다. 내 write() 함수의 끝에 문제가 있다고 가정합니다. 여기서 짧은 문자를 부호있는 문자로 캐스팅합니다. 여기에서 콘솔 응용 프로그램은 파일에 쓰는 대신 벡터로 추진하고있다 : 나는 fwrite 설명서를 읽고

int res = (int)fwrite(temp, 1, numBytes, fptr); 

그러나 나는 무엇을 알 수있는 비트 만지작 또는 오디오 처리에 대해 충분히 모른다 여기에 제대로 파일에 쓰는 대신 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; 
} 
+0

안녕하세요! 와우. SoundTouch로 작업 프로젝트를 작성 했습니까 ?? 존경! 몇 가지 테스트 프로젝트 (pcm 데이터 (바이트 또는 단락) 설정, 피치 쉬프트 및 AudioTrack에서 재생하기위한 데이터 가져 오기)를 공유 할 수 있습니까? [email protected] TY! –

답변

0

I을 char [] 안에 모든 비트를 얻는 데 필요한 것 :

for (int i = 0; i < numElems; ++i) 
{ 
    bufferOut.push_back(temp[i] & 0xff); 
    bufferOut.push_back((temp[i] >> 8) & 0xff); 
}