3 #if AUDIO_BACKEND == AUDIO_BACKEND_AO
4 #include "../c-flod/backends/aowriter.h"
5 #define BACKEND_STRUCT AoWriter
6 #define BACKEND_INIT AoWriter_init
7 #define BACKEND_CLOSE AoWriter_close
8 #define BACKEND_WRITE AoWriter_write
9 #elif AUDIO_BACKEND == AUDIO_BACKEND_SDL
10 #include "../c-flod/backends/sdlwriter.h"
11 #define BACKEND_STRUCT SdlWriter
12 #define BACKEND_INIT SdlWriter_init
13 #define BACKEND_CLOSE SdlWriter_close
14 #define BACKEND_WRITE SdlWriter_write
18 #if AUDIO_BACKEND == AUDIO_BACKEND_NONE
19 void audio_init(void) {}
20 int audio_open_music_resource(const unsigned char* data
, size_t data_size
, int track
) { return 0; }
21 int audio_open_music(const char* filename
, int track
) { return 0; }
22 void audio_play_wave_resource(const WAVE_HEADER_COMPLETE
* wave
) {}
23 int audio_process(void) { return -1; }
25 #include "../c-flod/backends/wave_format.h"
26 #include "../c-flod/neoart/flod/core/CorePlayer.h"
27 #include "../c-flod/neoart/flod/whittaker/DWPlayer.h"
28 #include "../c-flod/flashlib/ByteArray.h"
29 #include "../c-flod/neoart/flod/core/Amiga.h"
33 #include "../lib/include/timelib.h"
34 #pragma RcB2 LINK "-lpthread"
45 struct CorePlayer core
;
49 struct CoreMixer core
;
53 struct Backend backend
;
54 struct BACKEND_STRUCT ao
;
56 struct ByteArray music_stream
;
57 struct ByteArray wave_streams
[2];
58 WAVE_HEADER_COMPLETE wavhdr
;
59 struct ByteArray out_wave
;
60 char wave_buffer
[COREMIXER_MAX_BUFFER
* 2 * sizeof(float)];
63 pthread_mutex_t music_mutex
;
64 pthread_mutex_t sound_mutex
;
65 enum thread_status thread_music_status
;
68 int empty_track_active
;
71 static struct AudioPlayer playa
;
73 #define mlock() pthread_mutex_lock(&playa.music_mutex)
74 #define munlock() pthread_mutex_unlock(&playa.music_mutex)
75 #define slock() pthread_mutex_lock(&playa.sound_mutex)
76 #define sunlock() pthread_mutex_unlock(&playa.sound_mutex)
78 static int handle_overflow(int *sample
) {
82 } else if (*sample
< -32768) {
89 #define MUSIC_FINISHED() (!playa.empty_track_active && CoreMixer_get_complete(&playa.hardware.core))
90 #define GEN_MUSIC() do{ \
91 if(!playa.empty_track_active) playa.hardware.core.accurate(&playa.hardware.core); \
92 else { assert(sizeof(playa.wave_buffer) >= 1024*3); \
93 memset(playa.wave_buffer, 0, 1024*3); playa.out_wave.pos = 1024*3;} \
95 #define MUSIC_AVAIL() (playa.out_wave.pos)
96 #define GET_MUSIC_WORD() (playa.empty_track_active ? 0 : ByteArray_readShort(out))
97 #define MUSIC_REWIND_WORD() do { if(!playa.empty_track_active) ByteArray_set_position_rel(out, -2); } while (0)
99 static void *thread_func(void* data
) {
103 if(playa
.thread_music_status
== TS_STOPPING
) {
104 playa
.thread_music_status
= TS_WAITING
;
108 } else if(playa
.thread_music_status
== TS_DONE
|| playa
.thread_music_status
== TS_WAITING
) {
114 if(MUSIC_FINISHED()) {
116 playa
.thread_music_status
= TS_DONE
;
122 //dprintf(2, "writing %zu bytes...\n", (size_t) playa.out_wave.pos);
124 if(playa
.play_waveslot
!= -1) {
125 struct ByteArray
* mine
= &playa
.wave_streams
[playa
.play_waveslot
];
126 if(!mine
->bytesAvailable(mine
)) {
127 playa
.play_waveslot
= -1;
130 struct ByteArray
* out
= &playa
.out_wave
;
131 off_t savepos
= out
->pos
;
132 size_t avail
= mine
->bytesAvailable(mine
);
133 size_t upsample_factor
= 44100 / playa
.wavhdr
.wave_hdr
.samplerate
;
134 size_t processed_m
= 0, processed_w
= 0;
135 size_t readbytes
= playa
.wavhdr
.wave_hdr
.bitwidth
== 8 ? 1 : 2;
136 int chan
[2] = { 0, 0 };
138 ByteArray_set_position(out
, 0);
139 while(processed_m
< (size_t)savepos
&& processed_w
< avail
) {
141 for(c
= 0; c
< 2; c
++) {
142 if(c
< playa
.wavhdr
.wave_hdr
.channels
) {
143 if(readbytes
== 1) next
[c
] = ((uint8_t) ByteArray_readByte(mine
) - 128) * 256;
144 else next
[c
] = ByteArray_readShort(mine
);
145 handle_overflow(&next
[c
]);
147 next
[c
] = next
[c
- 1];
148 processed_w
+= readbytes
;
150 for(u
= 0; u
< upsample_factor
; u
++) {
151 for(c
= 0; c
< 2; c
++) {
152 int interpolated
= u
== 0 ? chan
[c
] :
153 chan
[c
] + ((next
[c
]-chan
[c
]) * ((float)u
/(float)upsample_factor
));
154 interpolated
= (float) interpolated
* 0.3; // decrease volume to avoid overflow
155 int music
= GET_MUSIC_WORD();
156 int sample
= music
+ interpolated
;
157 if(handle_overflow(&sample
)) dprintf(2, "overflow\n");
159 ByteArray_writeShort(out
, sample
);
163 for (c
=0; c
<2; c
++) chan
[c
] = next
[c
];
165 ByteArray_set_position(out
, savepos
);
169 BACKEND_WRITE(&playa
.writer
.ao
, playa
.wave_buffer
, playa
.out_wave
.pos
);
170 //dprintf(2, "done\n");
171 playa
.out_wave
.pos
= 0;
177 void audio_init(void) {
178 Amiga_ctor(&playa
.hardware
.amiga
);
179 DWPlayer_ctor(&playa
.player
.dw
, &playa
.hardware
.amiga
);
180 BACKEND_INIT(&playa
.writer
.ao
, 0);
181 ByteArray_ctor(&playa
.music_stream
);
182 ByteArray_ctor(&playa
.wave_streams
[0]);
183 ByteArray_ctor(&playa
.wave_streams
[1]);
184 ByteArray_ctor(&playa
.out_wave
);
185 playa
.out_wave
.endian
= BAE_LITTLE
;
186 ByteArray_open_mem(&playa
.out_wave
, playa
.wave_buffer
, sizeof(playa
.wave_buffer
));
187 playa
.hardware
.core
.wave
= &playa
.out_wave
;
189 playa
.thread_music_status
= TS_WAITING
;
190 errno
= pthread_mutex_init(&playa
.music_mutex
, 0);
191 if(errno
) perror("1");
192 errno
= pthread_mutex_init(&playa
.sound_mutex
, 0);
193 if(errno
) perror("1.5");
194 errno
= pthread_attr_init(&playa
.attr
);
195 if(errno
) perror("2");
196 errno
= pthread_attr_setstacksize(&playa
.attr
, 128*1024);
197 if(errno
) perror("3");
198 errno
= pthread_create(&playa
.thread
, &playa
.attr
, thread_func
, 0);
199 if(errno
) perror("4");
200 playa
.free_waveslot
= 0;
201 playa
.play_waveslot
= -1;
204 int audio_open_music_resource(const unsigned char* data
, size_t data_size
, int track
) {
206 if(playa
.thread_music_status
!= TS_WAITING
) {
207 playa
.thread_music_status
= TS_STOPPING
;
212 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
218 playa
.empty_track_active
= 0;
220 if(track
== -1) { /* "empty" track */
221 playa
.empty_track_active
= 1;
222 memset(playa
.wave_buffer
, 0, sizeof(playa
.wave_buffer
));
225 ByteArray_open_mem(&playa
.music_stream
, (void*) data
, data_size
);
226 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
227 assert(playa
.player
.core
.version
);
228 if(track
> playa
.player
.core
.lastSong
) return -1;
229 playa
.player
.core
.playSong
= track
;
230 playa
.player
.core
.initialize(&playa
.player
.core
);
235 //FIXME: does not close file handle
236 int audio_open_music(const char* filename
, int track
) {
238 if(playa
.thread_music_status
!= TS_WAITING
) {
239 playa
.thread_music_status
= TS_STOPPING
;
244 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
251 ByteArray_open_file(&playa
.music_stream
, filename
);
252 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
253 assert(playa
.player
.core
.version
);
254 playa
.player
.core
.initialize(&playa
.player
.core
);
255 if(track
> playa
.player
.core
.lastSong
) return -1;
256 playa
.player
.core
.playSong
= track
;
262 void audio_play_wave_resource(const WAVE_HEADER_COMPLETE
* wave
) {
265 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
266 playa
.free_waveslot
= 0;
268 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
269 if(!ByteArray_open_mem(mine
, waveheader_get_data(wave
), waveheader_get_datasize(wave
))) {
272 ByteArray_set_endian(mine
, BAE_LITTLE
);
273 playa
.wavhdr
= *wave
;
275 playa
.play_waveslot
= playa
.free_waveslot
;
276 playa
.free_waveslot
++;
281 static void close_all_but_playing_slot() {
283 for(i
= 0; i
< ARRAY_SIZE(playa
.wave_streams
); i
++) {
284 /*if(i != playa.play_waveslot) */
285 ByteArray_close_file(&playa
.wave_streams
[i
]);
288 void audio_play_wav(const char* filename
) {
290 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
291 playa
.free_waveslot
= 0;
292 close_all_but_playing_slot();
294 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
295 if(!ByteArray_open_file(mine
, filename
)) {
299 ByteArray_set_endian(mine
, BAE_LITTLE
);
300 /* assuming 16bit, 44khz stereo wav for the beginning. */
301 ByteArray_readMultiByte(mine
, (void*) &playa
.wavhdr
, sizeof(WAVE_HEADER_COMPLETE
));
302 //ByteArray_set_position(mine, sizeof(WAVE_HEADER_COMPLETE));
304 playa
.play_waveslot
= playa
.free_waveslot
;
305 playa
.free_waveslot
++;
310 // return -1: when track is finished, 0 if something was played, 1 if nothing was played.
311 int audio_process(void) {
313 if(playa
.thread_music_status
== TS_DONE
) {
316 } else if (playa
.thread_music_status
== TS_WAITING
) {
317 playa
.thread_music_status
= TS_PLAYING
;
323 #endif /* AUDIO_BACKEND != AUDIO_BACKEND_NONE */