fix audio playback bug

This commit is contained in:
corey 2024-05-15 07:28:47 -05:00
parent ecdbc8c570
commit 8649141cbb
3 changed files with 43 additions and 61 deletions

24
audio.c
View File

@ -12,7 +12,7 @@
#include"audio.h"
/*******
* Allocate data, initialize struct
* Create new Audio struct
*******/
Audio aud_new(size_t samplerate,size_t nsamples,size_t channels)
{
@ -25,7 +25,7 @@ Audio aud_new(size_t samplerate,size_t nsamples,size_t channels)
}
/*******
* Free allocated data
* Free Audio struct resources
*******/
void aud_free(Audio*aud)
{
@ -79,6 +79,7 @@ void aud_tri(Audio*aud,double freq,size_t mode)
for(size_t i=0;i<aud->nsamples;++i)
{
/* for(size_t ch=0;ch<aud->channels;++ch,++i) */
//aud->data[i]=sin(i);
uint16_t sample=(i%(int)(aud->samplerate/freq))*7;
if(mode==GEN)
aud->data[i]=sample;
@ -87,23 +88,6 @@ void aud_tri(Audio*aud,double freq,size_t mode)
}
}
/*******
* Sine waveform generator
*******/
void aud_sine(Audio*aud,double freq,size_t mode)
{
if(!aud->data||!aud->nsamples||!aud->samplerate||!aud->channels)return;
for(size_t i=0;i<aud->nsamples;++i)
{
/* for(size_t ch=0;ch<aud->channels;++ch,++i) */
uint16_t sample=sin((2*PI)/(aud->samplerate/freq)*i)*8000;
if(mode==GEN)
aud->data[i]=sample;
else if(mode==ADD)
aud->data[i]=(aud->data[i]+sample)/2;
}
}
/*******
* Zero all data
*******/
@ -114,7 +98,7 @@ void aud_zero(Audio*aud)
}
/*******
* Naïve amplitude envelope to smooth popping
* Naïve amplitude envelope
*******/
void aud_env(Audio*aud)
{

35
audio.h
View File

@ -12,24 +12,6 @@
#include<time.h>
#include<unistd.h>
#ifndef PI
#define PI 3.141592653589793L
#endif
#define SEMITONE_CONSTANT 1.0594630943592953L // pow(2,1/12.0)
// Raise by one semitone
#define raisesemitone(freq,nsemitones) ((freq)*pow(SEMITONE_CONSTANT,(nsemitones)))
// Macro to generate chord
// composed of semitone intervals
#define makechord(aud,freq,...) do{int _l[]={__VA_ARGS__};aud_tri(aud,(freq),GEN);for(size_t i=0;i<sizeof(_l)/sizeof(int);++i)aud_tri(aud,raisesemitone((freq),_l[i]),ADD);}while(0)
enum{GEN,ADD};
/*******
* Type to store audio
* data information
*******/
typedef struct Audio
{
size_t samplerate;
@ -39,10 +21,21 @@ typedef struct Audio
} Audio;
Audio aud_new(size_t samplerate,size_t nsamples,size_t channels);
void aud_avg(Audio*aud,size_t blocksize);
void aud_env(Audio*aud);
void aud_free(Audio*aud);
// Audio data manipulation
#define SEMITONE_CONSTANT 1.0594630943592953 // pow(2,1/12.0)
#define raisesemitone(freq,nsemitones) ((freq)*pow(SEMITONE_CONSTANT,(nsemitones)))
// Generate chord in Audio struct
// starting at base freq, and using
// all specified semitone intervals
#define makechord(aud,freq,...) do{double _f=(freq);int _l[]={__VA_ARGS__};aud_tri((aud),_f,GEN);for(size_t i=0;i<sizeof(_l)/sizeof(int);++i)aud_tri((aud),raisesemitone(_f,_l[i]),ADD);}while(0)
enum{GEN,ADD};
void aud_avg(Audio*aud,size_t blocksize);
void aud_rnd(Audio*aud,size_t mode);
void aud_sine(Audio*aud,double freq,size_t mode);
void aud_tri(Audio*aud,double freq,size_t mode);
void aud_zero(Audio*aud);
void aud_env(Audio*aud);

45
main.c
View File

@ -18,14 +18,16 @@
#define USAGE "chord [CHORDs]\n"\
"\tCHORD\t[a-g][#b]?[0-9][m]?\n"
#define chord(aud,f,...) makechord((aud),(nametofreq(f)),__VA_ARGS__)
#define M7(aud,f) chord(aud,f,4,7,11) // major 7
#define f7(aud,f) chord(aud,f,4,7,10) // flat 7
#define m7(aud,f) chord(aud,f,3,7,10) // minor 7
#define d7(aud,f) chord(aud,f,3,6,10) // diminished 7
double nametofreq(const char*name);
void cleanup(int sig);
// Chord generator macros
#define chord(aud,f,...) makechord(aud,nametofreq(f),__VA_ARGS__)
#define M7(aud,f) chord(aud,f,4,7,11)
#define f7(aud,f) chord(aud,f,4,7,10)
#define m7(aud,f) chord(aud,f,3,7,10)
#define d7(aud,f) chord(aud,f,3,6,10)
static double nametofreq(const char*name);
static void cleanup(int sig);
static Audio aud=(Audio){0};
static PaStream*pa=NULL;
@ -53,21 +55,22 @@ int main(int argc,char**argv)
// Macro to play audio
#define play() do{Pa_WriteStream(pa,aud.data,aud.nsamples);usleep((((float)aud.nsamples)/aud.samplerate)*1000000);}while(0)
// Play pre-written chords
// Play pre-designed chord scale
if(argc<2)
{
// Play chord scale
chord(&aud,"a4",4,7,11,14);aud_env(&aud);play();
chord(&aud,"g#4",3,6,9,13);aud_env(&aud);play();
chord(&aud,"f#4",3,7,10,14);aud_env(&aud);play();
chord(&aud,"e4",4,7,10,14);aud_env(&aud);play();
chord(&aud,"d4",4,7,11,14);aud_env(&aud);play();
chord(&aud,"c#4",3,7,10,13);aud_env(&aud);play();
chord(&aud,"b3",3,7,10,14);aud_env(&aud);play();
chord(&aud,"a3",4,7,11,14);aud_env(&aud);play();
chord(&aud, "a4",4,7,11,14);aud_env(&aud);play();
chord(&aud, "g#4",3,6,9,13);aud_env(&aud);play();
chord(&aud, "f#4",3,7,10,14);aud_env(&aud);play();
chord(&aud, "e4",4,7,10,14);aud_env(&aud);play();
chord(&aud, "d4",4,7,11,14);aud_env(&aud);play();
chord(&aud, "c#4",3,7,10,13);aud_env(&aud);play();
chord(&aud, "b3",3,7,10,14);aud_env(&aud);play();
chord(&aud, "a3",4,7,11,14);aud_env(&aud);play();
//Pa_Sleep((((float)aud.nsamples)/aud.samplerate)*8);
}
// Play command-line supplied chords
// Play command-line supplied chord names
else
{
for(size_t i=1;i<(size_t)argc;++i)
@ -101,7 +104,7 @@ int main(int argc,char**argv)
/*******
* Convert note name into frequency
*******/
double nametofreq(const char*name)
static double nametofreq(const char*name)
{
char letter='a';
double a0=27.5;
@ -134,12 +137,14 @@ double nametofreq(const char*name)
}
/*******
* Free resources
* Free resources and quit
*******/
void cleanup(int sig)
static void cleanup(int sig)
{
if(sig==SIGINT)
puts("exiting due to SIGINT");
/* else */
/* puts("bye"); */
Pa_AbortStream(pa);
Pa_CloseStream(pa);
Pa_Terminate();