Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >用立体声录音分离Android上的两个音频通道

用立体声录音分离Android上的两个音频通道
EN

Stack Overflow用户
提问于 2021-12-21 05:36:35
回答 1查看 176关注 0票数 1

我试图用AudioRecord在安卓上录制一个音频,并将左右通道的录音分离成两个不同的文件,然后将其转换为wav,以便能够在phone.But上播放,录制的文件速度快,音高高。

我阅读了所有的示例并编写了这段代码,但我不确定是哪一部分导致了问题。

这是我的AudioRecord定义。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    minBufLength = AudioTrack.getMinBufferSize(48000,AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);

    recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 48000, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufLength);

然后读取短数据,然后将短数据转换为字节,最后将其分离为两个通道的字节数组。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 shortData = new short[minBufLength/2];
 int readSize = recorder.read(shortData,0,minBufLength/2);

 byte bData[] = short2byte(shortData);

 for(int i = 0; i < readSize/2; i++)
  {

    final int offset = i * 2 * 2; // two bytes per sample and 2 channels
    rightChannelFos.write(bData, offset , 2);
    leftChannelFos.write(bData, offset + 2 , 2 );
  }

File rightChannelF1 = new File("/sdcard/rightChannelaudio"); // The location of your PCM file
File leftChannelF1 = new File("/sdcard/leftChannelaudio"); // The location of your PCM file
File rightChannelF2 = new File("/sdcard/rightChannelaudio.wav"); // The location where you want your WAV file
File leftChannelF2 = new File("/sdcard/leftChannelaudio.wav"); // The location where you want your WAV file
rawToWave(rightChannelF1, rightChannelF2);
rawToWave(leftChannelF1, leftChannelF2);

// convert short to byte
private byte[] short2byte(short[] sData) {
    int shortArrsize = sData.length;
    byte[] bytes = new byte[shortArrsize * 2];
    for (int i = 0; i < shortArrsize; i++) {
        bytes[i * 2] = (byte) (sData[i] & 0x00FF);
        bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
        sData[i] = 0;
    }
    return bytes;

}

这是rawToWave函数。我没有包括其他的写函数来保持文章的简单性。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void rawToWave(final File rawFile, final File waveFile) throws IOException {

    byte[] rawData = new byte[(int) rawFile.length()];
    DataInputStream input = null;
    try {
        input = new DataInputStream(new FileInputStream(rawFile));
        input.read(rawData);
    } finally {
        if (input != null) {
            input.close();
        }
    }

    DataOutputStream output = null;
    try {
        output = new DataOutputStream(new FileOutputStream(waveFile));
        // WAVE header
        // see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
        writeString(output, "RIFF"); // chunk id
        writeInt(output, 36 + rawData.length); // chunk size
        writeString(output, "WAVE"); // format
        writeString(output, "fmt "); // subchunk 1 id
        writeInt(output, 16); // subchunk 1 size
        writeShort(output, (short) 1); // audio format (1 = PCM)
        writeShort(output, (short) 2); // number of channels
        writeInt(output, 48000); // sample rate
        writeInt(output, 48000 * 2); // byte rate
        writeShort(output, (short) 2); // block align
        writeShort(output, (short) 16); // bits per sample
        writeString(output, "data"); // subchunk 2 id
        writeInt(output, rawData.length); // subchunk 2 size
        // Audio data (conversion big endian -> little endian)
        short[] shorts = new short[rawData.length / 2];
        ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
        for (short s : shorts) {
            bytes.putShort(s);
        }

        output.write(fullyReadFileToBytes(rawFile));
    } finally {
        if (output != null) {
            output.close();
        }
    }
}

更新:

我将此添加为一个更新,以防其他人面临这样的问题。由于一些我不明白的原因,信道更新循环不起作用。因此,我分别更新了每个通道的字节数组。既然这是一个16位的方案,那就意味着每个样本有2个字节,所以原始数据中的样本都是这种格式的LLLL,这就是为什么循环应该基于以下内容

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 for(int i = 0; i < readSize; i= i + 2)
        {
            leftChannelAudioData[i] = bData[2*i];
            leftChannelAudioData[i+1] = bData[2*i+1];

            rightChannelAudioData[i] =  bData[2*i+2];
            rightChannelAudioData[i+1] = bData[2*i+3];
        }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-12-21 06:40:19

在WAV-头中,您有两个通道(立体声)输出格式:

writeShort(output, (short) 2); // number of channels

如果是这样,那么byterate应该是48000 *4 (=每个通道*每个样本2个字节),而且由于同样的原因,块对齐应该是4。

另外,您需要编写每个示例两次,因为您的输出是立体声的:每个通道一次。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    rightChannelFos.write(bData, offset , 2);
    rightChannelFos.write(bData, offset , 2);
    leftChannelFos.write(bData, offset + 2 , 2 );
    leftChannelFos.write(bData, offset + 2 , 2 );

但更简单的解决方案只是将输出格式更改为单通道(1通道):

writeShort(output, (short) 1); // number of channels

UPD

对于输入缓冲区,您需要选择足够大的大小(例如1秒),以便在以小块读取它时不会出现不足。当您处理数据时,系统将保存它,例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 48000, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, 48000 * 4); // 1 second long

您可以将读取缓冲区保持较小,但某些预定义大小的缓冲区较小。(例如1024-4096个样本)。调用recorder.read时,它返回获得的数据的实际大小,不超过缓冲区大小(作为参数传递),也不超过缓冲区中可用的数据。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70436367

复制
相关文章
MySQL根据条件返回bool值
有时候我希望从数据库中拉取数据时能够获得一些较为复杂的信息,比如获取活动信息时还想知道当前用户是否参加了活动(需要再做一次查询才能判断),为了简化后台逻辑,避免查询两次获得两组结果再合并,我发现了CASE语句。
gojam
2019/05/14
4.2K0
Ext根据条件显示隐藏列
  写在ExtonReady函数里面,并在表格成功渲染之后,可以添加判断是否隐藏或者显示某一列
河岸飞流
2019/08/09
2.7K0
问与答99:如何根据组合条件求和?
Q:如下图1所示的数据排列,每组数据都由“月份、分类、字母、数值”组成,但是月份在单独的行,其他的数据分布在各行中且存在重复。
fanjy
2021/03/12
2.8K0
R 语言根据条件判断返回ABCD状态
有朋友给我写信,问我R语言的问题,与其回复代码,不如写篇博客,顺便试试CSDN的新模板。
邓飞
2020/09/14
1K0
R 语言根据条件判断返回ABCD状态
SpringBoot根据条件注入Bean@Condition用法
@Condition:这个注解在Spring4中引入,其主要作用就是判断条件是否满足,从而决定是否初始化并向容器注册Bean!
时光_赌徒
2020/05/25
2.4K0
Excel公式技巧50: 根据条件来排序
有时候,我们想基于指定的条件对数据进行排序,如下图1所示,记录了不同区域员工的销售额。
fanjy
2020/09/04
2.6K0
Excel公式技巧50: 根据条件来排序
『前端技术』相比后端是否只能打辅助?
论坛上人们经常会为前后端的问题展开撕 x 大战,很多时候问题的根源是没有定义好前后端的概念.
秃头哥编程
2019/07/04
5770
『前端技术』相比后端是否只能打辅助?
Excel公式技巧51: 根据条件来排序(续)
在《Excel公式技巧50:根据条件来排序》中,我们基于指定的一个条件对数据进行排序,所举示例为给不同区域的员工按销售额从大到小的顺序排序,结果如下图1所示。
fanjy
2020/09/04
2.1K0
Excel公式技巧51: 根据条件来排序(续)
根据select下拉框值判断验证条件
根据select下拉框值判断当前选中的是哪个区域,并且判断当前选中区域里面的值是否为空,如果为空,则弹出弹框提示,请输入xx区域名称,以下只是一个小demo,随手复制黏贴到代码里面,能看的更加明白。
王小婷
2019/08/01
3.7K0
根据select下拉框值判断验证条件
【说站】js如何检查是否满足条件
1、every只有满足每个条件才能返回true,some是任何一个满足返回true的项目,filter过滤出所有符合条件的项目(找不到返回空)。
很酷的站长
2022/11/24
2.2K0
【说站】js如何检查是否满足条件
小程序根据返回值是否为空判断标签是否显示
如果为空,则不显示奖励这两个字的标签 wxml <view class="cu-item" wx:for="{{allSignList}}" wx:key="index"> <view class="content"> <view wx:if="{{item.taskReward}}">奖励:{{item.taskReward}}</view> </view> </view> js Page({ data: { allSignList: [] }, onLoad: fun
王小婷
2020/12/28
2.8K0
小程序根据返回值是否为空判断标签是否显示
VBA应用技巧:根据条件设置工作表标签颜色
使用VBA可以为我们的工作簿添加很多额外的功能,让我们更好地了解工作簿所呈现的信息。下面是一个例子。
fanjy
2023/02/14
1.8K0
VBA应用技巧:根据条件设置工作表标签颜色
mybatis plus 根据model的字段,自动拼生成条件
2021-05-06 发表在 编程语言 16 mybatis plus 根据model的字段,自动拼生成条件 /** * 根据model的字段,自动拼生成条件 */ public class QueryHelper { public static <T> QueryWrapper<T> getQuery(T model) { var query = new QueryWrapper<T>(); Arrays.asList(model.get
小贝壳
2021/05/08
1.1K0
Python是否可以根据不同条件判断,让lst=lis_1或者lst=lst_2,经常随意切换?
前几天在Python白银群【大侠】问了一个Python列表基础问题,一起来看看吧。
前端皮皮
2023/08/17
1560
Python是否可以根据不同条件判断,让lst=lis_1或者lst=lst_2,经常随意切换?
Vue2.x-02根据条件动态设置下拉框、时间选择器、文本框是否可编辑
需求是:特定环节,数据只能查看,不能修改。 (查看页面和新增复用的同一个子组件)。 因此需要动态判断。
小小工匠
2021/08/17
1.1K0
[代码结构设计]根据不同条件使用不同实现类的业务代码设计
这样大家可能不是太理解。举个例子,现在大街小巷上的商户都采用了聚合支付的支付方式,聚合支付也就是商户柜台前放了一个支持支付宝、微信、京东钱包、银联等等的二维码,用户可以通过任意一款支付APP进行支付。
云枭
2018/11/08
2.3K0
mysql根据分组和条件查询以后如何统计记录的条数
1、子查询,查询出的数据随便起一个别名,然后根据分组和条件查询出的数据,作为一个具有一列的一个表,然后外面的查询查询这个数据表的这一列的总数,即可。    
别先生
2018/12/07
4.7K0
单点登录filter根据redis中的key判断是否退出
其实可以直接用userSession 但由于项目已经封装了,所以再创建个UserMessage实体类,在登录后将token存入session,当从redis中通过key获取token为空时,便清除userSession,跳转到指定系统页面。
用户3003813
2018/09/06
1.1K0
评估是否使用微服务架构的五个关键条件
​为了实施微服务架构,我们一直在遵循实践原则:每个微服务都必须拥有自己的独立数据库来避免数据库级别的耦合。
海岛船长加西亚
2023/02/23
5040
点击加载更多

相似问题

根据条件打印行

36

使用unix根据条件打印行

27

根据output2值从output1打印行

12

根据用户输入的条件从.csv打印行

328

在同一打印行中阅读某物

22
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文