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
;
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 static void *thread_func(void* data
) {
93 if(playa
.thread_music_status
== TS_STOPPING
) {
94 playa
.thread_music_status
= TS_WAITING
;
98 } else if(playa
.thread_music_status
== TS_DONE
|| playa
.thread_music_status
== TS_WAITING
) {
104 if(CoreMixer_get_complete(&playa
.hardware
.core
)) {
106 playa
.thread_music_status
= TS_DONE
;
110 playa
.hardware
.core
.accurate(&playa
.hardware
.core
);
111 if(playa
.out_wave
.pos
) {
112 //dprintf(2, "writing %zu bytes...\n", (size_t) playa.out_wave.pos);
114 if(playa
.play_waveslot
!= -1) {
115 struct ByteArray
* mine
= &playa
.wave_streams
[playa
.play_waveslot
];
116 if(!mine
->bytesAvailable(mine
)) {
117 playa
.play_waveslot
= -1;
120 struct ByteArray
* out
= &playa
.out_wave
;
121 off_t savepos
= out
->pos
;
122 size_t avail
= mine
->bytesAvailable(mine
);
123 size_t upsample_factor
= 44100 / playa
.wavhdr
.wave_hdr
.samplerate
;
124 size_t processed_m
= 0, processed_w
= 0;
125 size_t readbytes
= playa
.wavhdr
.wave_hdr
.bitwidth
== 8 ? 1 : 2;
126 int chan
[2] = { 0, 0 };
128 ByteArray_set_position(out
, 0);
129 while(processed_m
< (size_t)savepos
&& processed_w
< avail
) {
131 for(c
= 0; c
< 2; c
++) {
132 if(c
< playa
.wavhdr
.wave_hdr
.channels
) {
133 if(readbytes
== 1) next
[c
] = ((uint8_t) ByteArray_readByte(mine
) - 128) * 256;
134 else next
[c
] = ByteArray_readShort(mine
);
135 handle_overflow(&next
[c
]);
137 next
[c
] = next
[c
- 1];
138 processed_w
+= readbytes
;
140 for(u
= 0; u
< upsample_factor
; u
++) {
141 for(c
= 0; c
< 2; c
++) {
142 int interpolated
= u
== 0 ? chan
[c
] :
143 chan
[c
] + ((next
[c
]-chan
[c
]) * ((float)u
/(float)upsample_factor
));
144 interpolated
= (float) interpolated
* 0.3; // decrease volume to avoid overflow
145 int music
= ByteArray_readShort(out
);
146 int sample
= music
+ interpolated
;
147 if(handle_overflow(&sample
)) dprintf(2, "overflow\n");
148 ByteArray_set_position_rel(out
, -2);
149 ByteArray_writeShort(out
, sample
);
153 for (c
=0; c
<2; c
++) chan
[c
] = next
[c
];
155 ByteArray_set_position(out
, savepos
);
159 BACKEND_WRITE(&playa
.writer
.ao
, playa
.wave_buffer
, playa
.out_wave
.pos
);
160 //dprintf(2, "done\n");
161 playa
.out_wave
.pos
= 0;
167 void audio_init(void) {
168 Amiga_ctor(&playa
.hardware
.amiga
);
169 DWPlayer_ctor(&playa
.player
.dw
, &playa
.hardware
.amiga
);
170 BACKEND_INIT(&playa
.writer
.ao
, 0);
171 ByteArray_ctor(&playa
.music_stream
);
172 ByteArray_ctor(&playa
.wave_streams
[0]);
173 ByteArray_ctor(&playa
.wave_streams
[1]);
174 ByteArray_ctor(&playa
.out_wave
);
175 playa
.out_wave
.endian
= BAE_LITTLE
;
176 ByteArray_open_mem(&playa
.out_wave
, playa
.wave_buffer
, sizeof(playa
.wave_buffer
));
177 playa
.hardware
.core
.wave
= &playa
.out_wave
;
179 playa
.thread_music_status
= TS_WAITING
;
180 errno
= pthread_mutex_init(&playa
.music_mutex
, 0);
181 if(errno
) perror("1");
182 errno
= pthread_mutex_init(&playa
.sound_mutex
, 0);
183 if(errno
) perror("1.5");
184 errno
= pthread_attr_init(&playa
.attr
);
185 if(errno
) perror("2");
186 errno
= pthread_attr_setstacksize(&playa
.attr
, 128*1024);
187 if(errno
) perror("3");
188 errno
= pthread_create(&playa
.thread
, &playa
.attr
, thread_func
, 0);
189 if(errno
) perror("4");
190 playa
.free_waveslot
= 0;
191 playa
.play_waveslot
= -1;
194 int audio_open_music_resource(const unsigned char* data
, size_t data_size
, int track
) {
196 if(playa
.thread_music_status
!= TS_WAITING
) {
197 playa
.thread_music_status
= TS_STOPPING
;
202 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
209 ByteArray_open_mem(&playa
.music_stream
, (void*) data
, data_size
);
210 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
211 assert(playa
.player
.core
.version
);
212 if(track
> playa
.player
.core
.lastSong
) return -1;
213 playa
.player
.core
.playSong
= track
;
214 playa
.player
.core
.initialize(&playa
.player
.core
);
219 //FIXME: does not close file handle
220 int audio_open_music(const char* filename
, int track
) {
222 if(playa
.thread_music_status
!= TS_WAITING
) {
223 playa
.thread_music_status
= TS_STOPPING
;
228 if(playa
.thread_music_status
== TS_WAITING
) done
= 1;
235 ByteArray_open_file(&playa
.music_stream
, filename
);
236 CorePlayer_load(&playa
.player
.core
, &playa
.music_stream
);
237 assert(playa
.player
.core
.version
);
238 playa
.player
.core
.initialize(&playa
.player
.core
);
239 if(track
> playa
.player
.core
.lastSong
) return -1;
240 playa
.player
.core
.playSong
= track
;
246 void audio_play_wave_resource(const WAVE_HEADER_COMPLETE
* wave
) {
249 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
250 playa
.free_waveslot
= 0;
252 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
253 if(!ByteArray_open_mem(mine
, waveheader_get_data(wave
), waveheader_get_datasize(wave
))) {
256 ByteArray_set_endian(mine
, BAE_LITTLE
);
257 playa
.wavhdr
= *wave
;
259 playa
.play_waveslot
= playa
.free_waveslot
;
260 playa
.free_waveslot
++;
265 static void close_all_but_playing_slot() {
267 for(i
= 0; i
< ARRAY_SIZE(playa
.wave_streams
); i
++) {
268 /*if(i != playa.play_waveslot) */
269 ByteArray_close_file(&playa
.wave_streams
[i
]);
272 void audio_play_wav(const char* filename
) {
274 if(playa
.free_waveslot
>= (int) ARRAY_SIZE(playa
.wave_streams
)) {
275 playa
.free_waveslot
= 0;
276 close_all_but_playing_slot();
278 struct ByteArray
*mine
= &playa
.wave_streams
[playa
.free_waveslot
];
279 if(!ByteArray_open_file(mine
, filename
)) {
283 ByteArray_set_endian(mine
, BAE_LITTLE
);
284 /* assuming 16bit, 44khz stereo wav for the beginning. */
285 ByteArray_readMultiByte(mine
, (void*) &playa
.wavhdr
, sizeof(WAVE_HEADER_COMPLETE
));
286 //ByteArray_set_position(mine, sizeof(WAVE_HEADER_COMPLETE));
288 playa
.play_waveslot
= playa
.free_waveslot
;
289 playa
.free_waveslot
++;
294 // return -1: when track is finished, 0 if something was played, 1 if nothing was played.
295 int audio_process(void) {
297 if(playa
.thread_music_status
== TS_DONE
) {
300 } else if (playa
.thread_music_status
== TS_WAITING
) {
301 playa
.thread_music_status
= TS_PLAYING
;