void * dumba5_update_thread(ALLEGRO_THREAD * thread, void * arg)
{
	DUMBA5_PLAYER * dp = (DUMBA5_PLAYER *)arg;
	ALLEGRO_EVENT_QUEUE * queue;
	unsigned short *fragment;
	long n;
	long size;
	int n_channels;
	
	queue = al_create_event_queue();
	al_register_event_source(queue, al_get_audio_stream_event_source(dp->stream));
	
	while(1)
	{
		ALLEGRO_EVENT event;

		al_wait_for_event(queue, &event);

		if(event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT)
		{
			fragment = (unsigned short *)al_get_audio_stream_fragment(dp->stream);
			if(!fragment)
			{
				return NULL;
			}
			n = duh_render(dp->sigrenderer, 16, 0, dp->volume, 65536.0 / dp->freq, dp->bufsize, fragment);

			if (n == 0)
			{
				if (++dp->silentcount >= 2)
				{
					duh_end_sigrenderer(dp->sigrenderer);
					if(!al_set_audio_stream_fragment(dp->stream, fragment))
					{
					}
					al_destroy_audio_stream(dp->stream);
					dp->sigrenderer = NULL;
					return NULL;
				}
			}

			n_channels = duh_sigrenderer_get_n_channels(dp->sigrenderer);
			n *= n_channels;
			size = dp->bufsize * n_channels;
			for (; n < size; n++)
			{
				fragment[n] = 0x8000;
			}
			if(!al_set_audio_stream_fragment(dp->stream, fragment))
			{
			}
		}
		if(al_get_thread_should_stop(thread))
		{
			break;
		}
	}
	
	al_destroy_event_queue(queue);

	return NULL;
}
Exemple #2
0
int main(int argc, char **argv)
{
   ALLEGRO_AUDIO_RECORDER *r;
   ALLEGRO_AUDIO_STREAM *s;
   
   ALLEGRO_EVENT_QUEUE *q;
   ALLEGRO_DISPLAY *d;
   ALLEGRO_FILE *fp = NULL;
   ALLEGRO_PATH *tmp_path = NULL;
      
   int prev = 0;
   bool is_recording = false;
   
   int n = 0; /* number of samples written to disk */
   
   (void) argc;
   (void) argv;

   if (!al_init()) {
      abort_example("Could not init Allegro.\n");
   }
   
   if (!al_init_primitives_addon()) {
      abort_example("Unable to initialize primitives addon");
   }
      
   if (!al_install_keyboard()) {
      abort_example("Unable to install keyboard");
   }
      
   if (!al_install_audio()) {
      abort_example("Unable to initialize audio addon");
   }
   
   if (!al_init_acodec_addon()) {
      abort_example("Unable to initialize acodec addon");
   }
   
   /* Note: increasing the number of channels will break this demo. Other
    * settings can be changed by modifying the constants at the top of the
    * file.
    */
   r = al_create_audio_recorder(1000, samples_per_fragment, frequency,
      audio_depth, ALLEGRO_CHANNEL_CONF_1);
   if (!r) {
      abort_example("Unable to create audio recorder");
   }
   
   s = al_create_audio_stream(playback_fragment_count,
      playback_samples_per_fragment, frequency, audio_depth,
      ALLEGRO_CHANNEL_CONF_1);      
   if (!s) {
      abort_example("Unable to create audio stream");
   }
      
   al_reserve_samples(0);
   al_set_audio_stream_playing(s, false);
   al_attach_audio_stream_to_mixer(s, al_get_default_mixer());
      
   q = al_create_event_queue();
   
   /* Note: the following two options are referring to pixel samples, and have
    * nothing to do with audio samples. */
   al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
   al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
   
   d = al_create_display(320, 256);
   if (!d) {
      abort_example("Error creating display\n");
   }
      
   al_set_window_title(d, "SPACE to record. P to playback.");
   
   al_register_event_source(q, al_get_audio_recorder_event_source(r));
   al_register_event_source(q, al_get_audio_stream_event_source(s));
   al_register_event_source(q, al_get_display_event_source(d));
   al_register_event_source(q, al_get_keyboard_event_source());
   
   al_start_audio_recorder(r);
   
   while (true) {
      ALLEGRO_EVENT e;

      al_wait_for_event(q, &e);
       
      if (e.type == ALLEGRO_EVENT_AUDIO_RECORDER_FRAGMENT) {
         /* We received an incoming fragment from the microphone. In this
          * example, the recorder is constantly recording even when we aren't
          * saving to disk. The display is updated every time a new fragment
          * comes in, because it makes things more simple. If the fragments
          * are coming in faster than we can update the screen, then it will be
          * a problem.
          */          
         ALLEGRO_AUDIO_RECORDER_EVENT *re = al_get_audio_recorder_event(&e);
         audio_buffer_t input = (audio_buffer_t) re->buffer;
         int sample_count = re->samples; 
         const int R = sample_count / 320;
         int i, gain = 0;
         
         /* Calculate the volume, and display it regardless if we are actively
          * recording to disk. */
         for (i = 0; i < sample_count; ++i) {
            if (gain < abs(input[i] - sample_center))
               gain = abs(input[i] - sample_center);
         }
        
         al_clear_to_color(al_map_rgb(0,0,0));
        
         if (is_recording) {
            /* Save raw bytes to disk. Assumes everything is written
             * succesfully. */
            if (fp && n < frequency / (float) samples_per_fragment * 
               max_seconds_to_record) {
               al_fwrite(fp, input, sample_count * sample_size);
               ++n;
            }

            /* Draw a pathetic visualization. It draws exactly one fragment
             * per frame. This means the visualization is dependent on the 
             * various parameters. A more thorough implementation would use this
             * event to copy the new data into a circular buffer that holds a
             * few seconds of audio. The graphics routine could then always
             * draw that last second of audio, which would cause the
             * visualization to appear constant across all different settings.
             */
            for (i = 0; i < 320; ++i) {
               int j, c = 0;
               
               /* Take the average of R samples so it fits on the screen */
               for (j = i * R; j < i * R + R && j < sample_count; ++j) {
                  c += input[j] - sample_center;
               }
               c /= R;
               
               /* Draws a line from the previous sample point to the next */
               al_draw_line(i - 1, 128 + ((prev - min_sample_val) /
                  (float) sample_range) * 256 - 128, i, 128 +
                  ((c - min_sample_val) / (float) sample_range) * 256 - 128,
                  al_map_rgb(255,255,255), 1.2);
               
               prev = c;
            }
         }
         
         /* draw volume bar */
         al_draw_filled_rectangle((gain / (float) max_sample_val) * 320, 251,
            0, 256, al_map_rgba(0, 255, 0, 128));
            
         al_flip_display();
      }
      else if (e.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) {
         /* This event is received when we are playing back the audio clip.
          * See ex_saw.c for an example dedicated to playing streams.
          */
         if (fp) {
            audio_buffer_t output = al_get_audio_stream_fragment(s);
            if (output) {
               /* Fill the buffer from the data we have recorded into the file.
                * If an error occurs (or end of file) then silence out the
                * remainder of the buffer and stop the playback.
                */
               const size_t bytes_to_read =
                  playback_samples_per_fragment * sample_size;
               size_t bytes_read = 0, i;
               
               do {
                  bytes_read += al_fread(fp, (uint8_t *)output + bytes_read,
                     bytes_to_read - bytes_read);                  
               } while (bytes_read < bytes_to_read && !al_feof(fp) &&
                  !al_ferror(fp));
               
               /* silence out unused part of buffer (end of file) */
               for (i = bytes_read / sample_size;
                  i < bytes_to_read / sample_size; ++i) {
                     output[i] = sample_center;
               }
               
               al_set_audio_stream_fragment(s, output);
               
               if (al_ferror(fp) || al_feof(fp)) {
                  al_drain_audio_stream(s);
                  al_fclose(fp);
                  fp = NULL;
               }
            }
         }
      }      
      else if (e.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
         break;
      }
      else if (e.type == ALLEGRO_EVENT_KEY_CHAR) {
         if (e.keyboard.unichar == 27) {
            /* pressed ESC */
            break;
         }
         else if (e.keyboard.unichar == ' ') {
            if (!is_recording) {
               /* Start the recording */
               is_recording = true;
               
               if (al_get_audio_stream_playing(s)) {
                  al_drain_audio_stream(s);
               }
               
               /* Reuse the same temp file for all recordings */
               if (!tmp_path) {
                  fp = al_make_temp_file("alrecXXX.raw", &tmp_path);
               }
               else {
                  if (fp) al_fclose(fp);
                  fp = al_fopen(al_path_cstr(tmp_path, '/'), "w");
               }
               
               n = 0;
            }
            else {
               is_recording = false;
               if (fp) {
                  al_fclose(fp);
                  fp = NULL;
               }
            }
         }
         else if (e.keyboard.unichar == 'p') {
            /* Play the previously recorded wav file */
            if (!is_recording) {
               if (tmp_path) {
                  fp = al_fopen(al_path_cstr(tmp_path, '/'), "r");
                  if (fp) {
                     al_set_audio_stream_playing(s, true);
                  }
               }
            }
         }
      }
   }
   
   /* clean up */
   al_destroy_audio_recorder(r);
   al_destroy_audio_stream(s);
      
   if (fp)
      al_fclose(fp);
      
   if (tmp_path) {
      al_remove_filename(al_path_cstr(tmp_path, '/'));
      al_destroy_path(tmp_path);
   }
   
   return 0;
}
static void mainloop(void)
{
   ALLEGRO_EVENT_QUEUE *queue;
   ALLEGRO_TIMER *timer;
   float *buf;
   double pitch = 440;
   int i, si;
   int n = 0;
   bool redraw = false;
   
   for (i = 0; i < N; i++) {
      frequency[i] = 22050 * pow(2, i / (double)N);
      stream[i] = al_create_audio_stream(4, SAMPLES_PER_BUFFER, frequency[i],
         ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_1);
      if (!stream[i]) {
         abort_example("Could not create stream.\n");
         return;
      }

      if (!al_attach_audio_stream_to_mixer(stream[i], al_get_default_mixer())) {
         abort_example("Could not attach stream to mixer.\n");
         return;
      }
   }

   queue = al_create_event_queue();
   al_register_event_source(queue, al_get_keyboard_event_source());
   for (i = 0; i < N; i++) {
      al_register_event_source(queue,
         al_get_audio_stream_event_source(stream[i]));
   }
#ifdef ALLEGRO_POPUP_EXAMPLES
   if (textlog) {
      al_register_event_source(queue, al_get_native_text_log_event_source(textlog));
   }
#endif

   log_printf("Generating %d sine waves of different sampling quality\n", N);
   log_printf("If Allegro's resampling is correct there should be little variation\n", N);

   timer = al_create_timer(1.0 / 60);
   al_register_event_source(queue, al_get_timer_event_source(timer));
   
   al_register_event_source(queue, al_get_display_event_source(display));

   al_start_timer(timer);
   while (n < 60 * frequency[0] / SAMPLES_PER_BUFFER * N) {
      ALLEGRO_EVENT event;

      al_wait_for_event(queue, &event);

      if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT) {
         for (si = 0; si < N; si++) {
            buf = al_get_audio_stream_fragment(stream[si]);
            if (!buf) {
               continue;
            }

            for (i = 0; i < SAMPLES_PER_BUFFER; i++) {
               double t = samplepos[si]++ / (double)frequency[si];
               buf[i] = sin(t * pitch * ALLEGRO_PI * 2) / N;
            }

            if (!al_set_audio_stream_fragment(stream[si], buf)) {
               log_printf("Error setting stream fragment.\n");
            }

            n++;
            log_printf("%d", si);
            if ((n % 60) == 0)
               log_printf("\n");
         }
      }
      
      if (event.type == ALLEGRO_EVENT_TIMER) {
         redraw = true;
      }

      if (event.type == ALLEGRO_EVENT_KEY_DOWN &&
            event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
         break;
      }

      if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
         break;
      }

#ifdef ALLEGRO_POPUP_EXAMPLES
      if (event.type == ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE) {
         break;
      }
#endif

      if (redraw &&al_is_event_queue_empty(queue)) {
         ALLEGRO_COLOR c = al_map_rgb(0, 0, 0);
         int i;
         al_clear_to_color(al_map_rgb_f(1, 1, 1));
        
         for (i = 0; i < 640; i++) {
            al_draw_pixel(i, 50 + waveform[i] * 50, c);
         }

         al_flip_display();
         redraw = false;
      }
   }

   for (si = 0; si < N; si++) {
      al_drain_audio_stream(stream[si]);
   }

   log_printf("\n");

   al_destroy_event_queue(queue);
}
Exemple #4
0
/* _al_kcm_feed_stream:
 * A routine running in another thread that feeds the stream buffers as
 * neccesary, usually getting data from some file reader backend.
 */
void *_al_kcm_feed_stream(ALLEGRO_THREAD *self, void *vstream)
{
   ALLEGRO_AUDIO_STREAM *stream = vstream;
   ALLEGRO_EVENT_QUEUE *queue;
   ALLEGRO_EVENT event;
   (void)self;

   ALLEGRO_DEBUG("Stream feeder thread started.\n");

   queue = al_create_event_queue();
   al_register_event_source(queue, &stream->spl.es);

   al_lock_mutex(stream->feed_thread_started_mutex);
   stream->feed_thread_started = true;
   al_broadcast_cond(stream->feed_thread_started_cond);
   al_unlock_mutex(stream->feed_thread_started_mutex);

   stream->quit_feed_thread = false;

   while (!stream->quit_feed_thread) {
      char *fragment;
      ALLEGRO_EVENT event;

      al_wait_for_event(queue, &event);

      if (event.type == ALLEGRO_EVENT_AUDIO_STREAM_FRAGMENT
          && !stream->is_draining) {
         unsigned long bytes;
         unsigned long bytes_written;
         ALLEGRO_MUTEX *stream_mutex;

         fragment = al_get_audio_stream_fragment(stream);
         if (!fragment) {
            /* This is not an error. */
            continue;
         }

         bytes = (stream->spl.spl_data.len) *
               al_get_channel_count(stream->spl.spl_data.chan_conf) *
               al_get_audio_depth_size(stream->spl.spl_data.depth);

         stream_mutex = maybe_lock_mutex(stream->spl.mutex);
         bytes_written = stream->feeder(stream, fragment, bytes);
         maybe_unlock_mutex(stream_mutex);

         if (stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
            /* Keep rewinding until the fragment is filled. */
            while (bytes_written < bytes &&
                     stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONEDIR) {
               size_t bw;
               al_rewind_audio_stream(stream);
               stream_mutex = maybe_lock_mutex(stream->spl.mutex);
               bw = stream->feeder(stream, fragment + bytes_written,
                  bytes - bytes_written);
               bytes_written += bw;
               maybe_unlock_mutex(stream_mutex);
            }
         }
         else if (bytes_written < bytes) {
            /* Fill the rest of the fragment with silence. */
            int silence_samples = (bytes - bytes_written) /
               (al_get_channel_count(stream->spl.spl_data.chan_conf) *
                al_get_audio_depth_size(stream->spl.spl_data.depth));
            al_fill_silence(fragment + bytes_written, silence_samples,
                            stream->spl.spl_data.depth, stream->spl.spl_data.chan_conf);
         }

         if (!al_set_audio_stream_fragment(stream, fragment)) {
            ALLEGRO_ERROR("Error setting stream buffer.\n");
            continue;
         }

         /* The streaming source doesn't feed any more, drain buffers and quit. */
         if (bytes_written != bytes &&
            stream->spl.loop == _ALLEGRO_PLAYMODE_STREAM_ONCE) {
            al_drain_audio_stream(stream);
            stream->quit_feed_thread = true;
         }
      }
      else if (event.type == _KCM_STREAM_FEEDER_QUIT_EVENT_TYPE) {
         stream->quit_feed_thread = true;
      }
   }
   
   event.user.type = ALLEGRO_EVENT_AUDIO_STREAM_FINISHED;
   event.user.timestamp = al_get_time();
   al_emit_user_event(&stream->spl.es, &event, NULL);

   al_destroy_event_queue(queue);

   ALLEGRO_DEBUG("Stream feeder thread finished.\n");

   return NULL;
}