2 #define AUDIO_BACKEND_AO 1
3 #define AUDIO_BACKEND_SDL 2
5 #define AUDIO_BACKEND AUDIO_BACKEND_AO
8 #if AUDIO_BACKEND == AUDIO_BACKEND_AO
9 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_SDL"
10 #include "../c-flod/backends/aowriter.h"
11 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_SDL"
12 #define BACKEND_STRUCT AoWriter
13 #define BACKEND_INIT AoWriter_init
14 #define BACKEND_CLOSE AoWriter_close
15 #define BACKEND_WRITE AoWriter_write
17 //RcB: SKIPON "AUDIO_BACKEND=AUDIO_BACKEND_AO"
18 #include "../c-flod/backends/sdlwriter.h"
19 //RcB: SKIPOFF "AUDIO_BACKEND=AUDIO_BACKEND_AO"
20 #define BACKEND_STRUCT SdlWriter
21 #define BACKEND_INIT SdlWriter_init
22 #define BACKEND_CLOSE SdlWriter_close
23 #define BACKEND_WRITE SdlWriter_write
26 #include "../c-flod/backends/wave_format.h"
27 #include "../c-flod/neoart/flod/core/CorePlayer.h"
28 #include "../c-flod/neoart/flod/whittaker/DWPlayer.h"
29 #include "../c-flod/flashlib/ByteArray.h"
30 #include "../c-flod/neoart/flod/core/Amiga.h"
34 #include "../lib/include/timelib.h"
35 //RcB: LINK "-lpthread"
46 struct CorePlayer core
;
50 struct CoreMixer core
;
54 struct Backend backend
;
55 struct BACKEND_STRUCT ao
;
57 struct ByteArray music_stream
;
58 struct ByteArray wave_streams
[2];
59 WAVE_HEADER_COMPLETE wavhdr
;
60 struct ByteArray out_wave
;
61 char wave_buffer
[COREMIXER_MAX_BUFFER
* 2 * sizeof(float)];
64 pthread_mutex_t music_mutex
;
65 pthread_mutex_t sound_mutex
;
66 enum thread_status thread_music_status
;
69 int empty_track_active
;
72 static struct AudioPlayer playa
;
74 #define mlock() pthread_mutex_lock(&playa.music_mutex)
75 #define munlock() pthread_mutex_unlock(&playa.music_mutex)
76 #define slock() pthread_mutex_lock(&playa.sound_mutex)
77 #define sunlock() pthread_mutex_unlock(&playa.sound_mutex)
79 static int handle_overflow(int *sample
) {
83 } else if (*sample
< -32768) {
90 #define MUSIC_FINISHED() (!playa.empty_track_active && CoreMixer_get_complete(&playa.hardware.core))
91 #define GEN_MUSIC() do{ \
92 if(!playa.empty_track_active) playa.hardware.core.accurate(&playa.hardware.core); \
93 else { assert(sizeof(playa.wave_buffer) >= 1024*3); \
94 memset(playa.wave_buffer, 0, 1024*3); playa.out_wave.pos = 1024*3;} \
96 #define MUSIC_AVAIL() (playa.out_wave.pos)
97 #define GET_MUSIC_WORD() (playa.empty_track_active ? 0 : ByteArray_readShort(out))
98 #define MUSIC_REWIND_WORD() do { if(!playa.empty_track_active) ByteArray_set_position_rel(out, -2); } while (0)
100 static void *thread_func(void* data
) {
104 if(playa
.thread_music_status
== TS_STOPPING
) {
105 playa
.thread_music_status
= TS_WAITING
;
109 } else if(playa
.thread_music_status
== TS_DONE
|| playa
.thread_music_status
== TS_WAITING
) {
115 if(MUSIC_FINISHED()) {
117 playa
.thread_music_status
= TS_DONE
;
123 //dprintf(2, "writing %zu bytes...\n", (size_t) playa.out_wave.pos);
125 if(playa
.play_waveslot
!= -1) {
126 struct ByteArray
* mine
= &playa
.wave_streams
[playa
.play_waveslot
];
127 if(!mine
->bytesAvailable(mine
)) {
128 playa
.play_waveslot
= -1;
131 struct ByteArray
* out
= &playa
.out_wave
;
132 off_t savepos
= out
->pos
;
133 size_t avail
= mine
->bytesAvailable(mine
);
134 size_t upsample_factor
= 44100 / playa
.wavhdr
.wave_hdr
.samplerate
;
135 size_t processed_m
= 0, processed_w
= 0;
136 size_t readbytes
= playa
.wavhdr
.wave_hdr
.bitwidth
== 8 ? 1 : 2;
137 int chan
[2] = { 0, 0 };
139 ByteArray_set_position(out
, 0);
140 while(processed_m
< (size_t)savepos
&& processed_w
< avail
) {
142 for(c
= 0; c
< 2; c
++) {
143 if(c
< playa
.wavhdr
.wave_hdr
.channels
) {
144 if(readbytes
== 1) next
[c
] = ((uint8_t) ByteArray_readByte(mine
) - 128) * 256;
145 else next
[c
] = ByteArray_readShort(mine
);
146 handle_overflow(&next
[c
]);
148 next
[c
] = next
[c
- 1];
149 processed_w
+= readbytes
;
151 for(u
= 0; u
< upsample_factor
; u
++) {
152 for(c
= 0; c
< 2; c
++) {
153 int interpolated
= u
== 0 ? chan
[c
] :
154 chan
[c
] + ((next
[c
]-chan
[c
]) * ((float)u
/(float)upsample_factor
));
155 interpolated
= (float) interpolated
* 0.3; // decrease volume to avoid overflow
156 int music
= GET_MUSIC_WORD();
157 int sample
= music
+ interpolated
;
158 if(handle_overflow(&sample
)) dprintf(2, "overflow\n");
160 ByteArray_writeShort(out
, sample
);
164 for (c
=0; c
<2; c
++) chan
[c
] = next
[c
];
166 ByteArray_set_position(out
, savepos
);
170 BACKEND_WRITE(&playa
.writer
.ao
, playa
.wave_buffer
, playa
.out_wave
.pos
);
171 //dprintf(2, "done\n");
172 playa
.out_wave
.pos
= 0;
178 void audio_init(void) {
179 Amiga_ctor(&playa
.hardware
.amiga
);
180 DWPlayer_ctor(&playa
.player
.dw
, &playa
.hardware
.amiga
);
181 BACKEND_INIT(&playa
.writer
.ao
, 0);
182 ByteArray_ctor(&playa
.music_stream
);
183 ByteArray_ctor(&playa
.wave_streams
[0]);
184 ByteArray_ctor(&playa
.wave_streams
[1]);
185 ByteArray_ctor(&playa
.out_wave
);
186 playa
.out_wave
.endian
= BAE_LITTLE
;
187 ByteArray_open_mem(&playa
.out_wave
, playa
.wave_buffer
, sizeof(playa
.wave_buffer
));
188 playa
.hardware
.core
.wave
= &playa
.out_wave
;
190 playa
.thread_music_status
= TS_WAITING
;
191 errno
= pthread_mutex_init(&playa
.music_mutex
, 0);
192 if(errno
) perror("1");
193 errno
= pthread_mutex_init(&playa
.sound_mutex
, 0);
194 if(errno
) perror("1.5");
195 errno
= pthread_attr_init(&playa
.attr
);
196 if(errno
) perror("2");
197 errno
= pthread_attr_setstacksize(&playa
.attr
, 128*1024);
198 if(errno
) perror("3");
199 errno
= pthread_create(&playa
.thread
, &playa
.attr
, thread_func
, 0);
200 if(errno
) perror("4");
201 playa
.free_waveslot
= 0;
202 playa
.play_waveslot
= -1;
205 int audio_open_music_resource(const unsigned char* data
, size_t data_size
, int track
) {
207 if(playa
.thread_music_status
!= TS_WAITING
) {
208 playa
.thread_music_status
= TS_STOPPING
;
213 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
219 playa
.empty_track_active
= 0;
221 if(track
== -1) { /* "empty" track */
222 playa
.empty_track_active
= 1;
223 memset(playa
.wave_buffer
, 0, sizeof(playa
.wave_buffer
));
226 ByteArray_open_mem(&playa
.music_stream
, (void*) data
, data_size
);
227 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
228 assert(playa
.player
.core
.version
);
229 if(track
> playa
.player
.core
.lastSong
) return -1;
230 playa
.player
.core
.playSong
= track
;
231 playa
.player
.core
.initialize(&playa
.player
.core
);
236 //FIXME: does not close file handle
237 int audio_open_music(const char* filename
, int track
) {
239 if(playa
.thread_music_status
!= TS_WAITING
) {
240 playa
.thread_music_status
= TS_STOPPING
;
245 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
252 ByteArray_open_file(&playa
.music_stream
, filename
);
253 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
254 assert(playa
.player
.core
.version
);
255 playa
.player
.core
.initialize(&playa
.player
.core
);
256 if(track
> playa
.player
.core
.lastSong
) return -1;
257 playa
.player
.core
.playSong
= track
;
263 void audio_play_wave_resource(const WAVE_HEADER_COMPLETE
* wave
) {
266 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
267 playa
.free_waveslot
= 0;
269 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
270 if(!ByteArray_open_mem(mine
, waveheader_get_data(wave
), waveheader_get_datasize(wave
))) {
273 ByteArray_set_endian(mine
, BAE_LITTLE
);
274 playa
.wavhdr
= *wave
;
276 playa
.play_waveslot
= playa
.free_waveslot
;
277 playa
.free_waveslot
++;
282 static void close_all_but_playing_slot() {
284 for(i
= 0; i
< ARRAY_SIZE(playa
.wave_streams
); i
++) {
285 /*if(i != playa.play_waveslot) */
286 ByteArray_close_file(&playa
.wave_streams
[i
]);
289 void audio_play_wav(const char* filename
) {
291 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
292 playa
.free_waveslot
= 0;
293 close_all_but_playing_slot();
295 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
296 if(!ByteArray_open_file(mine
, filename
)) {
300 ByteArray_set_endian(mine
, BAE_LITTLE
);
301 /* assuming 16bit, 44khz stereo wav for the beginning. */
302 ByteArray_readMultiByte(mine
, (void*) &playa
.wavhdr
, sizeof(WAVE_HEADER_COMPLETE
));
303 //ByteArray_set_position(mine, sizeof(WAVE_HEADER_COMPLETE));
305 playa
.play_waveslot
= playa
.free_waveslot
;
306 playa
.free_waveslot
++;
311 // return -1: when track is finished, 0 if something was played, 1 if nothing was played.
312 int audio_process(void) {
314 if(playa
.thread_music_status
== TS_DONE
) {
317 } else if (playa
.thread_music_status
== TS_WAITING
) {
318 playa
.thread_music_status
= TS_PLAYING
;