static void sndfile_stream_decode(struct decoder *decoder, struct input_stream *is) { GError *error = NULL; SNDFILE *sf; SF_INFO info; struct audio_format audio_format; size_t frame_size; sf_count_t read_frames, num_frames; int buffer[4096]; enum decoder_command cmd; info.format = 0; sf = sf_open_virtual(&vio, SFM_READ, &info, is); if (sf == NULL) { g_warning("sf_open_virtual() failed"); return; } /* for now, always read 32 bit samples. Later, we could lower MPD's CPU usage by reading 16 bit samples with sf_readf_short() on low-quality source files. */ if (!audio_format_init_checked(&audio_format, info.samplerate, SAMPLE_FORMAT_S32, info.channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } decoder_initialized(decoder, &audio_format, info.seekable, frame_to_time(info.frames, &audio_format)); frame_size = audio_format_frame_size(&audio_format); read_frames = sizeof(buffer) / frame_size; do { num_frames = sf_readf_int(sf, buffer, read_frames); if (num_frames <= 0) break; cmd = decoder_data(decoder, is, buffer, num_frames * frame_size, 0); if (cmd == DECODE_COMMAND_SEEK) { sf_count_t c = time_to_frame(decoder_seek_where(decoder), &audio_format); c = sf_seek(sf, c, SEEK_SET); if (c < 0) decoder_seek_error(decoder); else decoder_command_finished(decoder); cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); sf_close(sf); }
static void pcm_stream_decode(struct decoder *decoder, struct input_stream *is) { static const struct audio_format audio_format = { .sample_rate = 44100, .format = SAMPLE_FORMAT_S16, .channels = 2, }; GError *error = NULL; enum decoder_command cmd; double time_to_size = audio_format_time_to_size(&audio_format); float total_time = -1; if (is->size >= 0) total_time = is->size / time_to_size; decoder_initialized(decoder, &audio_format, is->seekable, total_time); do { char buffer[4096]; size_t nbytes = decoder_read(decoder, is, buffer, sizeof(buffer)); if (nbytes == 0 && input_stream_eof(is)) break; cmd = nbytes > 0 ? decoder_data(decoder, is, buffer, nbytes, 0) : decoder_get_command(decoder); if (cmd == DECODE_COMMAND_SEEK) { goffset offset = (goffset)(time_to_size * decoder_seek_where(decoder)); if (input_stream_seek(is, offset, SEEK_SET, &error)) { decoder_command_finished(decoder); } else { g_warning("seeking failed: %s", error->message); g_error_free(error); decoder_seek_error(decoder); } cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); } static const char *const pcm_mime_types[] = { /* for streams obtained by the cdio_paranoia input plugin */ "audio/x-mpd-cdda-pcm", NULL }; const struct decoder_plugin pcm_decoder_plugin = { .name = "pcm", .stream_decode = pcm_stream_decode, .mime_types = pcm_mime_types, };
static void flac_decoder_loop(struct flac_data *data, FLAC__StreamDecoder *flac_dec, FLAC__uint64 t_start, FLAC__uint64 t_end) { struct decoder *decoder = data->decoder; enum decoder_command cmd; data->first_frame = t_start; while (true) { if (data->tag != NULL && !tag_is_empty(data->tag)) { cmd = decoder_tag(data->decoder, data->input_stream, data->tag); tag_free(data->tag); data->tag = tag_new(); } else cmd = decoder_get_command(decoder); if (cmd == DECODE_COMMAND_SEEK) { FLAC__uint64 seek_sample = t_start + decoder_seek_where(decoder) * data->audio_format.sample_rate; if (seek_sample >= t_start && (t_end == 0 || seek_sample <= t_end) && FLAC__stream_decoder_seek_absolute(flac_dec, seek_sample)) { data->next_frame = seek_sample; data->position = 0; decoder_command_finished(decoder); } else decoder_seek_error(decoder); } else if (cmd == DECODE_COMMAND_STOP || FLAC__stream_decoder_get_state(flac_dec) == FLAC__STREAM_DECODER_END_OF_STREAM) break; if (t_end != 0 && data->next_frame >= t_end) /* end of this sub track */ break; if (!FLAC__stream_decoder_process_single(flac_dec)) { cmd = decoder_get_command(decoder); if (cmd != DECODE_COMMAND_SEEK) break; } } if (cmd != DECODE_COMMAND_STOP) { flacPrintErroredState(FLAC__stream_decoder_get_state(flac_dec)); FLAC__stream_decoder_finish(flac_dec); } }
/* public */ static void vorbis_stream_decode(struct decoder *decoder, struct input_stream *input_stream) { GError *error = NULL; OggVorbis_File vf; struct vorbis_input_stream vis; struct audio_format audio_format; float total_time; int current_section; int prev_section = -1; long ret; char chunk[OGG_CHUNK_SIZE]; long bitRate = 0; long test; const vorbis_info *vi; enum decoder_command cmd = DECODE_COMMAND_NONE; if (ogg_stream_type_detect(input_stream) != VORBIS) return; /* rewind the stream, because ogg_stream_type_detect() has moved it */ input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL); if (!vorbis_is_open(&vis, &vf, decoder, input_stream)) return; vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); return; } if (!audio_format_init_checked(&audio_format, vi->rate, SAMPLE_FORMAT_S16, vi->channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } total_time = ov_time_total(&vf, -1); if (total_time < 0) total_time = 0; decoder_initialized(decoder, &audio_format, vis.seekable, total_time); do { if (cmd == DECODE_COMMAND_SEEK) { double seek_where = decoder_seek_where(decoder); if (0 == ov_time_seek_page(&vf, seek_where)) { decoder_command_finished(decoder); } else decoder_seek_error(decoder); } ret = ov_read(&vf, chunk, sizeof(chunk), OGG_DECODE_USE_BIGENDIAN, 2, 1, ¤t_section); if (ret == OV_HOLE) /* bad packet */ ret = 0; else if (ret <= 0) /* break on EOF or other error */ break; if (current_section != prev_section) { char **comments; vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); break; } if (vi->rate != (long)audio_format.sample_rate || vi->channels != (int)audio_format.channels) { /* we don't support audio format change yet */ g_warning("audio format change, stopping here"); break; } comments = ov_comment(&vf, -1)->user_comments; vorbis_send_comments(decoder, input_stream, comments); struct replay_gain_info rgi; if (vorbis_comments_to_replay_gain(&rgi, comments)) decoder_replay_gain(decoder, &rgi); prev_section = current_section; } if ((test = ov_bitrate_instant(&vf)) > 0) bitRate = test / 1000; cmd = decoder_data(decoder, input_stream, chunk, ret, bitRate); } while (cmd != DECODE_COMMAND_STOP); ov_clear(&vf); }
static bool mp3_read(struct mp3_data *data, struct replay_gain_info **replay_gain_info_r) { struct decoder *decoder = data->decoder; enum mp3_action ret; enum decoder_command cmd; mp3_update_timer_next_frame(data); switch (data->mute_frame) { case MUTEFRAME_SKIP: data->mute_frame = MUTEFRAME_NONE; break; case MUTEFRAME_SEEK: if (data->elapsed_time >= data->seek_where) data->mute_frame = MUTEFRAME_NONE; break; case MUTEFRAME_NONE: cmd = mp3_synth_and_send(data, replay_gain_info_r != NULL ? *replay_gain_info_r : NULL); if (cmd == DECODE_COMMAND_SEEK) { unsigned long j; assert(data->input_stream->seekable); j = mp3_time_to_frame(data, decoder_seek_where(decoder)); if (j < data->highest_frame) { if (mp3_seek(data, data->frame_offsets[j])) { data->current_frame = j; decoder_command_finished(decoder); } else decoder_seek_error(decoder); } else { data->seek_where = decoder_seek_where(decoder); data->mute_frame = MUTEFRAME_SEEK; decoder_command_finished(decoder); } } else if (cmd != DECODE_COMMAND_NONE) return false; } while (true) { bool skip = false; do { struct tag *tag = NULL; ret = decode_next_frame_header(data, &tag, replay_gain_info_r); if (tag != NULL) { decoder_tag(decoder, data->input_stream, tag); tag_free(tag); } } while (ret == DECODE_CONT); if (ret == DECODE_BREAK) return false; else if (ret == DECODE_SKIP) skip = true; if (data->mute_frame == MUTEFRAME_NONE) { do { ret = decodeNextFrame(data); } while (ret == DECODE_CONT); if (ret == DECODE_BREAK) return false; } if (!skip && ret == DECODE_OK) break; } return ret != DECODE_BREAK; }
static void mod_decode(struct decoder *decoder, struct input_stream *is) { ModPlugFile *f; ModPlug_Settings settings; GByteArray *bdatas; struct audio_format audio_format; int ret; char audio_buffer[MODPLUG_FRAME_SIZE]; enum decoder_command cmd = DECODE_COMMAND_NONE; bdatas = mod_loadfile(decoder, is); if (!bdatas) { g_warning("could not load stream\n"); return; } ModPlug_GetSettings(&settings); /* alter setting */ settings.mResamplingMode = MODPLUG_RESAMPLE_FIR; /* RESAMP */ settings.mChannels = 2; settings.mBits = 16; settings.mFrequency = 44100; /* insert more setting changes here */ ModPlug_SetSettings(&settings); f = ModPlug_Load(bdatas->data, bdatas->len); g_byte_array_free(bdatas, TRUE); if (!f) { g_warning("could not decode stream\n"); return; } audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2); assert(audio_format_valid(&audio_format)); decoder_initialized(decoder, &audio_format, is->seekable, ModPlug_GetLength(f) / 1000.0); do { ret = ModPlug_Read(f, audio_buffer, MODPLUG_FRAME_SIZE); if (ret <= 0) break; cmd = decoder_data(decoder, NULL, audio_buffer, ret, 0); if (cmd == DECODE_COMMAND_SEEK) { float where = decoder_seek_where(decoder); ModPlug_Seek(f, (int)(where * 1000.0)); decoder_command_finished(decoder); } } while (cmd != DECODE_COMMAND_STOP); ModPlug_Unload(f); }
static void wildmidi_file_decode(struct decoder *decoder, const char *path_fs) { static const struct audio_format audio_format = { .sample_rate = WILDMIDI_SAMPLE_RATE, .format = SAMPLE_FORMAT_S16, .channels = 2, }; midi *wm; const struct _WM_Info *info; enum decoder_command cmd; wm = WildMidi_Open(path_fs); if (wm == NULL) return; info = WildMidi_GetInfo(wm); if (info == NULL) { WildMidi_Close(wm); return; } decoder_initialized(decoder, &audio_format, true, info->approx_total_samples / WILDMIDI_SAMPLE_RATE); do { char buffer[4096]; int len; info = WildMidi_GetInfo(wm); if (info == NULL) break; len = WildMidi_GetOutput(wm, buffer, sizeof(buffer)); if (len <= 0) break; cmd = decoder_data(decoder, NULL, buffer, len, 0); if (cmd == DECODE_COMMAND_SEEK) { unsigned long seek_where = WILDMIDI_SAMPLE_RATE * decoder_seek_where(decoder); WildMidi_SampledSeek(wm, &seek_where); decoder_command_finished(decoder); cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); WildMidi_Close(wm); } static struct tag * wildmidi_tag_dup(const char *path_fs) { midi *wm; const struct _WM_Info *info; struct tag *tag; wm = WildMidi_Open(path_fs); if (wm == NULL) return NULL; info = WildMidi_GetInfo(wm); if (info == NULL) { WildMidi_Close(wm); return NULL; } tag = tag_new(); tag->time = info->approx_total_samples / WILDMIDI_SAMPLE_RATE; WildMidi_Close(wm); return tag; }
/* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek, struct replay_gain_info *replay_gain_info) { struct audio_format audio_format; format_samples_t format_samples; char chunk[CHUNK_SIZE]; int samples_requested, samples_got; float total_time, current_time; int bytes_per_sample, output_sample_size; int position; audio_format.sample_rate = WavpackGetSampleRate(wpc); audio_format.channels = WavpackGetReducedChannels(wpc); audio_format.bits = WavpackGetBitsPerSample(wpc); /* round bitwidth to 8-bit units */ audio_format.bits = (audio_format.bits + 7) & (~7); /* mpd handles max 24-bit samples */ if (audio_format.bits > 24) { audio_format.bits = 24; } if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", audio_format.sample_rate, audio_format.bits, audio_format.channels); return; } if ((WavpackGetMode(wpc) & MODE_FLOAT) == MODE_FLOAT) { format_samples = format_samples_float; } else { format_samples = format_samples_int; } total_time = WavpackGetNumSamples(wpc); total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); output_sample_size = audio_format_frame_size(&audio_format); /* wavpack gives us all kind of samples in a 32-bit space */ samples_requested = sizeof(chunk) / (4 * audio_format.channels); decoder_initialized(decoder, &audio_format, can_seek, total_time); position = 0; do { if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) { if (can_seek) { int where; where = decoder_seek_where(decoder); where *= audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { position = where; decoder_command_finished(decoder); } else { decoder_seek_error(decoder); } } else { decoder_seek_error(decoder); } } if (decoder_get_command(decoder) == DECODE_COMMAND_STOP) { break; } samples_got = WavpackUnpackSamples( wpc, (int32_t *)chunk, samples_requested ); if (samples_got > 0) { int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); position += samples_got; current_time = position; current_time /= audio_format.sample_rate; format_samples( bytes_per_sample, chunk, samples_got * audio_format.channels ); decoder_data( decoder, NULL, chunk, samples_got * output_sample_size, current_time, bitrate, replay_gain_info ); } } while (samples_got > 0); }
static void audiofile_stream_decode(struct decoder *decoder, struct input_stream *is) { AFvirtualfile *vf; int fs, frame_count; AFfilehandle af_fp; int bits; struct audio_format audio_format; float total_time; uint16_t bit_rate; int ret, current = 0; char chunk[CHUNK_SIZE]; enum decoder_command cmd; if (!is->seekable) { g_warning("not seekable"); return; } vf = setup_virtual_fops(is); af_fp = afOpenVirtualFile(vf, "r", NULL); if (af_fp == AF_NULL_FILEHANDLE) { g_warning("failed to input stream\n"); return; } afGetSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits); if (!audio_valid_sample_format(bits)) { g_debug("input file has %d bit samples, converting to 16", bits); bits = 16; } afSetVirtualSampleFormat(af_fp, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bits); afGetVirtualSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits); audio_format.bits = (uint8_t)bits; audio_format.sample_rate = (unsigned int)afGetRate(af_fp, AF_DEFAULT_TRACK); audio_format.channels = (uint8_t)afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK); if (!audio_format_valid(&audio_format)) { g_warning("Invalid audio format: %u:%u:%u\n", audio_format.sample_rate, audio_format.bits, audio_format.channels); afCloseFile(af_fp); return; } frame_count = afGetFrameCount(af_fp, AF_DEFAULT_TRACK); total_time = ((float)frame_count / (float)audio_format.sample_rate); bit_rate = (uint16_t)(is->size * 8.0 / total_time / 1000.0 + 0.5); fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1); decoder_initialized(decoder, &audio_format, true, total_time); do { ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, CHUNK_SIZE / fs); if (ret <= 0) break; current += ret; cmd = decoder_data(decoder, NULL, chunk, ret * fs, (float)current / (float)audio_format.sample_rate, bit_rate, NULL); if (cmd == DECODE_COMMAND_SEEK) { current = decoder_seek_where(decoder) * audio_format.sample_rate; afSeekFrame(af_fp, AF_DEFAULT_TRACK, current); decoder_command_finished(decoder); cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); afCloseFile(af_fp); }
static void audiofile_stream_decode(struct decoder *decoder, struct input_stream *is) { GError *error = NULL; AFvirtualfile *vf; int fs, frame_count; AFfilehandle af_fp; struct audio_format audio_format; float total_time; uint16_t bit_rate; int ret; char chunk[CHUNK_SIZE]; enum decoder_command cmd; if (!is->seekable) { g_warning("not seekable"); return; } vf = setup_virtual_fops(is); af_fp = afOpenVirtualFile(vf, "r", NULL); if (af_fp == AF_NULL_FILEHANDLE) { g_warning("failed to input stream\n"); return; } if (!audio_format_init_checked(&audio_format, afGetRate(af_fp, AF_DEFAULT_TRACK), audiofile_setup_sample_format(af_fp), afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK), &error)) { g_warning("%s", error->message); g_error_free(error); afCloseFile(af_fp); return; } frame_count = afGetFrameCount(af_fp, AF_DEFAULT_TRACK); total_time = ((float)frame_count / (float)audio_format.sample_rate); bit_rate = (uint16_t)(is->size * 8.0 / total_time / 1000.0 + 0.5); fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1); decoder_initialized(decoder, &audio_format, true, total_time); do { ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, CHUNK_SIZE / fs); if (ret <= 0) break; cmd = decoder_data(decoder, NULL, chunk, ret * fs, bit_rate); if (cmd == DECODE_COMMAND_SEEK) { AFframecount frame = decoder_seek_where(decoder) * audio_format.sample_rate; afSeekFrame(af_fp, AF_DEFAULT_TRACK, frame); decoder_command_finished(decoder); cmd = DECODE_COMMAND_NONE; } } while (cmd == DECODE_COMMAND_NONE); afCloseFile(af_fp); }
/* public */ static void vorbis_stream_decode(struct decoder *decoder, struct input_stream *input_stream) { GError *error = NULL; if (ogg_codec_detect(decoder, input_stream) != OGG_CODEC_VORBIS) return; /* rewind the stream, because ogg_codec_detect() has moved it */ input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL); struct vorbis_input_stream vis; OggVorbis_File vf; if (!vorbis_is_open(&vis, &vf, decoder, input_stream)) return; const vorbis_info *vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); return; } struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, vi->rate, #ifdef HAVE_TREMOR SAMPLE_FORMAT_S16, #else SAMPLE_FORMAT_FLOAT, #endif vi->channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } float total_time = ov_time_total(&vf, -1); if (total_time < 0) total_time = 0; decoder_initialized(decoder, &audio_format, vis.seekable, total_time); enum decoder_command cmd = decoder_get_command(decoder); #ifdef HAVE_TREMOR char buffer[4096]; #else float buffer[2048]; const int frames_per_buffer = G_N_ELEMENTS(buffer) / audio_format.channels; const unsigned frame_size = sizeof(buffer[0]) * audio_format.channels; #endif int prev_section = -1; unsigned kbit_rate = 0; do { if (cmd == DECODE_COMMAND_SEEK) { double seek_where = decoder_seek_where(decoder); if (0 == ov_time_seek_page(&vf, seek_where)) { decoder_command_finished(decoder); } else decoder_seek_error(decoder); } int current_section; #ifdef HAVE_TREMOR long nbytes = ov_read(&vf, buffer, sizeof(buffer), VORBIS_BIG_ENDIAN, 2, 1, ¤t_section); #else float **per_channel; long nframes = ov_read_float(&vf, &per_channel, frames_per_buffer, ¤t_section); long nbytes = nframes; if (nframes > 0) { vorbis_interleave(buffer, (const float*const*)per_channel, nframes, audio_format.channels); nbytes *= frame_size; } #endif if (nbytes == OV_HOLE) /* bad packet */ nbytes = 0; else if (nbytes <= 0) /* break on EOF or other error */ break; if (current_section != prev_section) { vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); break; } if (vi->rate != (long)audio_format.sample_rate || vi->channels != (int)audio_format.channels) { /* we don't support audio format change yet */ g_warning("audio format change, stopping here"); break; } char **comments = ov_comment(&vf, -1)->user_comments; vorbis_send_comments(decoder, input_stream, comments); struct replay_gain_info rgi; if (vorbis_comments_to_replay_gain(&rgi, comments)) decoder_replay_gain(decoder, &rgi); prev_section = current_section; } long test = ov_bitrate_instant(&vf); if (test > 0) kbit_rate = test / 1000; cmd = decoder_data(decoder, input_stream, buffer, nbytes, kbit_rate); } while (cmd != DECODE_COMMAND_STOP); ov_clear(&vf); }
/* * This does the main decoding thing. * Requires an already opened WavpackContext. */ static void wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek) { GError *error = NULL; bool is_float; enum sample_format sample_format; struct audio_format audio_format; format_samples_t format_samples; float total_time; int bytes_per_sample, output_sample_size; is_float = (WavpackGetMode(wpc) & MODE_FLOAT) != 0; sample_format = wavpack_bits_to_sample_format(is_float, WavpackGetBytesPerSample(wpc)); if (!audio_format_init_checked(&audio_format, WavpackGetSampleRate(wpc), sample_format, WavpackGetNumChannels(wpc), &error)) { g_warning("%s", error->message); g_error_free(error); return; } if (is_float) { format_samples = format_samples_float; } else { format_samples = format_samples_int; } total_time = WavpackGetNumSamples(wpc); total_time /= audio_format.sample_rate; bytes_per_sample = WavpackGetBytesPerSample(wpc); output_sample_size = audio_format_frame_size(&audio_format); /* wavpack gives us all kind of samples in a 32-bit space */ int32_t chunk[1024]; const uint32_t samples_requested = G_N_ELEMENTS(chunk) / audio_format.channels; decoder_initialized(decoder, &audio_format, can_seek, total_time); enum decoder_command cmd = decoder_get_command(decoder); while (cmd != DECODE_COMMAND_STOP) { if (cmd == DECODE_COMMAND_SEEK) { if (can_seek) { unsigned where = decoder_seek_where(decoder) * audio_format.sample_rate; if (WavpackSeekSample(wpc, where)) { decoder_command_finished(decoder); } else { decoder_seek_error(decoder); } } else { decoder_seek_error(decoder); } } uint32_t samples_got = WavpackUnpackSamples(wpc, chunk, samples_requested); if (samples_got == 0) break; int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 + 0.5); format_samples(bytes_per_sample, chunk, samples_got * audio_format.channels); cmd = decoder_data(decoder, NULL, chunk, samples_got * output_sample_size, bitrate); } }