DUMBA5_PLAYER * dumba5_encapsulate_sigrenderer(DUH_SIGRENDERER * sigrenderer, float volume, long bufsize, int freq) { DUMBA5_PLAYER * dp; int n_channels; ALLEGRO_CHANNEL_CONF c_conf; if (!sigrenderer) return NULL; dp = (DUMBA5_PLAYER *) malloc(sizeof(*dp)); if (!dp) return NULL; n_channels = duh_sigrenderer_get_n_channels(sigrenderer); if(n_channels == 1) { c_conf = ALLEGRO_CHANNEL_CONF_1; } else { c_conf = ALLEGRO_CHANNEL_CONF_2; } /* This restriction is imposed by Allegro. */ ASSERT(n_channels > 0); ASSERT(n_channels <= 2); dp->flags = ADP_PLAYING; dp->bufsize = bufsize; dp->freq = freq; dp->stream = al_create_audio_stream(4, bufsize, freq, ALLEGRO_AUDIO_DEPTH_UINT16, c_conf); if (!dp->stream) { free(dp); return NULL; } dp->stream = al_create_audio_stream(4, bufsize, freq, ALLEGRO_AUDIO_DEPTH_UINT16, c_conf); if (!dp->stream) { free(dp); return NULL; } dp->volume = volume; dp->silentcount = 0; return dp; }
void init_audio(void) { al_reserve_samples(num_samples); // Sets up the default mixer // Set up the audio stream and mixer attachment if (stream) { if (al_get_mixer_attached(al_get_default_mixer())) { al_detach_mixer(al_get_default_mixer()); } al_destroy_audio_stream(stream); } stream = al_create_audio_stream( num_fragments, size_fragment, audio_rate, AUDIO_DEPTH, CHANNEL_CONF); al_attach_audio_stream_to_mixer(stream, al_get_default_mixer()); al_register_event_source(event_queue, al_get_audio_stream_event_source(stream)); }
static int allua_audio_stream_create(lua_State * L) { int buffer_count = luaL_checkint(L, 1); int samples = luaL_checkint(L, 2); int freq = luaL_checkint(L, 3); int depth = luaL_checkint(L, 4); int chan_conf = luaL_checkint(L, 5); ALLEGRO_AUDIO_STREAM *stream = al_create_audio_stream(buffer_count, samples, freq, depth, chan_conf); if (stream) allua_pushaudio_stream(L, stream, true); else lua_pushnil(L); return 1; }
/* Function: al_load_ogg_vorbis_audio_stream_f */ ALLEGRO_AUDIO_STREAM *al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples) { const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ OggVorbis_File* vf; vorbis_info* vi; int channels; long rate; long total_samples; long total_size; AL_OV_DATA* extra; ALLEGRO_AUDIO_STREAM* stream; extra = _AL_MALLOC(sizeof(AL_OV_DATA)); if (extra == NULL) { ALLEGRO_ERROR("Failed to allocate AL_OV_DATA struct.\n"); return NULL; } if (file == NULL) { ALLEGRO_WARN("File failed to open\n"); fprintf(stderr, "File failed to open\n"); return NULL; } extra->file = file; vf = _AL_MALLOC(sizeof(OggVorbis_File)); if (ov_open_callbacks(extra, vf, NULL, 0, callbacks) < 0) { ALLEGRO_WARN("ogg: Input does not appear to be an Ogg bitstream.\n"); al_fclose(file); return NULL; } extra->vf = vf; vi = ov_info(vf, -1); channels = vi->channels; rate = vi->rate; total_samples = ov_pcm_total(vf,-1); total_size = total_samples * channels * word_size; extra->vi = vi; extra->bitstream = -1; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); stream = al_create_audio_stream(buffer_count, samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels)); if (!stream) { free(vf); return NULL; } stream->extra = extra; extra->loop_start = 0.0; extra->loop_end = ogg_stream_get_length(stream); stream->feed_thread = al_create_thread(_al_kcm_feed_stream, stream); stream->quit_feed_thread = false; stream->feeder = ogg_stream_update; stream->rewind_feeder = ogg_stream_rewind; stream->seek_feeder = ogg_stream_seek; stream->get_feeder_position = ogg_stream_get_position; stream->get_feeder_length = ogg_stream_get_length; stream->set_feeder_loop = ogg_stream_set_loop; stream->unload_feeder = ogg_stream_close; al_start_thread(stream->feed_thread); return stream; }
static ALLEGRO_AUDIO_STREAM *modaudio_stream_init(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples #if (DUMB_MAJOR_VERSION) < 2 /* For DUMB 0.9.3, we must choose a loader function ourselves. */ , DUH *(loader)(DUMBFILE *) #endif ) { ALLEGRO_AUDIO_STREAM *stream; DUMBFILE *df; DUH_SIGRENDERER *sig = NULL; DUH *duh = NULL; DUMB_IT_SIGRENDERER *it_sig = NULL; int64_t start_pos = -1; df = lib.dumbfile_open_ex(f, &dfs_f); if (!df) { ALLEGRO_ERROR("dumbfile_open_ex failed.\n"); return NULL; } start_pos = al_ftell(f); #if (DUMB_MAJOR_VERSION) >= 2 /* * DUMB 2.0 introduces dumb_read_any. It takes two extra int arguments. * * The first int, restrict_, changes how a MOD module is interpreted. * int restrict_ is a two-bit bitfield, and 0 is a good default. * For discussion, see: https://github.com/kode54/dumb/issues/53 * * The second int, subsong, matters only for very few formats. * A5 doesn't allow to choose a subsong from the 5.2 API anyway, thus 0. */ duh = lib.dumb_read_any(df, 0, 0); #else duh = loader(df); #endif if (!duh) { ALLEGRO_ERROR("Failed to create DUH.\n"); goto Error; } sig = lib.duh_start_sigrenderer(duh, 0, 2, 0); if (!sig) { ALLEGRO_ERROR("duh_start_sigrenderer failed.\n"); goto Error; } it_sig = lib.duh_get_it_sigrenderer(sig); if (it_sig) { /* Turn off freezing for XM files. Seems completely pointless. */ lib.dumb_it_set_xm_speed_zero_callback(it_sig, lib.dumb_it_callback_terminate, NULL); } stream = al_create_audio_stream(buffer_count, samples, 44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (stream) { MOD_FILE *mf = al_malloc(sizeof(MOD_FILE)); mf->duh = duh; mf->sig = sig; mf->fh = NULL; mf->length = lib.duh_get_length(duh) / 65536.0; if (mf->length < 0) mf->length = 0; mf->loop_start = -1; mf->loop_end = -1; stream->extra = mf; stream->feeder = modaudio_stream_update; stream->unload_feeder = modaudio_stream_close; stream->rewind_feeder = modaudio_stream_rewind; stream->seek_feeder = modaudio_stream_seek; stream->get_feeder_position = modaudio_stream_get_position; stream->get_feeder_length = modaudio_stream_get_length; stream->set_feeder_loop = modaudio_stream_set_loop; _al_acodec_start_feed_thread(stream); } else { ALLEGRO_ERROR("Failed to create stream.\n"); goto Error; } return stream; Error: if (sig) { lib.duh_end_sigrenderer(sig); } if (duh) { lib.unload_duh(duh); } /* try to return back to where we started to load */ if (start_pos != -1) al_fseek(f, start_pos, ALLEGRO_SEEK_SET); return NULL; }
static int stream_component_open(VideoState * is, int stream_index) { AVFormatContext *format_context = is->format_context; AVCodecContext *codecCtx; AVCodec *codec; if (stream_index < 0 || stream_index >= (int)format_context->nb_streams) { return -1; } // Get a pointer to the codec context for the video stream codecCtx = format_context->streams[stream_index]->codec; if (codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) { // Set audio settings from codec info is->video->audio = al_create_audio_stream(4, AUDIO_BUFFER_SIZE / 4, codecCtx->sample_rate, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_1 + codecCtx->channels - 1); if (!is->video->audio) { ALLEGRO_ERROR("al_create_audio_stream failed\n"); return -1; } is->audio_thread = al_create_thread(stream_audio, is); al_start_thread(is->audio_thread); is->audio_hw_buf_size = AUDIO_BUFFER_SIZE; } codec = avcodec_find_decoder(codecCtx->codec_id); if (codec) { #ifdef FFMPEG_0_8 if (avcodec_open2(codecCtx, codec, NULL) < 0) codec = NULL; #else if (avcodec_open(codecCtx, codec) < 0) codec = NULL; #endif } if (!codec) { ALLEGRO_ERROR("Unsupported codec!\n"); return -1; } switch (codecCtx->codec_type) { case AVMEDIA_TYPE_AUDIO: is->audioStream = stream_index; is->audio_st = format_context->streams[stream_index]; is->audio_buf_size = 0; is->audio_buf_index = 0; /* averaging filter for audio sync */ is->audio_diff_avg_coef = exp(log(0.01 / AUDIO_DIFF_AVG_NB)); is->audio_diff_avg_count = 0; /* Correct audio only if larger error than this */ is->audio_diff_threshold = 0.1; memset(&is->audio_pkt, 0, sizeof(is->audio_pkt)); packet_queue_init(&is->audioq); break; case AVMEDIA_TYPE_VIDEO: is->videoStream = stream_index; is->video_st = format_context->streams[stream_index]; is->frame_timer = (double)av_gettime() / 1000000.0; is->frame_last_delay = 40e-3; is->video_current_pts_time = av_gettime(); packet_queue_init(&is->videoq); is->video_thread = al_create_thread(video_thread, is); al_start_thread(is->video_thread); codecCtx->get_buffer = our_get_buffer; codecCtx->release_buffer = our_release_buffer; break; default: break; } return 0; }
ALLEGRO_AUDIO_STREAM *_al_load_ogg_opus_audio_stream_f(ALLEGRO_FILE *file, size_t buffer_count, unsigned int samples) { const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ OggOpusFile* of; int channels; long rate; long total_samples; long total_size; int bitstream; AL_OP_DATA* extra; ALLEGRO_AUDIO_STREAM* stream; if (!init_dynlib()) { return NULL; } extra = al_malloc(sizeof(AL_OP_DATA)); if (extra == NULL) { ALLEGRO_ERROR("Failed to allocate AL_OP_DATA struct.\n"); return NULL; } extra->file = file; of = lib.op_open_callbacks(extra, &callbacks, NULL, 0, NULL); if (!of) { ALLEGRO_WARN("ogg: Input does not appear to be an Ogg bitstream.\n"); return NULL; } extra->of = of; extra->bitstream = -1; bitstream = extra->bitstream; extra->channels = lib.op_channel_count(of, bitstream); channels = extra->channels; rate = 48000; total_samples = lib.op_pcm_total(of, bitstream); total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); stream = al_create_audio_stream(buffer_count, samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels)); if (!stream) { lib.op_free(of); return NULL; } stream->extra = extra; extra->loop_start = 0.0; extra->loop_end = ogg_stream_get_length(stream); stream->quit_feed_thread = false; stream->feeder = ogg_stream_update; stream->rewind_feeder = ogg_stream_rewind; stream->seek_feeder = ogg_stream_seek; stream->get_feeder_position = ogg_stream_get_position; stream->get_feeder_length = ogg_stream_get_length; stream->set_feeder_loop = ogg_stream_set_loop; stream->unload_feeder = ogg_stream_close; _al_acodec_start_feed_thread(stream); return stream; }
static ALLEGRO_AUDIO_STREAM *mod_stream_init(ALLEGRO_FILE* f, size_t buffer_count, unsigned int samples, DUH *(loader)(DUMBFILE *)) { ALLEGRO_AUDIO_STREAM *stream; DUMBFILE *df; DUH_SIGRENDERER *sig = NULL; DUH *duh = NULL; DUMB_IT_SIGRENDERER *it_sig = NULL; int64_t start_pos = -1; df = lib.dumbfile_open_ex(f, &dfs_f); if (!df) return NULL; start_pos = al_ftell(f); duh = loader(df); if (!duh) { goto Error; } sig = lib.duh_start_sigrenderer(duh, 0, 2, 0); if (!sig) { goto Error; } it_sig = lib.duh_get_it_sigrenderer(sig); if (it_sig) { /* Turn off freezing for XM files. Seems completely pointless. */ lib.dumb_it_set_xm_speed_zero_callback(it_sig, lib.dumb_it_callback_terminate, NULL); } stream = al_create_audio_stream(buffer_count, samples, 44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (stream) { MOD_FILE *mf = al_malloc(sizeof(MOD_FILE)); mf->duh = duh; mf->sig = sig; mf->fh = NULL; mf->length = lib.duh_get_length(duh) / 65536.0; if (mf->length < 0) mf->length = 0; mf->loop_start = -1; mf->loop_end = -1; stream->extra = mf; stream->feeder = modaudio_stream_update; stream->unload_feeder = modaudio_stream_close; stream->rewind_feeder = modaudio_stream_rewind; stream->seek_feeder = modaudio_stream_seek; stream->get_feeder_position = modaudio_stream_get_position; stream->get_feeder_length = modaudio_stream_get_length; stream->set_feeder_loop = modaudio_stream_set_loop; _al_acodec_start_feed_thread(stream); } else { goto Error; } return stream; Error: if (sig) { lib.duh_end_sigrenderer(sig); } if (duh) { lib.unload_duh(duh); } /* try to return back to where we started to load */ if (start_pos != -1) al_fseek(f, start_pos, ALLEGRO_SEEK_SET); return NULL; }
/* return the player so you can use more advanced features if you want you can safely ignore the return value if all you want is to play a mod */ DUMBA5_PLAYER * dumba5_create_player(DUH * dp, int pattern, bool loop, int bufsize, int frequency, bool stereo) { DUMBA5_PLAYER * player; ALLEGRO_CHANNEL_CONF c_conf; int n_channels = 2; /* This restriction is imposed by Allegro. */ ASSERT(n_channels > 0); ASSERT(n_channels <= 2); if(!dp) { return NULL; } player = (DUMBA5_PLAYER *) malloc(sizeof(DUMBA5_PLAYER)); if(!player) { return NULL; } player->flags = 0; player->bufsize = bufsize; player->freq = frequency; player->channels = n_channels; if(n_channels == 1) { c_conf = ALLEGRO_CHANNEL_CONF_1; } else { c_conf = ALLEGRO_CHANNEL_CONF_2; } player->stream = al_create_audio_stream(4, bufsize, frequency, ALLEGRO_AUDIO_DEPTH_INT16, c_conf); if(!player->stream) { free(player); return NULL; } al_attach_audio_stream_to_mixer(player->stream, al_get_default_mixer()); player->sigrenderer = dumb_it_start_at_order(dp, n_channels, pattern); if(!player->sigrenderer) { al_destroy_audio_stream(player->stream); free(player); return NULL; } player->mutex = al_create_mutex(); if(!player->mutex) { return NULL; } player->thread = al_create_thread(dumba5_update_thread, player); if(!player->thread) { return NULL; } player->volume = 1.0; player->silentcount = 0; player->duh = dp; return player; }
DUMBA5_PLAYER * dumba5_start_duh_x(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq) { DUMBA5_PLAYER * dp; ALLEGRO_CHANNEL_CONF c_conf; /* This restriction is imposed by Allegro. */ ASSERT(n_channels > 0); ASSERT(n_channels <= 2); if(!duh) { return NULL; } dp = (DUMBA5_PLAYER *) malloc(sizeof(DUMBA5_PLAYER)); if(!dp) { return NULL; } dp->flags = ADP_PLAYING; dp->bufsize = bufsize; dp->freq = freq; dp->channels = n_channels; if(n_channels == 1) { c_conf = ALLEGRO_CHANNEL_CONF_1; } else { c_conf = ALLEGRO_CHANNEL_CONF_2; } dp->stream = al_create_audio_stream(4, bufsize, freq, ALLEGRO_AUDIO_DEPTH_INT16, c_conf); if (!dp->stream) { free(dp); return NULL; } al_attach_audio_stream_to_mixer(dp->stream, al_get_default_mixer()); dp->sigrenderer = dumb_it_start_at_order(duh, n_channels, pos); if (!dp->sigrenderer) { al_destroy_audio_stream(dp->stream); free(dp); return NULL; } dp->thread = al_create_thread(dumba5_update_thread, dp); if(!dp->thread) { return NULL; } dp->volume = volume; dp->silentcount = 0; dp->duh = duh; al_start_thread(dp->thread); return dp; }
int main(int argc, char *argv[]) { ALLEGRO_DISPLAY *display; (void)argc; (void)argv; if (!al_init()) { abort_example("Could not init Allegro.\n"); } open_log(); al_install_keyboard(); al_install_mouse(); al_init_primitives_addon(); al_init_font_addon(); al_init_ttf_addon(); al_set_new_display_flags(ALLEGRO_GENERATE_EXPOSE_EVENTS); display = al_create_display(800, 600); if (!display) { abort_example("Unable to create display\n"); } al_set_window_title(display, "Synthesiser of sorts"); font_gui = al_load_ttf_font("data/DejaVuSans.ttf", 12, 0); if (!font_gui) { abort_example("Failed to load data/fixed_font.tga\n"); } if (!al_install_audio()) { abort_example("Could not init sound!\n"); } if (!al_reserve_samples(0)) { abort_example("Could not set up voice and mixer.\n"); } size_t buffers = 8; unsigned samples = SAMPLES_PER_BUFFER; unsigned freq = STREAM_FREQUENCY; ALLEGRO_AUDIO_DEPTH depth = ALLEGRO_AUDIO_DEPTH_FLOAT32; ALLEGRO_CHANNEL_CONF ch = ALLEGRO_CHANNEL_CONF_1; stream1 = al_create_audio_stream(buffers, samples, freq, depth, ch); stream2 = al_create_audio_stream(buffers, samples, freq, depth, ch); stream3 = al_create_audio_stream(buffers, samples, freq, depth, ch); stream4 = al_create_audio_stream(buffers, samples, freq, depth, ch); stream5 = al_create_audio_stream(buffers, samples, freq, depth, ch); if (!stream1 || !stream2 || !stream3 || !stream4 || !stream5) { abort_example("Could not create stream.\n"); } ALLEGRO_MIXER *mixer = al_get_default_mixer(); if ( !al_attach_audio_stream_to_mixer(stream1, mixer) || !al_attach_audio_stream_to_mixer(stream2, mixer) || !al_attach_audio_stream_to_mixer(stream3, mixer) || !al_attach_audio_stream_to_mixer(stream4, mixer) || !al_attach_audio_stream_to_mixer(stream5, mixer) ) { abort_example("Could not attach stream to mixer.\n"); } al_set_mixer_postprocess_callback(mixer, mixer_pp_callback, mixer); /* Prog is destroyed at the end of this scope. */ { Theme theme(font_gui); Prog prog(theme, display); prog.run(); } al_destroy_audio_stream(stream1); al_destroy_audio_stream(stream2); al_destroy_audio_stream(stream3); al_destroy_audio_stream(stream4); al_destroy_audio_stream(stream5); al_uninstall_audio(); al_destroy_font(font_gui); al_fclose(save_fp); close_log(false); 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); }
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; }