1 /* uade123 - a simple command line frontend for uadecore. 2 3 Copyright (C) 2005 Heikki Orsila <heikki.orsila@iki.fi> 4 5 This source code module is dual licensed under GPL and Public Domain. 6 Hence you may use _this_ module (not another code module) in any way you 7 want in your projects. 8 */ 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <netinet/in.h> 13 #include <string.h> 14 #include <ctype.h> 15 #include <assert.h> 16 17 #include <uadecontrol.h> 18 #include <uadeconstants.h> 19 #include <songinfo.h> 20 #include <sysincludes.h> 21 22 #include "playloop.h" 23 #include "uadesimple.h" 24 #include "audio.h" 25 26 27 int play_loop(struct uade_state *state) 28 { 29 uint16_t *sm; 30 int i; 31 uint32_t *u32ptr; 32 33 uint8_t space[UADE_MAX_MESSAGE_SIZE]; 34 struct uade_msg *um = (struct uade_msg *) space; 35 36 uint8_t sampledata[UADE_MAX_MESSAGE_SIZE]; 37 int left = 0; 38 int what_was_left = 0; 39 40 int subsong_end = 0; 41 int next_song = 0; 42 int ret; 43 int tailbytes = 0; 44 int playbytes; 45 char *reason; 46 47 int64_t subsong_bytes = 0; 48 49 const int framesize = UADE_BYTES_PER_SAMPLE * UADE_CHANNELS; 50 const int bytes_per_second = UADE_BYTES_PER_FRAME * state->config.frequency; 51 52 enum uade_control_state controlstate = UADE_S_STATE; 53 54 struct uade_ipc *ipc = &state->ipc; 55 struct uade_song *us = state->song; 56 struct uade_effect *ue = &state->effects; 57 struct uade_config *uc = &state->config; 58 59 uade_effect_reset_internals(); 60 61 while (next_song == 0) { 62 63 if (controlstate == UADE_S_STATE) { 64 65 if (subsong_end && uade_song_end_trigger == 0) { 66 67 if (uc->one_subsong == 0 && us->cur_subsong != -1 && us->max_subsong != -1) { 68 69 us->cur_subsong++; 70 71 if (us->cur_subsong > us->max_subsong) { 72 uade_song_end_trigger = 1; 73 } else { 74 subsong_end = 0; 75 subsong_bytes = 0; 76 77 uade_change_subsong(state); 78 79 fprintf(stderr, "\nChanging to subsong %d from range [%d, %d]\n", us->cur_subsong, us->min_subsong, us->max_subsong); 80 } 81 } else { 82 uade_song_end_trigger = 1; 83 } 84 } 85 86 if (uade_song_end_trigger) { 87 next_song = 1; 88 if (uade_send_short_message(UADE_COMMAND_REBOOT, ipc)) { 89 fprintf(stderr, "\nCan not send reboot\n"); 90 return 0; 91 } 92 goto sendtoken; 93 } 94 95 left = uade_read_request(ipc); 96 97 sendtoken: 98 if (uade_send_short_message(UADE_COMMAND_TOKEN, ipc)) { 99 fprintf(stderr, "\nCan not send token\n"); 100 return 0; 101 } 102 103 controlstate = UADE_R_STATE; 104 105 if (what_was_left) { 106 if (subsong_end) { 107 /* We can only rely on 'tailbytes' amount which was determined 108 earlier when UADE_REPLY_SONG_END happened */ 109 playbytes = tailbytes; 110 tailbytes = 0; 111 } else { 112 playbytes = what_was_left; 113 } 114 115 us->out_bytes += playbytes; 116 subsong_bytes += playbytes; 117 118 uade_effect_run(ue, (int16_t *) sampledata, playbytes / framesize); 119 120 if (!audio_play(sampledata, playbytes)) { 121 fprintf(stderr, "\nlibao error detected.\n"); 122 return 0; 123 } 124 125 /* FIX ME */ 126 if (uc->timeout != -1 && uc->use_timeouts) { 127 if (uade_song_end_trigger == 0) { 128 if (us->out_bytes / bytes_per_second >= uc->timeout) { 129 fprintf(stderr, "\nSong end (timeout %ds)\n", uc->timeout); 130 uade_song_end_trigger = 1; 131 } 132 } 133 } 134 135 if (uc->subsong_timeout != -1 && uc->use_timeouts) { 136 if (subsong_end == 0 && uade_song_end_trigger == 0) { 137 if (subsong_bytes / bytes_per_second >= uc->subsong_timeout) { 138 fprintf(stderr, "\nSong end (subsong timeout %ds)\n", uc->subsong_timeout); 139 subsong_end = 1; 140 } 141 } 142 } 143 } 144 145 } else { 146 147 /* receive state */ 148 if (uade_receive_message(um, sizeof(space), ipc) <= 0) { 149 fprintf(stderr, "\nCan not receive events from uade\n"); 150 return 0; 151 } 152 153 switch (um->msgtype) { 154 155 case UADE_COMMAND_TOKEN: 156 controlstate = UADE_S_STATE; 157 break; 158 159 case UADE_REPLY_DATA: 160 sm = (uint16_t *) um->data; 161 for (i = 0; i < um->size; i += 2) { 162 *sm = ntohs(*sm); 163 sm++; 164 } 165 166 assert (left == um->size); 167 assert (sizeof sampledata >= um->size); 168 169 memcpy(sampledata, um->data, um->size); 170 171 what_was_left = left; 172 left = 0; 173 break; 174 175 case UADE_REPLY_FORMATNAME: 176 uade_check_fix_string(um, 128); 177 debug(uc->verbose, "\nFormat name: %s\n", (uint8_t *) um->data); 178 break; 179 180 case UADE_REPLY_MODULENAME: 181 uade_check_fix_string(um, 128); 182 debug(uc->verbose, "\nModule name: %s\n", (uint8_t *) um->data); 183 break; 184 185 case UADE_REPLY_MSG: 186 uade_check_fix_string(um, 128); 187 debug(uc->verbose, "\nMessage: %s\n", (char *) um->data); 188 break; 189 190 case UADE_REPLY_PLAYERNAME: 191 uade_check_fix_string(um, 128); 192 debug(uc->verbose, "\nPlayer name: %s\n", (uint8_t *) um->data); 193 break; 194 195 case UADE_REPLY_SONG_END: 196 if (um->size < 9) { 197 fprintf(stderr, "\nInvalid song end reply\n"); 198 exit(-1); 199 } 200 tailbytes = ntohl(((uint32_t *) um->data)[0]); slide_hash(s)201 /* next ntohl() is only there for a principle. it is not useful */ 202 if (ntohl(((uint32_t *) um->data)[1]) == 0) { 203 /* normal happy song end. go to next subsong if any */ 204 subsong_end = 1; 205 } else { 206 /* unhappy song end (error in the 68k side). skip to next song 207 ignoring possible subsongs */ 208 uade_song_end_trigger = 1; 209 } 210 i = 0; 211 reason = (char *) &um->data[8]; 212 while (reason[i] && i < (um->size - 8)) 213 i++; 214 if (reason[i] != 0 || (i != (um->size - 9))) { 215 fprintf(stderr, "\nbroken reason string with song end notice\n"); 216 exit(-1); 217 } 218 fprintf(stderr, "\nSong end (%s)\n", reason); 219 break; 220 221 case UADE_REPLY_SUBSONG_INFO: 222 if (um->size != 12) { 223 fprintf(stderr, "\nsubsong info: too short a message\n"); 224 exit(-1); 225 } 226 227 u32ptr = (uint32_t *) um->data; deflateInit_(strm,level,version,stream_size)228 us->min_subsong = ntohl(u32ptr[0]); 229 us->max_subsong = ntohl(u32ptr[1]); 230 us->cur_subsong = ntohl(u32ptr[2]); 231 232 debug(uc->verbose, "\nsubsong: %d from range [%d, %d]\n", us->cur_subsong, us->min_subsong, us->max_subsong); 233 234 if (!(-1 <= us->min_subsong && us->min_subsong <= us->cur_subsong && us->cur_subsong <= us->max_subsong)) { 235 int tempmin = us->min_subsong, tempmax = us->max_subsong; 236 fprintf(stderr, "\nThe player is broken. Subsong info does not match.\n"); 237 us->min_subsong = tempmin <= tempmax ? tempmin : tempmax; 238 us->max_subsong = tempmax >= tempmin ? tempmax : tempmin; 239 if (us->cur_subsong > us->max_subsong) deflateInit2_(strm,level,method,windowBits,memLevel,strategy,version,stream_size)240 us->max_subsong = us->cur_subsong; 241 else if (us->cur_subsong < us->min_subsong) 242 us->min_subsong = us->cur_subsong; 243 } 244 245 if ((us->max_subsong - us->min_subsong) != 0) 246 fprintf(stderr, "\nThere are %d subsongs in range [%d, %d].\n", 1 + us->max_subsong - us->min_subsong, us->min_subsong, us->max_subsong); 247 break; 248 249 default: 250 fprintf(stderr, "\nExpected sound data. got %u.\n", (unsigned int) um->msgtype); 251 return 0; 252 } 253 } 254 } 255 256 do { 257 ret = uade_receive_message(um, sizeof(space), ipc); 258 if (ret < 0) { 259 fprintf(stderr, "\nCan not receive events (TOKEN) from uade.\n"); 260 return 0; 261 } 262 if (ret == 0) { 263 fprintf(stderr, "\nEnd of input after reboot.\n"); 264 return 0; 265 } 266 } while (um->msgtype != UADE_COMMAND_TOKEN); 267 268 tprintf("\n"); 269 return 0; 270 } 271