Example #1
0
   static void *Func_Thread(ALLEGRO_THREAD *thr, void *arg){
 
   DATA *data  = (DATA*) arg;
   float num   = 0.1;
 
   al_lock_mutex(data->mutex);
 
   bool modi_X = data->modi_X;
   data->ready = true;
   al_broadcast_cond(data->cond);
 
   al_unlock_mutex(data->mutex);
 
   while(!al_get_thread_should_stop(thr)){
 
      al_lock_mutex(data->mutex);
      if(modi_X)
         data->posiX += num;
      else
         data->posiY += num;
      al_unlock_mutex(data->mutex);
 
      al_rest(0.01);
 
   }
 
 
   return NULL;
   }
Example #2
0
static void *android_app_trampoline(ALLEGRO_THREAD *thr, void *arg)
{
   const int argc = 1;
   const char *argv[2] = {system_data.user_lib, NULL};
   int ret;

   (void)thr;
   (void)arg;

   ALLEGRO_DEBUG("signaling running");

   al_lock_mutex(system_data.mutex);
   system_data.trampoline_running = true;
   al_broadcast_cond(system_data.cond);
   al_unlock_mutex(system_data.mutex);

   ALLEGRO_DEBUG("entering main function %p", system_data.user_main);

   ret = (system_data.user_main)(argc, (char **)argv);

   /* Can we do anything with this exit code? */
   ALLEGRO_DEBUG("returned from main function, exit code = %d", ret);

   /* NOTE: don't put any ALLEGRO_DEBUG in here after running main! */

   android_cleanup(true);

   return NULL;
}
Example #3
0
static void toggle_pausedness(int n)
{
   ThreadInfo *info = &thread_info[n];

   al_lock_mutex(info->mutex);
   info->is_paused = !info->is_paused;
   al_broadcast_cond(info->cond);
   al_unlock_mutex(info->mutex);
}
Example #4
0
void *CreateDisplay(ALLEGRO_THREAD *thr, void *arg)
{
    DISPLAY_DATA *data = (DISPLAY_DATA*) arg;   
    ALLEGRO_DISPLAY *display;

    ALLEGRO_EVENT_QUEUE *queue = al_create_event_queue();
    if(!queue) {
        fprintf(stderr, "failed to create event queue");
        return NULL;
    }

    al_lock_mutex(data->mutex);

    display = AllegroNewDisplay(data->sizeX, data->sizeY, queue);
    al_broadcast_cond(data->cond);

    // Define the size of the image
    Window<int> scr(0, data->sizeX, 0, data->sizeY);
    // Define the domain in which we test for points
    Window<double> fract(data->zoomXmin, data->zoomXmax, data->zoomYmin, data->zoomYmax);
    
    al_unlock_mutex(data->mutex);

    // Generate the fractal
    Mandelbrot(scr, fract);

    while(!al_get_thread_should_stop(thr)) {
        ALLEGRO_EVENT ev;
        al_wait_for_event(queue, &ev);

        if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
            al_set_thread_should_stop(thr);
            al_lock_mutex(data->mutex);
            al_broadcast_cond(data->cond);
            al_unlock_mutex(data->mutex);
            break;
        }       
    }

    al_destroy_display(display);
    al_destroy_event_queue(queue);
}
Example #5
0
static int pulseaudio_stop_voice(ALLEGRO_VOICE *voice)
{
   PULSEAUDIO_VOICE *pv = voice->extra;

   /* We hold the voice->mutex already. */

   if (pv->status == PV_PLAYING) {
      pv->status = PV_STOPPING;
      al_broadcast_cond(pv->status_cond);
   }

   while (pv->status != PV_IDLE) {
      al_wait_cond(pv->status_cond, voice->mutex);
   }

   return 0;
}
Example #6
0
static int pulseaudio_start_voice(ALLEGRO_VOICE *voice)
{
   PULSEAUDIO_VOICE *pv = voice->extra;   
   int ret;

   /* We hold the voice->mutex already. */

   if (pv->status == PV_IDLE) {
      pv->status = PV_PLAYING;
      al_broadcast_cond(pv->status_cond);
      ret = 0;
   }
   else {
      ret = 1;
   }

   return ret;
}
Example #7
0
static void pulseaudio_deallocate_voice(ALLEGRO_VOICE *voice)
{
   PULSEAUDIO_VOICE *pv = voice->extra;

   al_lock_mutex(voice->mutex);
   pv->status = PV_JOIN;
   al_broadcast_cond(pv->status_cond);
   al_unlock_mutex(voice->mutex);

   /* We do NOT hold the voice mutex here, so this does NOT result in a
    * deadlock when the thread calls _al_voice_update.
    */
   al_join_thread(pv->poll_thread, NULL);
   al_destroy_thread(pv->poll_thread);

   al_destroy_cond(pv->status_cond);
   al_destroy_mutex(pv->buffer_mutex);

   pa_simple_free(pv->s);
   al_free(pv);
}
/* Custom routine which runs in another thread to periodically check if DirectSound
   wants more data for a stream */
static void* _dsound_update(ALLEGRO_THREAD *self, void *arg)
{
   ALLEGRO_VOICE *voice = (ALLEGRO_VOICE *)arg;
   ALLEGRO_DS_DATA *ex_data = (ALLEGRO_DS_DATA*)voice->extra;
   const int bytes_per_sample = ex_data->bits_per_sample / 8;
   DWORD play_cursor = 0;
   DWORD write_cursor;
   DWORD saved_play_cursor = 0;
   unsigned int samples;
   LPVOID ptr1, ptr2;
   DWORD block1_bytes, block2_bytes;
   unsigned char *data;
   HRESULT hr;

   (void)self;

   unsigned char *silence = (unsigned char *)al_malloc(buffer_size);
   int silence_value = _al_kcm_get_silence(voice->depth);
   memset(silence, silence_value, buffer_size);

   /* Fill buffer */
   hr = ex_data->ds8_buffer->Lock(0, buffer_size,
      &ptr1, &block1_bytes, &ptr2, &block2_bytes,
      DSBLOCK_ENTIREBUFFER);
   if (!FAILED(hr)) {
      samples = buffer_size / bytes_per_sample / ex_data->channels;
      data = (unsigned char *) _al_voice_update(voice, &samples);
      memcpy(ptr1, data, block1_bytes);
      memcpy(ptr2, data + block1_bytes, block2_bytes);
      ex_data->ds8_buffer->Unlock(ptr1, block1_bytes, ptr2, block2_bytes);
   }

   ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING);

   do {
      if (!_dsound_voice_is_playing(voice)) {
         ex_data->ds8_buffer->Play(0, 0, DSBPLAY_LOOPING);
      }

      ex_data->ds8_buffer->GetCurrentPosition(&play_cursor, &write_cursor);

      /* We try to fill the gap between the saved_play_cursor and the
       * play_cursor.
       */
      int d = play_cursor - saved_play_cursor;
      if (d < 0)
         d += buffer_size;

      /* Don't fill small gaps.  Let it accumulate to amortise the cost of
       * mixing the samples and locking/unlocking the buffer.
       */
      if (d < MIN_FILL) {
         al_rest(0.005);
         continue;
      }

      /* Don't generate too many samples at once.  The buffer may underrun
       * while we wait for _al_voice_update to complete.
       */
      samples = d / bytes_per_sample / ex_data->channels;
      if (samples > MAX_FILL) {
         samples = MAX_FILL;
      }

      /* Generate the samples. */
      data = (unsigned char *) _al_voice_update(voice, &samples);
      if (data == NULL) {
         data = silence;
      }

      hr = ex_data->ds8_buffer->Lock(saved_play_cursor,
         samples * bytes_per_sample * ex_data->channels,
         &ptr1, &block1_bytes, &ptr2, &block2_bytes, 0);
      if (!FAILED(hr)) {
         memcpy(ptr1, data, block1_bytes);
         memcpy(ptr2, data + block1_bytes, block2_bytes);
         hr = ex_data->ds8_buffer->Unlock(ptr1, block1_bytes,
            ptr2, block2_bytes);
         if (FAILED(hr)) {
            ALLEGRO_ERROR("Unlock failed: %s\n", ds_get_error(hr));
         }
      }
      saved_play_cursor += block1_bytes + block2_bytes;
      saved_play_cursor %= buffer_size;
   } while (!ex_data->stop_voice);

   ex_data->ds8_buffer->Stop();

   al_free(silence);

   ex_data->stop_voice = 0;
   al_broadcast_cond(voice->cond);

   return NULL;
}
Example #9
0
int main(void)
{
   ALLEGRO_THREAD *thread[NUM_THREADS];
   ALLEGRO_DISPLAY *display;
   ALLEGRO_TIMER *timer;
   ALLEGRO_EVENT_QUEUE *queue;
   ALLEGRO_EVENT event;
   bool need_draw;
   int i;

   for (i = 0; i < 256; i++) {
      sin_lut[i] = 128 + (int) (127.0 * sin(i / 8.0));
   }

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

   al_install_keyboard();
   al_install_mouse();
   display = al_create_display(W * IMAGES_PER_ROW,
      H * NUM_THREADS / IMAGES_PER_ROW);
   if (!display) {
      abort_example("Error creating display\n");
      return 1;
   }
   timer = al_install_timer(1.0/3);
   if (!timer) {
      abort_example("Error creating timer\n");
      return 1;
   }
   queue = al_create_event_queue();
   if (!queue) {
      abort_example("Error creating event queue\n");
      return 1;
   }
   al_register_event_source(queue, al_get_display_event_source(display));
   al_register_event_source(queue, al_get_keyboard_event_source());
   al_register_event_source(queue, al_get_mouse_event_source());
   al_register_event_source(queue, al_get_timer_event_source(timer));

   /* Note:
    * Right now, A5 video displays can only be accessed from the thread which
    * created them (at lesat for OpenGL). To lift this restriction, we could
    * keep track of the current OpenGL context for each thread and make all
    * functions accessing the display check for it.. not sure it's worth the
    * additional complexity though.
    */
   al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_RGB_888);
   al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
   for (i = 0; i < NUM_THREADS; i++) {
      thread_info[i].bitmap = al_create_bitmap(W, H);
      if (!thread_info[i].bitmap) {
         goto Error;
      }
      thread_info[i].mutex = al_create_mutex();
      if (!thread_info[i].mutex) {
         goto Error;
      }
      thread_info[i].cond = al_create_cond();
      if (!thread_info[i].cond) {
         goto Error;
      }
      thread_info[i].is_paused = false;
      thread_info[i].random_seed = i;
      thread[i] = al_create_thread(thread_func, &thread_info[i]);
      if (!thread[i]) {
         goto Error;
      }
   }
   set_target(0, -0.56062033041600878303, -0.56064322926933807256);
   set_target(1, -0.57798076669230014080, -0.63449861991138123418);
   set_target(2,  0.36676836392830602929, -0.59081385302214906030);
   set_target(3, -1.48319283039401317303, -0.00000000200514696273);
   set_target(4, -0.74052910500707636032,  0.18340899525730713915);
   set_target(5,  0.25437906525768350097, -0.00046678223345789554);
   set_target(6, -0.56062033041600878303,  0.56064322926933807256);
   set_target(7, -0.57798076669230014080,  0.63449861991138123418);
   set_target(8,  0.36676836392830602929,  0.59081385302214906030);

   for (i = 0; i < NUM_THREADS; i++) {
      al_start_thread(thread[i]);
   }
   al_start_timer(timer);

   need_draw = true;
   while (true) {
      if (need_draw && al_event_queue_is_empty(queue)) {
         show_images();
         need_draw = false;
      }

      al_wait_for_event(queue, &event);
      if (event.type == ALLEGRO_EVENT_TIMER) {
         need_draw = true;
      }
      else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) {
         int n = (event.mouse.y / H) * IMAGES_PER_ROW + (event.mouse.x / W);
         if (n < NUM_THREADS) {
            double x = event.mouse.x - (event.mouse.x / W) * W;
            double y = event.mouse.y - (event.mouse.y / H) * H;
            /* Center to the mouse click position. */
            if (thread_info[n].is_paused) {
               thread_info[n].target_x = x / W - 0.5;
               thread_info[n].target_y = y / H - 0.5;
            }
            toggle_pausedness(n);
         }
      }
      else if (event.type == ALLEGRO_EVENT_DISPLAY_EXPOSE) {
         need_draw = true;
      }
      else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
         break;
      }
      else if (event.type == ALLEGRO_EVENT_KEY_DOWN) {
         if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE) {
            break;
         }
         need_draw = true;
      }
   }

   for (i = 0; i < NUM_THREADS; i++) {
      /* Set the flag to stop the thread.  The thread might be waiting on a
       * condition variable, so signal the condition to force it to wake up.
       */
      al_set_thread_should_stop(thread[i]);
      al_lock_mutex(thread_info[i].mutex);
      al_broadcast_cond(thread_info[i].cond);
      al_unlock_mutex(thread_info[i].mutex);

      /* al_destroy_thread() implicitly joins the thread, so this call is not
       * strictly necessary.
       */
      al_join_thread(thread[i], NULL);
      al_destroy_thread(thread[i]);
   }

   al_destroy_event_queue(queue);
   al_uninstall_timer(timer);
   al_destroy_display(display);

   return 0;

Error:

   return 1;
}
Example #10
0
/* TODO: review */
static void *_openal_update(ALLEGRO_THREAD *self, void *arg)
{
   ALLEGRO_VOICE *voice = (ALLEGRO_VOICE*) arg;
   ALLEGRO_AL_DATA *ex_data = (ALLEGRO_AL_DATA*)voice->extra;
   unsigned int i, samples_per_update;
   unsigned int bytes_per_sample;
   const void *data;
   void *silence;

   /* Streams should not be set to looping */
   alSourcei(ex_data->source, AL_LOOPING, AL_FALSE);

   silence = al_calloc(1, ex_data->buffer_size);
   if (ex_data->format == AL_FORMAT_STEREO8 ||
         ex_data->format == AL_FORMAT_MONO8) {
      memset(silence, 0x80, ex_data->buffer_size);
   }

   for (i = 0; i < ex_data->num_buffers; i++) {
      alBufferData(ex_data->buffers[i], ex_data->format, silence,
         ex_data->buffer_size, voice->frequency);
   }

   alSourceQueueBuffers(ex_data->source, ex_data->num_buffers,
      ex_data->buffers);

   alSourcePlay(ex_data->source);

   switch (ex_data->format) {
      case AL_FORMAT_STEREO16:
         bytes_per_sample = 4;
         break;
      case AL_FORMAT_STEREO8:
      case AL_FORMAT_MONO16:
         bytes_per_sample = 2;
         break;
      default:
         bytes_per_sample = 1;
         break;
   }

   samples_per_update = ex_data->buffer_size / bytes_per_sample;

   data = silence;

   while (!al_get_thread_should_stop(self)) {
      ALint status = 0;

      alGetSourcei(ex_data->source, AL_BUFFERS_PROCESSED, &status);
      if (status <= 0) {
         /* FIXME what is this for ? */
         al_rest(0.001);
         continue;
      }

      while (--status >= 0) {
         ALuint buffer;

         data = _al_voice_update(voice, voice->mutex, &samples_per_update);
         if (data == NULL)
            data = silence;

         alSourceUnqueueBuffers(ex_data->source, 1, &buffer);
         alBufferData(buffer, ex_data->format, data,
            samples_per_update * bytes_per_sample, voice->frequency);
         alSourceQueueBuffers(ex_data->source, 1, &buffer);
      }
      alGetSourcei(ex_data->source, AL_SOURCE_STATE, &status);
      if (status == AL_STOPPED) {
         alSourcePlay(ex_data->source);
      }
   }

   alSourceStop(ex_data->source);

   al_free(silence);

   ex_data->stopped = true;
   al_broadcast_cond(voice->cond);

   return NULL;
}
Example #11
0
static void *pulseaudio_update(ALLEGRO_THREAD *self, void *data)
{
   ALLEGRO_VOICE *voice = data;
   PULSEAUDIO_VOICE *pv = voice->extra;
   (void)self;

   for (;;) {
      enum PULSEAUDIO_VOICE_STATUS status;

      al_lock_mutex(voice->mutex);
      while ((status = pv->status) == PV_IDLE) {
         al_wait_cond(pv->status_cond, voice->mutex);
      }
      al_unlock_mutex(voice->mutex);

      if (status == PV_JOIN) {
         break;
      }

      if (status == PV_PLAYING) {
         unsigned int frames = pv->buffer_size_in_frames;
         if (voice->is_streaming) { 
            // streaming audio           
            const void *data = _al_voice_update(voice, voice->mutex, &frames);
            if (data) {
               pa_simple_write(pv->s, data,
                  frames * pv->frame_size_in_bytes, NULL);
            }
         }
         else {
            // direct buffer audio
            al_lock_mutex(pv->buffer_mutex);
            const char *data = pv->buffer;
            unsigned int len = frames * pv->frame_size_in_bytes;
            pv->buffer += frames * pv->frame_size_in_bytes;
            if (pv->buffer > pv->buffer_end) {
               len = pv->buffer_end - data;
               pv->buffer = voice->attached_stream->spl_data.buffer.ptr;
               voice->attached_stream->pos = 0;
               if (voice->attached_stream->loop == ALLEGRO_PLAYMODE_ONCE) {
                  al_lock_mutex(voice->mutex);
                  pv->status = PV_STOPPING;
                  al_broadcast_cond(pv->status_cond);
                  al_unlock_mutex(voice->mutex);
               }
            }
            else {
               voice->attached_stream->pos += frames;
            }
            al_unlock_mutex(pv->buffer_mutex);

            pa_simple_write(pv->s, data, len, NULL);
         }
      }
      else if (status == PV_STOPPING) {
         pa_simple_drain(pv->s, NULL);
         al_lock_mutex(voice->mutex);
         pv->status = PV_IDLE;
         al_broadcast_cond(pv->status_cond);
         al_unlock_mutex(voice->mutex);
      }
   }

   return NULL;
}
Example #12
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;
}