int play_loop(struct uade_state *state) { uint16_t *sm; int i; uint32_t *u32ptr; uint8_t space[UADE_MAX_MESSAGE_SIZE]; struct uade_msg *um = (struct uade_msg *) space; uint8_t sampledata[UADE_MAX_MESSAGE_SIZE]; int left = 0; int what_was_left = 0; int subsong_end = 0; int next_song = 0; int ret; int new_sub; int tailbytes = 0; int playbytes; char *reason; int64_t skip_bytes; int record_playtime = 1; int64_t subsong_bytes = 0; int deciseconds; int jump_sub = 0; int have_subsong_info = 0; const int framesize = UADE_BYTES_PER_SAMPLE * UADE_CHANNELS; const int bytes_per_second = UADE_BYTES_PER_FRAME * state->config.frequency; enum uade_control_state controlstate = UADE_S_STATE; int plistdir = UADE_PLAY_NEXT; struct uade_ipc *ipc = &state->ipc; struct uade_song *us = state->song; struct uade_effect *ue = &state->effects; struct uade_config *uc = &state->config; uade_effect_reset_internals(); /* Skip bytes must be a multiple of audio frame size */ skip_bytes = uade_jump_pos * bytes_per_second; skip_bytes = (skip_bytes / framesize) * framesize; test_song_end_trigger(); /* clear a pending SIGINT */ while (next_song == 0) { if (uade_terminated) { if (!uade_no_text_output) tprintf("\n"); return UADE_PLAY_FAILURE; } if (controlstate == UADE_S_STATE) { if (skip_bytes == 0) { deciseconds = subsong_bytes * 10 / bytes_per_second; if (!uade_no_text_output) { if (us->playtime >= 0) { int ptimesecs = us->playtime / 1000; int ptimesubsecs = (us->playtime / 100) % 10; tprintf("Playing time position %d.%ds in subsong %d (all subs %d.%ds) \r", deciseconds / 10, deciseconds % 10, us->cur_subsong == -1 ? 0 : us->cur_subsong, ptimesecs, ptimesubsecs); } else { tprintf("Playing time position %d.%ds in subsong %d \r", deciseconds / 10, deciseconds % 10, us->cur_subsong == -1 ? 0 : us->cur_subsong); } fflush(stdout); } } if (uc->action_keys) { switch ((ret = poll_terminal())) { case 0: break; case '<': plistdir = UADE_PLAY_PREVIOUS; uade_song_end_trigger = 1; record_playtime = 0; break; case '.': if (skip_bytes == 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSkipping 10 seconds\n"); skip_bytes = bytes_per_second * 10; } break; case ' ': case 'b': subsong_end = 1; record_playtime = 0; break; case 'c': pause_terminal(); break; case 'f': uade_set_config_option(uc, UC_FORCE_LED, uc->led_state ? "off" : "on"); tprintf("\nForcing LED %s\n", (uc->led_state & 1) ? "ON" : "OFF"); uade_send_filter_command(state); break; case 'g': uade_effect_toggle(ue, UADE_EFFECT_GAIN); tprintf("\nGain effect %s %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_GAIN) ? "ON" : "OFF", (uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) == 0 && uade_effect_is_enabled(ue, UADE_EFFECT_GAIN)) ? "(Remember to turn ON postprocessing!)" : ""); break; case 'h': tprintf("\n\n"); print_action_keys(); tprintf("\n"); break; case 'H': uade_effect_toggle(ue, UADE_EFFECT_HEADPHONES); tprintf("\nHeadphones effect %s %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_HEADPHONES) ? "ON" : "OFF", (uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) == 0 && uade_effect_is_enabled(ue, UADE_EFFECT_HEADPHONES) == 1) ? "(Remember to turn ON postprocessing!)" : ""); break; case 'i': if (!uade_no_text_output) print_song_info(us, UADE_MODULE_INFO); break; case 'I': if (!uade_no_text_output) print_song_info(us, UADE_HEX_DUMP_INFO); break; case '\n': case 'n': uade_song_end_trigger = 1; record_playtime = 0; break; case 'N': uade_effect_toggle(ue, UADE_EFFECT_NORMALISE); tprintf("\nNormalise effect %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_NORMALISE) ? "ON" : "OFF"); break; case 'p': uade_effect_toggle(ue, UADE_EFFECT_ALLOW); tprintf("\nPostprocessing effects %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) ? "ON" : "OFF"); break; case 'P': uade_effect_toggle(ue, UADE_EFFECT_PAN); tprintf("\nPanning effect %s %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_PAN) ? "ON" : "OFF", (uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) == 0 && uade_effect_is_enabled(ue, UADE_EFFECT_PAN) == 1) ? "(Remember to turn ON postprocessing!)" : ""); break; case 'q': tprintf("\n"); return UADE_PLAY_EXIT; case 's': playlist_random(&uade_playlist, -1); tprintf("\n%s mode\n", uade_playlist.randomize ? "Shuffle" : "Normal"); break; case 'v': uc->verbose ^= 1; tprintf("\nVerbose mode %s\n", uc->verbose ? "ON" : "OFF"); break; case 'x': us->cur_subsong--; subsong_end = 1; jump_sub = 1; record_playtime = 0; break; case 'z': record_playtime = 0; if (us->cur_subsong == 0 || (us->min_subsong >= 0 && us->cur_subsong == us->min_subsong)) { plistdir = UADE_PLAY_PREVIOUS; uade_song_end_trigger = 1; break; } new_sub = us->cur_subsong - 2; if (new_sub < 0) new_sub = -1; if (us->min_subsong >= 0 && new_sub < us->min_subsong) new_sub = us->min_subsong - 1; us->cur_subsong = new_sub; subsong_end = 1; jump_sub = 1; break; default: if (isdigit(ret)) { new_sub = ret - '0'; if (us->min_subsong >= 0 && new_sub < us->min_subsong) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\ntoo low a subsong number\n"); break; } if (us->max_subsong >= 0 && new_sub > us->max_subsong) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\ntoo high a subsong number\n"); break; } us->cur_subsong = new_sub - 1; subsong_end = 1; jump_sub = 1; us->out_bytes = 0; /* to prevent timeout */ record_playtime = 0; /* to not record playtime */ } else if (!isspace(ret)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\n%c is not a valid command\n", ret); } } } if (uade_debug_trigger == 1) { if (uade_send_short_message(UADE_COMMAND_ACTIVATE_DEBUGGER, ipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not active debugger\n"); return UADE_PLAY_FAILURE; } uade_debug_trigger = 0; } if (uade_info_mode && have_subsong_info) { /* we assume that subsong info is the last info we get */ uade_song_end_trigger = 1; subsong_end = 0; } if (uade_song_end_trigger) record_playtime = 0; if (subsong_end && uade_song_end_trigger == 0) { if (jump_sub || (uc->one_subsong == 0 && us->cur_subsong != -1 && us->max_subsong != -1)) { us->cur_subsong++; jump_sub = 0; if (us->cur_subsong > us->max_subsong) { uade_song_end_trigger = 1; } else { subsong_end = 0; subsong_bytes = 0; uade_change_subsong(state); __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nChanging to subsong %d from range [%d, %d]\n", us->cur_subsong, us->min_subsong, us->max_subsong); } } else { uade_song_end_trigger = 1; } } if (uade_song_end_trigger) { next_song = 1; if (uade_send_short_message(UADE_COMMAND_REBOOT, ipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send reboot\n"); return UADE_PLAY_FAILURE; } goto sendtoken; } left = uade_read_request(ipc); sendtoken: if (uade_send_short_message(UADE_COMMAND_TOKEN, ipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send token\n"); return UADE_PLAY_FAILURE; } controlstate = UADE_R_STATE; if (what_was_left) { if (subsong_end) { /* We can only rely on 'tailbytes' amount which was determined earlier when UADE_REPLY_SONG_END happened */ playbytes = tailbytes; tailbytes = 0; } else { playbytes = what_was_left; } if (subsong_end == 0 && uade_song_end_trigger == 0 && uade_test_silence(um->data, playbytes, state)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nsilence detected (%d seconds)\n", uc->silence_timeout); subsong_end = 1; } us->out_bytes += playbytes; subsong_bytes += playbytes; if (skip_bytes > 0) { if (playbytes <= skip_bytes) { skip_bytes -= playbytes; playbytes = 0; } else { playbytes -= skip_bytes; memmove(sampledata, sampledata + skip_bytes, playbytes); skip_bytes = 0; } } uade_effect_run(ue, (int16_t *) sampledata, playbytes / framesize); if (!audio_play(sampledata, playbytes)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nlibao error detected.\n"); return UADE_PLAY_FAILURE; } if (uc->timeout != -1 && uc->use_timeouts) { if (uade_song_end_trigger == 0) { if (us->out_bytes / bytes_per_second >= uc->timeout) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSong end (timeout %ds)\n", uc->timeout); uade_song_end_trigger = 1; record_playtime = 0; } } } if (uc->subsong_timeout != -1 && uc->use_timeouts) { if (subsong_end == 0 && uade_song_end_trigger == 0) { if (subsong_bytes / bytes_per_second >= uc->subsong_timeout) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSong end (subsong timeout %ds)\n", uc->subsong_timeout); subsong_end = 1; record_playtime = 0; } } } } } else { /* receive state */ if (uade_receive_message(um, sizeof(space), ipc) <= 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events from uade\n"); return UADE_PLAY_FAILURE; } 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++; } assert (left == um->size); assert (sizeof sampledata >= um->size); memcpy(sampledata, um->data, um->size); what_was_left = left; left = 0; break; case UADE_REPLY_FORMATNAME: uade_check_fix_string(um, 128); debug(uc->verbose, "\nFormat name: %s\n", (uint8_t *) um->data); if (uade_info_mode) tprintf("formatname: %s\n", (char *) um->data); break; case UADE_REPLY_MODULENAME: uade_check_fix_string(um, 128); debug(uc->verbose, "\nModule name: %s\n", (uint8_t *) um->data); if (uade_info_mode) tprintf("modulename: %s\n", (char *) um->data); break; case UADE_REPLY_MSG: uade_check_fix_string(um, 128); debug(uc->verbose, "\nMessage: %s\n", (char *) um->data); break; case UADE_REPLY_PLAYERNAME: uade_check_fix_string(um, 128); debug(uc->verbose, "\nPlayer name: %s\n", (uint8_t *) um->data); if (uade_info_mode) tprintf("playername: %s\n", (char *) um->data); break; case UADE_REPLY_SONG_END: if (um->size < 9) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nInvalid 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 */ uade_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", "\nbroken reason string with song end notice\n"); exit(-1); } __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSong end (%s)\n", reason); break; case UADE_REPLY_SUBSONG_INFO: if (um->size != 12) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nsubsong info: too short a message\n"); exit(-1); } u32ptr = (uint32_t *) um->data; us->min_subsong = ntohl(u32ptr[0]); us->max_subsong = ntohl(u32ptr[1]); us->cur_subsong = ntohl(u32ptr[2]); debug(uc->verbose, "\nsubsong: %d from range [%d, %d]\n", us->cur_subsong, us->min_subsong, us->max_subsong); if (!(-1 <= us->min_subsong && us->min_subsong <= us->cur_subsong && us->cur_subsong <= us->max_subsong)) { int tempmin = us->min_subsong, tempmax = us->max_subsong; __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nThe player is broken. Subsong info does not match.\n"); us->min_subsong = tempmin <= tempmax ? tempmin : tempmax; us->max_subsong = tempmax >= tempmin ? tempmax : tempmin; if (us->cur_subsong > us->max_subsong) us->max_subsong = us->cur_subsong; else if (us->cur_subsong < us->min_subsong) us->min_subsong = us->cur_subsong; } if ((us->max_subsong - us->min_subsong) != 0) __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nThere are %d subsongs in range [%d, %d].\n", 1 + us->max_subsong - us->min_subsong, us->min_subsong, us->max_subsong); uade_lookup_volume_normalisation(state); have_subsong_info = 1; if (uade_info_mode) tprintf("subsong_info: %d %d %d (cur, min, max)\n", us->cur_subsong, us->min_subsong, us->max_subsong); break; default: __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nExpected sound data. got %u.\n", (unsigned int) um->msgtype); return UADE_PLAY_FAILURE; } } } if (record_playtime && us->md5[0] != 0) { uint32_t playtime = (us->out_bytes * 1000) / bytes_per_second; uade_add_playtime(us->md5, playtime); } do { ret = uade_receive_message(um, sizeof(space), ipc); if (ret < 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events (TOKEN) from uade.\n"); return UADE_PLAY_FAILURE; } if (ret == 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nEnd of input after reboot.\n"); return UADE_PLAY_FAILURE; } } while (um->msgtype != UADE_COMMAND_TOKEN); tprintf("\n"); return plistdir; }
static int run_client() { // __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "UADE STATE %d", ctrlstate); if(ctrlstate == UADE_S_STATE) { if(uade_song_end_trigger) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "song_end_trigger"); return -1; } /*if(uade_song_end_trigger) { next_song = 1; if(uade_send_short_message(UADE_COMMAND_REBOOT, &uadeipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send reboot\n"); return 0; } } else */ if(new_subsong >= 0) { state.song->cur_subsong = state.song->min_subsong + new_subsong; __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "New subsong %d", state.song->cur_subsong); uade_change_subsong(&state); //uade_change_subsong(new_subsong, &uadeipc); new_subsong = -1; } if(state.config.no_filter_set) { uade_send_filter_command(&state); state.config.no_filter_set = 0; } if(state.config.panning_enable_set || state.config.panning_set) { uade_set_effects(&state); state.config.no_filter_set = 0; state.config.panning_set = 0; state.config.panning_enable_set = 0; } //if(state.config.use_ntsc_set) { // uade_set_effects(&state); // state.config.use_ntsc_set = 0; //} left = uade_read_request(&uadeipc); /* Request another batch of sample data from uadecore */ if(uade_send_short_message(UADE_COMMAND_TOKEN, &uadeipc)) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send token\n"); return 0; } ctrlstate = UADE_R_STATE; } /* receive ctrlstate */ if(ctrlstate == UADE_R_STATE) { uint16_t *sm; if (uade_receive_message(um, sizeof(space), &uadeipc) <= 0) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events from uade\n"); return 0; } //__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Got msg %d", um->msgtype); switch (um->msgtype) { case UADE_COMMAND_TOKEN: ctrlstate = UADE_S_STATE; //__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Got token"); break; case UADE_REPLY_DATA: sm = (uint16_t *)um->data; if(!soundPtr) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "No soundPtr"); return -1; } if(subsong_end) { playbytes = tailbytes; /* Determined by UADE_REPLY_SONG_END */ tailbytes = 0; } else playbytes = um->size; if(1) //plugin.freq == 44100) { for (int i = 0; i < um->size/2; i++) soundPtr[i] = ntohs(sm[i]); soundPtr += (playbytes/2); } else if(0) // plugin.freq == 22050) { for (int i = 0; i < um->size/2; i+=4) { soundPtr[i/2] = (ntohs(sm[i]) + ntohs(sm[i+2])) / 2; soundPtr[i/2+1] = (ntohs(sm[i+1]) + ntohs(sm[i+3])) / 2; } soundPtr += (playbytes/4); } //dbprintf("Got %d bytes sampledata\n", playbytes); //__android_log_print(ANDROID_LOG_VERBOSE, "UADEPlugin", "Got %d bytes sampledata\n", playbytes); // time_bytes += playbytes; //assert(left >= um->size); left -= um->size; return 1; break; case UADE_REPLY_FORMATNAME: uade_check_fix_string(um, MAX_LEN); __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Format name: %s\n", (char*) um->data); strcpy(current_format, (char *)um->data); break; case UADE_REPLY_MODULENAME: uade_check_fix_string(um, MAX_LEN); __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Module name: %s\n", (char*) um->data); break; case UADE_REPLY_MSG: uade_check_fix_string(um, MAX_LEN); __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Message: %s\n", (char *) um->data); break; case UADE_REPLY_PLAYERNAME: uade_check_fix_string(um, MAX_LEN); __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Player name: %s\n", (char*) um->data); strcpy(current_format, (char *)um->data); break; case UADE_REPLY_SONG_END: if (um->size < 9) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Invalid song end reply\n"); //exit(-1); return -1; } tailbytes = ntohl(((uint32_t *) um->data)[0]); uade_song_end_trigger = 1; __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Song end: %s", (char*)um->data+8); break; case UADE_REPLY_SUBSONG_INFO: if(um->size != 12) { __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong info: too short a message\n"); } { unsigned int *u32ptr = (unsigned int *)um->data; int min_sub = ntohl(u32ptr[0]); int max_sub = ntohl(u32ptr[1]); int cur_sub = ntohl(u32ptr[2]); state.song->min_subsong = min_sub; state.song->max_subsong = max_sub; state.song->cur_subsong = cur_sub; startSong = cur_sub - min_sub; __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong: %d from range [%d, %d]\n", cur_sub, min_sub, max_sub); } break; case UADE_REPLY_CANT_PLAY: case UADE_REPLY_CAN_PLAY: default: __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Expected sound data. got %d.\n", um->msgtype); return 0; } } return 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; }