static const struct audio_format * ao_filter_open(struct audio_output *ao, struct audio_format *audio_format, GError **error_r) { assert(audio_format_valid(audio_format)); /* the replay_gain filter cannot fail here */ if (ao->replay_gain_filter != NULL) filter_open(ao->replay_gain_filter, audio_format, error_r); if (ao->other_replay_gain_filter != NULL) filter_open(ao->other_replay_gain_filter, audio_format, error_r); const struct audio_format *af = filter_open(ao->filter, audio_format, error_r); if (af == NULL) { if (ao->replay_gain_filter != NULL) filter_close(ao->replay_gain_filter); if (ao->other_replay_gain_filter != NULL) filter_close(ao->other_replay_gain_filter); } return af; }
void decoder_initialized(G_GNUC_UNUSED struct decoder * decoder, const struct audio_format *audio_format, bool seekable, float total_time) { assert(dc.state == DECODE_STATE_START); assert(decoder != NULL); assert(decoder->stream_tag == NULL); assert(decoder->decoder_tag == NULL); assert(!decoder->seeking); assert(audio_format != NULL); assert(audio_format_defined(audio_format)); assert(audio_format_valid(audio_format)); dc.in_audio_format = *audio_format; getOutputAudioFormat(audio_format, &dc.out_audio_format); dc.seekable = seekable; dc.total_time = total_time; dc.state = DECODE_STATE_DECODE; notify_signal(&pc.notify); g_debug("audio_format=%u:%u:%u, seekable=%s", dc.in_audio_format.sample_rate, dc.in_audio_format.bits, dc.in_audio_format.channels, seekable ? "true" : "false"); if (!audio_format_equals(&dc.in_audio_format, &dc.out_audio_format)) g_debug("converting to %u:%u:%u", dc.out_audio_format.sample_rate, dc.out_audio_format.bits, dc.out_audio_format.channels); }
bool audio_format_parse(struct audio_format *dest, const char *src, bool mask, GError **error_r) { uint32_t rate; enum sample_format sample_format; uint8_t channels; audio_format_clear(dest); /* parse sample rate */ #if GCC_CHECK_VERSION(4,7) /* workaround -Wmaybe-uninitialized false positive */ rate = 0; #endif if (!parse_sample_rate(src, mask, &rate, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Sample format missing"); return false; } /* parse sample format */ #if GCC_CHECK_VERSION(4,7) /* workaround -Wmaybe-uninitialized false positive */ sample_format = SAMPLE_FORMAT_UNDEFINED; #endif if (!parse_sample_format(src, mask, &sample_format, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Channel count missing"); return false; } /* parse channel count */ if (!parse_channel_count(src, mask, &channels, &src, error_r)) return false; if (*src != 0) { g_set_error(error_r, audio_parser_quark(), 0, "Extra data after channel count: %s", src); return false; } audio_format_init(dest, rate, sample_format, channels); assert(mask ? audio_format_mask_valid(dest) : audio_format_valid(dest)); return true; }
void audio_format_mask_apply(struct audio_format *af, const struct audio_format *mask) { assert(audio_format_valid(af)); assert(audio_format_mask_valid(mask)); if (mask->sample_rate != 0) af->sample_rate = mask->sample_rate; if (mask->format != SAMPLE_FORMAT_UNDEFINED) af->format = mask->format; if (mask->channels != 0) af->channels = mask->channels; assert(audio_format_valid(af)); }
static const struct audio_format * autoconvert_filter_open(struct filter *_filter, struct audio_format *in_audio_format, GError **error_r) { struct autoconvert_filter *filter = (struct autoconvert_filter *)_filter; const struct audio_format *out_audio_format; assert(audio_format_valid(in_audio_format)); /* open the "real" filter */ filter->in_audio_format = *in_audio_format; out_audio_format = filter_open(filter->filter, &filter->in_audio_format, error_r); if (out_audio_format == NULL) return NULL; /* need to convert? */ if (!audio_format_equals(&filter->in_audio_format, in_audio_format)) { /* yes - create a convert_filter */ struct audio_format audio_format2 = *in_audio_format; const struct audio_format *audio_format3; filter->convert = filter_new(&convert_filter_plugin, NULL, error_r); if (filter->convert == NULL) { filter_close(filter->filter); return NULL; } audio_format3 = filter_open(filter->convert, &audio_format2, error_r); if (audio_format3 == NULL) { filter_free(filter->convert); filter_close(filter->filter); return NULL; } assert(audio_format_equals(&audio_format2, in_audio_format)); convert_filter_set(filter->convert, &filter->in_audio_format); } else /* no */ filter->convert = NULL; return out_audio_format; }
static bool wave_encoder_open(struct encoder *_encoder, G_GNUC_UNUSED struct audio_format *audio_format, G_GNUC_UNUSED GError **error) { struct wave_encoder *encoder = (struct wave_encoder *)_encoder; assert(audio_format_valid(audio_format)); switch (audio_format->format) { case SAMPLE_FORMAT_S8: encoder->bits = 8; break; case SAMPLE_FORMAT_S16: encoder->bits = 16; break; case SAMPLE_FORMAT_S24: audio_format->format = SAMPLE_FORMAT_S24_P32; encoder->bits = 24; break; case SAMPLE_FORMAT_S24_P32: encoder->bits = 24; break; case SAMPLE_FORMAT_S32: encoder->bits = 32; break; default: audio_format->format = SAMPLE_FORMAT_S16; encoder->bits = 16; break; } encoder->buffer = growing_fifo_new(); struct wave_header *header = growing_fifo_write(&encoder->buffer, sizeof(*header)); /* create PCM wave header in initial buffer */ fill_wave_header(header, audio_format->channels, encoder->bits, audio_format->sample_rate, (encoder->bits / 8) * audio_format->channels ); fifo_buffer_append(encoder->buffer, sizeof(*header)); return true; }
bool audio_format_init_checked(struct audio_format *af, unsigned long sample_rate, enum sample_format sample_format, unsigned channels, GError **error_r) { if (audio_check_sample_rate(sample_rate, error_r) && audio_check_sample_format(sample_format, error_r) && audio_check_channel_count(channels, error_r)) { audio_format_init(af, sample_rate, sample_format, channels); assert(audio_format_valid(af)); return true; } else return false; }
bool audio_format_parse(struct audio_format *dest, const char *src, bool mask, GError **error_r) { uint32_t rate; enum sample_format sample_format; uint8_t channels; audio_format_clear(dest); /* parse sample rate */ if (!parse_sample_rate(src, mask, &rate, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Sample format missing"); return false; } /* parse sample format */ if (!parse_sample_format(src, mask, &sample_format, &src, error_r)) return false; if (*src++ != ':') { g_set_error(error_r, audio_parser_quark(), 0, "Channel count missing"); return false; } /* parse channel count */ if (!parse_channel_count(src, mask, &channels, &src, error_r)) return false; if (*src != 0) { g_set_error(error_r, audio_parser_quark(), 0, "Extra data after channel count: %s", src); return false; } audio_format_init(dest, rate, sample_format, channels); assert(mask ? audio_format_mask_valid(dest) : audio_format_valid(dest)); return true; }
void decoder_initialized(struct decoder *decoder, const struct audio_format *audio_format, G_GNUC_UNUSED bool seekable, G_GNUC_UNUSED float total_time) { struct audio_format_string af_string; assert(!decoder->initialized); assert(audio_format_valid(audio_format)); g_printerr("audio_format=%s\n", audio_format_to_string(audio_format, &af_string)); decoder->initialized = true; }
static bool wave_encoder_open(struct encoder *_encoder, G_GNUC_UNUSED struct audio_format *audio_format, G_GNUC_UNUSED GError **error) { struct wave_encoder *encoder = (struct wave_encoder *)_encoder; void *buffer; assert(audio_format_valid(audio_format)); switch (audio_format->format) { case SAMPLE_FORMAT_S8: encoder->bits = 8; break; case SAMPLE_FORMAT_S16: encoder->bits = 16; break; case SAMPLE_FORMAT_S24_P32: encoder->bits = 24; break; case SAMPLE_FORMAT_S32: encoder->bits = 32; break; default: audio_format->format = SAMPLE_FORMAT_S16; encoder->bits = 16; break; } buffer = pcm_buffer_get(&encoder->buffer, sizeof(struct wave_header) ); /* create PCM wave header in initial buffer */ fill_wave_header((struct wave_header *) buffer, audio_format->channels, encoder->bits, audio_format->sample_rate, (encoder->bits / 8) * audio_format->channels ); encoder->buffer_length = sizeof(struct wave_header); return true; }
unsigned cross_fade_calc(float duration, float total_time, float mixramp_db, float mixramp_delay, float replay_gain_db, float replay_gain_prev_db, char *mixramp_start, char *mixramp_prev_end, const struct audio_format *af, const struct audio_format *old_format, unsigned max_chunks) { unsigned int chunks = 0; float chunks_f; float mixramp_overlap; if (duration < 0 || duration >= total_time || /* we can't crossfade when the audio formats are different */ !audio_format_equals(af, old_format)) return 0; assert(duration >= 0); assert(audio_format_valid(af)); chunks_f = (float)audio_format_time_to_size(af) / (float)CHUNK_SIZE; if (isnan(mixramp_delay) || !(mixramp_start) || !(mixramp_prev_end)) { chunks = (chunks_f * duration + 0.5); } else { /* Calculate mixramp overlap. */ mixramp_overlap = mixramp_interpolate(mixramp_start, mixramp_db - replay_gain_db) + mixramp_interpolate(mixramp_prev_end, mixramp_db - replay_gain_prev_db); if (!isnan(mixramp_overlap) && (mixramp_delay <= mixramp_overlap)) { chunks = (chunks_f * (mixramp_overlap - mixramp_delay)); g_debug("will overlap %d chunks, %fs", chunks, mixramp_overlap - mixramp_delay); } } if (chunks > max_chunks) { chunks = max_chunks; g_warning("audio_buffer_size too small for computed MixRamp overlap"); } return chunks; }
void decoder_initialized(struct decoder *decoder, const struct audio_format *audio_format, bool seekable, float total_time) { struct decoder_control *dc = decoder->dc; struct audio_format_string af_string; assert(dc->state == DECODE_STATE_START); assert(dc->pipe != NULL); assert(decoder != NULL); assert(decoder->stream_tag == NULL); assert(decoder->decoder_tag == NULL); assert(!decoder->seeking); assert(audio_format != NULL); assert(audio_format_defined(audio_format)); assert(audio_format_valid(audio_format)); dc->in_audio_format = *audio_format; getOutputAudioFormat(audio_format, &dc->out_audio_format); dc->seekable = seekable; dc->total_time = total_time; decoder_lock(dc); dc->state = DECODE_STATE_DECODE; decoder_unlock(dc); player_lock_signal(); g_debug("audio_format=%s, seekable=%s", audio_format_to_string(&dc->in_audio_format, &af_string), seekable ? "true" : "false"); if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) g_debug("converting to %s", audio_format_to_string(&dc->out_audio_format, &af_string)); }
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); }
/** * Object must be locked (and unlocked) by the caller. */ static bool audio_output_open(struct audio_output *ao, const struct audio_format *audio_format, const struct music_pipe *mp) { bool open; assert(ao != NULL); assert(ao->allow_play); assert(audio_format_valid(audio_format)); assert(mp != NULL); if (ao->fail_timer != NULL) { g_timer_destroy(ao->fail_timer); ao->fail_timer = NULL; } if (ao->open && audio_format_equals(audio_format, &ao->in_audio_format)) { assert(ao->pipe == mp || (ao->always_on && ao->pause)); if (ao->pause) { ao->chunk = NULL; ao->pipe = mp; /* unpause with the CANCEL command; this is a hack, but suits well for forcing the thread to leave the ao_pause() thread, and we need to flush the device buffer anyway */ /* we're not using audio_output_cancel() here, because that function is asynchronous */ ao_command(ao, AO_COMMAND_CANCEL); } return true; } ao->in_audio_format = *audio_format; ao->chunk = NULL; ao->pipe = mp; if (ao->thread == NULL) audio_output_thread_start(ao); ao_command(ao, ao->open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN); open = ao->open; if (open && ao->mixer != NULL) { GError *error = NULL; if (!mixer_open(ao->mixer, &error)) { g_warning("Failed to open mixer for '%s': %s", ao->name, error->message); g_error_free(error); } } return open; }
static void ao_open(struct audio_output *ao) { bool success; GError *error = NULL; const struct audio_format *filter_audio_format; struct audio_format_string af_string; assert(!ao->open); assert(ao->pipe != NULL); assert(ao->chunk == NULL); assert(audio_format_valid(&ao->in_audio_format)); if (ao->fail_timer != NULL) { /* this can only happen when this output thread fails while audio_output_open() is run in the player thread */ g_timer_destroy(ao->fail_timer); ao->fail_timer = NULL; } /* enable the device (just in case the last enable has failed) */ if (!ao_enable(ao)) /* still no luck */ return; /* open the filter */ filter_audio_format = ao_filter_open(ao, &ao->in_audio_format, &error); if (filter_audio_format == NULL) { g_warning("Failed to open filter for \"%s\" [%s]: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao->fail_timer = g_timer_new(); return; } assert(audio_format_valid(filter_audio_format)); ao->out_audio_format = *filter_audio_format; audio_format_mask_apply(&ao->out_audio_format, &ao->config_audio_format); g_mutex_unlock(ao->mutex); success = ao_plugin_open(ao->plugin, ao->data, &ao->out_audio_format, &error); g_mutex_lock(ao->mutex); assert(!ao->open); if (!success) { g_warning("Failed to open \"%s\" [%s]: %s", ao->name, ao->plugin->name, error->message); g_error_free(error); ao_filter_close(ao); ao->fail_timer = g_timer_new(); return; } convert_filter_set(ao->convert_filter, &ao->out_audio_format); ao->open = true; g_debug("opened plugin=%s name=\"%s\" " "audio_format=%s", ao->plugin->name, ao->name, audio_format_to_string(&ao->out_audio_format, &af_string)); if (!audio_format_equals(&ao->in_audio_format, &ao->out_audio_format)) g_debug("converting from %s", audio_format_to_string(&ao->in_audio_format, &af_string)); }
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); }
/* * 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); }