Mercurial > audlegacy-plugins
comparison src/alac/plugin.c @ 3146:87b0c47089e5
alac: Various patches from Hans de Goede. (Closes #61)
| author | William Pitcock <nenolod@atheme.org> |
|---|---|
| date | Sat, 09 May 2009 13:47:30 -0500 |
| parents | 3134a0987162 |
| children | d7eea4d29d4a |
comparison
equal
deleted
inserted
replaced
| 3145:76f5bcf547d5 | 3146:87b0c47089e5 |
|---|---|
| 54 | 54 |
| 55 static int input_opened = 0; | 55 static int input_opened = 0; |
| 56 | 56 |
| 57 gpointer decode_thread(void *args); | 57 gpointer decode_thread(void *args); |
| 58 static GThread *playback_thread; | 58 static GThread *playback_thread; |
| 59 static int going = 0; | |
| 60 static int seek_to = -1; | 59 static int seek_to = -1; |
| 61 | 60 |
| 62 extern void set_endian(); | 61 extern void set_endian(); |
| 63 | 62 |
| 64 static void alac_about(void) | 63 static void alac_about(void) |
| 99 } | 98 } |
| 100 | 99 |
| 101 stream_destroy(input_stream); | 100 stream_destroy(input_stream); |
| 102 | 101 |
| 103 return TRUE; | 102 return TRUE; |
| 103 } | |
| 104 | |
| 105 static int get_duration(demux_res_t *demux_res) | |
| 106 { | |
| 107 int i; | |
| 108 long long samples = 0; | |
| 109 | |
| 110 for (i = 0; i < demux_res->num_time_to_samples; i++) | |
| 111 samples += demux_res->time_to_sample[i].sample_count * | |
| 112 demux_res->time_to_sample[i].sample_duration; | |
| 113 | |
| 114 return (samples * 1000) / demux_res->sample_rate; | |
| 104 } | 115 } |
| 105 | 116 |
| 106 Tuple *build_aud_tuple_from_demux(demux_res_t *demux_res, char *path) | 117 Tuple *build_aud_tuple_from_demux(demux_res_t *demux_res, char *path) |
| 107 { | 118 { |
| 108 Tuple *ti = aud_tuple_new_from_filename(path); | 119 Tuple *ti = aud_tuple_new_from_filename(path); |
| 120 if (demux_res->tuple.day != NULL) | 131 if (demux_res->tuple.day != NULL) |
| 121 aud_tuple_associate_int(ti, FIELD_YEAR, NULL, atoi(demux_res->tuple.day)); | 132 aud_tuple_associate_int(ti, FIELD_YEAR, NULL, atoi(demux_res->tuple.day)); |
| 122 | 133 |
| 123 aud_tuple_associate_string(ti, FIELD_CODEC, NULL, "Apple Lossless (ALAC)"); | 134 aud_tuple_associate_string(ti, FIELD_CODEC, NULL, "Apple Lossless (ALAC)"); |
| 124 aud_tuple_associate_string(ti, FIELD_QUALITY, NULL, "lossless"); | 135 aud_tuple_associate_string(ti, FIELD_QUALITY, NULL, "lossless"); |
| 136 aud_tuple_associate_int(ti, FIELD_LENGTH, NULL, get_duration(demux_res)); | |
| 125 | 137 |
| 126 return ti; | 138 return ti; |
| 127 } | 139 } |
| 128 | 140 |
| 129 Tuple *build_tuple(char *filename) | 141 Tuple *build_tuple(char *filename) |
| 161 static InputPlayback *playback; | 173 static InputPlayback *playback; |
| 162 | 174 |
| 163 static void play_file(InputPlayback *data) | 175 static void play_file(InputPlayback *data) |
| 164 { | 176 { |
| 165 char *filename = data->filename; | 177 char *filename = data->filename; |
| 166 going = 1; | |
| 167 playback = data; | 178 playback = data; |
| 179 playback->playing = TRUE; | |
| 168 playback_thread = g_thread_self(); | 180 playback_thread = g_thread_self(); |
| 169 playback->set_pb_ready(playback); | 181 playback->set_pb_ready(playback); |
| 170 decode_thread(filename); | 182 decode_thread(filename); |
| 171 } | 183 } |
| 172 | 184 |
| 173 static void stop(InputPlayback * data) | 185 static void stop(InputPlayback * data) |
| 174 { | 186 { |
| 175 going = 0; | 187 playback->playing = FALSE; |
| 176 g_thread_join(playback_thread); | 188 g_thread_join(playback_thread); |
| 177 data->output->close_audio(); | 189 data->output->close_audio(); |
| 178 } | 190 } |
| 179 | 191 |
| 180 static void do_pause(InputPlayback *data, short paused) | 192 static void do_pause(InputPlayback *data, short paused) |
| 183 } | 195 } |
| 184 | 196 |
| 185 static void seek(InputPlayback * data, gint time) | 197 static void seek(InputPlayback * data, gint time) |
| 186 { | 198 { |
| 187 seek_to = time; | 199 seek_to = time; |
| 188 } | |
| 189 | |
| 190 static int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, | |
| 191 uint32_t *sample_duration, | |
| 192 uint32_t *sample_byte_size) | |
| 193 { | |
| 194 unsigned int duration_index_accum = 0; | |
| 195 unsigned int duration_cur_index = 0; | |
| 196 | |
| 197 if (samplenum >= demux_res->num_sample_byte_sizes) | |
| 198 return 0; | |
| 199 | |
| 200 if (!demux_res->num_time_to_samples) | |
| 201 return 0; | |
| 202 | |
| 203 while ((demux_res->time_to_sample[duration_cur_index].sample_count + duration_index_accum) | |
| 204 <= samplenum) | |
| 205 { | |
| 206 duration_index_accum += demux_res->time_to_sample[duration_cur_index].sample_count; | |
| 207 duration_cur_index++; | |
| 208 | |
| 209 if (duration_cur_index >= demux_res->num_time_to_samples) | |
| 210 return 0; | |
| 211 } | |
| 212 | |
| 213 *sample_duration = demux_res->time_to_sample[duration_cur_index].sample_duration; | |
| 214 *sample_byte_size = demux_res->sample_byte_size[samplenum]; | |
| 215 | |
| 216 return 1; | |
| 217 } | 200 } |
| 218 | 201 |
| 219 void GetBuffer(demux_res_t *demux_res) | 202 void GetBuffer(demux_res_t *demux_res) |
| 220 { | 203 { |
| 221 unsigned long destBufferSize = 1024*16; /* 16kb buffer = 4096 frames = 1 alac sample */ | 204 unsigned long destBufferSize = 1024*16; /* 16kb buffer = 4096 frames = 1 alac sample */ |
| 227 | 210 |
| 228 unsigned int i; | 211 unsigned int i; |
| 229 | 212 |
| 230 buffer = malloc(buffer_size); | 213 buffer = malloc(buffer_size); |
| 231 | 214 |
| 232 for (i = 0; i < demux_res->num_sample_byte_sizes && going == 1; i++) | 215 for (i = 0; i < demux_res->num_sample_byte_sizes && playback->playing; i++) |
| 233 { | 216 { |
| 234 uint32_t sample_duration; | |
| 235 uint32_t sample_byte_size; | 217 uint32_t sample_byte_size; |
| 236 | 218 |
| 237 int outputBytes; | 219 int outputBytes; |
| 238 | 220 |
| 239 #if 0 | 221 #if 0 |
| 251 seek_to = -1; | 233 seek_to = -1; |
| 252 } | 234 } |
| 253 #endif | 235 #endif |
| 254 | 236 |
| 255 /* just get one sample for now */ | 237 /* just get one sample for now */ |
| 256 if (!get_sample_info(demux_res, i, | 238 sample_byte_size = demux_res->sample_byte_size[i]; |
| 257 &sample_duration, &sample_byte_size)) | |
| 258 return; | |
| 259 | 239 |
| 260 if (buffer_size < sample_byte_size) | 240 if (buffer_size < sample_byte_size) |
| 261 return; | 241 return; |
| 262 | 242 |
| 263 stream_read(demux_res->stream, sample_byte_size, buffer); | 243 stream_read(demux_res->stream, sample_byte_size, buffer); |
| 267 decode_frame(demux_res->alac, buffer, pDestBuffer, &outputBytes); | 247 decode_frame(demux_res->alac, buffer, pDestBuffer, &outputBytes); |
| 268 | 248 |
| 269 /* write */ | 249 /* write */ |
| 270 bytes_read += outputBytes; | 250 bytes_read += outputBytes; |
| 271 | 251 |
| 272 playback->pass_audio(playback, FMT_S16_LE, demux_res->num_channels, outputBytes, pDestBuffer, &going); | 252 playback->pass_audio(playback, FMT_S16_LE, demux_res->num_channels, outputBytes, pDestBuffer, &playback->playing); |
| 273 } | 253 } |
| 274 | 254 |
| 275 free(buffer); | 255 free(buffer); |
| 276 free(pDestBuffer); | 256 free(pDestBuffer); |
| 277 } | 257 } |
| 295 DECLARE_PLUGIN(alac, NULL, NULL, alac_iplist, NULL, NULL, NULL, NULL, NULL); | 275 DECLARE_PLUGIN(alac, NULL, NULL, alac_iplist, NULL, NULL, NULL, NULL, NULL); |
| 296 | 276 |
| 297 gpointer decode_thread(void *args) | 277 gpointer decode_thread(void *args) |
| 298 { | 278 { |
| 299 demux_res_t demux_res; | 279 demux_res_t demux_res; |
| 300 gulong duration = 0; /* samples added up */ | |
| 301 VFSFile *input_file; | 280 VFSFile *input_file; |
| 302 stream_t *input_stream; | 281 stream_t *input_stream; |
| 303 Tuple *ti; | 282 Tuple *ti; |
| 304 gchar *title; | 283 gchar *title; |
| 305 | 284 |
| 326 | 305 |
| 327 /* initialise the sound converter */ | 306 /* initialise the sound converter */ |
| 328 demux_res.alac = create_alac(demux_res.sample_size, demux_res.num_channels); | 307 demux_res.alac = create_alac(demux_res.sample_size, demux_res.num_channels); |
| 329 alac_set_info(demux_res.alac, demux_res.codecdata); | 308 alac_set_info(demux_res.alac, demux_res.codecdata); |
| 330 | 309 |
| 331 /* Sample rates are multiples of 251?! Apple is *fucking* *insane*! -nenolod */ | |
| 332 duration = (demux_res.num_sample_byte_sizes * (float)((1024 * demux_res.sample_size) - 1.0) / | |
| 333 (float)(demux_res.sample_rate / 251)); | |
| 334 | |
| 335 playback->output->open_audio(FMT_S16_LE, demux_res.sample_rate, demux_res.num_channels); | 310 playback->output->open_audio(FMT_S16_LE, demux_res.sample_rate, demux_res.num_channels); |
| 336 playback->set_params(playback, title, duration, -1, demux_res.sample_rate, demux_res.num_channels); | 311 playback->set_params(playback, title, get_duration(&demux_res), -1, demux_res.sample_rate, demux_res.num_channels); |
| 337 | 312 |
| 338 /* will convert the entire buffer */ | 313 /* will convert the entire buffer */ |
| 339 GetBuffer(&demux_res); | 314 GetBuffer(&demux_res); |
| 340 | 315 |
| 341 going = 0; | 316 if (playback->playing) { |
| 317 playback->output->buffer_free(); | |
| 318 playback->output->buffer_free(); | |
| 319 while (playback->output->buffer_playing() && playback->playing) | |
| 320 g_usleep(100000); | |
| 321 } | |
| 342 | 322 |
| 343 stream_destroy(input_stream); | 323 stream_destroy(input_stream); |
| 344 | 324 |
| 345 if (input_opened) | 325 if (input_opened) |
| 346 aud_vfs_fclose(input_file); | 326 aud_vfs_fclose(input_file); |
| 347 | 327 |
| 348 playback->output->close_audio(); | 328 playback->output->close_audio(); |
| 349 | 329 |
| 330 playback->playing = FALSE; | |
| 331 | |
| 350 return NULL; | 332 return NULL; |
| 351 } | 333 } |
