首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用SoudTouch实现变速变调

使用SoudTouch实现变速变调

作者头像
曾大稳
发布于 2018-09-11 02:33:06
发布于 2018-09-11 02:33:06
2.4K00
代码可运行
举报
文章被收录于专栏:曾大稳的博客曾大稳的博客
运行总次数:0
代码可运行
  1. 声明SoundTouch对象和内存变量,根据声道数和采样率初始化对象和内存
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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处理
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//采样个数,具体怎么获取看具体情况
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. 设置变速和变调
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
soundTouch->setPitch(1.0); //变调
soundTouch->setTempo(1.5);//变速
  1. SoudTouch选择处理数据是16bit还是32bit,在STTypes.h里面找到
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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处理方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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. 官方示例,将一个文件变速变调转为另外一个文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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示例
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

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 );
 }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
AAC的音频编码和解码实现
折腾了几天的AAC编码和解码,最开始用的是ffmpeg的接口,实现好实现,但是调试总是有各种问题,最后还是使用faac-1.28/faad2-2.7实现了AAC的编码和解码功能,使用这两个库的原因,是因为手里有另一套代码工程,已经实现了AAC的编码和解码,所以就直接拿来用了。代码参考:https://gitee.com/anyRTC/anyRTC-RTMP-OpenSource/blob/master/ArLiveLite/codec/aacencode.cc
呱牛笔记
2023/05/02
1K0
AAC的音频编码和解码实现
FFMPEG音视频开发: Linux下采集音频(alsa-lib库)与视频(V4L2框架)实时同步编码保存为MP4文件(视频录制)
参考这篇文章: https://blog.csdn.net/xiaolong1126626497/article/details/104919095
DS小龙哥
2022/01/12
2.3K0
FFMPEG音视频开发:  Linux下采集音频(alsa-lib库)与视频(V4L2框架)实时同步编码保存为MP4文件(视频录制)
libmad学习进阶3-----基于oss音频驱动架构的一个mp3播放器
以上就是通过libmad将mp3先解码成pcm,然后将pcm直接扔到/ dev/dsp音频设备中,但dsp音频设备属于oss架构,已经逐渐被alsa驱动取代,后续会介绍基于alsa驱动架构的mp3播放器
用户4148957
2022/06/14
7360
音视频开发之旅(67) - 变速不变调之sonic源码分析
上一篇我们学习了音频变速不变调的原理以及WSOLA波形相似叠加算法进行时域压扩处理。其中在寻找相似帧方面,Sonic采用AMDF(平均幅度差函数法)方法来进行寻找。
音视频开发之旅
2022/08/12
8980
音视频开发之旅(67) - 变速不变调之sonic源码分析
FFmpeg进行音频的解码和播放
上一篇FFmpeg 内容介绍 音视频解码和播放 介绍了FFmpeg进行解码的常见函数和,解码的过程。相关的函数介绍忘记了,可以参考上一篇。
包子388321
2020/07/27
6.7K2
ffplay源码分析6-音频重采样
FFmpeg解码得到的音频帧的格式未必能被SDL支持,在这种情况下,需要进行音频重采样,即将音频帧格式转换为SDL支持的音频格式,否则是无法正常播放的。 音频重采样涉及两个步骤: 1) 打开音频设备时进行的准备工作:确定SDL支持的音频格式,作为后期音频重采样的目标格式 2) 音频播放线程中,取出音频帧后,若有需要(音频帧格式与SDL支持音频格式不匹配)则进行重采样,否则直接输出
叶余
2019/04/02
1.7K0
ffmpeg 音频播放器相关
因为每一个AVframe的pts不一定都有,所以就需要自己手维护一个当前时间的变量
曾大稳
2018/09/11
2.1K0
ffplay.c 源码分析- 音频部分
1. 读取线程-read_thread 在main方法中会启动的读取的线程。 这个和视频的线程模型中是一致的。不同的是,循环读取的数据是音频数据。
deep_sadness
2018/12/18
1.4K0
如何将PCM格式的原始音频采样数据编码为MP3格式或AAC格式的音频文件?
    音频采样格式可以分为packed和planar两类。以packed格式保存的采样数据,各声道间按照采样值交替存储;以planar格式保存的采样数据,各个采样值按照不同声道连续存储
故乡的樱花开了
2023/10/22
8880
使用libswresample库实现音频重采样
  在音频重采样时,用到的核心结构是SwrContext,我们可以通过swr_alloc()获取swr_ctx实例,然后通过av_opt_set_int()函数和av_opt_set_sample_fmt()函数来设置音频重采样的参数,最后通过swr_init()函数初始化SwrContext实例即可。下面给出代码:
故乡的樱花开了
2023/10/22
5320
FFMPEG音频视频开发:QT采集摄像头数据帧与声卡音频通过FFMPEG实时推流到RTMP服务器(v1.0)
如果已经完成FFMPEG录制视频保存到本地的功能,完成RTMP推流只需要修改几行代码即可完成。
DS小龙哥
2022/01/12
1.2K0
NDK--利用OpenSL ES实现播放FFmpeg解码后的音频流
1、创建引擎接口对象 2、创建混音器 3、创建播放器(录音器) 4、设置缓冲队列和回调函数 5、设置播放状态 6、启动回调函数
aruba
2020/07/13
1.2K0
libmad学习进阶4 -----基于atlas音频驱动架构的MP3播放器
 /*modify by hfl 20140216*/ #define ALSA_PCM_NEW_HW_PARAMS_API # include <stdio.h> # include <unistd.h> # include <sys/stat.h> # include <sys/mman.h> # include "mad.h" #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<stdlib.h> #include <sys/ioctl.h> #include <sys/soundcard.h> #include <alsa/asoundlib.h> /*  * This is perhaps the simplest example use of the MAD high-level API.  * Standard input is mapped into memory via mmap(), then the high-level API  * is invoked with three callbacks: input, output, and error. The output  * callback converts MAD's high-resolution PCM samples to 16 bits, then  * writes them to standard output in little-endian, stereo-interleaved  * format.  */  //#define printf     static Get_file_length(char *PATH); static int init_dsp(); static int Uninit_dsp(); static int decode(unsigned char const *, unsigned long); static enum mad_flow outputplay(void *data,     struct mad_header const *header,     struct mad_pcm *pcm); int main(int argc, char *argv[]) { printf("The main is start!\n");   struct stat stat;   void *fdm;   int  fd;   //char buffer1[80000];   printf("###The input file is %s  ! the arc=%d###\n",argv[1],argc);   if (argc == 1)    {    printf("The argc is wrong!\n");     return 1;  } #if 0   if (fstat(STDIN_FILENO, &stat) == -1 ||       stat.st_size == 0)     return 2; #endif  fd =open(argv[1],O_RDWR); if(-1==fd) {    printf("sorry,The file open is faild!\n"); } else {  printf("The file open is sucessed!\n"); } //read(fd,buffer1,sizeof(buffer1)); //printf("%s", buffer1); stat.st_size = Get_file_length(argv[1]); printf("The file size is %d\n",stat.st_size ); printf("The Map is begin ok!\n"); fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);   if (fdm == MAP_FAILED) { printf("mmap is failed\n");     return 3; }   decode(fdm, stat.st_size);   if (munmap(fdm, stat.st
用户4148957
2022/06/14
8710
FFmpeg+OpenSLES 实现音频播放
最近一直在学习FFmpeg,看了网上各位大神的,都玩得很溜,自己也来一波骚操作。于是乎利用FFmpeg结合OpenSles来进行对音频文件的播放。网上看的都是别人的写的代码,拿来运行下,发现不是很适用。别人的毕竟是别人的,还是要自己打通下筋脉掌握下。
包子388321
2020/07/30
4.4K0
PCM文件添加WAV头
在asr平台实现pcm格式录制的文件增加wav头,发现根据网上给的方法添加wav头的wav文件播放异常,播放没有声音!
呱牛笔记
2023/05/02
1.2K0
PCM文件添加WAV头
使用libavcodec将mp3音频文件解码为pcm音频采样数据【[mp3float @ 0x561c1ec49940] Header missing】
  想要解决上面提到的问题,我们需要对mp3文件的格式有个大致了解,为了方便讲解,我这里画了个示意图:
故乡的樱花开了
2023/10/22
7170
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
福大大架构师每日一题
2023/03/17
2.1K0
2023-03-17:使用Go语言和FFmpeg库实现音频重采样解码,并将其保存为PCM格式的文件。
音频编码(一)——FFmpeg编码
这里为啥讲到了声波,讲到了我们的中学物理上的知识,因为我想大家能从根本理解后面音频编码的各种参数以及原因。当然这些知识网上都能搜到,我只是整合一下。
用户2929716
2018/08/23
5.9K0
音频编码(一)——FFmpeg编码
FFmpeg之重采样demo解析!
通俗的讲,重采样就是改变音频的采样率、sample format(采样格式)、声道数(channel)等参数,使之按照我们期望的参数输出。
用户6280468
2022/03/21
1.6K0
FFmpeg之重采样demo解析!
Android平台RTSP轻量级服务|RTMP推送摄像头或屏幕之音频接口设计
好多开发者在做Android平台录像或者RTSP轻量级服务、RTMP推送相关模块时,对需要设计哪些常用接口会心存疑惑,本文主要以大牛直播SDK(官方)为例,简单介绍下Android平台直播推送SDK所有音频相关的接口,感兴趣的开发者可以参考。
音视频牛哥
2021/04/20
7930
推荐阅读
相关推荐
AAC的音频编码和解码实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档