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