[off-topic] Applying gain to an audio sample
Marcel Bonnet
marcelbonnet at gmail.com
Sat Dec 21 04:54:51 UTC 2019
On Fri, 20 Dec 2019 at 19:43, Hans Petter Selasky <hps at 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 at 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
More information about the freebsd-multimedia
mailing list