Logo Search packages:      
Sourcecode: allegro4.2 version File versions  Download package

akaitest.c

/*         ______   ___    ___
 *        /\  _  \ /\_ \  /\_ \ 
 *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___ 
 *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
 *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
 *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
 *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
 *                                           /\____/
 *                                           \_/__/
 *
 *      Audio input test program for the Allegro library.
 *
 *      By Shawn Hargreaves.
 *
 *      See readme.txt for copyright information.
 */


#include <stdio.h>
#include <string.h>
#include <math.h>

#include "allegro.h"



/* the current sound */
SAMPLE *the_sample = NULL;


/* table of voice numbers for each MIDI key */
int voice[128];


/* lookup table for the MIDI pitch -> sample frequency conversion */
float pitch[128]; 


/* ring buffer for storing MIDI input */
#define MIDI_BUFFER_SIZE    4096

volatile int midi_buffer_head = 0; 
volatile int midi_buffer_tail = 0;
volatile unsigned char midi_buffer[MIDI_BUFFER_SIZE];


/* the current MIDI command and data bytes */
int midi_cmd = -1;
int midi_data1 = -1;
int midi_data2 = -1;



/* interrupt hook for dealing with MIDI input */
void midi_input_callback(unsigned char data)
{
   midi_buffer[midi_buffer_tail] = data;
   midi_buffer_tail++;
   if (midi_buffer_tail >= MIDI_BUFFER_SIZE)
      midi_buffer_tail = 0;
}

END_OF_FUNCTION(midi_input_callback);



/* checks if there is any data in the MIDI input buffer */
int midi_waiting(void)
{
   if (midi_buffer_head == midi_buffer_tail)
      return 0;
   else
      return 1;
}



/* reads a byte from the MIDI input buffer */
int get_midi(void)
{
   int ret;

   if (midi_buffer_head == midi_buffer_tail)
      return -1;

   ret = midi_buffer[midi_buffer_head];
   midi_buffer_head++;
   if (midi_buffer_head >= MIDI_BUFFER_SIZE)
      midi_buffer_head = 0;

   return ret; 
}



/* trigger a sample */
void start_note(int note, int vol)
{
   if (voice[note] >= 0) {
      voice_stop(voice[note]);
      deallocate_voice(voice[note]);
   }

   voice[note] = allocate_voice(the_sample);

   if (voice[note] >= 0) {
      voice_set_frequency(voice[note], MIN(pitch[note]*the_sample->freq, 0x7FFFF));
      voice_set_volume(voice[note], vol);
      voice_start(voice[note]);
   }
}



/* kill off a playing sample */
void stop_note(int note)
{
   if (voice[note] >= 0) {
      voice_stop(voice[note]);
      deallocate_voice(voice[note]);
      voice[note] = -1;
   }
}



/* load samples in from disk */
int load_proc(int msg, DIALOG *d, int c)
{
   int ret = d_button_proc(msg, d, c);

   if (ret & D_CLOSE) {
      static char name[80*6] = EMPTY_STRING;  /* 80 chars * max UTF8 char width */

      if (file_select_ex("Load Sample", name, "wav;voc", sizeof(name), 0, 0)) {
       if (the_sample)
          destroy_sample(the_sample);

       the_sample = load_sample(name);

       if (!the_sample)
          alert("Error reading sample", NULL, NULL, "What a pity", NULL, 13, 0);
      }

      return D_REDRAW;
   }

   return ret;
}



char record_length[16] = "5.0";
char record_freq[16] = "";

int waveform_proc(int msg, DIALOG *d, int c);



DIALOG record_dialog[] =
{
   /* (dialog proc)     (x)   (y)   (w)   (h)   (fg)  (bg)  (key)    (flags)     (d1)           (d2)     (dp)              (dp2) (dp3) */
   { d_shadow_box_proc, 160,  120,  321,  265,  255,  0,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { d_ctext_proc,      320,  136,  0,    0,    255,  0,    0,       0,          0,             0,       "Record Sample",  NULL, NULL  },
   { d_button_proc,     208,  336,  97,   25,   255,  0,    13,      D_EXIT,     0,             0,       "OK",             NULL, NULL  },
   { d_button_proc,     338,  336,  97,   25,   255,  0,    27,      D_EXIT,     0,             0,       "Cancel",         NULL, NULL  },
   { d_text_proc,       208,  176,  0,    0,    255,  0,    0,       0,          0,             0,       "Length:",        NULL, NULL  },
   { d_edit_proc,       277,  176,  64,   8,    255,  0,    0,       0,          15,            0,       record_length,    NULL, NULL  },
   { d_text_proc,       208,  200,  0,    0,    255,  0,    0,       0,          0,             0,       "Freq:",          NULL, NULL  },
   { d_edit_proc,       277,  200,  64,   8,    255,  0,    0,       0,          15,            0,       record_freq,      NULL, NULL  },
   { d_text_proc,       208,  224,  0,    0,    255,  0,    0,       0,          0,             0,       "16 bit:",        NULL, NULL  },
   { d_check_proc,      272,  221,  17,   13,   255,  0,    0,       0,          0,             0,       "",               NULL, NULL  },
   { d_text_proc,       208,  248,  0,    0,    255,  0,    0,       0,          0,             0,       "Stereo:",        NULL, NULL  },
   { d_check_proc,      272,  245,  17,   13,   255,  0,    0,       0,          0,             0,       "",               NULL, NULL  },
   { d_radio_proc,      368,  176,  49,   13,   255,  0,    0,       D_SELECTED, 1,             0,       "Mic",            NULL, NULL  },
   { d_radio_proc,      368,  200,  49,   13,   255,  0,    0,       0,          1,             0,       "Line",           NULL, NULL  },
   { d_radio_proc,      368,  224,  49,   13,   255,  0,    0,       0,          1,             0,       "CD",             NULL, NULL  },
   { waveform_proc,     208,  280,  226,  32,   1,    0,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { NULL,              0,    0,    0,    0,    0,    0,    0,       0,          0,             0,       NULL,             NULL, NULL  }
};



#define RECORD_OK       2
#define RECORD_CANCEL   3
#define RECORD_LENGTH   5
#define RECORD_FREQ     7
#define RECORD_16BIT    9
#define RECORD_STEREO   11
#define RECORD_MIC      12
#define RECORD_LINE     13
#define RECORD_CD       14



int waveform_size = 0;
unsigned char *waveform_buffer = NULL;



/* display the input waveform for the sampling dialog */
int waveform_proc(int msg, DIALOG *d, int c)
{
   int rate, source, i;
   static int last_source = -1;

   switch (msg) {

      case MSG_START:
       rate = get_sound_input_cap_parm(8000, 8, FALSE);
       if (rate > 0)
          rate = 8000;
       else if (rate < 0)
          rate = -rate;
       else
          return D_O_K;

       waveform_size = start_sound_input(rate, 8, FALSE);

       if (waveform_size > 0) {
          waveform_buffer = malloc(waveform_size);
          memset(waveform_buffer, 0x80, waveform_size);
       }
       break;

      case MSG_END:
       if (waveform_buffer) {
          stop_sound_input();
          free(waveform_buffer);
          waveform_buffer = NULL;
          waveform_size = 0;
       }
       break;

      case MSG_DRAW:
       if (waveform_buffer) {
          for (i=0; i<MIN(d->w, waveform_size); i++) {
             if (waveform_buffer[i] < 0x80) {
              vline(screen, d->x+i, d->y, d->y+waveform_buffer[i]*d->h/255-1, d->bg);
              vline(screen, d->x+i, d->y+waveform_buffer[i]*d->h/255, d->y+d->h/2, d->fg);
              vline(screen, d->x+i, d->y+d->h/2+1, d->y+d->h, d->bg);
             }
             else {
              vline(screen, d->x+i, d->y, d->y+d->h/2-1, d->bg);
              vline(screen, d->x+i, d->y+d->h/2, d->y+waveform_buffer[i]*d->h/255, d->fg);
              vline(screen, d->x+i, d->y+waveform_buffer[i]*d->h/255+1, d->y+d->h, d->bg);
             }
          }
       }
       break;

      case MSG_IDLE:
       if (waveform_buffer) {
          if (read_sound_input(waveform_buffer)) {
             freeze_mouse_flag = TRUE;
             poll_mouse();
             object_message(d, MSG_DRAW, 0);
             freeze_mouse_flag = FALSE;
          }
       }

       if (record_dialog[RECORD_MIC].flags & D_SELECTED)
          source = SOUND_INPUT_MIC;
       else if (record_dialog[RECORD_LINE].flags & D_SELECTED)
          source = SOUND_INPUT_LINE;
       else
          source = SOUND_INPUT_CD;

       if (source != last_source) {
          set_sound_input_source(source);
          last_source = source;
       }
       break;
   }

   return D_O_K;
}



/* main sample recording function */
int record_proc(int msg, DIALOG *d, int c)
{
   int ret = d_button_proc(msg, d, c);
   int sel = -1;
   int bits;
   int stereo;
   int freq, freq2;
   int buffer_size;
   int bytes_per_sample;
   int sample_len;
   int sample_todo;
   int sample_todo_orig;
   char *sample_data;
   float length;

   if (ret & D_CLOSE) {
      bits = get_sound_input_cap_bits();
      stereo = get_sound_input_cap_stereo();

      if (!bits) {
       alert("The current audio input driver does", "not support sample recording", NULL, "I'll change it then", NULL, 13, 0);
       return D_REDRAW;
      }

      if (bits&16)
       record_dialog[RECORD_16BIT].flags |= D_SELECTED;
      else
       record_dialog[RECORD_16BIT].flags &= ~D_SELECTED;

      if (stereo)
       record_dialog[RECORD_STEREO].flags |= D_SELECTED;
      else
       record_dialog[RECORD_STEREO].flags &= ~D_SELECTED;

      if (!record_freq[0])
       sprintf(record_freq, "%d", get_sound_input_cap_rate(((bits&16) ? 16 : 8), stereo));

      retry:

      /* ask the user for settings */
      if (do_dialog(record_dialog, sel) == RECORD_OK) {
       length = atof(record_length);
       freq = atof(record_freq);
       bits = (record_dialog[RECORD_16BIT].flags & D_SELECTED) ? 16 : 8;
       stereo = (record_dialog[RECORD_STEREO].flags & D_SELECTED) ? TRUE : FALSE;

       /* make sure we got a valid length */
       if ((length < 0.1) || (length > 30)) {
          alert("Please enter a length", "between 0.1 and 30 seconds", NULL, "Understood", NULL, 13, 0);
          sel = RECORD_LENGTH;
          goto retry;
       }

       /* make sure we got a valid frequency */
       if ((freq < 4000) || (freq > 50000)) {
          alert("Please enter a sampling frequency", "between 4000 and 50000", NULL, "Understood", NULL, 13, 0);
          sel = RECORD_FREQ;
          goto retry;
       }

       /* check that the card likes this frequency */
       freq2 = get_sound_input_cap_parm(freq, bits, stereo);

       if (freq2 == 0) {
          alert("The current input driver does", "not support these settings", NULL, "Drat", NULL, 13, 0);
          sel = RECORD_16BIT;
          goto retry;
       }

       if (freq2 < 0) {
          sprintf(record_freq, "%d", -freq2);
          alert("Invalid sampling frequency", "Suggested alternative:", record_freq, "Understood", NULL, 13, 0);
          sel = RECORD_FREQ;
          goto retry;
       }

       /* set the sample source */
       if (record_dialog[RECORD_MIC].flags & D_SELECTED)
          set_sound_input_source(SOUND_INPUT_MIC);
       else if (record_dialog[RECORD_LINE].flags & D_SELECTED)
          set_sound_input_source(SOUND_INPUT_LINE);
       else if (record_dialog[RECORD_CD].flags & D_SELECTED)
          set_sound_input_source(SOUND_INPUT_CD);

       /* draw progress bar */
       show_mouse(NULL);

       rect(screen, 95, 175, 545, 273, 255);
       rectfill(screen, 96, 176, 544, 272, 0);
       rect(screen, 127, 235, 513, 257, 255);
       rectfill(screen, 128, 236, 512, 256, 8);
       textout_centre_ex(screen, font, "Recording...", 320, 200, 255, -1);

       /* start the input! */
       buffer_size = start_sound_input(freq, bits, stereo);

       if (buffer_size <= 0) {
          alert("Error recording sample", NULL, NULL, "Drat", NULL, 13, 0);
          destroy_sample(the_sample);
          the_sample = NULL;
          show_mouse(screen);
          return D_REDRAW;
       }

       /* round the sample length to an even number of buffer transfers.
        * Really the recording code ought to handle odd amounts of data 
        * left over at the end, but it is much easier like this :-)
        */
       bytes_per_sample = ((bits==8) ? 1 : sizeof(short)) * ((stereo) ? 2 : 1);
       sample_len = length * freq;
       sample_len = MAX((((sample_len * bytes_per_sample) / buffer_size) * buffer_size), buffer_size) / bytes_per_sample;
       sample_todo = sample_todo_orig = sample_len * bytes_per_sample;

       if (the_sample)
          destroy_sample(the_sample);

       /* create a new sample to hold our data */
       the_sample = create_sample(bits, stereo, freq, sample_len);
       sample_data = (char *)the_sample->data;

       /* discard the first input buffer, to prevent clicks */
       do {
       } while (!read_sound_input(sample_data));

       /* finally, record the sound */
       while (sample_todo >= buffer_size) {
          if (read_sound_input(sample_data)) {
             sample_data += buffer_size;
             sample_todo -= buffer_size;
             rectfill(screen, 128, 236, 128+(sample_todo_orig-sample_todo)*384/sample_todo_orig, 256, 1);
          }
       }

       stop_sound_input();

       show_mouse(screen);
      }

      return D_REDRAW;
   }

   return ret;
}



/* helper for redrawing a specific part of the keyboard object */
void redraw_keyboard(DIALOG *d, int c)
{
   set_clip_rect(screen, d->x+(c-36)*12-6, d->y, d->x+(c-36)*12+18, d->y+d->h);
   object_message(d, MSG_DRAW, 0);
   set_clip_rect(screen, 0, 0, SCREEN_W-1, SCREEN_H-1);
}



/* GUI interface for playing sounds */
int piano_proc(int msg, DIALOG *d, int c)
{
   static char blackkey[12] = 
   { 
      FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, 
      TRUE, FALSE, TRUE, FALSE, TRUE, FALSE 
   };

   int i, l, r;

   switch (msg) {

      case MSG_START:
       d->d1 = -1;
       break;

      case MSG_DRAW:
       /* display the keyboard graphic */
       for (i=0; i<d->w/12; i++) {
          if (!blackkey[i%12]) {
             l = i*12;
             r = (i+1)*12;
             if (blackkey[(i-1)%12])
              l -= 6;
             if (blackkey[(i+1)%12])
              r += 6;
             rectfill(screen, d->x+l+1, d->y+1, d->x+r-1, d->y+d->h-1, (voice[i+36] >= 0) ? 1 : d->bg);
             rect(screen, d->x+l, d->y, d->x+r, d->y+d->h, d->fg);
          }
       }
       for (i=0; i<d->w/12; i++) {
          if (blackkey[i%12]) {
             l = i*12 + 1;
             r = (i+1)*12 - 1;
             rectfill(screen, d->x+l, d->y+d->h/4, d->x+r, d->y+d->h, (voice[i+36] >= 0) ? 1 : d->fg);
          }
       }
       break;

      case MSG_CLICK:
       /* handle mouse clicks (playing sounds from the GUI) */
       if (!the_sample) {
          alert("You must read in or record a", "sample before you can play it", NULL, "Sorry. I won't do it again", NULL, 13, 0);
          return D_O_K;
       }

       do {
          poll_mouse();
          i = ((mouse_x - d->x) / 12) + 36;

          if (i != d->d1) {
             if (d->d1 >= 0) {
              stop_note(d->d1);
              redraw_keyboard(d, d->d1);
              d->d1 = -1;
             }

             d->d1 = i;
             start_note(d->d1, 255);
             redraw_keyboard(d, d->d1);
          }
       } while (mouse_b);

       if (d->d1 >= 0) {
          stop_note(d->d1);
          redraw_keyboard(d, d->d1);
          d->d1 = -1;
       }
       break;

      case MSG_IDLE:
       /* check for MIDI input */
       if (midi_waiting()) {
          i = get_midi();

          if (i & 0x80) {
             /* start of a new MIDI command */
             midi_cmd = i&0xF0;
             midi_data1 = -1;
             midi_data2 = -1;
          }
          else if (midi_data1 < 0) {
             /* got the first parameter */
             midi_data1 = i;
          }
          else if (midi_data2 < 0) {
             /* got the second parameter */
             midi_data2 = i;

             if (the_sample) {
              if ((midi_cmd == 0x80) || ((midi_cmd == 0x90) && (midi_data2 == 0))) {
                 /* note off */
                 stop_note(midi_data1);
                 redraw_keyboard(d, midi_data1);
              }
              else if (midi_cmd == 0x90) {
                 /* note on */
                 start_note(midi_data1, midi_data2);
                 redraw_keyboard(d, midi_data1);
              }
             }

             midi_data1 = -1;
             midi_data2 = -1;
          }
       }
       break;
   }

   return D_O_K;
}



DIALOG the_dialog[] =
{
   /* (dialog proc)     (x)   (y)   (w)   (h)   (fg)  (bg)  (key)    (flags)     (d1)           (d2)     (dp)              (dp2) (dp3) */
   { d_clear_proc,      0,    0,    0,    0,    0,    8,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { d_ctext_proc,      320,  4,    0,    0,    255,  8,    0,       0,          0,             0,       "Audio input test program for Allegro " ALLEGRO_VERSION_STR ", " ALLEGRO_PLATFORM_STR, NULL, NULL },
   { d_ctext_proc,      320,  20,   0,    0,    255,  8,    0,       0,          0,             0,       "By Shawn Hargreaves, " ALLEGRO_DATE_STR, NULL, NULL },
   { d_text_proc,       224,  88,   0,    0,    255,  8,    0,       0,          0,             0,       "MIDI Input:",    NULL, NULL  },
   { d_text_proc,       328,  88,   0,    0,    255,  8,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { d_text_proc,       216,  112,  0,    0,    255,  8,    0,       0,          0,             0,       "Audio Input:",   NULL, NULL  },
   { d_text_proc,       328,  112,  0,    0,    255,  8,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { d_text_proc,       208,  136,  0,    0,    255,  8,    0,       0,          0,             0,       "Audio Output:",  NULL, NULL  },
   { d_text_proc,       328,  136,  0,    0,    255,  8,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { load_proc,         160,  232,  129,  25,   255,  0,    0,       D_EXIT,     0,             0,       "Load Sample",    NULL, NULL  },
   { record_proc,       352,  232,  129,  25,   255,  0,    0,       D_EXIT,     0,             0,       "Record Sample",  NULL, NULL  },
   { d_button_proc,     256,  320,  129,  25,   255,  0,    0,       D_EXIT,     0,             0,       "Quit",           NULL, NULL  },
   { piano_proc,        2,    440,  636,  40,   255,  0,    0,       0,          0,             0,       NULL,             NULL, NULL  },
   { NULL,              0,    0,    0,    0,    0,    0,    0,       0,          0,             0,       NULL,             NULL, NULL  }
};



int main(void)
{
   int i;

   for (i=0; i<128; i++)
      voice[i] = -1;

   pitch[127] = 48;
   for (i=126; i>=0; i--)
      pitch[i] = pitch[i+1] / pow(2.0, 1.0/12.0);

   if (allegro_init() != 0)
      return 1;
   install_keyboard();
   install_mouse();
   install_timer();

   if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) != 0) {
      allegro_message("\nError initialising sound\n%s\n", allegro_error);
      return 1;
   }

   if (install_sound_input(DIGI_AUTODETECT, MIDI_AUTODETECT) != 0) {
      allegro_message("\nError initialising sound input\n%s\n\n"
                  "Try changing the digi_input_card and midi_input_card settings in your\n"
                  "allegro.cfg, in particular disabling (set to zero) one of those drivers.\n",
                  allegro_error);
      return 1;
   }

   if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
      set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
      allegro_message("Error setting graphics mode\n%s\n", allegro_error);
      return 1;
   }

   set_palette(desktop_palette);

   LOCK_VARIABLE(midi_buffer_head);
   LOCK_VARIABLE(midi_buffer_tail);
   LOCK_VARIABLE(midi_buffer);
   LOCK_FUNCTION(midi_input_callback);

   midi_recorder = midi_input_callback;

   the_dialog[4].dp = (void*)midi_input_driver->name;
   the_dialog[6].dp = (void*)digi_input_driver->name;
   the_dialog[8].dp = (void*)digi_driver->name;

   do_dialog(the_dialog, -1);

   if (the_sample)
      destroy_sample(the_sample);

   return 0;
}

END_OF_MAIN()

Generated by  Doxygen 1.6.0   Back to index