Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 21 Dec 2019 01:54:24 -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:  <CAPe0dBmQkpTroA5=E865xTUxdH6K-HNbmrmG_7vJXo-kYsBJKA@mail.gmail.com>
In-Reply-To: <7639f4fe-f021-bfca-13a7-f4d529aa3080@selasky.org>
References:  <CAPe0dB=BGyeLX3Xue=nNpHqRn8s-4xAO_T4Asmv-DUGk8uu2Jg@mail.gmail.com> <77875a51-0cef-a27f-7d27-9eac8426bb74@selasky.org> <CAPe0dB=DF62Nq-h-mne8itZD-U6dTdhAqPrrV8g9OvHGGmooXg@mail.gmail.com> <7639f4fe-f021-bfca-13a7-f4d529aa3080@selasky.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 20 Dec 2019 at 19:43, Hans Petter Selasky <hps@selasky.org> wrote:

> On 2019-12-20 23:02, Marcel Bonnet wrote:
> > 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>
>
> #include <stdint.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;
>
> Look here:
>
> >
> >
> > 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");
> >
>
> This buffer declaration is wrong.
>
> >           int *buf[fragmentSize];
>
> Use:
>             int16_t buf[fragmentSize / sizeof(int16_t)];
>
> >           read(fdDsp, buf, sizeof(buf));
> >           write(fdOutput, buf, sizeof(buf));
> >
> >       } 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.");
> >
> >          }
> >
> Ditto:
>            int16_t buf[fragmentSize / sizeof(int16_t)];
>
> >          eof = read(fdInput, buf, sizeof(buf)); //bytes read or -1 if EOF
> >
> >          // audio processing:
> >          for(int i=0;i < fragmentSize;i++){
>                 float sample = buf[i];
>
>                 sample *= 0.3;
>                 buf[i] = sample;
> >          }
> >
> >          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?
>
> Yes.
>
> Try my corrections first.
>
> --HPS
>


Thank you! As you pointed out, I was using the wrong type for my buffer and
also the wrong number for nbytes in read()/write() .
I updated the code with other changes needed.

Now gain factor works perfectly as observed in SoX source code I previously
mentioned.

Updated Code:

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

-- 
Marcel Bonnet



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAPe0dBmQkpTroA5=E865xTUxdH6K-HNbmrmG_7vJXo-kYsBJKA>