Example #1
0
/* Function: al_open_video
 */
ALLEGRO_VIDEO *al_open_video(char const *filename)
{
   ALLEGRO_VIDEO *video;
   const char *extension = filename + strlen(filename) - 1;

   while ((extension >= filename) && (*extension != '.'))
      extension--;
   video = al_calloc(1, sizeof *video);
   
   video->vtable = find_handler(extension);

   if (video->vtable == NULL) {
      ALLEGRO_ERROR("No handler for video extension %s - "
         "therefore not trying to load %s.\n", extension, filename);
      al_free(video);
      return NULL;
   }
   
   video->filename = al_create_path(filename);
   video->playing = true;

   if (!video->vtable->open_video(video)) {
      ALLEGRO_ERROR("Could not open %s.\n", filename);
      al_destroy_path(video->filename);
      al_free(video);
      return NULL;
   }
   
   al_init_user_event_source(&video->es);
   video->es_inited = true;
   
   return video;
}
int main(int argc, char **argv)
{
   ALLEGRO_EVENT_SOURCE fake_src;
   ALLEGRO_EVENT_QUEUE *queue;
   ALLEGRO_EVENT fake_keydown_event, fake_joystick_event;
   ALLEGRO_EVENT event;

   (void)argc;
   (void)argv;

   if (!al_init()) {
      abort_example("Could not init Allegro.\n");
   }

   open_log();

   /* register our 'fake' event source with the queue */
   al_init_user_event_source(&fake_src);
   queue = al_create_event_queue();
   al_register_event_source(queue, &fake_src);

   /* fake a joystick event */
   fake_joystick_event.any.type = ALLEGRO_EVENT_JOYSTICK_AXIS;
   fake_joystick_event.joystick.stick = 1;
   fake_joystick_event.joystick.axis = 0;
   fake_joystick_event.joystick.pos = 0.5;
   al_emit_user_event(&fake_src, &fake_joystick_event, NULL);

   /* fake a keyboard event */
   fake_keydown_event.any.type = ALLEGRO_EVENT_KEY_DOWN;
   fake_keydown_event.keyboard.keycode = ALLEGRO_KEY_ENTER;
   al_emit_user_event(&fake_src, &fake_keydown_event, NULL);

   /* poll for the events we injected */
   while (!al_is_event_queue_empty(queue)) {
      al_wait_for_event(queue, &event);

      switch (event.type) {
         case ALLEGRO_EVENT_KEY_DOWN:
            ALLEGRO_ASSERT(event.user.source == &fake_src);
            log_printf("Got keydown: %d\n", event.keyboard.keycode);
            break;
         case ALLEGRO_EVENT_JOYSTICK_AXIS:
            ALLEGRO_ASSERT(event.user.source == &fake_src);
            log_printf("Got joystick axis: stick=%d axis=%d pos=%f\n",
               event.joystick.stick, event.joystick.axis, event.joystick.pos);
            break;
      }
   }

   al_destroy_user_event_source(&fake_src);
   al_destroy_event_queue(queue);

   log_printf("Done.\n");
   close_log(true);

   return 0;
}
Example #3
0
//!The constructor for the sword weapon
//In - 
//		ALLEGRO_EVENT_QUEUE* InputEventQueue = the allegro event queue of the game
//		ALLEGROEVENT& InputAlEvent - the allegro event of the game
SwordWeapon::SwordWeapon(ALLEGRO_EVENT_QUEUE* InputEventQueue, ALLEGRO_EVENT& InputAlEvent) : 
				Weapon(InputEventQueue, InputAlEvent, 16, 16, false, 0.2, 10),
				m_SwordWeaponTile(0, 0, 70, 70, true, true, false, true, 6)
{
	//initialize member variables
	m_OnActive = true;

	al_init_user_event_source(&m_SwordActiveEventSource);
	al_register_event_source(m_EventQueue, &m_SwordActiveEventSource);
}
Example #4
0
/* Function: al_enable_menu_event_source
 */
ALLEGRO_EVENT_SOURCE *al_enable_menu_event_source(ALLEGRO_MENU *menu)
{
   ASSERT(menu);

   if (!menu->is_event_source) {
      al_init_user_event_source(&menu->es);
      menu->is_event_source = true;
   }

   return &menu->es;
}
ALLEGRO_EVENT_NETWORK_SOURCE *al_create_network_event_source(void)
{
	ALLEGRO_EVENT_NETWORK_SOURCE *thing = (ALLEGRO_EVENT_NETWORK_SOURCE *)malloc(sizeof(ALLEGRO_EVENT_NETWORK_SOURCE)); 
	if (thing) {
		al_init_user_event_source(&thing->event_source);
		thing->field1 = 0;
		thing->field2 = 0;
	}

	return thing;
}
Example #6
0
bool init_connection() {
    int ret = enet_initialize();
    peers = list_new();
    if (!ret) {
        atexit(enet_deinitialize);
        al_init_user_event_source(&event_source);

        al_register_event_source(game.event_queue, &event_source);
        return true;
    }

    return false;
}
/* Function: al_init_native_dialog_addon
 */
bool al_init_native_dialog_addon(void)
{
   if (!inited_addon) {
      if (!_al_init_native_dialog_addon()) {
         ALLEGRO_ERROR("_al_init_native_dialog_addon failed.\n");
         return false;
      }
      inited_addon = true;
      al_init_user_event_source(al_get_default_menu_event_source());
      _al_add_exit_func(al_shutdown_native_dialog_addon,
         "al_shutdown_native_dialog_addon");
   }
   return true;
}
/* Function: al_open_native_text_log
 */
ALLEGRO_TEXTLOG *al_open_native_text_log(char const *title, int flags)
{
   ALLEGRO_NATIVE_DIALOG *textlog = NULL;

   /* Avoid warnings when log windows are unimplemented. */
   (void)title;
   (void)flags;

   textlog = al_calloc(1, sizeof *textlog);
   textlog->title = al_ustr_new(title);
   textlog->flags = flags;
   if (TEXT_LOG_EXTRA_THREAD) {
      textlog->tl_thread = al_create_thread(text_log_thread_proc, textlog);
   }
   textlog->tl_text_cond = al_create_cond();
   textlog->tl_text_mutex = al_create_mutex();
   textlog->tl_pending_text = al_ustr_new("");
   al_init_user_event_source(&textlog->tl_events);

   textlog->tl_init_error = false;
   textlog->tl_done = false;

   if (TEXT_LOG_EXTRA_THREAD) {
      /* Unlike the other dialogs, this one never blocks as the intended
       * use case is a log window running in the background for debugging
       * purposes when no console can be used. Therefore we have it run
       * in a separate thread.
       */
      al_start_thread(textlog->tl_thread);
      al_lock_mutex(textlog->tl_text_mutex);
      while (!textlog->tl_done && !textlog->tl_init_error) {
         al_wait_cond(textlog->tl_text_cond, textlog->tl_text_mutex);
      }
      al_unlock_mutex(textlog->tl_text_mutex);
   }
   else {
      textlog->tl_init_error = !_al_open_native_text_log(textlog);
   }

   if (textlog->tl_init_error) {
      al_close_native_text_log((ALLEGRO_TEXTLOG *)textlog);
      return NULL;
   }

   _al_register_destructor(_al_dtor_list, textlog,
      (void (*)(void *))al_close_native_text_log);

   return (ALLEGRO_TEXTLOG *)textlog;
}
Example #9
0
Control::Control()
{
	Position.X = 0;
	Position.Y = 0;
	Size.X = 0;
	Size.Y = 0;
	Enabled = true;
	Visible = true;
	FontName = "Resource/anonymous_pro.ttf";
	FontSize = 14;
	FontFlags = ALLEGRO_TTF_MONOCHROME;

	al_init_user_event_source( &controlEventSource );
	al_register_event_source( EventQueue, &controlEventSource );
}
Example #10
0
/* Function: al_install_audio
 */
bool al_install_audio(void)
{
    if (_al_kcm_driver)
        return true;

    /* The destructors are initialised even if the audio driver fails to install
     * because the user may still create samples.
     */
    _al_kcm_init_destructors();
    _al_add_exit_func(al_uninstall_audio, "al_uninstall_audio");

    al_init_user_event_source((ALLEGRO_EVENT_SOURCE *)&audio_event_source);

    return do_install_audio(ALLEGRO_AUDIO_DRIVER_AUTODETECT);
}
Example #11
0
Mouse::Mouse() : AllowBoxing(false), ClickFidelity(3), isBoxing(false), DoubleClickFidelity(0.4), blockBoxing(false)
{
	mouseQueue = al_create_event_queue();
	al_register_event_source( mouseQueue, al_get_mouse_event_source() );

	al_init_user_event_source( &mouseEventSource );
	al_register_event_source( EventQueue, &mouseEventSource );

	ALLEGRO_MOUSE_STATE state;
	al_get_mouse_state( &state );
	
	Position.X = state.x;
	Position.Y = state.y;
	mouseDownAt.X = 0;
	mouseDownAt.Y = 0;
	mouseDownButton = 0;
	lastClickTime = 0;
}
Example #12
0
/* Function: al_open_video
 */
ALLEGRO_VIDEO *al_open_video(char const *filename)
{
   ALLEGRO_VIDEO *video;

   video = al_calloc(1, sizeof *video);
   
   video->vtable = _al_video_vtable;
   
   video->filename = al_create_path(filename);

   if (!video->vtable->open_video(video)) {
      al_destroy_path(video->filename);
      al_free(video);
      return NULL;
   }
   
   al_init_user_event_source(&video->es);
   video->es_inited = true;
   
   return video;
}
Example #13
0
/*
Function: wz_init_widget

Initializes a generic widget to some sane values
*/
void wz_init_widget(WZ_WIDGET* wgt, WZ_WIDGET* parent, float x, float y, float w, float h, int id)
{
	wgt->x = x;
	wgt->y = y;
	wgt->h = h;
	wgt->w = w;
	wgt->flags = 1;
	wgt->theme = (WZ_THEME*) & wz_def_theme;
	wgt->proc = wz_widget_proc;
	
	wgt->parent = 0;
	wgt->last_child = 0;
	wgt->first_child = 0;
	wgt->next_sib = 0;
	wgt->prev_sib = 0;
	wgt->id = id;
	if (wgt->id == -1)
	{
		if (parent == 0)
			wgt->id = 0;
		else if (parent->last_child != 0)
		{
			wgt->id = parent->last_child->id + 1;
		}
		else
		{
			wgt->id = parent->id + 1;
		}
	}
	wgt->source = malloc(sizeof(ALLEGRO_EVENT_SOURCE));
	al_init_user_event_source(wgt->source);
	wgt->shortcut.modifiers = 0;
	wgt->shortcut.keycode = -1;
	
	wz_attach(wgt, parent);
	wz_ask_parent_for_focus(wgt);
}
Example #14
0
bool install_network()
{
	al_init_user_event_source( &netEventSource );
	return ( enet_initialize() == 0 );
}
Example #15
0
void PlayingField::createEventSource(void) {
	al_init_user_event_source(getEventSource());
}
Example #16
0
int main(void)
{
	//Initialize allegro--------------------------------
	MainUtility.InitAllegro();
	if (MainUtility.Get_GameOver())
	{
		return -1;
	}


	srand(time(NULL));

	//variables-----------------------------------------
	const int FPS = 60;

	//Allegro variables---------------------------------
	ALLEGRO_EVENT_QUEUE *Event_Queue = NULL;
	ALLEGRO_TIMER *Timer = NULL;

	Event_Queue = al_create_event_queue();				
	Timer = al_create_timer(1.0 / FPS);

	Display MainDisplay(Event_Queue);

	if (!MainDisplay.TestDisplay())
	{
		return -1;
	}

	ALLEGRO_BITMAP *DungeonTiles = al_load_bitmap("Test.png");
	ALLEGRO_BITMAP *AIImage = al_load_bitmap("AI_Sprite.png");
	ALLEGRO_BITMAP *PlayerImage = al_load_bitmap("Player_Sprite.png");
	ALLEGRO_BITMAP *BowImage = al_load_bitmap("Bow_Sprite.png");
	ALLEGRO_BITMAP *SwordImage = al_load_bitmap("Sword_Sprite.png");

	Player MainPlayer(PlayerImage, SwordImage, BowImage, MainDisplay.Get_ScreenWidth(), MainDisplay.Get_ScreenHeight(), Event_Queue);
	Camera MainCamera(Event_Queue);
	AI_Group TestAIGroup;  // Instance of an AI_Group

	TerrainGenerator Terrain(1);
	Terrain.generateTerrain();

	DungeonGenerator Dungeon(Event_Queue, &MainPlayer);
	Dungeon.GenerateDungeon(MainDisplay);

	MainPlayer.SetXPosition(Dungeon.GetStartPosition().x());
	MainPlayer.SetYPosition(Dungeon.GetStartPosition().y());

	TestAIGroup.RandomSetup(4, Dungeon, AIImage);  // Generates 4 AI with random attributes in the group. Their spawn points will also be set randomly.
	TestAIGroup.GetPathToPlayer(MainPlayer);  // For testing, generate a path to the player's start position from each AI


	ALLEGRO_EVENT_SOURCE ProjectileEvent;
	al_init_user_event_source(&ProjectileEvent);

	

	
	al_register_event_source(Event_Queue, al_get_timer_event_source(Timer));
	al_register_event_source(Event_Queue, al_get_keyboard_event_source());
	al_register_event_source(Event_Queue, al_get_mouse_event_source());
	

	al_start_timer(Timer);
	//Main game loop------------------------------------
	while (!MainUtility.Get_GameOver())
	{
		ALLEGRO_EVENT ev;
		al_wait_for_event(Event_Queue, &ev);
		
		MainPlayer.EventHandler(ev, MainCamera.GetMouseXWorldCoordinate(), MainCamera.GetMouseYWorldCoordinate());
		TestAIGroup.ProcessAll(ev, MainPlayer);  // Process each AI in the group
		MainCamera.EventHandler(ev, MainPlayer.GetXPosition(), MainPlayer.GetYPosition());
		MainDisplay.Event_Handler(ev); 
		Dungeon.Event_Handler(ev);
		
		// Collide with AI
		if (TestAIGroup.CollideWithAI(MainPlayer.GetCollisionXBoundOne(), MainPlayer.GetCollisionYBoundOne()))
			MainPlayer.MovementCollidingBoundOne();
		if (TestAIGroup.CollideWithAI(MainPlayer.GetCollisionXBoundTwo(), MainPlayer.GetCollisionYBoundTwo()))
			MainPlayer.MovementCollidingBoundTwo();
		// Hit the AI
		TestAIGroup.HitAI(MainPlayer.GetWeaponHitBoxXBoundOne(), MainPlayer.GetWeaponHitBoxYBoundOne(), MainPlayer.GetWeaponDamage());
		TestAIGroup.HitAI(MainPlayer.GetWeaponHitBoxXBoundTwo(), MainPlayer.GetWeaponHitBoxYBoundTwo(), MainPlayer.GetWeaponDamage());

		if (Dungeon.Get_Map()->CheckMapCollision(Vec2f(MainPlayer.GetCollisionXBoundOne(), MainPlayer.GetCollisionYBoundOne())))
			MainPlayer.MovementCollidingBoundOne();
		if (Dungeon.Get_Map()->CheckMapCollision(Vec2f(MainPlayer.GetCollisionXBoundTwo(), MainPlayer.GetCollisionYBoundTwo())))
			MainPlayer.MovementCollidingBoundTwo();


		//Code Dealing with drawing to the screen goes within this if statement
		if (al_is_event_queue_empty(Event_Queue))
		{
			Dungeon.Draw();
			MainPlayer.DrawPlayer();
			//Terrain.draw();
			TestAIGroup.DrawAll();  // Draw all AI (magenta squares). Their generated paths will also be drawn (small magenta circles).
			
			//Draw display last
			MainDisplay.Draw();
		}
	}

	
	//Game Ending--------------------------------------

	return 0;
}
Example #17
0
void init_sound(int camstate_rand_seed)
{

 settings.sound_on = 1;

//    al_init_acodec_addon(); - shouldn't need this


 if (!al_install_audio()
  || !al_init_acodec_addon())
 {
  fprintf(stdout, "\nAllegro audio installation failed. Starting without sound.");
  settings.sound_on = 0;
  return;
 }


 if (!al_reserve_samples(24))
 {
  fprintf(stdout, "\nCould not set up Allegro audio voice/mixer. Starting without sound.");
  settings.sound_on = 0;
  return;
 }

 if (settings.option [OPTION_VOL_MUSIC] == 0
		&& settings.option [OPTION_VOL_EFFECT] == 0)
	{
  settings.sound_on = 0;
  return;
	}


 load_in_sample(SAMPLE_BLIP1, "data/sound/blip.wav");
 load_in_sample(SAMPLE_BLIP2, "data/sound/blip2.wav");
 load_in_sample(SAMPLE_BLIP3, "data/sound/blip3.wav");
 load_in_sample(SAMPLE_BLIP4, "data/sound/blip4.wav");
 load_in_sample(SAMPLE_KILL, "data/sound/kill.wav");
 load_in_sample(SAMPLE_CHIRP, "data/sound/chirp.wav");
 load_in_sample(SAMPLE_OVER, "data/sound/over.wav");
 load_in_sample(SAMPLE_ALLOC, "data/sound/alloc.wav");
 load_in_sample(SAMPLE_NEW, "data/sound/new.wav");

 load_in_sample(SAMPLE_BANG, "data/sound/bang.wav");
 load_in_sample(SAMPLE_BANG2, "data/sound/bang2.wav");
 load_in_sample(SAMPLE_INT_UP, "data/sound/int_up.wav");
 load_in_sample(SAMPLE_INT_BREAK, "data/sound/int_break.wav");
 load_in_sample(SAMPLE_RESTORE, "data/sound/restore.wav");
 load_in_sample(SAMPLE_STREAM1, "data/sound/stream1.wav");
 load_in_sample(SAMPLE_STREAM2, "data/sound/stream2.wav");
 load_in_sample(SAMPLE_ZAP, "data/sound/zap.wav");
 load_in_sample(SAMPLE_SPIKE, "data/sound/spike.wav");
 load_in_sample(SAMPLE_SLICE, "data/sound/slice.wav");
 load_in_sample(SAMPLE_ULTRA, "data/sound/ultra.wav");
 load_in_sample(SAMPLE_BUBBLE, "data/sound/bubble.wav");

 load_in_sample(SAMPLE_DRUM1, "data/sound/music/drum1.wav");
 load_in_sample(SAMPLE_DRUM2, "data/sound/music/drum2.wav");
 load_in_sample(SAMPLE_DRUM3, "data/sound/music/drum3.wav");
 load_in_sample(SAMPLE_CLICK, "data/sound/music/click.wav");
 load_in_sample(SAMPLE_THUMP, "data/sound/music/thump.wav");

// load_in_msample(MSAMPLE_NOTE, "data/sound/amb/note.wav");
// load_in_msample(MSAMPLE_NOTE2, "data/sound/amb/note_harm.wav");
// load_in_msample(MSAMPLE_NOTE3, "data/sound/amb/note_sine.wav");
// load_in_msample(MSAMPLE_NOTE4, "data/sound/amb/note_sq.wav");

// load_in_amb_sample(AMB_WARBLE, "sound/amb/warble.wav");
// load_in_amb_sample(AMB_NOTE, "sound/amb/note.wav");



 //al_stop_samples();

 build_tone_array();

 sound_config.music_volume = settings.option [OPTION_VOL_MUSIC] * 0.01;
 sound_config.effect_volume = settings.option [OPTION_VOL_EFFECT] * 0.01;

 sound_timer = al_create_timer(0.22); // 0.20
 if (!sound_timer)
 {
    fprintf(stdout, "\nError: failed to create sound timer.");
    safe_exit(-1);
 }
 al_start_timer(sound_timer);
 al_init_user_event_source(&sound_event_source);

 sound_queue = al_create_event_queue();
 al_register_event_source(sound_queue, &sound_event_source);
 al_register_event_source(sound_queue, al_get_timer_event_source(sound_timer));

 sound_event.user.type = ALLEGRO_GET_EVENT_TYPE(1, 0, 4, 0);

 sthread_init_sample_pointers();

 if (settings.option [OPTION_VOL_MUSIC] != 0)
  init_camstate(-1, 1, 0, camstate_rand_seed); // this is usually only called from within the sound thread
   // but can be called here because the sound thread hasn't been started yet.
   // -1 means start new music
    else
     init_camstate(-2, 0, 0, 0); // -2 means turn the music off


 sound_thread = al_create_thread(thread_check_sound_queue, NULL);
 al_start_thread(sound_thread);

 started_sound_thread = 1;

}
int main(void)
{
   ALLEGRO_TIMER *timer;
   ALLEGRO_EVENT_SOURCE user_src;
   ALLEGRO_EVENT_QUEUE *queue;
   ALLEGRO_EVENT user_event;
   ALLEGRO_EVENT event;

   if (!al_init()) {
      abort_example("Could not init Allegro.\n");
      return 1;
   }

   timer = al_create_timer(0.5);
   if (!timer) {
      abort_example("Could not install timer.\n");
      return 1;
   }

   open_log();

   al_init_user_event_source(&user_src);

   queue = al_create_event_queue();
   al_register_event_source(queue, &user_src);
   al_register_event_source(queue, al_get_timer_event_source(timer));

   al_start_timer(timer);

   while (true) {
      al_wait_for_event(queue, &event);

      if (event.type == ALLEGRO_EVENT_TIMER) {
         int n = event.timer.count;

         log_printf("Got timer event %d\n", n);

         user_event.user.type = MY_SIMPLE_EVENT_TYPE;
         user_event.user.data1 = n;
         al_emit_user_event(&user_src, &user_event, NULL);

         user_event.user.type = MY_COMPLEX_EVENT_TYPE;
         user_event.user.data1 = (intptr_t)new_event(n);
         al_emit_user_event(&user_src, &user_event, my_event_dtor);
      }
      else if (event.type == MY_SIMPLE_EVENT_TYPE) {
         int n = (int) event.user.data1;
         ALLEGRO_ASSERT(event.user.source == &user_src);

         al_unref_user_event(&event.user);

         log_printf("Got simple user event %d\n", n);
         if (n == 5) {
            break;
         }
      }
      else if (event.type == MY_COMPLEX_EVENT_TYPE) {
         MY_EVENT *my_event = (void *)event.user.data1;
         ALLEGRO_ASSERT(event.user.source == &user_src);

         log_printf("Got complex user event %d\n", my_event->id);
         al_unref_user_event(&event.user);
      }
   }

   al_destroy_user_event_source(&user_src);
   al_destroy_event_queue(queue);
   al_destroy_timer(timer);

   log_printf("Done.\n");
   close_log(true);

   return 0;
}
UserEventEmitter::UserEventEmitter()
   : event_source()
{
   al_init_user_event_source(&event_source);
   al_register_event_source(Framework::event_queue, &event_source);
}
Example #20
0
/* Function: al_create_audio_stream
 */
ALLEGRO_AUDIO_STREAM *al_create_audio_stream(size_t fragment_count,
   unsigned int frag_samples, unsigned int freq, ALLEGRO_AUDIO_DEPTH depth,
   ALLEGRO_CHANNEL_CONF chan_conf)
{
   ALLEGRO_AUDIO_STREAM *stream;
   unsigned long bytes_per_sample;
   unsigned long bytes_per_frag_buf;
   size_t i;

   if (!fragment_count) {
      _al_set_error(ALLEGRO_INVALID_PARAM,
         "Attempted to create stream with no buffers");
      return NULL;
   }
   if (!frag_samples) {
      _al_set_error(ALLEGRO_INVALID_PARAM,
          "Attempted to create stream with no buffer size");
      return NULL;
   }
   if (!freq) {
      _al_set_error(ALLEGRO_INVALID_PARAM,
         "Attempted to create stream with no frequency");
      return NULL;
   }

   bytes_per_sample = al_get_channel_count(chan_conf) *
         al_get_audio_depth_size(depth);
   bytes_per_frag_buf = frag_samples * bytes_per_sample;

   stream = al_calloc(1, sizeof(*stream));
   if (!stream) {
      _al_set_error(ALLEGRO_GENERIC_ERROR,
         "Out of memory allocating stream object");
      return NULL;
   }

   stream->spl.is_playing = true;
   stream->is_draining = false;

   stream->spl.loop      = _ALLEGRO_PLAYMODE_STREAM_ONCE;
   stream->spl.spl_data.depth     = depth;
   stream->spl.spl_data.chan_conf = chan_conf;
   stream->spl.spl_data.frequency = freq;
   stream->spl.speed     = 1.0f;
   stream->spl.gain      = 1.0f;
   stream->spl.pan       = 0.0f;

   stream->spl.step = 0;
   stream->spl.pos  = frag_samples;
   stream->spl.spl_data.len  = stream->spl.pos;

   stream->buf_count = fragment_count;

   stream->used_bufs = al_calloc(1, fragment_count * sizeof(void *) * 2);
   if (!stream->used_bufs) {
      al_free(stream->used_bufs);
      al_free(stream);
      _al_set_error(ALLEGRO_GENERIC_ERROR,
         "Out of memory allocating stream buffer pointers");
      return NULL;
   }
   stream->pending_bufs = stream->used_bufs + fragment_count;

   /* The main_buffer holds all the buffer fragments in contiguous memory.
    * To support interpolation across buffer fragments, we allocate extra
    * MAX_LAG samples at the start of each buffer fragment, to hold the
    * last few sample values which came before that fragment.
    */
   stream->main_buffer = al_calloc(1,
      (MAX_LAG * bytes_per_sample + bytes_per_frag_buf) * fragment_count);
   if (!stream->main_buffer) {
      al_free(stream->used_bufs);
      al_free(stream);
      _al_set_error(ALLEGRO_GENERIC_ERROR,
         "Out of memory allocating stream buffer");
      return NULL;
   }

   for (i = 0; i < fragment_count; i++) {
      char *buffer = (char *)stream->main_buffer
         + i * (MAX_LAG * bytes_per_sample + bytes_per_frag_buf);
      al_fill_silence(buffer, MAX_LAG, depth, chan_conf);
      stream->used_bufs[i] = buffer + MAX_LAG * bytes_per_sample;
   }

   al_init_user_event_source(&stream->spl.es);

   /* This can lead to deadlocks on shutdown, hence we don't do it. */
   /* _al_kcm_register_destructor(stream, (void (*)(void *)) al_destroy_audio_stream); */

   return stream;
}