Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Dec 2019 19:02:33 -0300
From:      Marcel Bonnet <marcelbonnet@gmail.com>
To:        Hans Petter Selasky <hps@selasky.org>
Cc:        FreeBSD multimedia <freebsd-multimedia@freebsd.org>
Subject:   Re: [off-topic] Applying gain to an audio sample
Message-ID:  <CAPe0dB=DF62Nq-h-mne8itZD-U6dTdhAqPrrV8g9OvHGGmooXg@mail.gmail.com>
In-Reply-To: <77875a51-0cef-a27f-7d27-9eac8426bb74@selasky.org>
References:  <CAPe0dB=BGyeLX3Xue=nNpHqRn8s-4xAO_T4Asmv-DUGk8uu2Jg@mail.gmail.com> <77875a51-0cef-a27f-7d27-9eac8426bb74@selasky.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Em sex, 20 de dez de 2019 15:46, Hans Petter Selasky <hps@selasky.org>
escreveu:

> On 2019-12-20 19:43, Marcel Bonnet wrote:
> > - read an audio sample as integer (stereo 16 bit LE)
> > - convert to float
> > - apply a gain, like: sample *= 0.3f
> > - convert to integer again
>
> The attachment is missing.
>

Sorry, here it is.

#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;
}




> Probably better to use the host endian version of AFMT


You mean AFMT_S16_NE ? The native endian?


> --HPS
>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAPe0dB=DF62Nq-h-mne8itZD-U6dTdhAqPrrV8g9OvHGGmooXg>