Re: [LAD] starting out with tux audio

From: Jens M Andreasen <jens.andreasen@email-addr-hidden>
Date: Tue Jun 17 2008 - 14:00:05 EEST

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

_______________________________________________
Linux-audio-dev mailing list
Linux-audio-dev@email-addr-hidden
http://lists.linuxaudio.org/mailman/listinfo/linux-audio-dev
Received on Tue Jun 17 16:15:02 2008

This archive was generated by hypermail 2.1.8 : Tue Jun 17 2008 - 16:15:02 EEST