On Tue, 2008-06-17 at 11:55 +0530, AlgoMantra wrote:
But I would rather write my own realtime synthesis engine. If anyone
who has done so could tell me the basic requirements....I'm not
looking for
an easy solution. I just want to look at the architecture of synthesis
systems
from the inside.
Alrighty then. You previously had sound set up with OSS as well as the
sum of four sinewaves playing 5 seconds thru your speakers. Next step is
low latency and realtime control. The following program will do the same
as sound.c except that this time around you will have to bang the
keyboard to actually hear anything. I also added a rudimentary envelope
(as well as removed an embarrissing typo in setting up frequencies.)
The basic idea here is that the play() routine blocks for a short while
- here 64 samples - after which you do a non-blocking call to
read_input() to see if anything has happened and if so, act accordingly
and then play() the next 64 samples (and so ad infinitum ...)
--8<-- rt_sound.c -------------------------------------
// Compile with for example
// gcc4.3 -O3 -msse -ftree-vectorize -o rt_sound rt_sound.c
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <linux/soundcard.h>
/* We will use the keyboard for musical input
*/
int kbhit()
{
static const int STDIN = 0;
struct timeval timeout;
fd_set rdset;
FD_ZERO(&rdset);
FD_SET(STDIN, &rdset);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
return select(STDIN + 1, &rdset, NULL, NULL, &timeout);
}
/* Inverse of the odd factorials (n!) 1 - 9
*/
#define IF_1 (1.f)
#define IF_3 (1.f/6.f)
#define IF_5 (1.f/120.f)
#define IF_7 (1.f/5040.f)
#define IF_9 (1.f/362880.f)
/* -------------------------------------
* 16 bit Taylor approximation of sin()
* ------------------------------------ */
inline float tsin(float x)
{
float x2 = x*x;
float r = IF_9;
r *= x2;
r -= IF_7;
r *= x2;
r += IF_5;
r *= x2;
r -= IF_3;
r *= x2;
r += IF_1;
return r * x;
}
#define VEC 4
#define PI 3.141592f
#define RATE 44100.f
typedef struct
{
float x[VEC];
float y[VEC];
float w[VEC];
} sound_t;
void read_input(sound_t *s)
{
static sound_t s1 = // A preset
{
{0,0,0,0},
{8000,7000,6000,4000},
{220, 277,330,440}
};
if(!kbhit())
return;
int ch = getchar(); // unused for now ...
int i;
for(i = 0; i < VEC; ++i)
{
s->x[i] = s1.x[i];
s->y[i] = s1.y[i];
s->w[i] = 2 * tsin(s1.w[i] * PI/RATE);
}
}
void play(short *buf,sound_t *s,int size)
{
int i,j;
for(i = 0;i < size; ++i)
{
for(j=0;j < VEC; ++j)
{
// Waveform
s->x[j] -= s->w[j] * s->y[j];
s->y[j] += s->w[j] * s->x[j];
// Envelope
s->x[j] *= .99999f;
}
buf[i] = s->x[0] + s->x[1] + s->x[2]+ s->x[3];
}
}
int main(void)
{
int i;
int out = open("/dev/dsp",O_WRONLY);
// Sound
i=16; // 16 bit sound
ioctl(out,SOUND_PCM_WRITE_BITS,&i);
i=1; // 1 channel
ioctl(out,SOUND_PCM_WRITE_CHANNELS,&i);
i=44100; // 44.1 KHz
ioctl(out,SOUND_PCM_WRITE_RATE,&i);
// Latency / jitter
i = 0x00020007;
ioctl(out, SNDCTL_DSP_SETFRAGMENT, &i);
// Realtime
struct sched_param schp;
memset(&schp, 0, sizeof(schp));
schp.sched_priority = sched_get_priority_max(SCHED_FIFO)* 0.8;
if (sched_setscheduler(0, SCHED_FIFO, &schp) != 0)
fprintf(stderr,
"\n Can't get permission to run in realtime!"
"\n Try logging in as root instead?\n");
sound_t sound;
memset(&sound, 0, sizeof(schp));
int running = 1;
puts("\n Hit the any key for sound!");
while (running)
{
short int wave[64];
read_input(&sound);
play(wave,&sound,64);
write(out, wave, sizeof(wave));
}
close(out);
return 0;
}