3 #if AUDIO_BACKEND == AUDIO_BACKEND_AO
4 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_SDL"
5 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_NONE"
6 #include "../c-flod/backends/aowriter.h"
7 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_NONE"
8 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_SDL"
9 #define BACKEND_STRUCT AoWriter
10 #define BACKEND_INIT AoWriter_init
11 #define BACKEND_CLOSE AoWriter_close
12 #define BACKEND_WRITE AoWriter_write
13 #elif AUDIO_BACKEND == AUDIO_BACKEND_SDL
14 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_AO"
15 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_NONE"
16 #include "../c-flod/backends/sdlwriter.h"
17 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_NONE"
18 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_AO"
19 #define BACKEND_STRUCT SdlWriter
20 #define BACKEND_INIT SdlWriter_init
21 #define BACKEND_CLOSE SdlWriter_close
22 #define BACKEND_WRITE SdlWriter_write
26 #if AUDIO_BACKEND == AUDIO_BACKEND_NONE
27 void audio_init(void) {}
28 int audio_open_music_resource(const unsigned char* data
, size_t data_size
, int track
) { return 0; }
29 int audio_open_music(const char* filename
, int track
) { return 0; }
30 void audio_play_wave_resource(const WAVE_HEADER_COMPLETE
* wave
) {}
31 int audio_process(void) { return -1; }
33 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_NONE"
34 #include "../c-flod/backends/wave_format.h"
35 #include "../c-flod/neoart/flod/core/CorePlayer.h"
36 #include "../c-flod/neoart/flod/whittaker/DWPlayer.h"
37 #include "../c-flod/flashlib/ByteArray.h"
38 #include "../c-flod/neoart/flod/core/Amiga.h"
39 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_NONE"
43 #include "../lib/include/timelib.h"
44 //RcB: LINK "-lpthread"
55 struct CorePlayer core
;
59 struct CoreMixer core
;
63 struct Backend backend
;
64 struct BACKEND_STRUCT ao
;
66 struct ByteArray music_stream
;
67 struct ByteArray wave_streams
[2];
68 WAVE_HEADER_COMPLETE wavhdr
;
69 struct ByteArray out_wave
;
70 char wave_buffer
[COREMIXER_MAX_BUFFER
* 2 * sizeof(float)];
73 pthread_mutex_t music_mutex
;
74 pthread_mutex_t sound_mutex
;
75 enum thread_status thread_music_status
;
78 int empty_track_active
;
81 static struct AudioPlayer playa
;
83 #define mlock() pthread_mutex_lock(&playa.music_mutex)
84 #define munlock() pthread_mutex_unlock(&playa.music_mutex)
85 #define slock() pthread_mutex_lock(&playa.sound_mutex)
86 #define sunlock() pthread_mutex_unlock(&playa.sound_mutex)
88 static int handle_overflow(int *sample
) {
92 } else if (*sample
< -32768) {
99 #define MUSIC_FINISHED() (!playa.empty_track_active && CoreMixer_get_complete(&playa.hardware.core))
100 #define GEN_MUSIC() do{ \
101 if(!playa.empty_track_active) playa.hardware.core.accurate(&playa.hardware.core); \
102 else { assert(sizeof(playa.wave_buffer) >= 1024*3); \
103 memset(playa.wave_buffer, 0, 1024*3); playa.out_wave.pos = 1024*3;} \
105 #define MUSIC_AVAIL() (playa.out_wave.pos)
106 #define GET_MUSIC_WORD() (playa.empty_track_active ? 0 : ByteArray_readShort(out))
107 #define MUSIC_REWIND_WORD() do { if(!playa.empty_track_active) ByteArray_set_position_rel(out, -2); } while (0)
109 static void *thread_func(void* data
) {
113 if(playa
.thread_music_status
== TS_STOPPING
) {
114 playa
.thread_music_status
= TS_WAITING
;
118 } else if(playa
.thread_music_status
== TS_DONE
|| playa
.thread_music_status
== TS_WAITING
) {
124 if(MUSIC_FINISHED()) {
126 playa
.thread_music_status
= TS_DONE
;
132 //dprintf(2, "writing %zu bytes...\n", (size_t) playa.out_wave.pos);
134 if(playa
.play_waveslot
!= -1) {
135 struct ByteArray
* mine
= &playa
.wave_streams
[playa
.play_waveslot
];
136 if(!mine
->bytesAvailable(mine
)) {
137 playa
.play_waveslot
= -1;
140 struct ByteArray
* out
= &playa
.out_wave
;
141 off_t savepos
= out
->pos
;
142 size_t avail
= mine
->bytesAvailable(mine
);
143 size_t upsample_factor
= 44100 / playa
.wavhdr
.wave_hdr
.samplerate
;
144 size_t processed_m
= 0, processed_w
= 0;
145 size_t readbytes
= playa
.wavhdr
.wave_hdr
.bitwidth
== 8 ? 1 : 2;
146 int chan
[2] = { 0, 0 };
148 ByteArray_set_position(out
, 0);
149 while(processed_m
< (size_t)savepos
&& processed_w
< avail
) {
151 for(c
= 0; c
< 2; c
++) {
152 if(c
< playa
.wavhdr
.wave_hdr
.channels
) {
153 if(readbytes
== 1) next
[c
] = ((uint8_t) ByteArray_readByte(mine
) - 128) * 256;
154 else next
[c
] = ByteArray_readShort(mine
);
155 handle_overflow(&next
[c
]);
157 next
[c
] = next
[c
- 1];
158 processed_w
+= readbytes
;
160 for(u
= 0; u
< upsample_factor
; u
++) {
161 for(c
= 0; c
< 2; c
++) {
162 int interpolated
= u
== 0 ? chan
[c
] :
163 chan
[c
] + ((next
[c
]-chan
[c
]) * ((float)u
/(float)upsample_factor
));
164 interpolated
= (float) interpolated
* 0.3; // decrease volume to avoid overflow
165 int music
= GET_MUSIC_WORD();
166 int sample
= music
+ interpolated
;
167 if(handle_overflow(&sample
)) dprintf(2, "overflow\n");
169 ByteArray_writeShort(out
, sample
);
173 for (c
=0; c
<2; c
++) chan
[c
] = next
[c
];
175 ByteArray_set_position(out
, savepos
);
179 BACKEND_WRITE(&playa
.writer
.ao
, playa
.wave_buffer
, playa
.out_wave
.pos
);
180 //dprintf(2, "done\n");
181 playa
.out_wave
.pos
= 0;
187 void audio_init(void) {
188 Amiga_ctor(&playa
.hardware
.amiga
);
189 DWPlayer_ctor(&playa
.player
.dw
, &playa
.hardware
.amiga
);
190 BACKEND_INIT(&playa
.writer
.ao
, 0);
191 ByteArray_ctor(&playa
.music_stream
);
192 ByteArray_ctor(&playa
.wave_streams
[0]);
193 ByteArray_ctor(&playa
.wave_streams
[1]);
194 ByteArray_ctor(&playa
.out_wave
);
195 playa
.out_wave
.endian
= BAE_LITTLE
;
196 ByteArray_open_mem(&playa
.out_wave
, playa
.wave_buffer
, sizeof(playa
.wave_buffer
));
197 playa
.hardware
.core
.wave
= &playa
.out_wave
;
199 playa
.thread_music_status
= TS_WAITING
;
200 errno
= pthread_mutex_init(&playa
.music_mutex
, 0);
201 if(errno
) perror("1");
202 errno
= pthread_mutex_init(&playa
.sound_mutex
, 0);
203 if(errno
) perror("1.5");
204 errno
= pthread_attr_init(&playa
.attr
);
205 if(errno
) perror("2");
206 errno
= pthread_attr_setstacksize(&playa
.attr
, 128*1024);
207 if(errno
) perror("3");
208 errno
= pthread_create(&playa
.thread
, &playa
.attr
, thread_func
, 0);
209 if(errno
) perror("4");
210 playa
.free_waveslot
= 0;
211 playa
.play_waveslot
= -1;
214 int audio_open_music_resource(const unsigned char* data
, size_t data_size
, int track
) {
216 if(playa
.thread_music_status
!= TS_WAITING
) {
217 playa
.thread_music_status
= TS_STOPPING
;
222 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
228 playa
.empty_track_active
= 0;
230 if(track
== -1) { /* "empty" track */
231 playa
.empty_track_active
= 1;
232 memset(playa
.wave_buffer
, 0, sizeof(playa
.wave_buffer
));
235 ByteArray_open_mem(&playa
.music_stream
, (void*) data
, data_size
);
236 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
237 assert(playa
.player
.core
.version
);
238 if(track
> playa
.player
.core
.lastSong
) return -1;
239 playa
.player
.core
.playSong
= track
;
240 playa
.player
.core
.initialize(&playa
.player
.core
);
245 //FIXME: does not close file handle
246 int audio_open_music(const char* filename
, int track
) {
248 if(playa
.thread_music_status
!= TS_WAITING
) {
249 playa
.thread_music_status
= TS_STOPPING
;
254 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
261 ByteArray_open_file(&playa
.music_stream
, filename
);
262 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
263 assert(playa
.player
.core
.version
);
264 playa
.player
.core
.initialize(&playa
.player
.core
);
265 if(track
> playa
.player
.core
.lastSong
) return -1;
266 playa
.player
.core
.playSong
= track
;
272 void audio_play_wave_resource(const WAVE_HEADER_COMPLETE
* wave
) {
275 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
276 playa
.free_waveslot
= 0;
278 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
279 if(!ByteArray_open_mem(mine
, waveheader_get_data(wave
), waveheader_get_datasize(wave
))) {
282 ByteArray_set_endian(mine
, BAE_LITTLE
);
283 playa
.wavhdr
= *wave
;
285 playa
.play_waveslot
= playa
.free_waveslot
;
286 playa
.free_waveslot
++;
291 static void close_all_but_playing_slot() {
293 for(i
= 0; i
< ARRAY_SIZE(playa
.wave_streams
); i
++) {
294 /*if(i != playa.play_waveslot) */
295 ByteArray_close_file(&playa
.wave_streams
[i
]);
298 void audio_play_wav(const char* filename
) {
300 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
301 playa
.free_waveslot
= 0;
302 close_all_but_playing_slot();
304 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
305 if(!ByteArray_open_file(mine
, filename
)) {
309 ByteArray_set_endian(mine
, BAE_LITTLE
);
310 /* assuming 16bit, 44khz stereo wav for the beginning. */
311 ByteArray_readMultiByte(mine
, (void*) &playa
.wavhdr
, sizeof(WAVE_HEADER_COMPLETE
));
312 //ByteArray_set_position(mine, sizeof(WAVE_HEADER_COMPLETE));
314 playa
.play_waveslot
= playa
.free_waveslot
;
315 playa
.free_waveslot
++;
320 // return -1: when track is finished, 0 if something was played, 1 if nothing was played.
321 int audio_process(void) {
323 if(playa
.thread_music_status
== TS_DONE
) {
326 } else if (playa
.thread_music_status
== TS_WAITING
) {
327 playa
.thread_music_status
= TS_PLAYING
;
333 #endif /* AUDIO_BACKEND != AUDIO_BACKEND_NONE */