Audio C语言中的音频录制和播放:音频增益问题

Audio C语言中的音频录制和播放:音频增益问题,audio,freebsd,alsa,Audio,Freebsd,Alsa,问题本质上是如何正确地将增益应用于音频样本 我在FreeBSD和OSS上编程,但在音频样本中操纵音量对于其他操作系统和应用程序可能是相同的 我正在研究其他应用程序的内部结构,比如(在C++中)和(在C中),但我不知道当我阅读一个示例并将增益应用到它时会出现什么问题:它会变得扭曲和嘈杂我的重点是理解为什么调低音量不起作用(增益小于1) 我正在使用立体声16位LE样本。在不使用增益的情况下,它可以完美地工作(录制和播放) 我认为我应该将整数样本转换为浮点;乘以增益因子并将其恢复为整数。但它不起作用。

问题本质上是如何正确地将增益应用于音频样本

我在FreeBSD和OSS上编程,但在音频样本中操纵音量对于其他操作系统和应用程序可能是相同的

我正在研究其他应用程序的内部结构,比如(在C++中)和(在C中),但我不知道当我阅读一个示例并将增益应用到它时会出现什么问题:它会变得扭曲和嘈杂我的重点是理解为什么调低音量不起作用(增益小于1)

我正在使用立体声16位LE样本。在不使用增益的情况下,它可以完美地工作(录制和播放)

我认为我应该将整数样本转换为浮点;乘以增益因子并将其恢复为整数。但它不起作用。对于函数中的
静态int流
,这似乎是完全相同的方法

下面是我的代码(没有使用额外的lib)。函数回放是我应用增益的地方

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "/usr/include/sys/soundcard.h"
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/stat.h> //man 2 chmod
#include <signal.h>

#define DEBUG 1
#define log(msg) if (DEBUG) printf("[LOG] %s\n",msg)
#define err(msg)  {printf("[ERR] %s\n",msg); exit(1); }


const char *device = "/dev/dsp3.1";     //Audio device
char *rawFile = "/tmp/raw-file.wav";    //Raw file to record and playback
int fragmentSize = 256;
int b_continue = 1;


void signalHandler(int sigNum){
    log("Signal captured");
    b_continue = 0;
}


void configDevice(int fdDsp){
    int ossCapabilities = 0;

    if(fdDsp == -1)
        err("can't open device");

    if( ioctl(fdDsp, SNDCTL_DSP_GETCAPS, &ossCapabilities) == -1)
        err("unsupported: SNDCTL_DSP_GETCAPS");

    /*
     * http://www.opensound.com/pguide/audio2.html
     */

    if(ossCapabilities & DSP_CAP_TRIGGER != DSP_CAP_TRIGGER){
        err("Triggering of recording/playback is not possible with this OSS device.");

    }

    if(ossCapabilities & DSP_CAP_REALTIME != DSP_CAP_REALTIME){
        err("No DSP_CAP_REALTIME.");

    }

    if(ioctl(fdDsp, SNDCTL_DSP_SETDUPLEX, &ossCapabilities) == -1)
        err("can't SNDCTL_DSP_SETDUPLEX");

    if(ossCapabilities & DSP_CAP_DUPLEX != DSP_CAP_DUPLEX)
        err("can't DSP_CAP_DUPLEX");

    int format = AFMT_S16_LE;   //set format
    if(ioctl(fdDsp, SNDCTL_DSP_SETFMT, &format ) == -1){
        err("Error setting format.");

    }

    int channels = 1; //mono=0 stereo=1
    if(ioctl(fdDsp, SNDCTL_DSP_STEREO, &channels ) == -1){
        err("Error setting channels." );

    }
    // FREQUENCY RATE
    int speed = 44100;
    if(ioctl(fdDsp, SNDCTL_DSP_SPEED, &speed ) == -1){
        err("Error setting speed.");

    }

    // FRAGMENT SIZE
    if(ioctl(fdDsp, SNDCTL_DSP_SETBLKSIZE, &fragmentSize) == -1){ //normalmente 2048 bits
        err("Cannot SNDCTL_DSP_SETBLKSIZE.");

    }


}

void record(){
    int fdDsp = open(device, O_RDONLY);
    configDevice(fdDsp);
    //create file for writing
    const int fdOutput = open(rawFile, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);

    if(fdOutput ==-1)
        err("can't open file to write");
    log("Recording...");

    do{
         // Triggers recording
         int enableBits = PCM_ENABLE_INPUT;
         if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1)
             err("Can't record: SNDCTL_DSP_SETTRIGGER");

         int *buf[fragmentSize];
         read(fdDsp, buf, fragmentSize);
         write(fdOutput, buf, fragmentSize);

     } while(b_continue == 1);

     close(fdOutput);
     close(fdDsp);
}

void playback(){
    log("Opening file:");
    log(rawFile);
    log("On device:");
    log(device);

    int fdDsp = open(device, O_WRONLY);
    configDevice(fdDsp);

    const int fdInput = open(rawFile, O_RDONLY);

    if(fdInput ==-1)
        err("can't open file");
    log("Playing...");

    int eof = 0;

    do{
        // TRIGGERs PLAYBACK
        int enableBits = PCM_ENABLE_OUTPUT;
        if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1){
            err("Cannot SNDCTL_DSP_SETTRIGGER.");

        }

        int buf[fragmentSize];
        eof = read(fdInput, buf, fragmentSize); //bytes read or -1 if EOF

        // audio processing:
        for(int i=0;i<fragmentSize;i++){
            // learning how to get left and right channels from buffer
            int l = (buf)[i] & 0xffff;
            int r = ((buf)[i] >> 16)  & 0xffff ;

            // FIXME: it is causing distortion:
            float fl = l;
            float fr = r;
            fl *= 1.0;
            fr *= 0.3; //if different than 1, sounds distorted and noisy
            l = fl;
            r = fr;


            // OK: unite Left and Right channels again
            int lr = (l ) | (r << 16);
            // OK: other options to mix these two channels:
            int lleft = l;              //Just the left channel
            int rright = (r << 16);     //Just the right channel
            int lmono = (l << 16) | l;  //Left ch. on both channels
            int rmono = (r << 16) | r;  //Right ch. on both channels

            // the output:
            (buf)[i] = lr;

        }

        write(fdDsp, buf, fragmentSize);
        if(b_continue == 0) break;
    } while(eof > 0);

    close(fdInput);
    close(fdDsp);
}

int main(int argc, char *argv[])
{

    signal(SIGINT, signalHandler);
    log("Ctrl^C to stop recording/playback");
    record();
    b_continue = 1; playback();
    log("Stopped.");
    return 0;
}
我接受你的回答

现在音频处理循环每次使用一个样本(左和右交错)

更新代码:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "/usr/include/sys/soundcard.h"
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/stat.h> //man 2 chmod
#include <signal.h>
#include <stdint.h> //has type int16_t (short)

#define DEBUG 1
#define log(msg) if (DEBUG) printf("[LOG] %s\n",msg)
#define err(msg)  {printf("[ERR] %s\n",msg); exit(1); }


const char *device = "/dev/dsp3.1";     //Audio device
char *rawFile = "/tmp/stereo.wav";    //Raw file to record and playback
int fragmentSize = 256;
int b_continue = 1;


void signalHandler(int sigNum){
    log("Signal captured");
    b_continue = 0;
}


void configDevice(int fdDsp){
    int ossCapabilities = 0;

    if(fdDsp == -1)
        err("can't open device");

    if( ioctl(fdDsp, SNDCTL_DSP_GETCAPS, &ossCapabilities) == -1)
        err("unsupported: SNDCTL_DSP_GETCAPS");

    /*
     * http://www.opensound.com/pguide/audio2.html
     */

    if(ossCapabilities & DSP_CAP_TRIGGER != DSP_CAP_TRIGGER){
        err("Triggering of recording/playback is not possible with this OSS device.");

    }

    if(ossCapabilities & DSP_CAP_REALTIME != DSP_CAP_REALTIME){
        err("No DSP_CAP_REALTIME.");

    }

    if(ioctl(fdDsp, SNDCTL_DSP_SETDUPLEX, &ossCapabilities) == -1)
        err("can't SNDCTL_DSP_SETDUPLEX");

    if(ossCapabilities & DSP_CAP_DUPLEX != DSP_CAP_DUPLEX)
        err("can't DSP_CAP_DUPLEX");

    int format = AFMT_S16_LE;   //set format
    if(ioctl(fdDsp, SNDCTL_DSP_SETFMT, &format ) == -1){
        err("Error setting format.");

    }

    int channels = 1; //mono=0 stereo=1
    if(ioctl(fdDsp, SNDCTL_DSP_STEREO, &channels ) == -1){
        err("Error setting channels." );

    }
    // FREQUENCY RATE
    int speed = 44100;
    if(ioctl(fdDsp, SNDCTL_DSP_SPEED, &speed ) == -1){
        err("Error setting speed.");

    }

    // FRAGMENT SIZE
    if(ioctl(fdDsp, SNDCTL_DSP_SETBLKSIZE, &fragmentSize) == -1){ //normalmente 2048 bits
        err("Cannot SNDCTL_DSP_SETBLKSIZE.");

    }


}

void record(){
    int fdDsp = open(device, O_RDONLY);
    configDevice(fdDsp);
    //create file for writing
    const int fdOutput = open(rawFile, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);

    if(fdOutput ==-1)
        err("can't open file to write");
    log("Recording...");

    do{
         // Triggers recording
         int enableBits = PCM_ENABLE_INPUT;
         if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1)
             err("Can't record: SNDCTL_DSP_SETTRIGGER");

         // Wrong:
//         int *buf[fragmentSize];
//         read(fdDsp, buf, fragmentSize);
//         write(fdOutput, buf, fragmentSize);
         int16_t *buf[fragmentSize/sizeof (int16_t)];
         read(fdDsp, buf, fragmentSize/sizeof (int16_t));
         write(fdOutput, buf, fragmentSize/sizeof (int16_t));

     } while(b_continue == 1);

     close(fdOutput);
     close(fdDsp);
}

void playback(){
    log("Opening file:");
    log(rawFile);
    log("On device:");
    log(device);

    int fdDsp = open(device, O_WRONLY);
    configDevice(fdDsp);

    const int fdInput = open(rawFile, O_RDONLY);

    if(fdInput ==-1)
        err("can't open file");
    log("Playing...");

    int eof = 0;

    do{
        // TRIGGERs PLAYBACK
        int enableBits = PCM_ENABLE_OUTPUT;
        if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1){
            err("Cannot SNDCTL_DSP_SETTRIGGER.");

        }

        //Wrong buffer type (too large) and wrong last parameter for read():
//        int buf[fragmentSize];
//        eof = read(fdInput, buf, fragmentSize);
        int16_t buf[fragmentSize/sizeof (int16_t)];
        eof = read(fdInput, buf, fragmentSize/sizeof (int16_t));

        // audio processing:
        for(int i=0;i<fragmentSize/sizeof (int16_t);i++){
            int16_t l = buf[i];
            int16_t r = buf[i+1];

            // Using int16_t (short) buffer, gain works but stereo is inverted with factor >= 1.4f
            float fl = l;
            float fr = r;
            fl *= 2.0f;
            fr *= 3.0f;
            l = fl;
            r = fr;

            // the output:
            (buf)[i] = l;
            i++;
            (buf)[i] = r;

        }

//        write(fdDsp, buf, fragmentSize); //wrong
        write(fdDsp, buf, fragmentSize/sizeof (int16_t));
        if(b_continue == 0) break;
    } while(eof > 0);

    close(fdInput);
    close(fdDsp);
}

int main(int argc, char *argv[])
{

    signal(SIGINT, signalHandler);
    log("Ctrl^C to stop recording/playback");
    record();
    b_continue = 1; playback();
    log("Stopped.");
    return 0;
}
#包括
#包括
#包括
#include“/usr/include/sys/soundcard.h”
#包括
#包括
#包括//man 2 chmod
#包括
#include//has type int16\u t(short)
#定义调试1
#如果(调试)printf(“[log]%s\n”,msg),则定义日志(msg)
#定义err(msg){printf(“[err]%s\n”,msg);退出(1);}
const char*device=“/dev/dsp3.1”//音频设备
char*rawFile=“/tmp/stereo.wav”//要录制和播放的原始文件
int fragmentSize=256;
int b_continue=1;
无效信号处理器(int sigNum){
日志(“捕获的信号”);
b_continue=0;
}
无效配置设备(int fdDsp){
int=0;
如果(fdDsp==-1)
错误(“无法打开设备”);
如果(ioctl(fdDsp、SNDCTL_DSP_GETCAPS和OSS功能)=-1)
错误(“不支持:SNDCTL_DSP_GETCAPS”);
/*
* http://www.opensound.com/pguide/audio2.html
*/
中频(OSS功能和DSP_电容_触发器!=DSP_电容_触发器){
err(“此OSS设备无法触发录制/播放。”);
}
if(OSS功能和DSP_CAP_REALTIME!=DSP_CAP_REALTIME){
错误(“没有DSP\u CAP\u实时”);
}
如果(ioctl(fdDsp、SNDCTL\U DSP\U SETDUPLEX和OSS功能)=-1)
错误(“不能使用DSP设置双工”);
if(OSS功能和DSP_CAP_双工!=DSP_CAP_双工)
错误(“不能进行双工”);
int format=AFMT\u S16\u LE;//设置格式
如果(ioctl(fdDsp、SNDCTL\U DSP\U SETFMT和格式)=-1){
错误(“错误设置格式”);
}
int channels=1;//单声道=0立体声=1
中频(ioctl(fdDsp、SNDCTL\U DSP\U立体声和声道)=-1){
err(“设置通道时出错”);
}
//频率率
内速度=44100;
如果(ioctl(fdDsp、SNDCTL\U DSP\U速度和速度)=-1){
错误(“错误设置速度”);
}
//碎片大小
if(ioctl(fdDsp、SNDCTL\u DSP\u SETBLKSIZE和fragmentSize)==-1){//normalmente 2048位
err(“无法SNDCTL_DSP_SETBLKSIZE.”);
}
}
无效记录(){
int fdDsp=打开(仅限设备);
配置设备(fdDsp);
//创建要写入的文件
const int fdOutput=open(rawFile、O|u WRONLY、O|u CREAT、S|u IWUSR、S|u IRUSR);
如果(fdOutput==-1)
错误(“无法打开文件进行写入”);
日志(“记录…”);
做{
//触发记录
int enableBits=PCM_ENABLE_输入;
如果(ioctl(fdDsp、SNDCTL\U DSP\U设置触发器和启用位)=-1)
错误(“无法录制:SNDCTL_DSP_SETTRIGGER”);
//错:
//int*buf[碎片大小];
//读取(fdDsp、buf、碎片大小);
//写入(fdOutput、buf、碎片大小);
int16_t*buf[碎片大小/大小(int16_t)];
读取(fdDsp、buf、碎片大小/大小(int16_t));
写入(fdOutput、buf、fragmentSize/sizeof(int16_t));
}而(b_continue==1);
关闭(FD输出);
关闭(fdDsp);
}
无效播放(){
日志(“打开文件:”);
日志(原始文件);
登录(“在设备:”);
日志(设备);
int fdDsp=打开(仅限设备,O_);
配置设备(fdDsp);
const int fdInput=open(仅限原始文件);
如果(fdInput==-1)
错误(“无法打开文件”);
日志(“播放…”);
int-eof=0;
做{
//触发播放
int enableBits=PCM_ENABLE_输出;
如果(ioctl(fdDsp、SNDCTL\U DSP\U设置触发器和启用位)=-1){
错误(“无法SNDCTL_DSP_设置触发器”);
}
//读取()的缓冲区类型错误(太大)和最后一个参数错误:
//int buf[碎片大小];
//eof=读取(fdInput、buf、碎片大小);
int16_t buf[碎片大小/大小(int16_t)];
eof=读取(fdInput、buf、碎片大小/sizeof(int16_t));
//音频处理:
对于(int i=0;i=1.4f
浮球fl=l;
浮点数fr=r;
fl*=2.0f;
fr*=3.0f;
l=fl;
r=fr;
//输出:
(buf)[i]=l;
i++;
(buf)[i]=r;
}
//写入(fdDsp、buf、碎片大小);//错误
写入(fdDsp、buf、碎片大小/大小(int16_t));
如果(b_continue==0)中断;
}而(eof>0);
关闭(FDI输入);
关闭(fdDsp);
}
int main(int argc,char*argv[])
{
信号(SIGINT,信号处理器);
日志(“Ctrl^C停止录制/播放”);
记录();
b_continue=1;播放();
日志(“停止”);
返回0;
}
谢谢,

read()/write()的最后一个参数是字节数,但是buf[]中的条目有多个字节

在二进制数的两个补码表示中,负值是(或必须)符号扩展的,即最高有效位是1。在该代码中,提取L/R通道或组合它们都不能正确地用于负采样

处理负样本的最简单方法是每个样本使用一个数组条目,即
short int

Than
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include "/usr/include/sys/soundcard.h"
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/stat.h> //man 2 chmod
#include <signal.h>
#include <stdint.h> //has type int16_t (short)

#define DEBUG 1
#define log(msg) if (DEBUG) printf("[LOG] %s\n",msg)
#define err(msg)  {printf("[ERR] %s\n",msg); exit(1); }


const char *device = "/dev/dsp3.1";     //Audio device
char *rawFile = "/tmp/stereo.wav";    //Raw file to record and playback
int fragmentSize = 256;
int b_continue = 1;


void signalHandler(int sigNum){
    log("Signal captured");
    b_continue = 0;
}


void configDevice(int fdDsp){
    int ossCapabilities = 0;

    if(fdDsp == -1)
        err("can't open device");

    if( ioctl(fdDsp, SNDCTL_DSP_GETCAPS, &ossCapabilities) == -1)
        err("unsupported: SNDCTL_DSP_GETCAPS");

    /*
     * http://www.opensound.com/pguide/audio2.html
     */

    if(ossCapabilities & DSP_CAP_TRIGGER != DSP_CAP_TRIGGER){
        err("Triggering of recording/playback is not possible with this OSS device.");

    }

    if(ossCapabilities & DSP_CAP_REALTIME != DSP_CAP_REALTIME){
        err("No DSP_CAP_REALTIME.");

    }

    if(ioctl(fdDsp, SNDCTL_DSP_SETDUPLEX, &ossCapabilities) == -1)
        err("can't SNDCTL_DSP_SETDUPLEX");

    if(ossCapabilities & DSP_CAP_DUPLEX != DSP_CAP_DUPLEX)
        err("can't DSP_CAP_DUPLEX");

    int format = AFMT_S16_LE;   //set format
    if(ioctl(fdDsp, SNDCTL_DSP_SETFMT, &format ) == -1){
        err("Error setting format.");

    }

    int channels = 1; //mono=0 stereo=1
    if(ioctl(fdDsp, SNDCTL_DSP_STEREO, &channels ) == -1){
        err("Error setting channels." );

    }
    // FREQUENCY RATE
    int speed = 44100;
    if(ioctl(fdDsp, SNDCTL_DSP_SPEED, &speed ) == -1){
        err("Error setting speed.");

    }

    // FRAGMENT SIZE
    if(ioctl(fdDsp, SNDCTL_DSP_SETBLKSIZE, &fragmentSize) == -1){ //normalmente 2048 bits
        err("Cannot SNDCTL_DSP_SETBLKSIZE.");

    }


}

void record(){
    int fdDsp = open(device, O_RDONLY);
    configDevice(fdDsp);
    //create file for writing
    const int fdOutput = open(rawFile, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);

    if(fdOutput ==-1)
        err("can't open file to write");
    log("Recording...");

    do{
         // Triggers recording
         int enableBits = PCM_ENABLE_INPUT;
         if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1)
             err("Can't record: SNDCTL_DSP_SETTRIGGER");

         // Wrong:
//         int *buf[fragmentSize];
//         read(fdDsp, buf, fragmentSize);
//         write(fdOutput, buf, fragmentSize);
         int16_t *buf[fragmentSize/sizeof (int16_t)];
         read(fdDsp, buf, fragmentSize/sizeof (int16_t));
         write(fdOutput, buf, fragmentSize/sizeof (int16_t));

     } while(b_continue == 1);

     close(fdOutput);
     close(fdDsp);
}

void playback(){
    log("Opening file:");
    log(rawFile);
    log("On device:");
    log(device);

    int fdDsp = open(device, O_WRONLY);
    configDevice(fdDsp);

    const int fdInput = open(rawFile, O_RDONLY);

    if(fdInput ==-1)
        err("can't open file");
    log("Playing...");

    int eof = 0;

    do{
        // TRIGGERs PLAYBACK
        int enableBits = PCM_ENABLE_OUTPUT;
        if(ioctl(fdDsp, SNDCTL_DSP_SETTRIGGER, &enableBits) == -1){
            err("Cannot SNDCTL_DSP_SETTRIGGER.");

        }

        //Wrong buffer type (too large) and wrong last parameter for read():
//        int buf[fragmentSize];
//        eof = read(fdInput, buf, fragmentSize);
        int16_t buf[fragmentSize/sizeof (int16_t)];
        eof = read(fdInput, buf, fragmentSize/sizeof (int16_t));

        // audio processing:
        for(int i=0;i<fragmentSize/sizeof (int16_t);i++){
            int16_t l = buf[i];
            int16_t r = buf[i+1];

            // Using int16_t (short) buffer, gain works but stereo is inverted with factor >= 1.4f
            float fl = l;
            float fr = r;
            fl *= 2.0f;
            fr *= 3.0f;
            l = fl;
            r = fr;

            // the output:
            (buf)[i] = l;
            i++;
            (buf)[i] = r;

        }

//        write(fdDsp, buf, fragmentSize); //wrong
        write(fdDsp, buf, fragmentSize/sizeof (int16_t));
        if(b_continue == 0) break;
    } while(eof > 0);

    close(fdInput);
    close(fdDsp);
}

int main(int argc, char *argv[])
{

    signal(SIGINT, signalHandler);
    log("Ctrl^C to stop recording/playback");
    record();
    b_continue = 1; playback();
    log("Stopped.");
    return 0;
}