美文网首页
使用SoudTouch实现变速变调

使用SoudTouch实现变速变调

作者: 曾大稳丶 | 来源:发表于2018-07-05 09:42 被阅读0次
    1. 声明SoundTouch对象和内存变量,根据声道数和采样率初始化对象和内存
        SoundTouch *soundTouch = NULL;
        SAMPLETYPE *sampleBuffer = NULL;
        //采样率
        int sample_rate=44100;
        //声道数
        int channels =2;
        //变调
        float pitch= 1.0f;
        //变数
        float speed= 1.0f;
        //采样位数 SoudTouch最低支持16bit,所以使用16bit的来播放
        int bits= 16;
         //每秒理论PCM大小
        int BUFF_SIZE =sample_rate * channels * bits/8;
        
       
        sampleBuffer = static_cast<SAMPLETYPE *>(malloc(BUFF_SIZE));
        soundTouch = new SoundTouch();
        soundTouch->setSampleRate(sample_rate);
        soundTouch->setChannels(channels);
        soundTouch->setPitch(pitch);
        soundTouch->setTempo(speed);
    
    
    
    1. PCM数据给SoundTouch处理
        //采样个数,具体怎么获取看具体情况
        int nb=0;
        //示例1 :文件读取
        int size = fread();
        nb = size/channels;
        //示例2 :ffmpeg解码
        int nb = swr_convert();
        
        //最大采样数
       
        int maxSamples = BUFF_SIZE / channels; 
        
        //处理数据
        soundTouch->putSamples(sampleBuffer, nb);
        //得到数据到sampleBuffer
        int num = soundTouch->receiveSamples(sampleBuffer, maxSamples);
    
    
    1. 设置变速和变调
        soundTouch->setPitch(1.0); //变调
        soundTouch->setTempo(1.5);//变速
    
    
    1. SoudTouch选择处理数据是16bit还是32bit,在STTypes.h里面找到
     #if !(SOUNDTOUCH_INTEGER_SAMPLES || SOUNDTOUCH_FLOAT_SAMPLES)
           
            /// Choose either 32bit floating point or 16bit integer sampletype
            /// by choosing one of the following defines, unless this selection 
            /// has already been done in some other file.
            ////
            /// Notes:
            /// - In Windows environment, choose the sample format with the
            ///   following defines.
            /// - In GNU environment, the floating point samples are used by 
            ///   default, but integer samples can be chosen by giving the 
            ///   following switch to the configure script:
            ///       ./configure --enable-integer-samples
            ///   However, if you still prefer to select the sample format here 
            ///   also in GNU environment, then please #undef the INTEGER_SAMPLE
            ///   and FLOAT_SAMPLE defines first as in comments above.
            //#define SOUNDTOUCH_INTEGER_SAMPLES     1    //< 16bit integer samples
            #define SOUNDTOUCH_FLOAT_SAMPLES       1    //< 32bit float samples
         
        #endif
    
    

    根据你的类型注释选择对应的宏定义即可

    1. ffmpeg里面使用的时候需要注意的点:因为FFmpeg解码出来的PCM数据是8bit (uint8)的,而SoundTouch中最低
      16bit( 16bit integer samples),所以我们需要将8bit的数据转换成16bit
      后再给SoundTouch处理。

    8bit->16bit处理方式:

    SAMPLETYPE *sampleBuffer=NULL ;
    uint8_t *out_buffer = NULL;
    
    //....初始化等
    
    //获取音频数据到out_buffer
    int data_size = resampleAudio(reinterpret_cast<void **>(&out_buffer));
    for(int i = 0; i < data_size / 2 + 1; i++)
    {
        sampleBuffer[i] = (buffer[i * 2] | ((buffer[i * 2 + 1]) << 8));
    }
    
    
    1. 官方示例,将一个文件变速变调转为另外一个文件
    static void
    _processFile(SoundTouch *pSoundTouch, const float pitch, const float tempo, const char *inFileName,
                 const char *outFileName) {
    
        SoundTouch *pSoundTouch = new SoundTouch();
        
        //设置音调
        pSoundTouch->setPitch(pitch);
        //设置音速
        pSoundTouch->setTempo(tempo);
        
        int nSamples;//采样率
        int nChannels;//声道
        int buffSizeSamples;//每一次缓冲大小
        SAMPLETYPE sampleBuffer[BUFF_SIZE];//缓冲
    
        // open input file
        WavInFile inFile(inFileName);
        int sampleRate = inFile.getSampleRate();
        int bits = inFile.getNumBits();
        nChannels = inFile.getNumChannels();
    
        // create output file
        WavOutFile outFile(outFileName, sampleRate, bits, nChannels);
    
        pSoundTouch->setSampleRate(sampleRate);
        pSoundTouch->setChannels(nChannels);
    
        assert(nChannels > 0);
        buffSizeSamples = BUFF_SIZE / nChannels;
    
        // Process samples read from the input file
        while (inFile.eof() == 0) {
            int num;
    
            // Read a chunk of samples from the input file
            num = inFile.read(sampleBuffer, BUFF_SIZE);
            nSamples = num / nChannels;
    
            // Feed the samples into SoundTouch processor
            pSoundTouch->putSamples(sampleBuffer, nSamples);
    
            // Read ready samples from SoundTouch processor & write them output file.
            // NOTES:
            // - 'receiveSamples' doesn't necessarily return any samples at all
            //   during some rounds!
            // - On the other hand, during some round 'receiveSamples' may have more
            //   ready samples than would fit into 'sampleBuffer', and for this reason
            //   the 'receiveSamples' call is iterated for as many times as it
            //   outputs samples.
            do {
                nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
                outFile.write(sampleBuffer, nSamples * nChannels);
            } while (nSamples != 0);
        }
    
        // Now the input file is processed, yet 'flush' few last samples that are
        // hiding in the SoundTouch's internal processing pipeline.
        pSoundTouch->flush();
        do {
            nSamples = pSoundTouch->receiveSamples(sampleBuffer, buffSizeSamples);
            outFile.write(sampleBuffer, nSamples * nChannels);
        } while (nSamples != 0);
    
        delete (pSoundTouch);
    }
    
    
    1. ffmpeg示例
    
        SoundTouch *soundTouch = NULL;
        SAMPLETYPE *sampleBuffer = NULL;
        //采样率
        int sample_rate=44100;
        //声道数
        int channels =2;
        //变调
        float pitch= 1.0f;
        //变数
        float speed= 1.0f;
        //采样位数 SoudTouch最低支持16bit,所以使用16bit的来播放
        int bits= 16;
         //每秒理论PCM大小
        int BUFF_SIZE =sample_rate * channels * bits/8;
        
       
        sampleBuffer = static_cast<SAMPLETYPE *>(malloc(BUFF_SIZE));
        soundTouch = new SoundTouch();
        soundTouch->setSampleRate(sample_rate);
        soundTouch->setChannels(channels);
        soundTouch->setPitch(pitch);
        soundTouch->setTempo(speed);
    
    
        //获取SoundTouch处理的数据
        int WlAudio::getSoundTouchData() {
            int maxSamples = BUFF_SIZE / channels;
            while (playstatus != NULL && !playstatus->exit) {
                out_buffer = NULL;
                if (finished) {
                    finished = false;
                    //获取pcm数据到out_buffer
                    data_size = resampleAudio(reinterpret_cast<void **>(&out_buffer));
                    if (data_size > 0) {
                        for (int i = 0; i < data_size / 2 + 1; i++) {
                            //解码的数据是8bit的
                            //8bit->16bit
                            sampleBuffer[i] = (out_buffer[i * 2] | ((out_buffer[i * 2 + 1]) << 8));
                        }
                        //nb 表示采样个数  在resampleAudio里面解码的时候通过swr_convert返回值回去
                        soundTouch->putSamples(sampleBuffer, nb);
                        //获取处理后的数据  到sampleBuffer
                        num = soundTouch->receiveSamples(sampleBuffer,maxSamples);
                    } else {
                        soundTouch->flush();
                    }
                }
                if (num == 0) {
                    finished = true;
                    continue;
                } else {
                    if (out_buffer == NULL) {
                        num = soundTouch->receiveSamples(sampleBuffer, maxSamples);
                        if (num == 0) {
                            finished = true;
                            continue;
                        }
                    }
                    return num;
                }
            }
            return 0;
        }
        
        //OpenSLES播放数据
        
        int buffersize = wlAudio->getSoundTouchData();
        if (buffersize > 0) {
        //两个8bit->一个16bit     转换为char*是为了都转换成字节来处理
         (*wlAudio->pcmBufferQueue)->Enqueue(wlAudio->pcmBufferQueue,
                                                        (char *) wlAudio->sampleBuffer, buffersize * nChannels * 2 );
         }
    
    
    

    相关文章

      网友评论

          本文标题:使用SoudTouch实现变速变调

          本文链接:https://www.haomeiwen.com/subject/kcmuuftx.html