Ejemplo n.º 1
0
/* XMMS calls this function to check if filename belongs to this plugin. */
static int uadexmms_is_our_file(char *filename)
{
  int ret;

  if (strncmp(filename, "uade://", 7) == 0)
    return TRUE;

  uade_lock();


  /* This is a performance optimization to avoid re-reading uade.conf
   * when state.config hasn't yet been read. uade_is_our_file() needs the
   * config. */
  if (!state.validconfig) {
    state.config = config_backup;
    state.validconfig = 1;

    /* Verify that this condition is true at most once */
    assert(!uade_config_optimization);
    uade_config_optimization = 1;
  }

  ret = uade_is_our_file(filename, 1, &state) ? TRUE : FALSE;

  uade_unlock();

  return ret;
}
Ejemplo n.º 2
0
/* XMMS calls this function when pausing or unpausing */
static void uade_pause(short paused)
{
  uade_lock();
  uade_is_paused = paused;
  uade_unlock();
  uade_ip.output->pause(paused);
}
Ejemplo n.º 3
0
int uade_get_min_subsong(int def)
{
    int subsong;
    uade_lock();
    subsong = -1;
    if (state.song != NULL)
      subsong = state.song->min_subsong;
    uade_unlock();
    if (subsong == -1)
    subsong = def;
    return subsong;
}
Ejemplo n.º 4
0
static int get_next_subsong(void)
{
    int ispaused;
    uade_lock();
    ispaused = uade_is_paused;
    uade_unlock();
    if (ispaused == 0) {
	int newsubsong;
	newsubsong = uade_get_cur_subsong(-1);
	if (newsubsong == -1)
	    return -1;
	newsubsong++;
	return newsubsong;
    }
    return -1;
}
Ejemplo n.º 5
0
static int get_previous_subsong(void)
{
    int ispaused;
    uade_lock();
    ispaused = uade_is_paused;
    uade_unlock();
    if (ispaused == 0) {
	int newsubsong;
	newsubsong = uade_get_cur_subsong(-1);
	if (newsubsong == -1)
	    return -1;
	if (newsubsong > uade_get_min_subsong(-1)) {
	    newsubsong--;
	    return newsubsong;
	}
    }
    return -1;
}
Ejemplo n.º 6
0
/* XMMS calls this function periodically to determine current playing time.
   We use this function to report song name and title after play_file(),
   and to tell XMMS to end playing if song ends for any reason. */
static int uade_get_time(void)
{
  if (abort_playing || last_beat_played)
    return -1;

  if (gui_info_set == 0 && state.song->max_subsong != -1) {

    uade_lock();

    if (state.song->max_subsong != -1)
      uade_info_string();

    gui_info_set = 1;
    uade_unlock();

    file_info_update(gui_module_filename, gui_player_filename, gui_modulename, gui_playername, gui_formatname);
  }

  return uade_ip.output->output_time();
}
Ejemplo n.º 7
0
static void uade_stop(void)
{
  /* Signal other subsystems to proceed to finished state as soon as possible
   */
  abort_playing = 1;

  /* Wait for playing thread to finish */
  if (uade_thread_running) {
    pthread_join(decode_thread, NULL);
    uade_thread_running = 0;
  }

  uade_gui_close_subsong_win();

  if (state.song != NULL) {
    /* If song ended volutarily, tell the play time for XMMS. */
    uade_lock();
    if (record_playtime) {
      int play_time = (state.song->out_bytes * 1000) / (UADE_BYTES_PER_FRAME * state.config.frequency);
      if (state.song->md5[0] != 0)
    uade_add_playtime(&state, state.song->md5, play_time);

      state.song->playtime = play_time;
      state.song->cur_subsong = state.song->max_subsong;
      uade_info_string();
    }

    /* We must free uadesong after playthread has finished and additional
       GUI windows have been closed. */
    uade_unalloc_song(&state);

    uade_unlock();
  }

  uade_ip.output->close_audio();
}
Ejemplo n.º 8
0
static void uade_ffwd(void)
{
    uade_lock();
    uade_seek_forward += 10;
    uade_unlock();
}
Ejemplo n.º 9
0
static void uade_play_file(char *filename)
{
  char tempname[PATH_MAX];
  char *t;

  load_config();

  uade_lock();

  abort_playing = 0;
  last_beat_played = 0;
  record_playtime = 0;

  uade_is_paused = 0;
  uade_select_sub = -1;
  uade_seek_forward = 0;

  assert(state.song == NULL);

  uade_unlock();

  if (strncmp(filename, "uade://", 7) == 0)
    filename += 7;

  strlcpy(tempname, filename, sizeof tempname);
  t = basename(tempname);
  if (t == NULL)
    t = filename;
  strlcpy(gui_filename, t, sizeof gui_filename);
  gui_info_set = 0;

  gui_formatname[0] = 0;
  gui_modulename[0] = 0;
  gui_playername[0] = 0;
  gui_module_filename[0] = 0;
  gui_player_filename[0] = 0;

  if (!state.pid) {
    char configname[PATH_MAX];
    snprintf(configname, sizeof configname, "%s/uaerc", state.permconfig.basedir.name);
    uade_spawn(&state, UADE_CONFIG_UADE_CORE, configname);
  }

  if (!uade_ip.output->open_audio(sample_format, state.permconfig.frequency, UADE_CHANNELS)) {
    abort_playing = 1;
    return;
  }

  if (plugin_disabled) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "An error has occured. uade plugin is internally disabled.\n");
    goto err;
  }

  /* If content db has changed (newer mtime chan previously read) then force
     a reload */
  load_content_db();

  /* Save current db if an hour has passed */
  if (contentname[0]) {
    time_t curtime = time(NULL);
    if (curtime >= (content_mtime + 3600)) {
      struct stat st;
      uade_save_content_db(contentname, &state);
      if (stat(contentname, &st) == 0)
    content_mtime = st.st_mtime;
    }
  }

  if (initialize_song(filename) == FALSE)
    goto err;

  if (pthread_create(&decode_thread, NULL, play_loop, NULL)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "uade: can't create play_loop() thread\n");
    goto err;
  }

  uade_thread_running = 1;
  return;

 err:
  /* close audio that was opened */
  uade_ip.output->close_audio();
  abort_playing = 1;

  uade_lock();

  if (state.song)
    uade_unalloc_song(&state);

  uade_unlock();
}
Ejemplo n.º 10
0
static void *play_loop(void *arg)
{
  enum uade_control_state controlstate = UADE_S_STATE;
  int ret;
  int left = 0;
  uint8_t space[UADE_MAX_MESSAGE_SIZE];
  struct uade_msg *um = (struct uade_msg *) space;
  int subsong_end = 0;
  uint16_t *sm;
  int i;
  unsigned int play_bytes, tailbytes = 0;
  uint64_t subsong_bytes = 0;
  char *reason;
  uint32_t *u32ptr;
  int writeoffs;
  int framesize = UADE_CHANNELS * UADE_BYTES_PER_SAMPLE;
  int song_end_trigger = 0;
  int64_t skip_bytes = 0;

  uade_lock();
  record_playtime = 1;
  uade_unlock();

  while (1) {
    if (controlstate == UADE_S_STATE) {

      assert(left == 0);

      if (abort_playing) {
    uade_lock();
    record_playtime = 0;
    uade_unlock();
    break;
      }

      uade_lock();
      if (uade_seek_forward) {
    skip_bytes += uade_seek_forward * UADE_BYTES_PER_FRAME * state.config.frequency;
    uade_ip.output->flush(uade_ip.output->written_time() + uade_seek_forward * 1000);
    uade_seek_forward = 0;
      }
      if (uade_select_sub != -1) {
    state.song->cur_subsong = uade_select_sub;

    uade_change_subsong(&state);

    uade_ip.output->flush(0);
    uade_select_sub = -1;
    subsong_end = 0;
    subsong_bytes = 0;

    /* we do this to avoid timeout, and to not record playtime */
    state.song->out_bytes = 0;
    record_playtime = 0;

    uade_info_string();
      }

      if (subsong_end && song_end_trigger == 0) {

    if (state.song->cur_subsong == -1 || state.song->max_subsong == -1) {
      song_end_trigger = 1;

    } else {

      state.song->cur_subsong++;

      if (state.song->cur_subsong > state.song->max_subsong) {
        song_end_trigger = 1;
      } else {
        int x = 0;

        uade_change_subsong(&state);

        while (uade_ip.output->buffer_playing()) {
          /* Sleep at most 5 secs */
          if (x >= 500) {
        __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "UADE: blocking work-around activated.\n");
        break;
          }
          x++;
          xmms_usleep(10000);
        }
        uade_ip.output->flush(0);
        subsong_end = 0;
        subsong_bytes = 0;

        uade_gui_subsong_changed(state.song->cur_subsong);

        uade_info_string();
      }
    }
      }
      uade_unlock();

      if (song_end_trigger) {
    /* We must drain the audio fast if abort_playing happens (e.g.
       the user changes song when we are here waiting the sound device) */
    while (uade_ip.output->buffer_playing() && abort_playing == 0)

      xmms_usleep(10000);
    break;
      }

      left = uade_read_request(&state.ipc);

      if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send token.\n");
    return NULL;
      }
      controlstate = UADE_R_STATE;

    } else {

      if (uade_receive_message(um, sizeof(space), &state.ipc) <= 0) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade\n");
    exit(1);
      }

      switch (um->msgtype) {

      case UADE_COMMAND_TOKEN:
    controlstate = UADE_S_STATE;
    break;

      case UADE_REPLY_DATA:
    sm = (uint16_t *) um->data;
    for (i = 0; i < um->size; i += 2) {
      *sm = ntohs(*sm);
      sm++;
    }

    if (subsong_end) {
      play_bytes = tailbytes;
      tailbytes = 0;
    } else {
      play_bytes = um->size;
    }

    if (subsong_end == 0 && song_end_trigger == 0 &&
        uade_test_silence(um->data, play_bytes, &state)) {
      subsong_end = 1;
    }

    subsong_bytes += play_bytes;
    uade_lock();
    state.song->out_bytes += play_bytes;
    uade_unlock();

    if (skip_bytes > 0) {
      if (play_bytes <= skip_bytes) {
        skip_bytes -= play_bytes;
        play_bytes = 0;
      } else {
        play_bytes -= skip_bytes;
        skip_bytes = 0;
      }
    }

    uade_effect_run(&state.effects, (int16_t *) um->data, play_bytes / framesize);
    uade_ip.add_vis_pcm(uade_ip.output->written_time(), sample_format, UADE_CHANNELS, play_bytes, um->data);

    writeoffs = 0;
    while (writeoffs < play_bytes) {
      int writable;
      while ((writable = uade_ip.output->buffer_free()) <= 0) {
        if (abort_playing)
          goto nowrite;
        xmms_usleep(10000);
      }

      if (writable > (play_bytes - writeoffs))
        writable = play_bytes - writeoffs;

      uade_ip.output->write_audio(&um->data[writeoffs], writable);

      writeoffs += writable;
    }


      nowrite:

    if (state.config.timeout != -1 && state.config.use_timeouts) {
      if (song_end_trigger == 0) {
        uade_lock();
        if (state.song->out_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.timeout) {
          song_end_trigger = 1;
          record_playtime = 0;
        }
        uade_unlock();
      }
    }

    if (state.config.subsong_timeout != -1 && state.config.use_timeouts) {
      if (subsong_end == 0 && song_end_trigger == 0) {
        if (subsong_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.subsong_timeout) {
          subsong_end = 1;
          record_playtime = 0;
        }
      }
    }

    assert (left >= um->size);
    left -= um->size;
    break;

      case UADE_REPLY_FORMATNAME:
    uade_check_fix_string(um, 128);
    strlcpy(gui_formatname, (char *) um->data, sizeof gui_formatname);
    strlcpy(state.song->formatname, (char *) um->data, sizeof state.song->formatname);
    break;

      case UADE_REPLY_MODULENAME:
    uade_check_fix_string(um, 128);
    strlcpy(gui_modulename, (char *) um->data, sizeof gui_modulename);
    strlcpy(state.song->modulename, (char *) um->data, sizeof state.song->modulename);
    break;

      case UADE_REPLY_MSG:
    uade_check_fix_string(um, 128);
    plugindebug("Message: %s\n", (char *) um->data);
    break;

      case UADE_REPLY_PLAYERNAME:
    uade_check_fix_string(um, 128);
    strlcpy(gui_playername, (char *) um->data, sizeof gui_playername);
    strlcpy(state.song->playername, (char *) um->data, sizeof state.song->playername);
    break;

      case UADE_REPLY_SONG_END:
    if (um->size < 9) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Invalid song end reply\n");
      exit(1);
    }
    tailbytes = ntohl(((uint32_t *) um->data)[0]);
    /* next ntohl() is only there for a principle. it is not useful */
    if (ntohl(((uint32_t *) um->data)[1]) == 0) {
      /* normal happy song end. go to next subsong if any */
      subsong_end = 1;
    } else {
      /* unhappy song end (error in the 68k side). skip to next song
         ignoring possible subsongs */
      song_end_trigger = 1;
    }
    i = 0;
    reason = (char *) &um->data[8];
    while (reason[i] && i < (um->size - 8))
      i++;
    if (reason[i] != 0 || (i != (um->size - 9))) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Broken reason string with song end notice\n");
      exit(1);
    }
    break;

      case UADE_REPLY_SUBSONG_INFO:
    if (um->size != 12) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong info: too short a message\n");
      exit(1);
    }
    u32ptr = (uint32_t *) um->data;
    uade_lock();
    state.song->min_subsong = ntohl(u32ptr[0]);
    state.song->max_subsong = ntohl(u32ptr[1]);
    state.song->cur_subsong = ntohl(u32ptr[2]);

    if (!(-1 <= state.song->min_subsong && state.song->min_subsong <= state.song->cur_subsong && state.song->cur_subsong <= state.song->max_subsong)) {
      int tempmin = state.song->min_subsong, tempmax = state.song->max_subsong;
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "uade: The player is broken. Subsong info does not match with %s.\n", gui_filename);
      state.song->min_subsong = tempmin <= tempmax ? tempmin : tempmax;
      state.song->max_subsong = tempmax >= tempmin ? tempmax : tempmin;
      if (state.song->cur_subsong > state.song->max_subsong)
        state.song->max_subsong = state.song->cur_subsong;
      else if (state.song->cur_subsong < state.song->min_subsong)
        state.song->min_subsong = state.song->cur_subsong;
    }
    uade_unlock();
    break;

      default:
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Expected sound data. got %d.\n", um->msgtype);
    plugin_disabled = 1;
    return NULL;
      }
    }
  }

  last_beat_played = 1;

  if (uade_send_short_message(UADE_COMMAND_REBOOT, &state.ipc)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send reboot.\n");
    return NULL;
  }

  if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send token.\n");
    return NULL;
  }

  do {
    ret = uade_receive_message(um, sizeof(space), &state.ipc);
    if (ret < 0) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade.\n");
      return NULL;
    }
    if (ret == 0) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "End of input after reboot.\n");
      return NULL;
    }
  } while (um->msgtype != UADE_COMMAND_TOKEN);

  return NULL;
}
Ejemplo n.º 11
0
/* Analyze file format, and handshake with uadecore. */
static int initialize_song(char *filename)
{
  int ret;
  char modulename[PATH_MAX];
  char playername[PATH_MAX];
  char scorename[PATH_MAX];

  uade_lock();

  state.config = state.permconfig;
  state.validconfig = 1;

  state.ep = NULL;
  state.song = NULL;

  ret = uade_is_our_file(filename, 0, &state);

  if (!ret)
    goto error;

  strlcpy(modulename, filename, sizeof modulename);
  strlcpy(gui_module_filename, filename, sizeof gui_module_filename);

  snprintf(scorename, sizeof scorename, "%s/score", state.config.basedir.name);

  if (strcmp(state.ep->playername, "custom") == 0) {
    strlcpy(playername, modulename, sizeof playername);
    modulename[0] = 0;
    gui_module_filename[0] = 0;
  } else {
    snprintf(playername, sizeof playername, "%s/players/%s", state.config.basedir.name, state.ep->playername);
  }

  if (!uade_alloc_song(&state, filename))
    goto error;

  uade_set_ep_attributes(&state);

  uade_set_song_attributes(&state, playername, sizeof playername);

  uade_set_effects(&state);

  strlcpy(gui_player_filename, playername, sizeof gui_player_filename);

  ret = uade_song_initialization(scorename, playername, modulename, &state);
  if (ret) {
    if (ret != UADECORE_CANT_PLAY && ret != UADECORE_INIT_ERROR) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not initialize song. Unknown error.\n");
      plugin_disabled = 1;
    }
    uade_unalloc_song(&state);

    goto error;
  }

  uade_unlock();
  return TRUE;

 error:
  uade_unlock();
  return FALSE;
}