144 lines
2.6 KiB
C
144 lines
2.6 KiB
C
#include<portaudio.h>
|
|
#include<stdio.h>
|
|
#include<stdlib.h>
|
|
#include<math.h>
|
|
#include<stdint.h>
|
|
#include<unistd.h>
|
|
#include<fcntl.h>
|
|
#include<string.h>
|
|
|
|
// Open .WAV file, read into buffer
|
|
// assuming samplerate, bitdepth, and
|
|
// channels
|
|
void op(const char*fn,float*buf,int len)
|
|
{
|
|
int fd;
|
|
int16_t tmpbuf[len];
|
|
if(!fn||!buf||!len)return;
|
|
|
|
fd=open(fn,O_RDONLY);
|
|
if(fd<0)
|
|
{
|
|
write(1,"fail\n",5);
|
|
return;
|
|
}
|
|
|
|
// Skip WAVE header (assume 44.1kHz
|
|
// samplerate, mono channels, and 16bit
|
|
lseek(fd,40,SEEK_SET);
|
|
|
|
// Read file into buffer and convert from
|
|
// int16_t to float
|
|
read(fd,tmpbuf,len*sizeof(int16_t));
|
|
for(int i=0;i<len;++i)
|
|
buf[i]=((float)tmpbuf[i])/(float)INT16_MAX;
|
|
|
|
close(fd);
|
|
}
|
|
|
|
// Low-pass convolving filter
|
|
void lp(float*cur,float*prev,float*next,int len,int winsz)
|
|
{
|
|
if(!cur||!prev||!next||!len||!winsz)return;
|
|
for(int i=0,k;i<len;++i)
|
|
{
|
|
float sum=0;
|
|
k=i-winsz/2;
|
|
for(int j=0;j<winsz;++j,++k)
|
|
{
|
|
if(k<0)
|
|
sum+=prev[k+len];
|
|
else if(k>=len)
|
|
sum+=next[k%len];
|
|
else
|
|
sum+=cur[k];
|
|
}
|
|
cur[i]=sum/winsz;
|
|
}
|
|
}
|
|
|
|
// Sine oscillator
|
|
void sn(float*d,int len,int cycle,int*offset)
|
|
{
|
|
for(int j=0,cycle=44100/440;j<len;++j,*offset=(*offset+1)%cycle)
|
|
d[j]=sin(2.0*M_PI*((float)*offset)/cycle)*0.25;
|
|
}
|
|
|
|
// Saw-tooth oscillator
|
|
void sw(float*d,int len,int cycle,int*offset)
|
|
{
|
|
*offset%=cycle;
|
|
for(int j=0,cycle=44100/440;j<len;++j,*offset=(*offset+1)%cycle)
|
|
d[j]=((float)*offset)/cycle*0.25;
|
|
}
|
|
|
|
|
|
|
|
#define swapbuffers() do{float*tmp=prev;prev=cur;cur=next;next=tmp;}while(0)
|
|
|
|
int main(void)
|
|
{
|
|
PaStream*pa;
|
|
const int len=1024;
|
|
float buffer1[len];
|
|
float buffer2[len];
|
|
float buffer3[len];
|
|
float wave[44100];
|
|
float*cur=buffer2,*next=buffer3,*prev=buffer1;
|
|
int envsize=400;
|
|
int offset=0;
|
|
int wave_or_osc=0;
|
|
|
|
if(envsize>len)envsize=len;
|
|
|
|
// Init portaudio
|
|
Pa_Initialize();
|
|
Pa_OpenDefaultStream(&pa,0,1,paFloat32,44100,len,NULL,NULL);
|
|
Pa_StartStream(pa);
|
|
|
|
// Read wave file into buffer
|
|
op("w.wav",wave,44100);
|
|
|
|
// Generate initial buffer
|
|
if(wave_or_osc==0)
|
|
sw(next,len,44100/440,&offset);
|
|
else
|
|
{
|
|
memcpy(next,wave+offset,len*sizeof(float));
|
|
offset+=len;
|
|
}
|
|
|
|
// Play dynamic audio
|
|
for(int i=0,last=44100/len;i<last;++i)
|
|
{
|
|
swapbuffers();
|
|
|
|
// Oscillator
|
|
if(wave_or_osc==0)
|
|
sw(next,len,44100/440,&offset);
|
|
else
|
|
{
|
|
memcpy(next,wave+offset,len*sizeof(float));
|
|
offset+=len;
|
|
}
|
|
|
|
// Filter
|
|
lp(cur,prev,next,len,44100/1000);
|
|
|
|
// Amplitude envelope
|
|
if(i==0)
|
|
for(int j=0;j<envsize;++j)
|
|
cur[j]*=((float)j)/envsize;
|
|
else if(i==last-1)
|
|
for(int j=0;j<envsize;++j)
|
|
cur[len-j]*=((float)j)/envsize;
|
|
|
|
Pa_WriteStream(pa,cur,len);
|
|
}
|
|
Pa_Sleep(800);
|
|
|
|
// Quit
|
|
Pa_CloseStream(pa);
|
|
Pa_Terminate();
|
|
}
|