audio_format: convert to C++
This commit is contained in:
parent
67f591a9ce
commit
d1e7b4e381
16
Makefile.am
16
Makefile.am
|
@ -51,7 +51,6 @@ src_mpd_LDADD = \
|
||||||
mpd_headers = \
|
mpd_headers = \
|
||||||
src/check.h \
|
src/check.h \
|
||||||
src/ack.h \
|
src/ack.h \
|
||||||
src/audio_format.h \
|
|
||||||
src/filter_internal.h \
|
src/filter_internal.h \
|
||||||
src/command.h \
|
src/command.h \
|
||||||
src/conf.h \
|
src/conf.h \
|
||||||
|
@ -97,7 +96,7 @@ src_mpd_SOURCES = \
|
||||||
src/notify.cxx src/notify.hxx \
|
src/notify.cxx src/notify.hxx \
|
||||||
src/AudioConfig.cxx src/AudioConfig.hxx \
|
src/AudioConfig.cxx src/AudioConfig.hxx \
|
||||||
src/CheckAudioFormat.cxx src/CheckAudioFormat.hxx \
|
src/CheckAudioFormat.cxx src/CheckAudioFormat.hxx \
|
||||||
src/audio_format.c \
|
src/AudioFormat.cxx src/AudioFormat.hxx \
|
||||||
src/AudioParser.cxx src/AudioParser.hxx \
|
src/AudioParser.cxx src/AudioParser.hxx \
|
||||||
src/protocol/ArgParser.cxx src/protocol/ArgParser.hxx \
|
src/protocol/ArgParser.cxx src/protocol/ArgParser.hxx \
|
||||||
src/protocol/Result.cxx src/protocol/Result.hxx \
|
src/protocol/Result.cxx src/protocol/Result.hxx \
|
||||||
|
@ -1173,8 +1172,7 @@ test_run_decoder_SOURCES = test/run_decoder.cxx \
|
||||||
src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagHandler.cxx \
|
src/Tag.cxx src/TagNames.c src/TagPool.cxx src/TagHandler.cxx \
|
||||||
src/ReplayGainInfo.cxx \
|
src/ReplayGainInfo.cxx \
|
||||||
src/fd_util.c \
|
src/fd_util.c \
|
||||||
src/CheckAudioFormat.cxx \
|
src/AudioFormat.cxx src/CheckAudioFormat.cxx \
|
||||||
src/audio_format.c \
|
|
||||||
$(ARCHIVE_SRC) \
|
$(ARCHIVE_SRC) \
|
||||||
$(INPUT_SRC) \
|
$(INPUT_SRC) \
|
||||||
$(TAG_SRC) \
|
$(TAG_SRC) \
|
||||||
|
@ -1221,7 +1219,7 @@ test_run_filter_SOURCES = test/run_filter.cxx \
|
||||||
test/stdbin.h \
|
test/stdbin.h \
|
||||||
src/FilterPlugin.cxx src/FilterRegistry.cxx \
|
src/FilterPlugin.cxx src/FilterRegistry.cxx \
|
||||||
src/CheckAudioFormat.cxx \
|
src/CheckAudioFormat.cxx \
|
||||||
src/audio_format.c \
|
src/AudioFormat.cxx \
|
||||||
src/AudioParser.cxx \
|
src/AudioParser.cxx \
|
||||||
src/ReplayGainInfo.cxx \
|
src/ReplayGainInfo.cxx \
|
||||||
src/AudioCompress/compress.c
|
src/AudioCompress/compress.c
|
||||||
|
@ -1240,7 +1238,7 @@ test_run_encoder_SOURCES = test/run_encoder.cxx \
|
||||||
test/stdbin.h \
|
test/stdbin.h \
|
||||||
src/Tag.cxx src/TagNames.c src/TagPool.cxx \
|
src/Tag.cxx src/TagNames.c src/TagPool.cxx \
|
||||||
src/CheckAudioFormat.cxx \
|
src/CheckAudioFormat.cxx \
|
||||||
src/audio_format.c \
|
src/AudioFormat.cxx \
|
||||||
src/AudioParser.cxx
|
src/AudioParser.cxx
|
||||||
test_run_encoder_LDADD = \
|
test_run_encoder_LDADD = \
|
||||||
$(ENCODER_LIBS) \
|
$(ENCODER_LIBS) \
|
||||||
|
@ -1258,7 +1256,7 @@ test_test_vorbis_encoder_SOURCES = test/test_vorbis_encoder.cxx \
|
||||||
test/stdbin.h \
|
test/stdbin.h \
|
||||||
src/Tag.cxx src/TagNames.c src/TagPool.cxx \
|
src/Tag.cxx src/TagNames.c src/TagPool.cxx \
|
||||||
src/CheckAudioFormat.cxx \
|
src/CheckAudioFormat.cxx \
|
||||||
src/audio_format.c \
|
src/AudioFormat.cxx \
|
||||||
src/AudioParser.cxx \
|
src/AudioParser.cxx \
|
||||||
$(ENCODER_SRC)
|
$(ENCODER_SRC)
|
||||||
test_test_vorbis_encoder_CPPFLAGS = $(AM_CPPFLAGS) \
|
test_test_vorbis_encoder_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||||
|
@ -1289,7 +1287,7 @@ test_run_normalize_LDADD = \
|
||||||
$(GLIB_LIBS)
|
$(GLIB_LIBS)
|
||||||
|
|
||||||
test_run_convert_SOURCES = test/run_convert.cxx \
|
test_run_convert_SOURCES = test/run_convert.cxx \
|
||||||
src/audio_format.c \
|
src/AudioFormat.cxx \
|
||||||
src/CheckAudioFormat.cxx \
|
src/CheckAudioFormat.cxx \
|
||||||
src/AudioParser.cxx
|
src/AudioParser.cxx
|
||||||
test_run_convert_LDADD = \
|
test_run_convert_LDADD = \
|
||||||
|
@ -1313,7 +1311,7 @@ test_run_output_SOURCES = test/run_output.cxx \
|
||||||
test/stdbin.h \
|
test/stdbin.h \
|
||||||
src/IOThread.cxx \
|
src/IOThread.cxx \
|
||||||
src/CheckAudioFormat.cxx \
|
src/CheckAudioFormat.cxx \
|
||||||
src/audio_format.c \
|
src/AudioFormat.cxx \
|
||||||
src/AudioParser.cxx \
|
src/AudioParser.cxx \
|
||||||
src/Timer.cxx src/clock.c \
|
src/Timer.cxx src/clock.c \
|
||||||
src/Tag.cxx src/TagNames.c src/TagPool.cxx \
|
src/Tag.cxx src/TagNames.c src/TagPool.cxx \
|
||||||
|
|
|
@ -19,18 +19,19 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "AudioConfig.hxx"
|
#include "AudioConfig.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "AudioParser.hxx"
|
#include "AudioParser.hxx"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "mpd_error.h"
|
#include "mpd_error.h"
|
||||||
|
|
||||||
static struct audio_format configured_audio_format;
|
static AudioFormat configured_audio_format;
|
||||||
|
|
||||||
void getOutputAudioFormat(const struct audio_format *inAudioFormat,
|
AudioFormat
|
||||||
struct audio_format *outAudioFormat)
|
getOutputAudioFormat(AudioFormat inAudioFormat)
|
||||||
{
|
{
|
||||||
*outAudioFormat = *inAudioFormat;
|
AudioFormat out_audio_format = inAudioFormat;
|
||||||
audio_format_mask_apply(outAudioFormat, &configured_audio_format);
|
out_audio_format.ApplyMask(configured_audio_format);
|
||||||
|
return out_audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAudioConfig(void)
|
void initAudioConfig(void)
|
||||||
|
@ -42,7 +43,7 @@ void initAudioConfig(void)
|
||||||
if (param == NULL)
|
if (param == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ret = audio_format_parse(&configured_audio_format, param->value,
|
ret = audio_format_parse(configured_audio_format, param->value,
|
||||||
true, &error);
|
true, &error);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
MPD_ERROR("error parsing line %i: %s",
|
MPD_ERROR("error parsing line %i: %s",
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
#ifndef MPD_AUDIO_CONFIG_HXX
|
#ifndef MPD_AUDIO_CONFIG_HXX
|
||||||
#define MPD_AUDIO_CONFIG_HXX
|
#define MPD_AUDIO_CONFIG_HXX
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
|
|
||||||
void getOutputAudioFormat(const struct audio_format *inFormat,
|
AudioFormat
|
||||||
struct audio_format *outFormat);
|
getOutputAudioFormat(AudioFormat inFormat);
|
||||||
|
|
||||||
/* make sure initPlayerData is called before this function!! */
|
/* make sure initPlayerData is called before this function!! */
|
||||||
void initAudioConfig(void);
|
void initAudioConfig(void);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2003-2011 The Music Player Daemon Project
|
* Copyright (C) 2003-2013 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -17,53 +17,52 @@
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
audio_format_mask_apply(struct audio_format *af,
|
AudioFormat::ApplyMask(AudioFormat mask)
|
||||||
const struct audio_format *mask)
|
|
||||||
{
|
{
|
||||||
assert(audio_format_valid(af));
|
assert(IsValid());
|
||||||
assert(audio_format_mask_valid(mask));
|
assert(mask.IsMaskValid());
|
||||||
|
|
||||||
if (mask->sample_rate != 0)
|
if (mask.sample_rate != 0)
|
||||||
af->sample_rate = mask->sample_rate;
|
sample_rate = mask.sample_rate;
|
||||||
|
|
||||||
if (mask->format != SAMPLE_FORMAT_UNDEFINED)
|
if (mask.format != SampleFormat::UNDEFINED)
|
||||||
af->format = mask->format;
|
format = mask.format;
|
||||||
|
|
||||||
if (mask->channels != 0)
|
if (mask.channels != 0)
|
||||||
af->channels = mask->channels;
|
channels = mask.channels;
|
||||||
|
|
||||||
assert(audio_format_valid(af));
|
assert(IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
sample_format_to_string(enum sample_format format)
|
sample_format_to_string(SampleFormat format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
return "?";
|
return "?";
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
return "8";
|
return "8";
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
return "16";
|
return "16";
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return "24";
|
return "24";
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
return "32";
|
return "32";
|
||||||
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return "f";
|
return "f";
|
||||||
|
|
||||||
case SAMPLE_FORMAT_DSD:
|
case SampleFormat::DSD:
|
||||||
return "dsd";
|
return "dsd";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,15 +72,14 @@ sample_format_to_string(enum sample_format format)
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
audio_format_to_string(const struct audio_format *af,
|
audio_format_to_string(const AudioFormat af,
|
||||||
struct audio_format_string *s)
|
struct audio_format_string *s)
|
||||||
{
|
{
|
||||||
assert(af != NULL);
|
assert(s != nullptr);
|
||||||
assert(s != NULL);
|
|
||||||
|
|
||||||
snprintf(s->buffer, sizeof(s->buffer), "%u:%s:%u",
|
snprintf(s->buffer, sizeof(s->buffer), "%u:%s:%u",
|
||||||
af->sample_rate, sample_format_to_string(af->format),
|
af.sample_rate, sample_format_to_string(af.format),
|
||||||
af->channels);
|
af.channels);
|
||||||
|
|
||||||
return s->buffer;
|
return s->buffer;
|
||||||
}
|
}
|
|
@ -0,0 +1,315 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2003-2013 The Music Player Daemon Project
|
||||||
|
* http://www.musicpd.org
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MPD_AUDIO_FORMAT_HXX
|
||||||
|
#define MPD_AUDIO_FORMAT_HXX
|
||||||
|
|
||||||
|
#include "gcc.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
|
||||||
|
/* on WIN32, "FLOAT" is already defined, and this triggers -Wshadow */
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wshadow"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum class SampleFormat : uint8_t {
|
||||||
|
UNDEFINED = 0,
|
||||||
|
|
||||||
|
S8,
|
||||||
|
S16,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signed 24 bit integer samples, packed in 32 bit integers
|
||||||
|
* (the most significant byte is filled with the sign bit).
|
||||||
|
*/
|
||||||
|
S24_P32,
|
||||||
|
|
||||||
|
S32,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 32 bit floating point samples in the host's format. The
|
||||||
|
* range is -1.0f to +1.0f.
|
||||||
|
*/
|
||||||
|
FLOAT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direct Stream Digital. 1-bit samples; each frame has one
|
||||||
|
* byte (8 samples) per channel.
|
||||||
|
*/
|
||||||
|
DSD,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr unsigned MAX_CHANNELS = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This structure describes the format of a raw PCM stream.
|
||||||
|
*/
|
||||||
|
struct AudioFormat {
|
||||||
|
/**
|
||||||
|
* The sample rate in Hz. A better name for this attribute is
|
||||||
|
* "frame rate", because technically, you have two samples per
|
||||||
|
* frame in stereo sound.
|
||||||
|
*/
|
||||||
|
uint32_t sample_rate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The format samples are stored in. See the #sample_format
|
||||||
|
* enum for valid values.
|
||||||
|
*/
|
||||||
|
SampleFormat format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of channels. Only mono (1) and stereo (2) are
|
||||||
|
* fully supported currently.
|
||||||
|
*/
|
||||||
|
uint8_t channels;
|
||||||
|
|
||||||
|
AudioFormat() = default;
|
||||||
|
|
||||||
|
constexpr AudioFormat(uint32_t _sample_rate,
|
||||||
|
SampleFormat _format, uint8_t _channels)
|
||||||
|
:sample_rate(_sample_rate),
|
||||||
|
format(_format), channels(_channels) {}
|
||||||
|
|
||||||
|
static constexpr AudioFormat Undefined() {
|
||||||
|
return AudioFormat(0, SampleFormat::UNDEFINED,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the #audio_format object, i.e. sets all attributes to an
|
||||||
|
* undefined (invalid) value.
|
||||||
|
*/
|
||||||
|
void Clear() {
|
||||||
|
sample_rate = 0;
|
||||||
|
format = SampleFormat::UNDEFINED;
|
||||||
|
channels = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the object has a defined value.
|
||||||
|
*/
|
||||||
|
constexpr bool IsDefined() const {
|
||||||
|
return sample_rate != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the object is full, i.e. all attributes are
|
||||||
|
* defined. This is more complete than IsDefined(), but
|
||||||
|
* slower.
|
||||||
|
*/
|
||||||
|
constexpr bool IsFullyDefined() const {
|
||||||
|
return sample_rate != 0 && format != SampleFormat::UNDEFINED &&
|
||||||
|
channels != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the object has at least one defined value.
|
||||||
|
*/
|
||||||
|
constexpr bool IsMaskDefined() const {
|
||||||
|
return sample_rate != 0 || format != SampleFormat::UNDEFINED ||
|
||||||
|
channels != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValid() const;
|
||||||
|
bool IsMaskValid() const;
|
||||||
|
|
||||||
|
constexpr bool operator==(const AudioFormat other) const {
|
||||||
|
return sample_rate == other.sample_rate &&
|
||||||
|
format == other.format &&
|
||||||
|
channels == other.channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool operator!=(const AudioFormat other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyMask(AudioFormat mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of each (mono) sample in bytes.
|
||||||
|
*/
|
||||||
|
unsigned GetSampleSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of each full frame in bytes.
|
||||||
|
*/
|
||||||
|
unsigned GetFrameSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the floating point factor which converts a time
|
||||||
|
* span to a storage size in bytes.
|
||||||
|
*/
|
||||||
|
double GetTimeToSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buffer for audio_format_string().
|
||||||
|
*/
|
||||||
|
struct audio_format_string {
|
||||||
|
char buffer[24];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the sample rate is valid.
|
||||||
|
*
|
||||||
|
* @param sample_rate the sample rate in Hz
|
||||||
|
*/
|
||||||
|
static constexpr inline bool
|
||||||
|
audio_valid_sample_rate(unsigned sample_rate)
|
||||||
|
{
|
||||||
|
return sample_rate > 0 && sample_rate < (1 << 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the sample format is valid.
|
||||||
|
*
|
||||||
|
* @param bits the number of significant bits per sample
|
||||||
|
*/
|
||||||
|
static inline bool
|
||||||
|
audio_valid_sample_format(SampleFormat format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case SampleFormat::S8:
|
||||||
|
case SampleFormat::S16:
|
||||||
|
case SampleFormat::S24_P32:
|
||||||
|
case SampleFormat::S32:
|
||||||
|
case SampleFormat::FLOAT:
|
||||||
|
case SampleFormat::DSD:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case SampleFormat::UNDEFINED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the number of channels is valid.
|
||||||
|
*/
|
||||||
|
static constexpr inline bool
|
||||||
|
audio_valid_channel_count(unsigned channels)
|
||||||
|
{
|
||||||
|
return channels >= 1 && channels <= MAX_CHANNELS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns false if the format is not valid for playback with MPD.
|
||||||
|
* This function performs some basic validity checks.
|
||||||
|
*/
|
||||||
|
inline bool
|
||||||
|
AudioFormat::IsValid() const
|
||||||
|
{
|
||||||
|
return audio_valid_sample_rate(sample_rate) &&
|
||||||
|
audio_valid_sample_format(format) &&
|
||||||
|
audio_valid_channel_count(channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns false if the format mask is not valid for playback with
|
||||||
|
* MPD. This function performs some basic validity checks.
|
||||||
|
*/
|
||||||
|
inline bool
|
||||||
|
AudioFormat::IsMaskValid() const
|
||||||
|
{
|
||||||
|
return (sample_rate == 0 ||
|
||||||
|
audio_valid_sample_rate(sample_rate)) &&
|
||||||
|
(format == SampleFormat::UNDEFINED ||
|
||||||
|
audio_valid_sample_format(format)) &&
|
||||||
|
(channels == 0 || audio_valid_channel_count(channels));
|
||||||
|
}
|
||||||
|
|
||||||
|
gcc_const
|
||||||
|
static inline unsigned
|
||||||
|
sample_format_size(SampleFormat format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case SampleFormat::S8:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case SampleFormat::S16:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case SampleFormat::S24_P32:
|
||||||
|
case SampleFormat::S32:
|
||||||
|
case SampleFormat::FLOAT:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case SampleFormat::DSD:
|
||||||
|
/* each frame has 8 samples per channel */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case SampleFormat::UNDEFINED:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(false);
|
||||||
|
gcc_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned
|
||||||
|
AudioFormat::GetSampleSize() const
|
||||||
|
{
|
||||||
|
return sample_format_size(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned
|
||||||
|
AudioFormat::GetFrameSize() const
|
||||||
|
{
|
||||||
|
return GetSampleSize() * channels;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double
|
||||||
|
AudioFormat::GetTimeToSize() const
|
||||||
|
{
|
||||||
|
return sample_rate * GetFrameSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a #sample_format enum into a string, e.g. for printing it
|
||||||
|
* in a log file.
|
||||||
|
*
|
||||||
|
* @param format a #sample_format enum value
|
||||||
|
* @return the string
|
||||||
|
*/
|
||||||
|
gcc_pure gcc_malloc
|
||||||
|
const char *
|
||||||
|
sample_format_to_string(SampleFormat format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the #audio_format object into a string, e.g. for printing
|
||||||
|
* it in a log file.
|
||||||
|
*
|
||||||
|
* @param af the #audio_format object
|
||||||
|
* @param s a buffer to print into
|
||||||
|
* @return the string, or NULL if the #audio_format object is invalid
|
||||||
|
*/
|
||||||
|
gcc_pure gcc_malloc
|
||||||
|
const char *
|
||||||
|
audio_format_to_string(AudioFormat af,
|
||||||
|
struct audio_format_string *s);
|
||||||
|
|
||||||
|
#endif
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "AudioParser.hxx"
|
#include "AudioParser.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "CheckAudioFormat.hxx"
|
#include "CheckAudioFormat.hxx"
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
|
||||||
|
@ -69,27 +69,27 @@ parse_sample_rate(const char *src, bool mask, uint32_t *sample_rate_r,
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
parse_sample_format(const char *src, bool mask,
|
parse_sample_format(const char *src, bool mask,
|
||||||
enum sample_format *sample_format_r,
|
SampleFormat *sample_format_r,
|
||||||
const char **endptr_r, GError **error_r)
|
const char **endptr_r, GError **error_r)
|
||||||
{
|
{
|
||||||
unsigned long value;
|
unsigned long value;
|
||||||
char *endptr;
|
char *endptr;
|
||||||
enum sample_format sample_format;
|
SampleFormat sample_format;
|
||||||
|
|
||||||
if (mask && *src == '*') {
|
if (mask && *src == '*') {
|
||||||
*sample_format_r = SAMPLE_FORMAT_UNDEFINED;
|
*sample_format_r = SampleFormat::UNDEFINED;
|
||||||
*endptr_r = src + 1;
|
*endptr_r = src + 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*src == 'f') {
|
if (*src == 'f') {
|
||||||
*sample_format_r = SAMPLE_FORMAT_FLOAT;
|
*sample_format_r = SampleFormat::FLOAT;
|
||||||
*endptr_r = src + 1;
|
*endptr_r = src + 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (memcmp(src, "dsd", 3) == 0) {
|
if (memcmp(src, "dsd", 3) == 0) {
|
||||||
*sample_format_r = SAMPLE_FORMAT_DSD;
|
*sample_format_r = SampleFormat::DSD;
|
||||||
*endptr_r = src + 3;
|
*endptr_r = src + 3;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -103,11 +103,11 @@ parse_sample_format(const char *src, bool mask,
|
||||||
|
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 8:
|
case 8:
|
||||||
sample_format = SAMPLE_FORMAT_S8;
|
sample_format = SampleFormat::S8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 16:
|
case 16:
|
||||||
sample_format = SAMPLE_FORMAT_S16;
|
sample_format = SampleFormat::S16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
|
@ -115,11 +115,11 @@ parse_sample_format(const char *src, bool mask,
|
||||||
/* for backwards compatibility */
|
/* for backwards compatibility */
|
||||||
endptr += 2;
|
endptr += 2;
|
||||||
|
|
||||||
sample_format = SAMPLE_FORMAT_S24_P32;
|
sample_format = SampleFormat::S24_P32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 32:
|
case 32:
|
||||||
sample_format = SAMPLE_FORMAT_S32;
|
sample_format = SampleFormat::S32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -162,14 +162,14 @@ parse_channel_count(const char *src, bool mask, uint8_t *channels_r,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_format_parse(struct audio_format *dest, const char *src,
|
audio_format_parse(AudioFormat &dest, const char *src,
|
||||||
bool mask, GError **error_r)
|
bool mask, GError **error_r)
|
||||||
{
|
{
|
||||||
uint32_t rate;
|
uint32_t rate;
|
||||||
enum sample_format sample_format;
|
SampleFormat sample_format;
|
||||||
uint8_t channels;
|
uint8_t channels;
|
||||||
|
|
||||||
audio_format_clear(dest);
|
dest.Clear();
|
||||||
|
|
||||||
/* parse sample rate */
|
/* parse sample rate */
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ audio_format_parse(struct audio_format *dest, const char *src,
|
||||||
|
|
||||||
#if GCC_CHECK_VERSION(4,7)
|
#if GCC_CHECK_VERSION(4,7)
|
||||||
/* workaround -Wmaybe-uninitialized false positive */
|
/* workaround -Wmaybe-uninitialized false positive */
|
||||||
sample_format = SAMPLE_FORMAT_UNDEFINED;
|
sample_format = SampleFormat::UNDEFINED;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!parse_sample_format(src, mask, &sample_format, &src, error_r))
|
if (!parse_sample_format(src, mask, &sample_format, &src, error_r))
|
||||||
|
@ -214,9 +214,10 @@ audio_format_parse(struct audio_format *dest, const char *src,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_format_init(dest, rate, sample_format, channels);
|
dest = AudioFormat(rate, sample_format, channels);
|
||||||
assert(mask ? audio_format_mask_valid(dest)
|
assert(mask
|
||||||
: audio_format_valid(dest));
|
? dest.IsMaskValid()
|
||||||
|
: dest.IsValid());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include "gerror.h"
|
#include "gerror.h"
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an
|
* Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an
|
||||||
|
@ -41,7 +41,7 @@ struct audio_format;
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
audio_format_parse(struct audio_format *dest, const char *src,
|
audio_format_parse(AudioFormat &dest, const char *src,
|
||||||
bool mask, GError **error_r);
|
bool mask, GError **error_r);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CheckAudioFormat.hxx"
|
#include "CheckAudioFormat.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
@ -35,11 +35,12 @@ audio_check_sample_rate(unsigned long sample_rate, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_check_sample_format(enum sample_format sample_format, GError **error_r)
|
audio_check_sample_format(SampleFormat sample_format, GError **error_r)
|
||||||
{
|
{
|
||||||
if (!audio_valid_sample_format(sample_format)) {
|
if (!audio_valid_sample_format(sample_format)) {
|
||||||
g_set_error(error_r, audio_format_quark(), 0,
|
g_set_error(error_r, audio_format_quark(), 0,
|
||||||
"Invalid sample format: %u", sample_format);
|
"Invalid sample format: %u",
|
||||||
|
unsigned(sample_format));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,15 +60,15 @@ audio_check_channel_count(unsigned channels, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_format_init_checked(struct audio_format *af, unsigned long sample_rate,
|
audio_format_init_checked(AudioFormat &af, unsigned long sample_rate,
|
||||||
enum sample_format sample_format, unsigned channels,
|
SampleFormat sample_format, unsigned channels,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
if (audio_check_sample_rate(sample_rate, error_r) &&
|
if (audio_check_sample_rate(sample_rate, error_r) &&
|
||||||
audio_check_sample_format(sample_format, error_r) &&
|
audio_check_sample_format(sample_format, error_r) &&
|
||||||
audio_check_channel_count(channels, error_r)) {
|
audio_check_channel_count(channels, error_r)) {
|
||||||
audio_format_init(af, sample_rate, sample_format, channels);
|
af = AudioFormat(sample_rate, sample_format, channels);
|
||||||
assert(audio_format_valid(af));
|
assert(af.IsValid());
|
||||||
return true;
|
return true;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef MPD_CHECK_AUDIO_FORMAT_HXX
|
#ifndef MPD_CHECK_AUDIO_FORMAT_HXX
|
||||||
#define MPD_CHECK_AUDIO_FORMAT_HXX
|
#define MPD_CHECK_AUDIO_FORMAT_HXX
|
||||||
|
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ bool
|
||||||
audio_check_sample_rate(unsigned long sample_rate, GError **error_r);
|
audio_check_sample_rate(unsigned long sample_rate, GError **error_r);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_check_sample_format(enum sample_format, GError **error_r);
|
audio_check_sample_format(SampleFormat sample_format, GError **error_r);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_check_channel_count(unsigned sample_format, GError **error_r);
|
audio_check_channel_count(unsigned sample_format, GError **error_r);
|
||||||
|
@ -47,8 +47,8 @@ audio_check_channel_count(unsigned sample_format, GError **error_r);
|
||||||
* Wrapper for audio_format_init(), which checks all attributes.
|
* Wrapper for audio_format_init(), which checks all attributes.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
audio_format_init_checked(struct audio_format *af, unsigned long sample_rate,
|
audio_format_init_checked(AudioFormat &af, unsigned long sample_rate,
|
||||||
enum sample_format sample_format, unsigned channels,
|
SampleFormat sample_format, unsigned channels,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "CrossFade.hxx"
|
#include "CrossFade.hxx"
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "Tag.hxx"
|
#include "Tag.hxx"
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
@ -97,8 +97,8 @@ unsigned cross_fade_calc(float duration, float total_time,
|
||||||
float mixramp_db, float mixramp_delay,
|
float mixramp_db, float mixramp_delay,
|
||||||
float replay_gain_db, float replay_gain_prev_db,
|
float replay_gain_db, float replay_gain_prev_db,
|
||||||
char *mixramp_start, char *mixramp_prev_end,
|
char *mixramp_start, char *mixramp_prev_end,
|
||||||
const struct audio_format *af,
|
const AudioFormat af,
|
||||||
const struct audio_format *old_format,
|
const AudioFormat old_format,
|
||||||
unsigned max_chunks)
|
unsigned max_chunks)
|
||||||
{
|
{
|
||||||
unsigned int chunks = 0;
|
unsigned int chunks = 0;
|
||||||
|
@ -107,13 +107,13 @@ unsigned cross_fade_calc(float duration, float total_time,
|
||||||
|
|
||||||
if (duration < 0 || duration >= total_time ||
|
if (duration < 0 || duration >= total_time ||
|
||||||
/* we can't crossfade when the audio formats are different */
|
/* we can't crossfade when the audio formats are different */
|
||||||
!audio_format_equals(af, old_format))
|
af != old_format)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
assert(duration >= 0);
|
assert(duration >= 0);
|
||||||
assert(audio_format_valid(af));
|
assert(af.IsValid());
|
||||||
|
|
||||||
chunks_f = (float)audio_format_time_to_size(af) / (float)CHUNK_SIZE;
|
chunks_f = (float)af.GetTimeToSize() / (float)CHUNK_SIZE;
|
||||||
|
|
||||||
if (std::isnan(mixramp_delay) || !mixramp_start || !mixramp_prev_end) {
|
if (std::isnan(mixramp_delay) || !mixramp_start || !mixramp_prev_end) {
|
||||||
chunks = (chunks_f * duration + 0.5);
|
chunks = (chunks_f * duration + 0.5);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef MPD_CROSSFADE_HXX
|
#ifndef MPD_CROSSFADE_HXX
|
||||||
#define MPD_CROSSFADE_HXX
|
#define MPD_CROSSFADE_HXX
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
struct music_chunk;
|
struct music_chunk;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,8 +44,7 @@ unsigned cross_fade_calc(float duration, float total_time,
|
||||||
float mixramp_db, float mixramp_delay,
|
float mixramp_db, float mixramp_delay,
|
||||||
float replay_gain_db, float replay_gain_prev_db,
|
float replay_gain_db, float replay_gain_prev_db,
|
||||||
char *mixramp_start, char *mixramp_prev_end,
|
char *mixramp_start, char *mixramp_prev_end,
|
||||||
const struct audio_format *af,
|
AudioFormat af, AudioFormat old_format,
|
||||||
const struct audio_format *old_format,
|
|
||||||
unsigned max_chunks);
|
unsigned max_chunks);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
void
|
void
|
||||||
decoder_initialized(struct decoder *decoder,
|
decoder_initialized(struct decoder *decoder,
|
||||||
const struct audio_format *audio_format,
|
const AudioFormat audio_format,
|
||||||
bool seekable, float total_time)
|
bool seekable, float total_time)
|
||||||
{
|
{
|
||||||
struct decoder_control *dc = decoder->dc;
|
struct decoder_control *dc = decoder->dc;
|
||||||
|
@ -52,12 +52,11 @@ decoder_initialized(struct decoder *decoder,
|
||||||
assert(decoder->stream_tag == NULL);
|
assert(decoder->stream_tag == NULL);
|
||||||
assert(decoder->decoder_tag == NULL);
|
assert(decoder->decoder_tag == NULL);
|
||||||
assert(!decoder->seeking);
|
assert(!decoder->seeking);
|
||||||
assert(audio_format != NULL);
|
assert(audio_format.IsDefined());
|
||||||
assert(audio_format_defined(audio_format));
|
assert(audio_format.IsValid());
|
||||||
assert(audio_format_valid(audio_format));
|
|
||||||
|
|
||||||
dc->in_audio_format = *audio_format;
|
dc->in_audio_format = audio_format;
|
||||||
getOutputAudioFormat(audio_format, &dc->out_audio_format);
|
dc->out_audio_format = getOutputAudioFormat(audio_format);
|
||||||
|
|
||||||
dc->seekable = seekable;
|
dc->seekable = seekable;
|
||||||
dc->total_time = total_time;
|
dc->total_time = total_time;
|
||||||
|
@ -68,13 +67,12 @@ decoder_initialized(struct decoder *decoder,
|
||||||
dc->Unlock();
|
dc->Unlock();
|
||||||
|
|
||||||
g_debug("audio_format=%s, seekable=%s",
|
g_debug("audio_format=%s, seekable=%s",
|
||||||
audio_format_to_string(&dc->in_audio_format, &af_string),
|
audio_format_to_string(dc->in_audio_format, &af_string),
|
||||||
seekable ? "true" : "false");
|
seekable ? "true" : "false");
|
||||||
|
|
||||||
if (!audio_format_equals(&dc->in_audio_format,
|
if (dc->in_audio_format != dc->out_audio_format)
|
||||||
&dc->out_audio_format))
|
|
||||||
g_debug("converting to %s",
|
g_debug("converting to %s",
|
||||||
audio_format_to_string(&dc->out_audio_format,
|
audio_format_to_string(dc->out_audio_format,
|
||||||
&af_string));
|
&af_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,7 +369,7 @@ decoder_data(struct decoder *decoder,
|
||||||
|
|
||||||
assert(dc->state == DECODE_STATE_DECODE);
|
assert(dc->state == DECODE_STATE_DECODE);
|
||||||
assert(dc->pipe != NULL);
|
assert(dc->pipe != NULL);
|
||||||
assert(length % audio_format_frame_size(&dc->in_audio_format) == 0);
|
assert(length % dc->in_audio_format.GetFrameSize() == 0);
|
||||||
|
|
||||||
dc->Lock();
|
dc->Lock();
|
||||||
cmd = decoder_get_virtual_command(decoder);
|
cmd = decoder_get_virtual_command(decoder);
|
||||||
|
@ -398,10 +396,10 @@ decoder_data(struct decoder *decoder,
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!audio_format_equals(&dc->in_audio_format, &dc->out_audio_format)) {
|
if (dc->in_audio_format != dc->out_audio_format) {
|
||||||
data = decoder->conv_state.Convert(&dc->in_audio_format,
|
data = decoder->conv_state.Convert(dc->in_audio_format,
|
||||||
data, length,
|
data, length,
|
||||||
&dc->out_audio_format,
|
dc->out_audio_format,
|
||||||
&length,
|
&length,
|
||||||
&error);
|
&error);
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
|
@ -457,7 +455,7 @@ decoder_data(struct decoder *decoder,
|
||||||
length -= nbytes;
|
length -= nbytes;
|
||||||
|
|
||||||
decoder->timestamp += (double)nbytes /
|
decoder->timestamp += (double)nbytes /
|
||||||
audio_format_time_to_size(&dc->out_audio_format);
|
dc->out_audio_format.GetTimeToSize();
|
||||||
|
|
||||||
if (dc->end_ms > 0 &&
|
if (dc->end_ms > 0 &&
|
||||||
decoder->timestamp >= dc->end_ms / 1000.0)
|
decoder->timestamp >= dc->end_ms / 1000.0)
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include "input_stream.h"
|
#include "input_stream.h"
|
||||||
#include "replay_gain_info.h"
|
#include "replay_gain_info.h"
|
||||||
#include "Tag.hxx"
|
#include "Tag.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,7 @@
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
decoder_initialized(struct decoder *decoder,
|
decoder_initialized(struct decoder *decoder,
|
||||||
const struct audio_format *audio_format,
|
AudioFormat audio_format,
|
||||||
bool seekable, float total_time);
|
bool seekable, float total_time);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define MPD_DECODER_CONTROL_HXX
|
#define MPD_DECODER_CONTROL_HXX
|
||||||
|
|
||||||
#include "DecoderCommand.hxx"
|
#include "DecoderCommand.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
|
@ -85,10 +85,10 @@ struct decoder_control {
|
||||||
double seek_where;
|
double seek_where;
|
||||||
|
|
||||||
/** the format of the song file */
|
/** the format of the song file */
|
||||||
struct audio_format in_audio_format;
|
AudioFormat in_audio_format;
|
||||||
|
|
||||||
/** the format being sent to the music pipe */
|
/** the format being sent to the music pipe */
|
||||||
struct audio_format out_audio_format;
|
AudioFormat out_audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The song currently being decoded. This attribute is set by
|
* The song currently being decoded. This attribute is set by
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#define MPD_ENCODER_API_HXX
|
#define MPD_ENCODER_API_HXX
|
||||||
|
|
||||||
#include "EncoderPlugin.hxx"
|
#include "EncoderPlugin.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "Tag.hxx"
|
#include "Tag.hxx"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct EncoderPlugin;
|
struct EncoderPlugin;
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
struct config_param;
|
struct config_param;
|
||||||
struct Tag;
|
struct Tag;
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ struct EncoderPlugin {
|
||||||
void (*finish)(Encoder *encoder);
|
void (*finish)(Encoder *encoder);
|
||||||
|
|
||||||
bool (*open)(Encoder *encoder,
|
bool (*open)(Encoder *encoder,
|
||||||
struct audio_format *audio_format,
|
AudioFormat &audio_format,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
void (*close)(Encoder *encoder);
|
void (*close)(Encoder *encoder);
|
||||||
|
@ -122,7 +122,7 @@ encoder_finish(Encoder *encoder)
|
||||||
* @return true on success
|
* @return true on success
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
encoder_open(Encoder *encoder, struct audio_format *audio_format,
|
encoder_open(Encoder *encoder, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
assert(!encoder->open);
|
assert(!encoder->open);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#ifndef MPD_FILTER_INTERNAL_HXX
|
#ifndef MPD_FILTER_INTERNAL_HXX
|
||||||
#define MPD_FILTER_INTERNAL_HXX
|
#define MPD_FILTER_INTERNAL_HXX
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
|
@ -40,10 +40,10 @@ public:
|
||||||
* format
|
* format
|
||||||
* @param error location to store the error occurring, or NULL
|
* @param error location to store the error occurring, or NULL
|
||||||
* to ignore errors.
|
* to ignore errors.
|
||||||
* @return the format of outgoing data
|
* @return the format of outgoing data or
|
||||||
|
* AudioFormat::Undefined() on error
|
||||||
*/
|
*/
|
||||||
virtual const audio_format *Open(audio_format &af,
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) = 0;
|
||||||
GError **error_r) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the filter. After that, you may call Open() again.
|
* Closes the filter. After that, you may call Open() again.
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "Tag.hxx"
|
#include "Tag.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -31,22 +31,21 @@ music_chunk::~music_chunk()
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
bool
|
bool
|
||||||
music_chunk::CheckFormat(const struct audio_format &other_format) const
|
music_chunk::CheckFormat(const AudioFormat other_format) const
|
||||||
{
|
{
|
||||||
assert(audio_format_valid(&other_format));
|
assert(other_format.IsValid());
|
||||||
|
|
||||||
return length == 0 ||
|
return length == 0 || audio_format == other_format;
|
||||||
audio_format_equals(&audio_format, &other_format);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *
|
void *
|
||||||
music_chunk::Write(const struct audio_format &af,
|
music_chunk::Write(const AudioFormat af,
|
||||||
float data_time, uint16_t _bit_rate,
|
float data_time, uint16_t _bit_rate,
|
||||||
size_t *max_length_r)
|
size_t *max_length_r)
|
||||||
{
|
{
|
||||||
assert(CheckFormat(af));
|
assert(CheckFormat(af));
|
||||||
assert(length == 0 || audio_format_valid(&audio_format));
|
assert(length == 0 || audio_format.IsValid());
|
||||||
|
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
/* if the chunk is empty, nobody has set bitRate and
|
/* if the chunk is empty, nobody has set bitRate and
|
||||||
|
@ -56,7 +55,7 @@ music_chunk::Write(const struct audio_format &af,
|
||||||
times = data_time;
|
times = data_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t frame_size = audio_format_frame_size(&af);
|
const size_t frame_size = af.GetFrameSize();
|
||||||
size_t num_frames = (sizeof(data) - length) / frame_size;
|
size_t num_frames = (sizeof(data) - length) / frame_size;
|
||||||
if (num_frames == 0)
|
if (num_frames == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -70,12 +69,12 @@ music_chunk::Write(const struct audio_format &af,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
music_chunk::Expand(const struct audio_format &af, size_t _length)
|
music_chunk::Expand(const AudioFormat af, size_t _length)
|
||||||
{
|
{
|
||||||
const size_t frame_size = audio_format_frame_size(&af);
|
const size_t frame_size = af.GetFrameSize();
|
||||||
|
|
||||||
assert(length + _length <= sizeof(data));
|
assert(length + _length <= sizeof(data));
|
||||||
assert(audio_format_equals(&audio_format, &af));
|
assert(audio_format == af);
|
||||||
|
|
||||||
length += _length;
|
length += _length;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "replay_gain_info.h"
|
#include "replay_gain_info.h"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -33,7 +33,7 @@ enum {
|
||||||
CHUNK_SIZE = 4096,
|
CHUNK_SIZE = 4096,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
struct Tag;
|
struct Tag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,7 +90,7 @@ struct music_chunk {
|
||||||
char data[CHUNK_SIZE];
|
char data[CHUNK_SIZE];
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
music_chunk()
|
music_chunk()
|
||||||
|
@ -111,7 +111,7 @@ struct music_chunk {
|
||||||
* specified audio_format.
|
* specified audio_format.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool CheckFormat(const struct audio_format &audio_format) const;
|
bool CheckFormat(AudioFormat audio_format) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,7 +128,7 @@ struct music_chunk {
|
||||||
* here
|
* here
|
||||||
* @return a writable buffer, or NULL if the chunk is full
|
* @return a writable buffer, or NULL if the chunk is full
|
||||||
*/
|
*/
|
||||||
void *Write(const struct audio_format &af,
|
void *Write(AudioFormat af,
|
||||||
float data_time, uint16_t bit_rate,
|
float data_time, uint16_t bit_rate,
|
||||||
size_t *max_length_r);
|
size_t *max_length_r);
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ struct music_chunk {
|
||||||
* @param length the number of bytes which were appended
|
* @param length the number of bytes which were appended
|
||||||
* @return true if the chunk is full
|
* @return true if the chunk is full
|
||||||
*/
|
*/
|
||||||
bool Expand(const struct audio_format &af, size_t length);
|
bool Expand(AudioFormat af, size_t length);
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -41,13 +41,13 @@ struct music_pipe {
|
||||||
mutable Mutex mutex;
|
mutable Mutex mutex;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
music_pipe()
|
music_pipe()
|
||||||
:head(nullptr), tail_r(&head), size(0) {
|
:head(nullptr), tail_r(&head), size(0) {
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
audio_format_clear(&audio_format);
|
audio_format.Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,13 +73,12 @@ music_pipe_free(struct music_pipe *mp)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
music_pipe_check_format(const struct music_pipe *pipe,
|
music_pipe_check_format(const struct music_pipe *pipe,
|
||||||
const struct audio_format *audio_format)
|
const AudioFormat audio_format)
|
||||||
{
|
{
|
||||||
assert(pipe != NULL);
|
assert(pipe != NULL);
|
||||||
assert(audio_format != NULL);
|
|
||||||
|
|
||||||
return !audio_format_defined(&pipe->audio_format) ||
|
return !pipe->audio_format.IsDefined() ||
|
||||||
audio_format_equals(&pipe->audio_format, audio_format);
|
pipe->audio_format == audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -131,7 +130,7 @@ music_pipe_shift(struct music_pipe *mp)
|
||||||
chunk->next = (struct music_chunk *)(void *)0x01010101;
|
chunk->next = (struct music_chunk *)(void *)0x01010101;
|
||||||
|
|
||||||
if (mp->size == 0)
|
if (mp->size == 0)
|
||||||
audio_format_clear(&mp->audio_format);
|
mp->audio_format.Clear();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,16 +150,16 @@ void
|
||||||
music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk)
|
music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk)
|
||||||
{
|
{
|
||||||
assert(!chunk->IsEmpty());
|
assert(!chunk->IsEmpty());
|
||||||
assert(chunk->length == 0 || audio_format_valid(&chunk->audio_format));
|
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
||||||
|
|
||||||
const ScopeLock protect(mp->mutex);
|
const ScopeLock protect(mp->mutex);
|
||||||
|
|
||||||
assert(mp->size > 0 || !audio_format_defined(&mp->audio_format));
|
assert(mp->size > 0 || !mp->audio_format.IsDefined());
|
||||||
assert(!audio_format_defined(&mp->audio_format) ||
|
assert(!mp->audio_format.IsDefined() ||
|
||||||
chunk->CheckFormat(mp->audio_format));
|
chunk->CheckFormat(mp->audio_format));
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (!audio_format_defined(&mp->audio_format) && chunk->length > 0)
|
if (!mp->audio_format.IsDefined() && chunk->length > 0)
|
||||||
mp->audio_format = chunk->audio_format;
|
mp->audio_format = chunk->audio_format;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct music_chunk;
|
struct music_chunk;
|
||||||
|
@ -56,7 +56,7 @@ music_pipe_free(struct music_pipe *mp);
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
music_pipe_check_format(const struct music_pipe *pipe,
|
music_pipe_check_format(const struct music_pipe *pipe,
|
||||||
const struct audio_format *audio_format);
|
AudioFormat audio_format);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the specified chunk is enqueued in the music pipe.
|
* Checks if the specified chunk is enqueued in the music pipe.
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
|
|
||||||
#include "OutputPlugin.hxx"
|
#include "OutputPlugin.hxx"
|
||||||
#include "OutputInternal.hxx"
|
#include "OutputInternal.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "Tag.hxx"
|
#include "Tag.hxx"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "output"
|
#define G_LOG_DOMAIN "output"
|
||||||
|
|
||||||
static struct audio_format input_audio_format;
|
static AudioFormat input_audio_format;
|
||||||
|
|
||||||
static struct audio_output **audio_outputs;
|
static struct audio_output **audio_outputs;
|
||||||
static unsigned int num_audio_outputs;
|
static unsigned int num_audio_outputs;
|
||||||
|
@ -246,12 +246,12 @@ audio_output_all_update(void)
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
if (!audio_format_defined(&input_audio_format))
|
if (!input_audio_format.IsDefined())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (i = 0; i < num_audio_outputs; ++i)
|
for (i = 0; i < num_audio_outputs; ++i)
|
||||||
ret = audio_output_update(audio_outputs[i],
|
ret = audio_output_update(audio_outputs[i],
|
||||||
&input_audio_format, g_mp) || ret;
|
input_audio_format, g_mp) || ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -291,14 +291,13 @@ audio_output_all_play(struct music_chunk *chunk, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_output_all_open(const struct audio_format *audio_format,
|
audio_output_all_open(const AudioFormat audio_format,
|
||||||
struct music_buffer *buffer,
|
struct music_buffer *buffer,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
bool ret = false, enabled = false;
|
bool ret = false, enabled = false;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
assert(audio_format != NULL);
|
|
||||||
assert(buffer != NULL);
|
assert(buffer != NULL);
|
||||||
assert(g_music_buffer == NULL || g_music_buffer == buffer);
|
assert(g_music_buffer == NULL || g_music_buffer == buffer);
|
||||||
assert((g_mp == NULL) == (g_music_buffer == NULL));
|
assert((g_mp == NULL) == (g_music_buffer == NULL));
|
||||||
|
@ -315,10 +314,9 @@ audio_output_all_open(const struct audio_format *audio_format,
|
||||||
/* if the pipe hasn't been cleared, the the audio
|
/* if the pipe hasn't been cleared, the the audio
|
||||||
format must not have changed */
|
format must not have changed */
|
||||||
assert(music_pipe_empty(g_mp) ||
|
assert(music_pipe_empty(g_mp) ||
|
||||||
audio_format_equals(audio_format,
|
audio_format == input_audio_format);
|
||||||
&input_audio_format));
|
|
||||||
|
|
||||||
input_audio_format = *audio_format;
|
input_audio_format = audio_format;
|
||||||
|
|
||||||
audio_output_all_reset_reopen();
|
audio_output_all_reset_reopen();
|
||||||
audio_output_all_enable_disable();
|
audio_output_all_enable_disable();
|
||||||
|
@ -547,7 +545,7 @@ audio_output_all_close(void)
|
||||||
|
|
||||||
g_music_buffer = NULL;
|
g_music_buffer = NULL;
|
||||||
|
|
||||||
audio_format_clear(&input_audio_format);
|
input_audio_format.Clear();
|
||||||
|
|
||||||
audio_output_all_elapsed_time = -1.0;
|
audio_output_all_elapsed_time = -1.0;
|
||||||
}
|
}
|
||||||
|
@ -570,7 +568,7 @@ audio_output_all_release(void)
|
||||||
|
|
||||||
g_music_buffer = NULL;
|
g_music_buffer = NULL;
|
||||||
|
|
||||||
audio_format_clear(&input_audio_format);
|
input_audio_format.Clear();
|
||||||
|
|
||||||
audio_output_all_elapsed_time = -1.0;
|
audio_output_all_elapsed_time = -1.0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "replay_gain_info.h"
|
#include "replay_gain_info.h"
|
||||||
#include "gerror.h"
|
#include "gerror.h"
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
struct music_buffer;
|
struct music_buffer;
|
||||||
struct music_chunk;
|
struct music_chunk;
|
||||||
struct player_control;
|
struct player_control;
|
||||||
|
@ -76,14 +76,13 @@ audio_output_all_enable_disable(void);
|
||||||
/**
|
/**
|
||||||
* Opens all audio outputs which are not disabled.
|
* Opens all audio outputs which are not disabled.
|
||||||
*
|
*
|
||||||
* @param audio_format the preferred audio format, or NULL to reuse
|
* @param audio_format the preferred audio format
|
||||||
* the previous format
|
|
||||||
* @param buffer the #music_buffer where consumed #music_chunk objects
|
* @param buffer the #music_buffer where consumed #music_chunk objects
|
||||||
* should be returned
|
* should be returned
|
||||||
* @return true on success, false on failure
|
* @return true on success, false on failure
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
audio_output_all_open(const struct audio_format *audio_format,
|
audio_output_all_open(AudioFormat audio_format,
|
||||||
struct music_buffer *buffer,
|
struct music_buffer *buffer,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
|
|
|
@ -139,14 +139,14 @@ audio_output_disable(struct audio_output *ao)
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
audio_output_open(struct audio_output *ao,
|
audio_output_open(struct audio_output *ao,
|
||||||
const struct audio_format *audio_format,
|
const AudioFormat audio_format,
|
||||||
const struct music_pipe *mp)
|
const struct music_pipe *mp)
|
||||||
{
|
{
|
||||||
bool open;
|
bool open;
|
||||||
|
|
||||||
assert(ao != NULL);
|
assert(ao != NULL);
|
||||||
assert(ao->allow_play);
|
assert(ao->allow_play);
|
||||||
assert(audio_format_valid(audio_format));
|
assert(audio_format.IsValid());
|
||||||
assert(mp != NULL);
|
assert(mp != NULL);
|
||||||
|
|
||||||
if (ao->fail_timer != NULL) {
|
if (ao->fail_timer != NULL) {
|
||||||
|
@ -154,8 +154,7 @@ audio_output_open(struct audio_output *ao,
|
||||||
ao->fail_timer = NULL;
|
ao->fail_timer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ao->open &&
|
if (ao->open && audio_format == ao->in_audio_format) {
|
||||||
audio_format_equals(audio_format, &ao->in_audio_format)) {
|
|
||||||
assert(ao->pipe == mp ||
|
assert(ao->pipe == mp ||
|
||||||
(ao->always_on && ao->pause));
|
(ao->always_on && ao->pause));
|
||||||
|
|
||||||
|
@ -176,7 +175,7 @@ audio_output_open(struct audio_output *ao,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ao->in_audio_format = *audio_format;
|
ao->in_audio_format = audio_format;
|
||||||
ao->chunk = NULL;
|
ao->chunk = NULL;
|
||||||
|
|
||||||
ao->pipe = mp;
|
ao->pipe = mp;
|
||||||
|
@ -225,7 +224,7 @@ audio_output_close_locked(struct audio_output *ao)
|
||||||
|
|
||||||
bool
|
bool
|
||||||
audio_output_update(struct audio_output *ao,
|
audio_output_update(struct audio_output *ao,
|
||||||
const struct audio_format *audio_format,
|
const AudioFormat audio_format,
|
||||||
const struct music_pipe *mp)
|
const struct music_pipe *mp)
|
||||||
{
|
{
|
||||||
assert(mp != NULL);
|
assert(mp != NULL);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct audio_output;
|
struct audio_output;
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
struct config_param;
|
struct config_param;
|
||||||
struct music_pipe;
|
struct music_pipe;
|
||||||
struct player_control;
|
struct player_control;
|
||||||
|
@ -53,7 +53,7 @@ audio_output_disable(struct audio_output *ao);
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
audio_output_update(struct audio_output *ao,
|
audio_output_update(struct audio_output *ao,
|
||||||
const struct audio_format *audio_format,
|
AudioFormat audio_format,
|
||||||
const struct music_pipe *mp);
|
const struct music_pipe *mp);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -155,16 +155,16 @@ ao_base_init(struct audio_output *ao,
|
||||||
NULL);
|
NULL);
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
bool success =
|
bool success =
|
||||||
audio_format_parse(&ao->config_audio_format,
|
audio_format_parse(ao->config_audio_format,
|
||||||
p, true, error_r);
|
p, true, error_r);
|
||||||
if (!success)
|
if (!success)
|
||||||
return false;
|
return false;
|
||||||
} else
|
} else
|
||||||
audio_format_clear(&ao->config_audio_format);
|
ao->config_audio_format.Clear();
|
||||||
} else {
|
} else {
|
||||||
ao->name = "default detected output";
|
ao->name = "default detected output";
|
||||||
|
|
||||||
audio_format_clear(&ao->config_audio_format);
|
ao->config_audio_format.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ao->plugin = plugin;
|
ao->plugin = plugin;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef MPD_OUTPUT_INTERNAL_HXX
|
#ifndef MPD_OUTPUT_INTERNAL_HXX
|
||||||
#define MPD_OUTPUT_INTERNAL_HXX
|
#define MPD_OUTPUT_INTERNAL_HXX
|
||||||
|
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "pcm/PcmBuffer.hxx"
|
#include "pcm/PcmBuffer.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
|
@ -134,13 +134,13 @@ struct audio_output {
|
||||||
/**
|
/**
|
||||||
* The configured audio format.
|
* The configured audio format.
|
||||||
*/
|
*/
|
||||||
struct audio_format config_audio_format;
|
AudioFormat config_audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The audio_format in which audio data is received from the
|
* The audio_format in which audio data is received from the
|
||||||
* player thread (which in turn receives it from the decoder).
|
* player thread (which in turn receives it from the decoder).
|
||||||
*/
|
*/
|
||||||
struct audio_format in_audio_format;
|
AudioFormat in_audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The audio_format which is really sent to the device. This
|
* The audio_format which is really sent to the device. This
|
||||||
|
@ -148,7 +148,7 @@ struct audio_output {
|
||||||
* in_audio_format, but may have been modified by
|
* in_audio_format, but may have been modified by
|
||||||
* plugin->open().
|
* plugin->open().
|
||||||
*/
|
*/
|
||||||
struct audio_format out_audio_format;
|
AudioFormat out_audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The buffer used to allocate the cross-fading result.
|
* The buffer used to allocate the cross-fading result.
|
||||||
|
|
|
@ -54,7 +54,7 @@ ao_plugin_disable(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ao_plugin_open(struct audio_output *ao, struct audio_format *audio_format,
|
ao_plugin_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
return ao->plugin->open(ao, audio_format, error);
|
return ao->plugin->open(ao, audio_format, error);
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
struct config_param;
|
struct config_param;
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
struct Tag;
|
struct Tag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +89,7 @@ struct audio_output_plugin {
|
||||||
* @param error location to store the error occurring, or NULL
|
* @param error location to store the error occurring, or NULL
|
||||||
* to ignore errors
|
* to ignore errors
|
||||||
*/
|
*/
|
||||||
bool (*open)(struct audio_output *data, struct audio_format *audio_format,
|
bool (*open)(struct audio_output *data, AudioFormat &audio_format,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,7 +181,7 @@ void
|
||||||
ao_plugin_disable(struct audio_output *ao);
|
ao_plugin_disable(struct audio_output *ao);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ao_plugin_open(struct audio_output *ao, struct audio_format *audio_format,
|
ao_plugin_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -94,11 +94,11 @@ ao_disable(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct audio_format *
|
static AudioFormat
|
||||||
ao_filter_open(struct audio_output *ao, audio_format &format,
|
ao_filter_open(struct audio_output *ao, AudioFormat &format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
assert(audio_format_valid(&format));
|
assert(format.IsValid());
|
||||||
|
|
||||||
/* the replay_gain filter cannot fail here */
|
/* the replay_gain filter cannot fail here */
|
||||||
if (ao->replay_gain_filter != NULL)
|
if (ao->replay_gain_filter != NULL)
|
||||||
|
@ -106,9 +106,8 @@ ao_filter_open(struct audio_output *ao, audio_format &format,
|
||||||
if (ao->other_replay_gain_filter != NULL)
|
if (ao->other_replay_gain_filter != NULL)
|
||||||
ao->other_replay_gain_filter->Open(format, error_r);
|
ao->other_replay_gain_filter->Open(format, error_r);
|
||||||
|
|
||||||
const struct audio_format *af
|
const AudioFormat af = ao->filter->Open(format, error_r);
|
||||||
= ao->filter->Open(format, error_r);
|
if (!af.IsDefined()) {
|
||||||
if (af == NULL) {
|
|
||||||
if (ao->replay_gain_filter != NULL)
|
if (ao->replay_gain_filter != NULL)
|
||||||
ao->replay_gain_filter->Close();
|
ao->replay_gain_filter->Close();
|
||||||
if (ao->other_replay_gain_filter != NULL)
|
if (ao->other_replay_gain_filter != NULL)
|
||||||
|
@ -139,7 +138,7 @@ ao_open(struct audio_output *ao)
|
||||||
assert(!ao->open);
|
assert(!ao->open);
|
||||||
assert(ao->pipe != NULL);
|
assert(ao->pipe != NULL);
|
||||||
assert(ao->chunk == NULL);
|
assert(ao->chunk == NULL);
|
||||||
assert(audio_format_valid(&ao->in_audio_format));
|
assert(ao->in_audio_format.IsValid());
|
||||||
|
|
||||||
if (ao->fail_timer != NULL) {
|
if (ao->fail_timer != NULL) {
|
||||||
/* this can only happen when this
|
/* this can only happen when this
|
||||||
|
@ -158,9 +157,9 @@ ao_open(struct audio_output *ao)
|
||||||
|
|
||||||
/* open the filter */
|
/* open the filter */
|
||||||
|
|
||||||
const audio_format *filter_audio_format =
|
const AudioFormat filter_audio_format =
|
||||||
ao_filter_open(ao, ao->in_audio_format, &error);
|
ao_filter_open(ao, ao->in_audio_format, &error);
|
||||||
if (filter_audio_format == NULL) {
|
if (!filter_audio_format.IsDefined()) {
|
||||||
g_warning("Failed to open filter for \"%s\" [%s]: %s",
|
g_warning("Failed to open filter for \"%s\" [%s]: %s",
|
||||||
ao->name, ao->plugin->name, error->message);
|
ao->name, ao->plugin->name, error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -169,14 +168,13 @@ ao_open(struct audio_output *ao)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(audio_format_valid(filter_audio_format));
|
assert(filter_audio_format.IsValid());
|
||||||
|
|
||||||
ao->out_audio_format = *filter_audio_format;
|
ao->out_audio_format = filter_audio_format;
|
||||||
audio_format_mask_apply(&ao->out_audio_format,
|
ao->out_audio_format.ApplyMask(ao->config_audio_format);
|
||||||
&ao->config_audio_format);
|
|
||||||
|
|
||||||
ao->mutex.unlock();
|
ao->mutex.unlock();
|
||||||
success = ao_plugin_open(ao, &ao->out_audio_format, &error);
|
success = ao_plugin_open(ao, ao->out_audio_format, &error);
|
||||||
ao->mutex.lock();
|
ao->mutex.lock();
|
||||||
|
|
||||||
assert(!ao->open);
|
assert(!ao->open);
|
||||||
|
@ -198,12 +196,11 @@ ao_open(struct audio_output *ao)
|
||||||
g_debug("opened plugin=%s name=\"%s\" "
|
g_debug("opened plugin=%s name=\"%s\" "
|
||||||
"audio_format=%s",
|
"audio_format=%s",
|
||||||
ao->plugin->name, ao->name,
|
ao->plugin->name, ao->name,
|
||||||
audio_format_to_string(&ao->out_audio_format, &af_string));
|
audio_format_to_string(ao->out_audio_format, &af_string));
|
||||||
|
|
||||||
if (!audio_format_equals(&ao->in_audio_format,
|
if (ao->in_audio_format != ao->out_audio_format)
|
||||||
&ao->out_audio_format))
|
|
||||||
g_debug("converting from %s",
|
g_debug("converting from %s",
|
||||||
audio_format_to_string(&ao->in_audio_format,
|
audio_format_to_string(ao->in_audio_format,
|
||||||
&af_string));
|
&af_string));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,12 +232,12 @@ ao_close(struct audio_output *ao, bool drain)
|
||||||
static void
|
static void
|
||||||
ao_reopen_filter(struct audio_output *ao)
|
ao_reopen_filter(struct audio_output *ao)
|
||||||
{
|
{
|
||||||
const struct audio_format *filter_audio_format;
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
|
||||||
ao_filter_close(ao);
|
ao_filter_close(ao);
|
||||||
filter_audio_format = ao_filter_open(ao, ao->in_audio_format, &error);
|
const AudioFormat filter_audio_format =
|
||||||
if (filter_audio_format == NULL) {
|
ao_filter_open(ao, ao->in_audio_format, &error);
|
||||||
|
if (!filter_audio_format.IsDefined()) {
|
||||||
g_warning("Failed to open filter for \"%s\" [%s]: %s",
|
g_warning("Failed to open filter for \"%s\" [%s]: %s",
|
||||||
ao->name, ao->plugin->name, error->message);
|
ao->name, ao->plugin->name, error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -268,7 +265,7 @@ ao_reopen_filter(struct audio_output *ao)
|
||||||
static void
|
static void
|
||||||
ao_reopen(struct audio_output *ao)
|
ao_reopen(struct audio_output *ao)
|
||||||
{
|
{
|
||||||
if (!audio_format_fully_defined(&ao->config_audio_format)) {
|
if (!ao->config_audio_format.IsFullyDefined()) {
|
||||||
if (ao->open) {
|
if (ao->open) {
|
||||||
const struct music_pipe *mp = ao->pipe;
|
const struct music_pipe *mp = ao->pipe;
|
||||||
ao_close(ao, true);
|
ao_close(ao, true);
|
||||||
|
@ -279,8 +276,7 @@ ao_reopen(struct audio_output *ao)
|
||||||
the output's open() method determine the effective
|
the output's open() method determine the effective
|
||||||
out_audio_format */
|
out_audio_format */
|
||||||
ao->out_audio_format = ao->in_audio_format;
|
ao->out_audio_format = ao->in_audio_format;
|
||||||
audio_format_mask_apply(&ao->out_audio_format,
|
ao->out_audio_format.ApplyMask(ao->config_audio_format);
|
||||||
&ao->config_audio_format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ao->open)
|
if (ao->open)
|
||||||
|
@ -327,7 +323,7 @@ ao_chunk_data(struct audio_output *ao, const struct music_chunk *chunk,
|
||||||
|
|
||||||
(void)ao;
|
(void)ao;
|
||||||
|
|
||||||
assert(length % audio_format_frame_size(&ao->in_audio_format) == 0);
|
assert(length % ao->in_audio_format.GetFrameSize() == 0);
|
||||||
|
|
||||||
if (length > 0 && replay_gain_filter != NULL) {
|
if (length > 0 && replay_gain_filter != NULL) {
|
||||||
if (chunk->replay_gain_serial != *replay_gain_serial_p) {
|
if (chunk->replay_gain_serial != *replay_gain_serial_p) {
|
||||||
|
@ -399,10 +395,10 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
|
||||||
void *dest = ao->cross_fade_buffer.Get(other_length);
|
void *dest = ao->cross_fade_buffer.Get(other_length);
|
||||||
memcpy(dest, other_data, other_length);
|
memcpy(dest, other_data, other_length);
|
||||||
if (!pcm_mix(dest, data, length,
|
if (!pcm_mix(dest, data, length,
|
||||||
sample_format(ao->in_audio_format.format),
|
ao->in_audio_format.format,
|
||||||
1.0 - chunk->mix_ratio)) {
|
1.0 - chunk->mix_ratio)) {
|
||||||
g_warning("Cannot cross-fade format %s",
|
g_warning("Cannot cross-fade format %s",
|
||||||
sample_format_to_string(sample_format(ao->in_audio_format.format)));
|
sample_format_to_string(ao->in_audio_format.format));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +475,7 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(nbytes <= size);
|
assert(nbytes <= size);
|
||||||
assert(nbytes % audio_format_frame_size(&ao->out_audio_format) == 0);
|
assert(nbytes % ao->out_audio_format.GetFrameSize() == 0);
|
||||||
|
|
||||||
data += nbytes;
|
data += nbytes;
|
||||||
size -= nbytes;
|
size -= nbytes;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "protocol/ArgParser.hxx"
|
#include "protocol/ArgParser.hxx"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "replay_gain_config.h"
|
#include "replay_gain_config.h"
|
||||||
|
@ -178,12 +178,12 @@ handle_status(Client *client,
|
||||||
player_status.elapsed_time,
|
player_status.elapsed_time,
|
||||||
player_status.bit_rate);
|
player_status.bit_rate);
|
||||||
|
|
||||||
if (audio_format_defined(&player_status.audio_format)) {
|
if (player_status.audio_format.IsDefined()) {
|
||||||
struct audio_format_string af_string;
|
struct audio_format_string af_string;
|
||||||
|
|
||||||
client_printf(client,
|
client_printf(client,
|
||||||
COMMAND_STATUS_AUDIO ": %s\n",
|
COMMAND_STATUS_AUDIO ": %s\n",
|
||||||
audio_format_to_string(&player_status.audio_format,
|
audio_format_to_string(player_status.audio_format,
|
||||||
&af_string));
|
&af_string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#ifndef MPD_PLAYER_H
|
#ifndef MPD_PLAYER_H
|
||||||
#define MPD_PLAYER_H
|
#define MPD_PLAYER_H
|
||||||
|
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "thread/Cond.hxx"
|
#include "thread/Cond.hxx"
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ enum player_error {
|
||||||
struct player_status {
|
struct player_status {
|
||||||
enum player_state state;
|
enum player_state state;
|
||||||
uint16_t bit_rate;
|
uint16_t bit_rate;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
float total_time;
|
float total_time;
|
||||||
float elapsed_time;
|
float elapsed_time;
|
||||||
};
|
};
|
||||||
|
@ -130,7 +130,7 @@ struct player_control {
|
||||||
GError *error;
|
GError *error;
|
||||||
|
|
||||||
uint16_t bit_rate;
|
uint16_t bit_rate;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
float total_time;
|
float total_time;
|
||||||
float elapsed_time;
|
float elapsed_time;
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ struct player {
|
||||||
/**
|
/**
|
||||||
* The current audio format for the audio outputs.
|
* The current audio format for the audio outputs.
|
||||||
*/
|
*/
|
||||||
struct audio_format play_audio_format;
|
AudioFormat play_audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time stamp of the chunk most recently sent to the
|
* The time stamp of the chunk most recently sent to the
|
||||||
|
@ -279,7 +279,7 @@ player_wait_for_decoder(struct player *player)
|
||||||
/* update player_control's song information */
|
/* update player_control's song information */
|
||||||
pc->total_time = pc->next_song->GetDuration();
|
pc->total_time = pc->next_song->GetDuration();
|
||||||
pc->bit_rate = 0;
|
pc->bit_rate = 0;
|
||||||
audio_format_clear(&pc->audio_format);
|
pc->audio_format.Clear();
|
||||||
|
|
||||||
/* clear the queued song */
|
/* clear the queued song */
|
||||||
pc->next_song = NULL;
|
pc->next_song = NULL;
|
||||||
|
@ -323,12 +323,12 @@ player_open_output(struct player *player)
|
||||||
{
|
{
|
||||||
struct player_control *pc = player->pc;
|
struct player_control *pc = player->pc;
|
||||||
|
|
||||||
assert(audio_format_defined(&player->play_audio_format));
|
assert(player->play_audio_format.IsDefined());
|
||||||
assert(pc->state == PLAYER_STATE_PLAY ||
|
assert(pc->state == PLAYER_STATE_PLAY ||
|
||||||
pc->state == PLAYER_STATE_PAUSE);
|
pc->state == PLAYER_STATE_PAUSE);
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
if (audio_output_all_open(&player->play_audio_format, player_buffer,
|
if (audio_output_all_open(player->play_audio_format, player_buffer,
|
||||||
&error)) {
|
&error)) {
|
||||||
player->output_open = true;
|
player->output_open = true;
|
||||||
player->paused = false;
|
player->paused = false;
|
||||||
|
@ -439,7 +439,7 @@ static bool
|
||||||
player_send_silence(struct player *player)
|
player_send_silence(struct player *player)
|
||||||
{
|
{
|
||||||
assert(player->output_open);
|
assert(player->output_open);
|
||||||
assert(audio_format_defined(&player->play_audio_format));
|
assert(player->play_audio_format.IsDefined());
|
||||||
|
|
||||||
struct music_chunk *chunk = music_buffer_allocate(player_buffer);
|
struct music_chunk *chunk = music_buffer_allocate(player_buffer);
|
||||||
if (chunk == NULL) {
|
if (chunk == NULL) {
|
||||||
|
@ -451,8 +451,7 @@ player_send_silence(struct player *player)
|
||||||
chunk->audio_format = player->play_audio_format;
|
chunk->audio_format = player->play_audio_format;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t frame_size =
|
const size_t frame_size = player->play_audio_format.GetFrameSize();
|
||||||
audio_format_frame_size(&player->play_audio_format);
|
|
||||||
/* this formula ensures that we don't send
|
/* this formula ensures that we don't send
|
||||||
partial frames */
|
partial frames */
|
||||||
unsigned num_frames = sizeof(chunk->data) / frame_size;
|
unsigned num_frames = sizeof(chunk->data) / frame_size;
|
||||||
|
@ -597,7 +596,7 @@ static void player_process_command(struct player *player)
|
||||||
pc->Lock();
|
pc->Lock();
|
||||||
|
|
||||||
pc->state = PLAYER_STATE_PAUSE;
|
pc->state = PLAYER_STATE_PAUSE;
|
||||||
} else if (!audio_format_defined(&player->play_audio_format)) {
|
} else if (!player->play_audio_format.IsDefined()) {
|
||||||
/* the decoder hasn't provided an audio format
|
/* the decoder hasn't provided an audio format
|
||||||
yet - don't open the audio device yet */
|
yet - don't open the audio device yet */
|
||||||
pc->Lock();
|
pc->Lock();
|
||||||
|
@ -689,10 +688,10 @@ update_song_tag(Song *song, const Tag &new_tag)
|
||||||
static bool
|
static bool
|
||||||
play_chunk(struct player_control *pc,
|
play_chunk(struct player_control *pc,
|
||||||
Song *song, struct music_chunk *chunk,
|
Song *song, struct music_chunk *chunk,
|
||||||
const struct audio_format *format,
|
const AudioFormat format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
assert(chunk->CheckFormat(*format));
|
assert(chunk->CheckFormat(format));
|
||||||
|
|
||||||
if (chunk->tag != NULL)
|
if (chunk->tag != NULL)
|
||||||
update_song_tag(song, *chunk->tag);
|
update_song_tag(song, *chunk->tag);
|
||||||
|
@ -712,7 +711,7 @@ play_chunk(struct player_control *pc,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pc->total_play_time += (double)chunk->length /
|
pc->total_play_time += (double)chunk->length /
|
||||||
audio_format_time_to_size(format);
|
format.GetTimeToSize();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,7 +824,7 @@ play_next_chunk(struct player *player)
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
if (!play_chunk(player->pc, player->song, chunk,
|
if (!play_chunk(player->pc, player->song, chunk,
|
||||||
&player->play_audio_format, &error)) {
|
player->play_audio_format, &error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
|
|
||||||
music_buffer_return(player_buffer, chunk);
|
music_buffer_return(player_buffer, chunk);
|
||||||
|
@ -1019,8 +1018,8 @@ static void do_play(struct player_control *pc, struct decoder_control *dc)
|
||||||
dc->replay_gain_prev_db,
|
dc->replay_gain_prev_db,
|
||||||
dc->mixramp_start,
|
dc->mixramp_start,
|
||||||
dc->mixramp_prev_end,
|
dc->mixramp_prev_end,
|
||||||
&dc->out_audio_format,
|
dc->out_audio_format,
|
||||||
&player.play_audio_format,
|
player.play_audio_format,
|
||||||
music_buffer_size(player_buffer) -
|
music_buffer_size(player_buffer) -
|
||||||
pc->buffered_before_play);
|
pc->buffered_before_play);
|
||||||
if (player.cross_fade_chunks > 0) {
|
if (player.cross_fade_chunks > 0) {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Timer.hxx"
|
#include "Timer.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
@ -28,10 +28,10 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
Timer::Timer(const struct audio_format &af)
|
Timer::Timer(const AudioFormat af)
|
||||||
: time(0),
|
: time(0),
|
||||||
started(false),
|
started(false),
|
||||||
rate(af.sample_rate * audio_format_frame_size(&af))
|
rate(af.sample_rate * af.GetFrameSize())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,14 +22,14 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
|
|
||||||
class Timer {
|
class Timer {
|
||||||
uint64_t time;
|
uint64_t time;
|
||||||
bool started;
|
bool started;
|
||||||
const int rate;
|
const int rate;
|
||||||
public:
|
public:
|
||||||
explicit Timer(const struct audio_format& af);
|
explicit Timer(AudioFormat af);
|
||||||
|
|
||||||
bool IsStarted() const { return started; }
|
bool IsStarted() const { return started; }
|
||||||
|
|
||||||
|
|
|
@ -1,316 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2003-2011 The Music Player Daemon Project
|
|
||||||
* http://www.musicpd.org
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPD_AUDIO_FORMAT_H
|
|
||||||
#define MPD_AUDIO_FORMAT_H
|
|
||||||
|
|
||||||
#include "gcc.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
enum sample_format {
|
|
||||||
SAMPLE_FORMAT_UNDEFINED = 0,
|
|
||||||
|
|
||||||
SAMPLE_FORMAT_S8,
|
|
||||||
SAMPLE_FORMAT_S16,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signed 24 bit integer samples, packed in 32 bit integers
|
|
||||||
* (the most significant byte is filled with the sign bit).
|
|
||||||
*/
|
|
||||||
SAMPLE_FORMAT_S24_P32,
|
|
||||||
|
|
||||||
SAMPLE_FORMAT_S32,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 32 bit floating point samples in the host's format. The
|
|
||||||
* range is -1.0f to +1.0f.
|
|
||||||
*/
|
|
||||||
SAMPLE_FORMAT_FLOAT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct Stream Digital. 1-bit samples; each frame has one
|
|
||||||
* byte (8 samples) per channel.
|
|
||||||
*/
|
|
||||||
SAMPLE_FORMAT_DSD,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned MAX_CHANNELS = 8;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This structure describes the format of a raw PCM stream.
|
|
||||||
*/
|
|
||||||
struct audio_format {
|
|
||||||
/**
|
|
||||||
* The sample rate in Hz. A better name for this attribute is
|
|
||||||
* "frame rate", because technically, you have two samples per
|
|
||||||
* frame in stereo sound.
|
|
||||||
*/
|
|
||||||
uint32_t sample_rate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The format samples are stored in. See the #sample_format
|
|
||||||
* enum for valid values.
|
|
||||||
*/
|
|
||||||
uint8_t format;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of channels. Only mono (1) and stereo (2) are
|
|
||||||
* fully supported currently.
|
|
||||||
*/
|
|
||||||
uint8_t channels;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffer for audio_format_string().
|
|
||||||
*/
|
|
||||||
struct audio_format_string {
|
|
||||||
char buffer[24];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the #audio_format object, i.e. sets all attributes to an
|
|
||||||
* undefined (invalid) value.
|
|
||||||
*/
|
|
||||||
static inline void audio_format_clear(struct audio_format *af)
|
|
||||||
{
|
|
||||||
af->sample_rate = 0;
|
|
||||||
af->format = SAMPLE_FORMAT_UNDEFINED;
|
|
||||||
af->channels = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes an #audio_format object, i.e. sets all
|
|
||||||
* attributes to valid values.
|
|
||||||
*/
|
|
||||||
static inline void audio_format_init(struct audio_format *af,
|
|
||||||
uint32_t sample_rate,
|
|
||||||
enum sample_format format, uint8_t channels)
|
|
||||||
{
|
|
||||||
af->sample_rate = sample_rate;
|
|
||||||
af->format = (uint8_t)format;
|
|
||||||
af->channels = channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the specified #audio_format object has a defined
|
|
||||||
* value.
|
|
||||||
*/
|
|
||||||
static inline bool audio_format_defined(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return af->sample_rate != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the specified #audio_format object is full, i.e. all
|
|
||||||
* attributes are defined. This is more complete than
|
|
||||||
* audio_format_defined(), but slower.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
audio_format_fully_defined(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return af->sample_rate != 0 && af->format != SAMPLE_FORMAT_UNDEFINED &&
|
|
||||||
af->channels != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the specified #audio_format object has at least one
|
|
||||||
* defined value.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
audio_format_mask_defined(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return af->sample_rate != 0 || af->format != SAMPLE_FORMAT_UNDEFINED ||
|
|
||||||
af->channels != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the sample rate is valid.
|
|
||||||
*
|
|
||||||
* @param sample_rate the sample rate in Hz
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
audio_valid_sample_rate(unsigned sample_rate)
|
|
||||||
{
|
|
||||||
return sample_rate > 0 && sample_rate < (1 << 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the sample format is valid.
|
|
||||||
*
|
|
||||||
* @param bits the number of significant bits per sample
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
audio_valid_sample_format(enum sample_format format)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case SAMPLE_FORMAT_S8:
|
|
||||||
case SAMPLE_FORMAT_S16:
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
|
||||||
case SAMPLE_FORMAT_S32:
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
|
||||||
case SAMPLE_FORMAT_DSD:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the number of channels is valid.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
audio_valid_channel_count(unsigned channels)
|
|
||||||
{
|
|
||||||
return channels >= 1 && channels <= MAX_CHANNELS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns false if the format is not valid for playback with MPD.
|
|
||||||
* This function performs some basic validity checks.
|
|
||||||
*/
|
|
||||||
gcc_pure
|
|
||||||
static inline bool audio_format_valid(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return audio_valid_sample_rate(af->sample_rate) &&
|
|
||||||
audio_valid_sample_format((enum sample_format)af->format) &&
|
|
||||||
audio_valid_channel_count(af->channels);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns false if the format mask is not valid for playback with
|
|
||||||
* MPD. This function performs some basic validity checks.
|
|
||||||
*/
|
|
||||||
gcc_pure
|
|
||||||
static inline bool audio_format_mask_valid(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return (af->sample_rate == 0 ||
|
|
||||||
audio_valid_sample_rate(af->sample_rate)) &&
|
|
||||||
(af->format == SAMPLE_FORMAT_UNDEFINED ||
|
|
||||||
audio_valid_sample_format((enum sample_format)af->format)) &&
|
|
||||||
(af->channels == 0 || audio_valid_channel_count(af->channels));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool audio_format_equals(const struct audio_format *a,
|
|
||||||
const struct audio_format *b)
|
|
||||||
{
|
|
||||||
return a->sample_rate == b->sample_rate &&
|
|
||||||
a->format == b->format &&
|
|
||||||
a->channels == b->channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
audio_format_mask_apply(struct audio_format *af,
|
|
||||||
const struct audio_format *mask);
|
|
||||||
|
|
||||||
gcc_const
|
|
||||||
static inline unsigned
|
|
||||||
sample_format_size(enum sample_format format)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case SAMPLE_FORMAT_S8:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
|
||||||
case SAMPLE_FORMAT_S32:
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_DSD:
|
|
||||||
/* each frame has 8 samples per channel */
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(false);
|
|
||||||
gcc_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size of each (mono) sample in bytes.
|
|
||||||
*/
|
|
||||||
gcc_pure
|
|
||||||
static inline unsigned audio_format_sample_size(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return sample_format_size((enum sample_format)af->format);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the size of each full frame in bytes.
|
|
||||||
*/
|
|
||||||
gcc_pure
|
|
||||||
static inline unsigned
|
|
||||||
audio_format_frame_size(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return audio_format_sample_size(af) * af->channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the floating point factor which converts a time span to a
|
|
||||||
* storage size in bytes.
|
|
||||||
*/
|
|
||||||
gcc_pure
|
|
||||||
static inline double audio_format_time_to_size(const struct audio_format *af)
|
|
||||||
{
|
|
||||||
return af->sample_rate * audio_format_frame_size(af);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders a #sample_format enum into a string, e.g. for printing it
|
|
||||||
* in a log file.
|
|
||||||
*
|
|
||||||
* @param format a #sample_format enum value
|
|
||||||
* @return the string
|
|
||||||
*/
|
|
||||||
gcc_pure gcc_malloc
|
|
||||||
const char *
|
|
||||||
sample_format_to_string(enum sample_format format);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders the #audio_format object into a string, e.g. for printing
|
|
||||||
* it in a log file.
|
|
||||||
*
|
|
||||||
* @param af the #audio_format object
|
|
||||||
* @param s a buffer to print into
|
|
||||||
* @return the string, or NULL if the #audio_format object is invalid
|
|
||||||
*/
|
|
||||||
gcc_pure gcc_malloc
|
|
||||||
const char *
|
|
||||||
audio_format_to_string(const struct audio_format *af,
|
|
||||||
struct audio_format_string *s);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -60,11 +60,10 @@ adplug_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
if (player == nullptr)
|
if (player == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
struct audio_format audio_format;
|
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
|
||||||
audio_format_init(&audio_format, sample_rate, SAMPLE_FORMAT_S16, 2);
|
assert(audio_format.IsValid());
|
||||||
assert(audio_format_valid(&audio_format));
|
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, false,
|
decoder_initialized(decoder, audio_format, false,
|
||||||
player->songlength() / 1000.);
|
player->songlength() / 1000.);
|
||||||
|
|
||||||
int16_t buffer[2048];
|
int16_t buffer[2048];
|
||||||
|
|
|
@ -114,27 +114,27 @@ setup_virtual_fops(struct input_stream *stream)
|
||||||
return vf;
|
return vf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum sample_format
|
static SampleFormat
|
||||||
audiofile_bits_to_sample_format(int bits)
|
audiofile_bits_to_sample_format(int bits)
|
||||||
{
|
{
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 8:
|
case 8:
|
||||||
return SAMPLE_FORMAT_S8;
|
return SampleFormat::S8;
|
||||||
|
|
||||||
case 16:
|
case 16:
|
||||||
return SAMPLE_FORMAT_S16;
|
return SampleFormat::S16;
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
return SAMPLE_FORMAT_S24_P32;
|
return SampleFormat::S24_P32;
|
||||||
|
|
||||||
case 32:
|
case 32:
|
||||||
return SAMPLE_FORMAT_S32;
|
return SampleFormat::S32;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SAMPLE_FORMAT_UNDEFINED;
|
return SampleFormat::UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum sample_format
|
static SampleFormat
|
||||||
audiofile_setup_sample_format(AFfilehandle af_fp)
|
audiofile_setup_sample_format(AFfilehandle af_fp)
|
||||||
{
|
{
|
||||||
int fs, bits;
|
int fs, bits;
|
||||||
|
@ -160,7 +160,7 @@ audiofile_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
AFvirtualfile *vf;
|
AFvirtualfile *vf;
|
||||||
int fs, frame_count;
|
int fs, frame_count;
|
||||||
AFfilehandle af_fp;
|
AFfilehandle af_fp;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
float total_time;
|
float total_time;
|
||||||
uint16_t bit_rate;
|
uint16_t bit_rate;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -180,7 +180,7 @@ audiofile_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!audio_format_init_checked(&audio_format,
|
if (!audio_format_init_checked(audio_format,
|
||||||
afGetRate(af_fp, AF_DEFAULT_TRACK),
|
afGetRate(af_fp, AF_DEFAULT_TRACK),
|
||||||
audiofile_setup_sample_format(af_fp),
|
audiofile_setup_sample_format(af_fp),
|
||||||
afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK),
|
afGetVirtualChannels(af_fp, AF_DEFAULT_TRACK),
|
||||||
|
@ -199,7 +199,7 @@ audiofile_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
|
|
||||||
fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1);
|
fs = (int)afGetVirtualFrameSize(af_fp, AF_DEFAULT_TRACK, 1);
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, true, total_time);
|
decoder_initialized(decoder, audio_format, true, total_time);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk,
|
ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk,
|
||||||
|
|
|
@ -433,9 +433,9 @@ dsdiff_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8,
|
if (!audio_format_init_checked(audio_format, metadata.sample_rate / 8,
|
||||||
SAMPLE_FORMAT_DSD,
|
SampleFormat::DSD,
|
||||||
metadata.channels, &error)) {
|
metadata.channels, &error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -448,7 +448,7 @@ dsdiff_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
(float) metadata.sample_rate;
|
(float) metadata.sample_rate;
|
||||||
|
|
||||||
/* success: file was recognized */
|
/* success: file was recognized */
|
||||||
decoder_initialized(decoder, &audio_format, false, songtime);
|
decoder_initialized(decoder, audio_format, false, songtime);
|
||||||
|
|
||||||
/* every iteration of the following loop decodes one "DSD"
|
/* every iteration of the following loop decodes one "DSD"
|
||||||
chunk from a DFF file */
|
chunk from a DFF file */
|
||||||
|
@ -487,9 +487,9 @@ dsdiff_scan_stream(struct input_stream *is,
|
||||||
if (!dsdiff_read_metadata(nullptr, is, &metadata, &chunk_header))
|
if (!dsdiff_read_metadata(nullptr, is, &metadata, &chunk_header))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8,
|
if (!audio_format_init_checked(audio_format, metadata.sample_rate / 8,
|
||||||
SAMPLE_FORMAT_DSD,
|
SampleFormat::DSD,
|
||||||
metadata.channels, nullptr))
|
metadata.channels, nullptr))
|
||||||
/* refuse to parse files which we cannot play anyway */
|
/* refuse to parse files which we cannot play anyway */
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -285,9 +285,9 @@ dsf_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8,
|
if (!audio_format_init_checked(audio_format, metadata.sample_rate / 8,
|
||||||
SAMPLE_FORMAT_DSD,
|
SampleFormat::DSD,
|
||||||
metadata.channels, &error)) {
|
metadata.channels, &error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -299,7 +299,7 @@ dsf_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
(float) metadata.sample_rate;
|
(float) metadata.sample_rate;
|
||||||
|
|
||||||
/* success: file was recognized */
|
/* success: file was recognized */
|
||||||
decoder_initialized(decoder, &audio_format, false, songtime);
|
decoder_initialized(decoder, audio_format, false, songtime);
|
||||||
|
|
||||||
if (!dsf_decode_chunk(decoder, is, metadata.channels,
|
if (!dsf_decode_chunk(decoder, is, metadata.channels,
|
||||||
chunk_size,
|
chunk_size,
|
||||||
|
@ -317,9 +317,9 @@ dsf_scan_stream(struct input_stream *is,
|
||||||
if (!dsf_read_metadata(NULL, is, &metadata))
|
if (!dsf_read_metadata(NULL, is, &metadata))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, metadata.sample_rate / 8,
|
if (!audio_format_init_checked(audio_format, metadata.sample_rate / 8,
|
||||||
SAMPLE_FORMAT_DSD,
|
SampleFormat::DSD,
|
||||||
metadata.channels, NULL))
|
metadata.channels, NULL))
|
||||||
/* refuse to parse files which we cannot play anyway */
|
/* refuse to parse files which we cannot play anyway */
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -248,7 +248,7 @@ faad_song_duration(DecoderBuffer *buffer, struct input_stream *is)
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
|
faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
|
||||||
struct audio_format *audio_format, GError **error_r)
|
AudioFormat &audio_format, GError **error_r)
|
||||||
{
|
{
|
||||||
int32_t nbytes;
|
int32_t nbytes;
|
||||||
uint32_t sample_rate;
|
uint32_t sample_rate;
|
||||||
|
@ -285,7 +285,7 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
|
||||||
decoder_buffer_consume(buffer, nbytes);
|
decoder_buffer_consume(buffer, nbytes);
|
||||||
|
|
||||||
return audio_format_init_checked(audio_format, sample_rate,
|
return audio_format_init_checked(audio_format, sample_rate,
|
||||||
SAMPLE_FORMAT_S16, channels, error_r);
|
SampleFormat::S16, channels, error_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -325,7 +325,7 @@ faad_get_file_time_float(struct input_stream *is)
|
||||||
|
|
||||||
if (length < 0) {
|
if (length < 0) {
|
||||||
bool ret;
|
bool ret;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
|
|
||||||
NeAACDecHandle decoder = NeAACDecOpen();
|
NeAACDecHandle decoder = NeAACDecOpen();
|
||||||
|
|
||||||
|
@ -336,7 +336,7 @@ faad_get_file_time_float(struct input_stream *is)
|
||||||
|
|
||||||
decoder_buffer_fill(buffer);
|
decoder_buffer_fill(buffer);
|
||||||
|
|
||||||
ret = faad_decoder_init(decoder, buffer, &audio_format, nullptr);
|
ret = faad_decoder_init(decoder, buffer, audio_format, nullptr);
|
||||||
if (ret)
|
if (ret)
|
||||||
length = 0;
|
length = 0;
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ faad_stream_decode(struct decoder *mpd_decoder, struct input_stream *is)
|
||||||
{
|
{
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
float total_time = 0;
|
float total_time = 0;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
bool ret;
|
bool ret;
|
||||||
uint16_t bit_rate = 0;
|
uint16_t bit_rate = 0;
|
||||||
DecoderBuffer *buffer;
|
DecoderBuffer *buffer;
|
||||||
|
@ -400,7 +400,7 @@ faad_stream_decode(struct decoder *mpd_decoder, struct input_stream *is)
|
||||||
|
|
||||||
/* initialize it */
|
/* initialize it */
|
||||||
|
|
||||||
ret = faad_decoder_init(decoder, buffer, &audio_format, &error);
|
ret = faad_decoder_init(decoder, buffer, audio_format, &error);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -410,7 +410,7 @@ faad_stream_decode(struct decoder *mpd_decoder, struct input_stream *is)
|
||||||
|
|
||||||
/* initialize the MPD core */
|
/* initialize the MPD core */
|
||||||
|
|
||||||
decoder_initialized(mpd_decoder, &audio_format, false, total_time);
|
decoder_initialized(mpd_decoder, audio_format, false, total_time);
|
||||||
|
|
||||||
/* the decoder loop */
|
/* the decoder loop */
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,11 @@ extern "C" {
|
||||||
#undef G_LOG_DOMAIN
|
#undef G_LOG_DOMAIN
|
||||||
#define G_LOG_DOMAIN "ffmpeg"
|
#define G_LOG_DOMAIN "ffmpeg"
|
||||||
|
|
||||||
|
/* suppress the ffmpeg compatibility macro */
|
||||||
|
#ifdef SampleFormat
|
||||||
|
#undef SampleFormat
|
||||||
|
#endif
|
||||||
|
|
||||||
static GLogLevelFlags
|
static GLogLevelFlags
|
||||||
level_ffmpeg_to_glib(int level)
|
level_ffmpeg_to_glib(int level)
|
||||||
{
|
{
|
||||||
|
@ -297,20 +302,20 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
|
||||||
}
|
}
|
||||||
|
|
||||||
G_GNUC_CONST
|
G_GNUC_CONST
|
||||||
static enum sample_format
|
static SampleFormat
|
||||||
ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
|
ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
|
||||||
{
|
{
|
||||||
switch (sample_fmt) {
|
switch (sample_fmt) {
|
||||||
case AV_SAMPLE_FMT_S16:
|
case AV_SAMPLE_FMT_S16:
|
||||||
case AV_SAMPLE_FMT_S16P:
|
case AV_SAMPLE_FMT_S16P:
|
||||||
return SAMPLE_FORMAT_S16;
|
return SampleFormat::S16;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_S32:
|
case AV_SAMPLE_FMT_S32:
|
||||||
case AV_SAMPLE_FMT_S32P:
|
case AV_SAMPLE_FMT_S32P:
|
||||||
return SAMPLE_FORMAT_S32;
|
return SampleFormat::S32;
|
||||||
|
|
||||||
case AV_SAMPLE_FMT_FLTP:
|
case AV_SAMPLE_FMT_FLTP:
|
||||||
return SAMPLE_FORMAT_FLOAT;
|
return SampleFormat::FLOAT;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -325,7 +330,7 @@ ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
|
||||||
else
|
else
|
||||||
g_warning("Unsupported libavcodec SampleFormat value: %d",
|
g_warning("Unsupported libavcodec SampleFormat value: %d",
|
||||||
sample_fmt);
|
sample_fmt);
|
||||||
return SAMPLE_FORMAT_UNDEFINED;
|
return SampleFormat::UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AVInputFormat *
|
static AVInputFormat *
|
||||||
|
@ -420,14 +425,14 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum sample_format sample_format =
|
const SampleFormat sample_format =
|
||||||
ffmpeg_sample_format(codec_context->sample_fmt);
|
ffmpeg_sample_format(codec_context->sample_fmt);
|
||||||
if (sample_format == SAMPLE_FORMAT_UNDEFINED)
|
if (sample_format == SampleFormat::UNDEFINED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format,
|
if (!audio_format_init_checked(audio_format,
|
||||||
codec_context->sample_rate,
|
codec_context->sample_rate,
|
||||||
sample_format,
|
sample_format,
|
||||||
codec_context->channels, &error)) {
|
codec_context->channels, &error)) {
|
||||||
|
@ -455,7 +460,7 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
|
||||||
? format_context->duration / AV_TIME_BASE
|
? format_context->duration / AV_TIME_BASE
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format,
|
decoder_initialized(decoder, audio_format,
|
||||||
input->seekable, total_time);
|
input->seekable, total_time);
|
||||||
|
|
||||||
AVFrame *frame = avcodec_alloc_frame();
|
AVFrame *frame = avcodec_alloc_frame();
|
||||||
|
|
|
@ -26,6 +26,11 @@ extern "C" {
|
||||||
#include <libavutil/dict.h>
|
#include <libavutil/dict.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* suppress the ffmpeg compatibility macro */
|
||||||
|
#ifdef SampleFormat
|
||||||
|
#undef SampleFormat
|
||||||
|
#endif
|
||||||
|
|
||||||
struct tag_handler;
|
struct tag_handler;
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -40,24 +40,24 @@ flac_data::flac_data(struct decoder *_decoder,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum sample_format
|
static SampleFormat
|
||||||
flac_sample_format(unsigned bits_per_sample)
|
flac_sample_format(unsigned bits_per_sample)
|
||||||
{
|
{
|
||||||
switch (bits_per_sample) {
|
switch (bits_per_sample) {
|
||||||
case 8:
|
case 8:
|
||||||
return SAMPLE_FORMAT_S8;
|
return SampleFormat::S8;
|
||||||
|
|
||||||
case 16:
|
case 16:
|
||||||
return SAMPLE_FORMAT_S16;
|
return SampleFormat::S16;
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
return SAMPLE_FORMAT_S24_P32;
|
return SampleFormat::S24_P32;
|
||||||
|
|
||||||
case 32:
|
case 32:
|
||||||
return SAMPLE_FORMAT_S32;
|
return SampleFormat::S32;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SAMPLE_FORMAT_UNDEFINED;
|
return SampleFormat::UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ flac_got_stream_info(struct flac_data *data,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
if (!audio_format_init_checked(&data->audio_format,
|
if (!audio_format_init_checked(data->audio_format,
|
||||||
stream_info->sample_rate,
|
stream_info->sample_rate,
|
||||||
flac_sample_format(stream_info->bits_per_sample),
|
flac_sample_format(stream_info->bits_per_sample),
|
||||||
stream_info->channels, &error)) {
|
stream_info->channels, &error)) {
|
||||||
|
@ -79,7 +79,7 @@ flac_got_stream_info(struct flac_data *data,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->frame_size = audio_format_frame_size(&data->audio_format);
|
data->frame_size = data->audio_format.GetFrameSize();
|
||||||
|
|
||||||
if (data->total_frames == 0)
|
if (data->total_frames == 0)
|
||||||
data->total_frames = stream_info->total_samples;
|
data->total_frames = stream_info->total_samples;
|
||||||
|
@ -132,7 +132,7 @@ flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
if (!audio_format_init_checked(&data->audio_format,
|
if (!audio_format_init_checked(data->audio_format,
|
||||||
header->sample_rate,
|
header->sample_rate,
|
||||||
flac_sample_format(header->bits_per_sample),
|
flac_sample_format(header->bits_per_sample),
|
||||||
header->channels, &error)) {
|
header->channels, &error)) {
|
||||||
|
@ -142,9 +142,9 @@ flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->frame_size = audio_format_frame_size(&data->audio_format);
|
data->frame_size = data->audio_format.GetFrameSize();
|
||||||
|
|
||||||
decoder_initialized(data->decoder, &data->audio_format,
|
decoder_initialized(data->decoder, data->audio_format,
|
||||||
data->input_stream->seekable,
|
data->input_stream->seekable,
|
||||||
(float)data->total_frames /
|
(float)data->total_frames /
|
||||||
(float)data->audio_format.sample_rate);
|
(float)data->audio_format.sample_rate);
|
||||||
|
@ -170,7 +170,7 @@ flac_common_write(struct flac_data *data, const FLAC__Frame * frame,
|
||||||
buffer = data->buffer.Get(buffer_size);
|
buffer = data->buffer.Get(buffer_size);
|
||||||
|
|
||||||
flac_convert(buffer, frame->header.channels,
|
flac_convert(buffer, frame->header.channels,
|
||||||
(enum sample_format)data->audio_format.format, buf,
|
data->audio_format.format, buf,
|
||||||
0, frame->header.blocksize);
|
0, frame->header.blocksize);
|
||||||
|
|
||||||
if (nbytes > 0)
|
if (nbytes > 0)
|
||||||
|
|
|
@ -56,7 +56,7 @@ struct flac_data : public FlacInput {
|
||||||
* The validated audio format of the FLAC file. This
|
* The validated audio format of the FLAC file. This
|
||||||
* attribute is defined if "initialized" is true.
|
* attribute is defined if "initialized" is true.
|
||||||
*/
|
*/
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The total number of frames in this song. The decoder
|
* The total number of frames in this song. The decoder
|
||||||
|
|
|
@ -144,7 +144,7 @@ flac_decoder_initialize(struct flac_data *data, FLAC__StreamDecoder *sd,
|
||||||
|
|
||||||
if (data->initialized) {
|
if (data->initialized) {
|
||||||
/* done */
|
/* done */
|
||||||
decoder_initialized(data->decoder, &data->audio_format,
|
decoder_initialized(data->decoder, data->audio_format,
|
||||||
data->input_stream->seekable,
|
data->input_stream->seekable,
|
||||||
(float)data->total_frames /
|
(float)data->total_frames /
|
||||||
(float)data->audio_format.sample_rate);
|
(float)data->audio_format.sample_rate);
|
||||||
|
|
|
@ -76,12 +76,12 @@ flac_convert_8(int8_t *dest,
|
||||||
|
|
||||||
void
|
void
|
||||||
flac_convert(void *dest,
|
flac_convert(void *dest,
|
||||||
unsigned int num_channels, enum sample_format sample_format,
|
unsigned int num_channels, SampleFormat sample_format,
|
||||||
const FLAC__int32 *const buf[],
|
const FLAC__int32 *const buf[],
|
||||||
unsigned int position, unsigned int end)
|
unsigned int position, unsigned int end)
|
||||||
{
|
{
|
||||||
switch (sample_format) {
|
switch (sample_format) {
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
if (num_channels == 2)
|
if (num_channels == 2)
|
||||||
flac_convert_stereo16((int16_t*)dest, buf,
|
flac_convert_stereo16((int16_t*)dest, buf,
|
||||||
position, end);
|
position, end);
|
||||||
|
@ -90,20 +90,20 @@ flac_convert(void *dest,
|
||||||
position, end);
|
position, end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
flac_convert_32((int32_t*)dest, num_channels, buf,
|
flac_convert_32((int32_t*)dest, num_channels, buf,
|
||||||
position, end);
|
position, end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
flac_convert_8((int8_t*)dest, num_channels, buf,
|
flac_convert_8((int8_t*)dest, num_channels, buf,
|
||||||
position, end);
|
position, end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
case SAMPLE_FORMAT_DSD:
|
case SampleFormat::DSD:
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
assert(false);
|
assert(false);
|
||||||
gcc_unreachable();
|
gcc_unreachable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,13 +20,13 @@
|
||||||
#ifndef MPD_FLAC_PCM_HXX
|
#ifndef MPD_FLAC_PCM_HXX
|
||||||
#define MPD_FLAC_PCM_HXX
|
#define MPD_FLAC_PCM_HXX
|
||||||
|
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <FLAC/ordinals.h>
|
#include <FLAC/ordinals.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
flac_convert(void *dest,
|
flac_convert(void *dest,
|
||||||
unsigned int num_channels, enum sample_format sample_format,
|
unsigned int num_channels, SampleFormat sample_format,
|
||||||
const FLAC__int32 *const buf[],
|
const FLAC__int32 *const buf[],
|
||||||
unsigned int position, unsigned int end);
|
unsigned int position, unsigned int end);
|
||||||
|
|
||||||
|
|
|
@ -166,9 +166,8 @@ fluidsynth_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
/* initialization complete - announce the audio format to the
|
/* initialization complete - announce the audio format to the
|
||||||
MPD core */
|
MPD core */
|
||||||
|
|
||||||
struct audio_format audio_format;
|
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
|
||||||
audio_format_init(&audio_format, sample_rate, SAMPLE_FORMAT_S16, 2);
|
decoder_initialized(decoder, audio_format, false, -1);
|
||||||
decoder_initialized(decoder, &audio_format, false, -1);
|
|
||||||
|
|
||||||
while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) {
|
while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) {
|
||||||
int16_t buffer[2048];
|
int16_t buffer[2048];
|
||||||
|
|
|
@ -153,9 +153,9 @@ gme_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
/* initialize the MPD decoder */
|
/* initialize the MPD decoder */
|
||||||
|
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, GME_SAMPLE_RATE,
|
if (!audio_format_init_checked(audio_format, GME_SAMPLE_RATE,
|
||||||
SAMPLE_FORMAT_S16, GME_CHANNELS,
|
SampleFormat::S16, GME_CHANNELS,
|
||||||
&error)) {
|
&error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -164,7 +164,7 @@ gme_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, true, song_len);
|
decoder_initialized(decoder, audio_format, true, song_len);
|
||||||
|
|
||||||
gme_err = gme_start_track(emu, song_num);
|
gme_err = gme_start_track(emu, song_num);
|
||||||
if (gme_err != nullptr)
|
if (gme_err != nullptr)
|
||||||
|
|
|
@ -1124,11 +1124,11 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
if (!audio_format_init_checked(&audio_format,
|
if (!audio_format_init_checked(audio_format,
|
||||||
data.frame.header.samplerate,
|
data.frame.header.samplerate,
|
||||||
SAMPLE_FORMAT_S24_P32,
|
SampleFormat::S24_P32,
|
||||||
MAD_NCHANNELS(&data.frame.header),
|
MAD_NCHANNELS(&data.frame.header),
|
||||||
&error)) {
|
&error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
|
@ -1138,7 +1138,7 @@ mp3_decode(struct decoder *decoder, struct input_stream *input_stream)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format,
|
decoder_initialized(decoder, audio_format,
|
||||||
input_stream_is_seekable(input_stream),
|
input_stream_is_seekable(input_stream),
|
||||||
data.total_time);
|
data.total_time);
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,6 @@ mikmod_decoder_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
{
|
{
|
||||||
char *path2;
|
char *path2;
|
||||||
MODULE *handle;
|
MODULE *handle;
|
||||||
struct audio_format audio_format;
|
|
||||||
int ret;
|
int ret;
|
||||||
SBYTE buffer[MIKMOD_FRAME_SIZE];
|
SBYTE buffer[MIKMOD_FRAME_SIZE];
|
||||||
enum decoder_command cmd = DECODE_COMMAND_NONE;
|
enum decoder_command cmd = DECODE_COMMAND_NONE;
|
||||||
|
@ -164,10 +163,10 @@ mikmod_decoder_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
/* Prevent module from looping forever */
|
/* Prevent module from looping forever */
|
||||||
handle->loop = 0;
|
handle->loop = 0;
|
||||||
|
|
||||||
audio_format_init(&audio_format, mikmod_sample_rate, SAMPLE_FORMAT_S16, 2);
|
const AudioFormat audio_format(mikmod_sample_rate, SampleFormat::S16, 2);
|
||||||
assert(audio_format_valid(&audio_format));
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, false, 0);
|
decoder_initialized(decoder, audio_format, false, 0);
|
||||||
|
|
||||||
Player_Start(handle);
|
Player_Start(handle);
|
||||||
while (cmd == DECODE_COMMAND_NONE && Player_Active()) {
|
while (cmd == DECODE_COMMAND_NONE && Player_Active()) {
|
||||||
|
|
|
@ -94,7 +94,6 @@ mod_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
ModPlugFile *f;
|
ModPlugFile *f;
|
||||||
ModPlug_Settings settings;
|
ModPlug_Settings settings;
|
||||||
GByteArray *bdatas;
|
GByteArray *bdatas;
|
||||||
struct audio_format audio_format;
|
|
||||||
int ret;
|
int ret;
|
||||||
char audio_buffer[MODPLUG_FRAME_SIZE];
|
char audio_buffer[MODPLUG_FRAME_SIZE];
|
||||||
enum decoder_command cmd = DECODE_COMMAND_NONE;
|
enum decoder_command cmd = DECODE_COMMAND_NONE;
|
||||||
|
@ -122,10 +121,10 @@ mod_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_format_init(&audio_format, 44100, SAMPLE_FORMAT_S16, 2);
|
static constexpr AudioFormat audio_format(44100, SampleFormat::S16, 2);
|
||||||
assert(audio_format_valid(&audio_format));
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format,
|
decoder_initialized(decoder, audio_format,
|
||||||
input_stream_is_seekable(is),
|
input_stream_is_seekable(is),
|
||||||
ModPlug_GetLength(f) / 1000.0);
|
ModPlug_GetLength(f) / 1000.0);
|
||||||
|
|
||||||
|
|
|
@ -154,9 +154,9 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
|
||||||
mpc_demux_get_info(demux, &info);
|
mpc_demux_get_info(demux, &info);
|
||||||
|
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, info.sample_freq,
|
if (!audio_format_init_checked(audio_format, info.sample_freq,
|
||||||
SAMPLE_FORMAT_S24_P32,
|
SampleFormat::S24_P32,
|
||||||
info.channels, &error)) {
|
info.channels, &error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
|
@ -173,7 +173,7 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
|
||||||
|
|
||||||
decoder_replay_gain(mpd_decoder, &replay_gain_info);
|
decoder_replay_gain(mpd_decoder, &replay_gain_info);
|
||||||
|
|
||||||
decoder_initialized(mpd_decoder, &audio_format,
|
decoder_initialized(mpd_decoder, audio_format,
|
||||||
input_stream_is_seekable(is),
|
input_stream_is_seekable(is),
|
||||||
mpc_streaminfo_get_length(&info));
|
mpc_streaminfo_get_length(&info));
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ mpd_mpg123_finish(void)
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
mpd_mpg123_open(mpg123_handle *handle, const char *path_fs,
|
mpd_mpg123_open(mpg123_handle *handle, const char *path_fs,
|
||||||
struct audio_format *audio_format)
|
AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
GError *gerror = nullptr;
|
GError *gerror = nullptr;
|
||||||
char *path_dup;
|
char *path_dup;
|
||||||
|
@ -90,7 +90,7 @@ mpd_mpg123_open(mpg123_handle *handle, const char *path_fs,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!audio_format_init_checked(audio_format, rate, SAMPLE_FORMAT_S16,
|
if (!audio_format_init_checked(audio_format, rate, SampleFormat::S16,
|
||||||
channels, &gerror)) {
|
channels, &gerror)) {
|
||||||
g_warning("%s", gerror->message);
|
g_warning("%s", gerror->message);
|
||||||
g_error_free(gerror);
|
g_error_free(gerror);
|
||||||
|
@ -103,7 +103,6 @@ mpd_mpg123_open(mpg123_handle *handle, const char *path_fs,
|
||||||
static void
|
static void
|
||||||
mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
|
mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
{
|
{
|
||||||
struct audio_format audio_format;
|
|
||||||
mpg123_handle *handle;
|
mpg123_handle *handle;
|
||||||
int error;
|
int error;
|
||||||
off_t num_samples;
|
off_t num_samples;
|
||||||
|
@ -119,7 +118,8 @@ mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpd_mpg123_open(handle, path_fs, &audio_format)) {
|
AudioFormat audio_format;
|
||||||
|
if (!mpd_mpg123_open(handle, path_fs, audio_format)) {
|
||||||
mpg123_delete(handle);
|
mpg123_delete(handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ mpd_mpg123_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
|
|
||||||
/* tell MPD core we're ready */
|
/* tell MPD core we're ready */
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, true,
|
decoder_initialized(decoder, audio_format, true,
|
||||||
(float)num_samples /
|
(float)num_samples /
|
||||||
(float)audio_format.sample_rate);
|
(float)audio_format.sample_rate);
|
||||||
|
|
||||||
|
@ -198,7 +198,6 @@ static bool
|
||||||
mpd_mpg123_scan_file(const char *path_fs,
|
mpd_mpg123_scan_file(const char *path_fs,
|
||||||
const struct tag_handler *handler, void *handler_ctx)
|
const struct tag_handler *handler, void *handler_ctx)
|
||||||
{
|
{
|
||||||
struct audio_format audio_format;
|
|
||||||
mpg123_handle *handle;
|
mpg123_handle *handle;
|
||||||
int error;
|
int error;
|
||||||
off_t num_samples;
|
off_t num_samples;
|
||||||
|
@ -210,7 +209,8 @@ mpd_mpg123_scan_file(const char *path_fs,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mpd_mpg123_open(handle, path_fs, &audio_format)) {
|
AudioFormat audio_format;
|
||||||
|
if (!mpd_mpg123_open(handle, path_fs, audio_format)) {
|
||||||
mpg123_delete(handle);
|
mpg123_delete(handle);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,11 +202,10 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
|
||||||
return DECODE_COMMAND_STOP;
|
return DECODE_COMMAND_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct audio_format audio_format;
|
const AudioFormat audio_format(opus_sample_rate,
|
||||||
audio_format_init(&audio_format, opus_sample_rate,
|
SampleFormat::S16, channels);
|
||||||
SAMPLE_FORMAT_S16, channels);
|
decoder_initialized(decoder, audio_format, false, -1);
|
||||||
decoder_initialized(decoder, &audio_format, false, -1);
|
frame_size = audio_format.GetFrameSize();
|
||||||
frame_size = audio_format_frame_size(&audio_format);
|
|
||||||
|
|
||||||
/* allocate an output buffer for 16 bit PCM samples big enough
|
/* allocate an output buffer for 16 bit PCM samples big enough
|
||||||
to hold a quarter second, larger than 120ms required by
|
to hold a quarter second, larger than 120ms required by
|
||||||
|
|
|
@ -36,9 +36,9 @@ extern "C" {
|
||||||
static void
|
static void
|
||||||
pcm_stream_decode(struct decoder *decoder, struct input_stream *is)
|
pcm_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
{
|
{
|
||||||
static constexpr struct audio_format audio_format = {
|
static constexpr AudioFormat audio_format = {
|
||||||
44100,
|
44100,
|
||||||
SAMPLE_FORMAT_S16,
|
SampleFormat::S16,
|
||||||
2,
|
2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,14 +49,14 @@ pcm_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
enum decoder_command cmd;
|
enum decoder_command cmd;
|
||||||
|
|
||||||
double time_to_size = audio_format_time_to_size(&audio_format);
|
const double time_to_size = audio_format.GetTimeToSize();
|
||||||
|
|
||||||
float total_time = -1;
|
float total_time = -1;
|
||||||
const goffset size = input_stream_get_size(is);
|
const goffset size = input_stream_get_size(is);
|
||||||
if (size >= 0)
|
if (size >= 0)
|
||||||
total_time = size / time_to_size;
|
total_time = size / time_to_size;
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format,
|
decoder_initialized(decoder, audio_format,
|
||||||
input_stream_is_seekable(is), total_time);
|
input_stream_is_seekable(is), total_time);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -99,7 +99,7 @@ static SF_VIRTUAL_IO vio = {
|
||||||
* Converts a frame number to a timestamp (in seconds).
|
* Converts a frame number to a timestamp (in seconds).
|
||||||
*/
|
*/
|
||||||
static float
|
static float
|
||||||
frame_to_time(sf_count_t frame, const struct audio_format *audio_format)
|
frame_to_time(sf_count_t frame, const AudioFormat *audio_format)
|
||||||
{
|
{
|
||||||
return (float)frame / (float)audio_format->sample_rate;
|
return (float)frame / (float)audio_format->sample_rate;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ frame_to_time(sf_count_t frame, const struct audio_format *audio_format)
|
||||||
* Converts a timestamp (in seconds) to a frame number.
|
* Converts a timestamp (in seconds) to a frame number.
|
||||||
*/
|
*/
|
||||||
static sf_count_t
|
static sf_count_t
|
||||||
time_to_frame(float t, const struct audio_format *audio_format)
|
time_to_frame(float t, const AudioFormat *audio_format)
|
||||||
{
|
{
|
||||||
return (sf_count_t)(t * audio_format->sample_rate);
|
return (sf_count_t)(t * audio_format->sample_rate);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,6 @@ sndfile_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
GError *error = nullptr;
|
GError *error = nullptr;
|
||||||
SNDFILE *sf;
|
SNDFILE *sf;
|
||||||
SF_INFO info;
|
SF_INFO info;
|
||||||
struct audio_format audio_format;
|
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
sf_count_t read_frames, num_frames;
|
sf_count_t read_frames, num_frames;
|
||||||
int buffer[4096];
|
int buffer[4096];
|
||||||
|
@ -136,18 +135,19 @@ sndfile_stream_decode(struct decoder *decoder, struct input_stream *is)
|
||||||
/* for now, always read 32 bit samples. Later, we could lower
|
/* for now, always read 32 bit samples. Later, we could lower
|
||||||
MPD's CPU usage by reading 16 bit samples with
|
MPD's CPU usage by reading 16 bit samples with
|
||||||
sf_readf_short() on low-quality source files. */
|
sf_readf_short() on low-quality source files. */
|
||||||
if (!audio_format_init_checked(&audio_format, info.samplerate,
|
AudioFormat audio_format;
|
||||||
SAMPLE_FORMAT_S32,
|
if (!audio_format_init_checked(audio_format, info.samplerate,
|
||||||
|
SampleFormat::S32,
|
||||||
info.channels, &error)) {
|
info.channels, &error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, info.seekable,
|
decoder_initialized(decoder, audio_format, info.seekable,
|
||||||
frame_to_time(info.frames, &audio_format));
|
frame_to_time(info.frames, &audio_format));
|
||||||
|
|
||||||
frame_size = audio_format_frame_size(&audio_format);
|
frame_size = audio_format.GetFrameSize();
|
||||||
read_frames = sizeof(buffer) / frame_size;
|
read_frames = sizeof(buffer) / frame_size;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -202,12 +202,12 @@ vorbis_stream_decode(struct decoder *decoder,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
if (!audio_format_init_checked(&audio_format, vi->rate,
|
if (!audio_format_init_checked(audio_format, vi->rate,
|
||||||
#ifdef HAVE_TREMOR
|
#ifdef HAVE_TREMOR
|
||||||
SAMPLE_FORMAT_S16,
|
SampleFormat::S16,
|
||||||
#else
|
#else
|
||||||
SAMPLE_FORMAT_FLOAT,
|
SampleFormat::FLOAT,
|
||||||
#endif
|
#endif
|
||||||
vi->channels, &error)) {
|
vi->channels, &error)) {
|
||||||
g_warning("%s", error->message);
|
g_warning("%s", error->message);
|
||||||
|
@ -219,7 +219,7 @@ vorbis_stream_decode(struct decoder *decoder,
|
||||||
if (total_time < 0)
|
if (total_time < 0)
|
||||||
total_time = 0;
|
total_time = 0;
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, vis.seekable, total_time);
|
decoder_initialized(decoder, audio_format, vis.seekable, total_time);
|
||||||
|
|
||||||
enum decoder_command cmd = decoder_get_command(decoder);
|
enum decoder_command cmd = decoder_get_command(decoder);
|
||||||
|
|
||||||
|
|
|
@ -106,27 +106,27 @@ format_samples_float(G_GNUC_UNUSED int bytes_per_sample, void *buffer,
|
||||||
/**
|
/**
|
||||||
* Choose a MPD sample format from libwavpacks' number of bits.
|
* Choose a MPD sample format from libwavpacks' number of bits.
|
||||||
*/
|
*/
|
||||||
static enum sample_format
|
static SampleFormat
|
||||||
wavpack_bits_to_sample_format(bool is_float, int bytes_per_sample)
|
wavpack_bits_to_sample_format(bool is_float, int bytes_per_sample)
|
||||||
{
|
{
|
||||||
if (is_float)
|
if (is_float)
|
||||||
return SAMPLE_FORMAT_FLOAT;
|
return SampleFormat::FLOAT;
|
||||||
|
|
||||||
switch (bytes_per_sample) {
|
switch (bytes_per_sample) {
|
||||||
case 1:
|
case 1:
|
||||||
return SAMPLE_FORMAT_S8;
|
return SampleFormat::S8;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
return SAMPLE_FORMAT_S16;
|
return SampleFormat::S16;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
return SAMPLE_FORMAT_S24_P32;
|
return SampleFormat::S24_P32;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
return SAMPLE_FORMAT_S32;
|
return SampleFormat::S32;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SAMPLE_FORMAT_UNDEFINED;
|
return SampleFormat::UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,8 +139,8 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
bool is_float;
|
bool is_float;
|
||||||
enum sample_format sample_format;
|
SampleFormat sample_format;
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
format_samples_t format_samples;
|
format_samples_t format_samples;
|
||||||
float total_time;
|
float total_time;
|
||||||
int bytes_per_sample, output_sample_size;
|
int bytes_per_sample, output_sample_size;
|
||||||
|
@ -150,7 +150,7 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
|
||||||
wavpack_bits_to_sample_format(is_float,
|
wavpack_bits_to_sample_format(is_float,
|
||||||
WavpackGetBytesPerSample(wpc));
|
WavpackGetBytesPerSample(wpc));
|
||||||
|
|
||||||
if (!audio_format_init_checked(&audio_format,
|
if (!audio_format_init_checked(audio_format,
|
||||||
WavpackGetSampleRate(wpc),
|
WavpackGetSampleRate(wpc),
|
||||||
sample_format,
|
sample_format,
|
||||||
WavpackGetNumChannels(wpc), &error)) {
|
WavpackGetNumChannels(wpc), &error)) {
|
||||||
|
@ -168,14 +168,14 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
|
||||||
total_time = WavpackGetNumSamples(wpc);
|
total_time = WavpackGetNumSamples(wpc);
|
||||||
total_time /= audio_format.sample_rate;
|
total_time /= audio_format.sample_rate;
|
||||||
bytes_per_sample = WavpackGetBytesPerSample(wpc);
|
bytes_per_sample = WavpackGetBytesPerSample(wpc);
|
||||||
output_sample_size = audio_format_frame_size(&audio_format);
|
output_sample_size = audio_format.GetFrameSize();
|
||||||
|
|
||||||
/* wavpack gives us all kind of samples in a 32-bit space */
|
/* wavpack gives us all kind of samples in a 32-bit space */
|
||||||
int32_t chunk[1024];
|
int32_t chunk[1024];
|
||||||
const uint32_t samples_requested = G_N_ELEMENTS(chunk) /
|
const uint32_t samples_requested = G_N_ELEMENTS(chunk) /
|
||||||
audio_format.channels;
|
audio_format.channels;
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, can_seek, total_time);
|
decoder_initialized(decoder, audio_format, can_seek, total_time);
|
||||||
|
|
||||||
enum decoder_command cmd = decoder_get_command(decoder);
|
enum decoder_command cmd = decoder_get_command(decoder);
|
||||||
while (cmd != DECODE_COMMAND_STOP) {
|
while (cmd != DECODE_COMMAND_STOP) {
|
||||||
|
|
|
@ -60,9 +60,9 @@ wildmidi_finish(void)
|
||||||
static void
|
static void
|
||||||
wildmidi_file_decode(struct decoder *decoder, const char *path_fs)
|
wildmidi_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
{
|
{
|
||||||
static const struct audio_format audio_format = {
|
static constexpr AudioFormat audio_format = {
|
||||||
WILDMIDI_SAMPLE_RATE,
|
WILDMIDI_SAMPLE_RATE,
|
||||||
SAMPLE_FORMAT_S16,
|
SampleFormat::S16,
|
||||||
2,
|
2,
|
||||||
};
|
};
|
||||||
midi *wm;
|
midi *wm;
|
||||||
|
@ -79,7 +79,7 @@ wildmidi_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, true,
|
decoder_initialized(decoder, audio_format, true,
|
||||||
info->approx_total_samples / WILDMIDI_SAMPLE_RATE);
|
info->approx_total_samples / WILDMIDI_SAMPLE_RATE);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -285,11 +285,10 @@ sidplay_file_decode(struct decoder *decoder, const char *path_fs)
|
||||||
|
|
||||||
/* initialize the MPD decoder */
|
/* initialize the MPD decoder */
|
||||||
|
|
||||||
struct audio_format audio_format;
|
const AudioFormat audio_format(48000, SampleFormat::S16, channels);
|
||||||
audio_format_init(&audio_format, 48000, SAMPLE_FORMAT_S16, channels);
|
assert(audio_format.IsValid());
|
||||||
assert(audio_format_valid(&audio_format));
|
|
||||||
|
|
||||||
decoder_initialized(decoder, &audio_format, true, (float)song_len);
|
decoder_initialized(decoder, audio_format, true, (float)song_len);
|
||||||
|
|
||||||
/* .. and play */
|
/* .. and play */
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "FlacEncoderPlugin.hxx"
|
#include "FlacEncoderPlugin.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "pcm/PcmBuffer.hxx"
|
#include "pcm/PcmBuffer.hxx"
|
||||||
#include "util/fifo_buffer.h"
|
#include "util/fifo_buffer.h"
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ extern "C" {
|
||||||
struct flac_encoder {
|
struct flac_encoder {
|
||||||
Encoder encoder;
|
Encoder encoder;
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
unsigned compression;
|
unsigned compression;
|
||||||
|
|
||||||
FLAC__StreamEncoder *fse;
|
FLAC__StreamEncoder *fse;
|
||||||
|
@ -160,31 +160,31 @@ flac_encoder_close(Encoder *_encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
flac_encoder_open(Encoder *_encoder, struct audio_format *audio_format,
|
flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
|
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
|
||||||
unsigned bits_per_sample;
|
unsigned bits_per_sample;
|
||||||
|
|
||||||
encoder->audio_format = *audio_format;
|
encoder->audio_format = audio_format;
|
||||||
|
|
||||||
/* FIXME: flac should support 32bit as well */
|
/* FIXME: flac should support 32bit as well */
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
bits_per_sample = 8;
|
bits_per_sample = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
bits_per_sample = 16;
|
bits_per_sample = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
bits_per_sample = 24;
|
bits_per_sample = 24;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
bits_per_sample = 24;
|
bits_per_sample = 24;
|
||||||
audio_format->format = SAMPLE_FORMAT_S24_P32;
|
audio_format.format = SampleFormat::S24_P32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate the encoder */
|
/* allocate the encoder */
|
||||||
|
@ -263,30 +263,33 @@ flac_encoder_write(Encoder *_encoder,
|
||||||
|
|
||||||
/* format conversion */
|
/* format conversion */
|
||||||
|
|
||||||
num_frames = length / audio_format_frame_size(&encoder->audio_format);
|
num_frames = length / encoder->audio_format.GetFrameSize();
|
||||||
num_samples = num_frames * encoder->audio_format.channels;
|
num_samples = num_frames * encoder->audio_format.channels;
|
||||||
|
|
||||||
switch (encoder->audio_format.format) {
|
switch (encoder->audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
exbuffer = encoder->expand_buffer.Get(length * 4);
|
exbuffer = encoder->expand_buffer.Get(length * 4);
|
||||||
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)data,
|
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)data,
|
||||||
num_samples);
|
num_samples);
|
||||||
buffer = exbuffer;
|
buffer = exbuffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
exbuffer = encoder->expand_buffer.Get(length * 2);
|
exbuffer = encoder->expand_buffer.Get(length * 2);
|
||||||
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)data,
|
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)data,
|
||||||
num_samples);
|
num_samples);
|
||||||
buffer = exbuffer;
|
buffer = exbuffer;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
/* nothing need to be done; format is the same for
|
/* nothing need to be done; format is the same for
|
||||||
both mpd and libFLAC */
|
both mpd and libFLAC */
|
||||||
buffer = data;
|
buffer = data;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
gcc_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* feed samples to encoder */
|
/* feed samples to encoder */
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "LameEncoderPlugin.hxx"
|
#include "LameEncoderPlugin.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <lame/lame.h>
|
#include <lame/lame.h>
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
struct LameEncoder final {
|
struct LameEncoder final {
|
||||||
Encoder encoder;
|
Encoder encoder;
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
float quality;
|
float quality;
|
||||||
int bitrate;
|
int bitrate;
|
||||||
|
|
||||||
|
@ -187,15 +187,15 @@ lame_encoder_setup(LameEncoder *encoder, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
lame_encoder_open(Encoder *_encoder, struct audio_format *audio_format,
|
lame_encoder_open(Encoder *_encoder, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
LameEncoder *encoder = (LameEncoder *)_encoder;
|
LameEncoder *encoder = (LameEncoder *)_encoder;
|
||||||
|
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
audio_format->channels = 2;
|
audio_format.channels = 2;
|
||||||
|
|
||||||
encoder->audio_format = *audio_format;
|
encoder->audio_format = audio_format;
|
||||||
|
|
||||||
encoder->gfp = lame_init();
|
encoder->gfp = lame_init();
|
||||||
if (encoder->gfp == nullptr) {
|
if (encoder->gfp == nullptr) {
|
||||||
|
@ -233,7 +233,7 @@ lame_encoder_write(Encoder *_encoder,
|
||||||
assert(encoder->buffer_length == 0);
|
assert(encoder->buffer_length == 0);
|
||||||
|
|
||||||
const unsigned num_frames =
|
const unsigned num_frames =
|
||||||
length / audio_format_frame_size(&encoder->audio_format);
|
length / encoder->audio_format.GetFrameSize();
|
||||||
float *left = g_new(float, num_frames);
|
float *left = g_new(float, num_frames);
|
||||||
float *right = g_new(float, num_frames);
|
float *right = g_new(float, num_frames);
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ null_encoder_close(Encoder *_encoder)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
null_encoder_open(Encoder *_encoder,
|
null_encoder_open(Encoder *_encoder,
|
||||||
gcc_unused struct audio_format *audio_format,
|
gcc_unused AudioFormat &audio_format,
|
||||||
gcc_unused GError **error)
|
gcc_unused GError **error)
|
||||||
{
|
{
|
||||||
NullEncoder *encoder = (NullEncoder *)_encoder;
|
NullEncoder *encoder = (NullEncoder *)_encoder;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "OpusEncoderPlugin.hxx"
|
#include "OpusEncoderPlugin.hxx"
|
||||||
#include "OggStream.hxx"
|
#include "OggStream.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "mpd_error.h"
|
#include "mpd_error.h"
|
||||||
|
|
||||||
#include <opus.h>
|
#include <opus.h>
|
||||||
|
@ -44,7 +44,7 @@ struct opus_encoder {
|
||||||
|
|
||||||
/* runtime information */
|
/* runtime information */
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
|
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
|
|
||||||
|
@ -144,37 +144,37 @@ opus_encoder_finish(Encoder *_encoder)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
opus_encoder_open(Encoder *_encoder,
|
opus_encoder_open(Encoder *_encoder,
|
||||||
struct audio_format *audio_format,
|
AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
struct opus_encoder *encoder = (struct opus_encoder *)_encoder;
|
struct opus_encoder *encoder = (struct opus_encoder *)_encoder;
|
||||||
|
|
||||||
/* libopus supports only 48 kHz */
|
/* libopus supports only 48 kHz */
|
||||||
audio_format->sample_rate = 48000;
|
audio_format.sample_rate = 48000;
|
||||||
|
|
||||||
if (audio_format->channels > 2)
|
if (audio_format.channels > 2)
|
||||||
audio_format->channels = 1;
|
audio_format.channels = 1;
|
||||||
|
|
||||||
switch ((enum sample_format)audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
audio_format->format = SAMPLE_FORMAT_FLOAT;
|
audio_format.format = SampleFormat::FLOAT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->audio_format = *audio_format;
|
encoder->audio_format = audio_format;
|
||||||
encoder->frame_size = audio_format_frame_size(audio_format);
|
encoder->frame_size = audio_format.GetFrameSize();
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
encoder->enc = opus_encoder_create(audio_format->sample_rate,
|
encoder->enc = opus_encoder_create(audio_format.sample_rate,
|
||||||
audio_format->channels,
|
audio_format.channels,
|
||||||
OPUS_APPLICATION_AUDIO,
|
OPUS_APPLICATION_AUDIO,
|
||||||
&error);
|
&error);
|
||||||
if (encoder->enc == nullptr) {
|
if (encoder->enc == nullptr) {
|
||||||
|
@ -190,7 +190,7 @@ opus_encoder_open(Encoder *_encoder,
|
||||||
|
|
||||||
opus_encoder_ctl(encoder->enc, OPUS_GET_LOOKAHEAD(&encoder->lookahead));
|
opus_encoder_ctl(encoder->enc, OPUS_GET_LOOKAHEAD(&encoder->lookahead));
|
||||||
|
|
||||||
encoder->buffer_frames = audio_format->sample_rate / 50;
|
encoder->buffer_frames = audio_format.sample_rate / 50;
|
||||||
encoder->buffer_size = encoder->frame_size * encoder->buffer_frames;
|
encoder->buffer_size = encoder->frame_size * encoder->buffer_frames;
|
||||||
encoder->buffer_position = 0;
|
encoder->buffer_position = 0;
|
||||||
encoder->buffer = (unsigned char *)g_malloc(encoder->buffer_size);
|
encoder->buffer = (unsigned char *)g_malloc(encoder->buffer_size);
|
||||||
|
@ -218,7 +218,7 @@ opus_encoder_do_encode(struct opus_encoder *encoder, bool eos,
|
||||||
assert(encoder->buffer_position == encoder->buffer_size);
|
assert(encoder->buffer_position == encoder->buffer_size);
|
||||||
|
|
||||||
opus_int32 result =
|
opus_int32 result =
|
||||||
encoder->audio_format.format == SAMPLE_FORMAT_S16
|
encoder->audio_format.format == SampleFormat::S16
|
||||||
? opus_encode(encoder->enc,
|
? opus_encode(encoder->enc,
|
||||||
(const opus_int16 *)encoder->buffer,
|
(const opus_int16 *)encoder->buffer,
|
||||||
encoder->buffer_frames,
|
encoder->buffer_frames,
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "TwolameEncoderPlugin.hxx"
|
#include "TwolameEncoderPlugin.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <twolame.h>
|
#include <twolame.h>
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
struct TwolameEncoder final {
|
struct TwolameEncoder final {
|
||||||
Encoder encoder;
|
Encoder encoder;
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
float quality;
|
float quality;
|
||||||
int bitrate;
|
int bitrate;
|
||||||
|
|
||||||
|
@ -187,15 +187,15 @@ twolame_encoder_setup(TwolameEncoder *encoder, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
twolame_encoder_open(Encoder *_encoder, struct audio_format *audio_format,
|
twolame_encoder_open(Encoder *_encoder, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
TwolameEncoder *encoder = (TwolameEncoder *)_encoder;
|
TwolameEncoder *encoder = (TwolameEncoder *)_encoder;
|
||||||
|
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
audio_format->channels = 2;
|
audio_format.channels = 2;
|
||||||
|
|
||||||
encoder->audio_format = *audio_format;
|
encoder->audio_format = audio_format;
|
||||||
|
|
||||||
encoder->options = twolame_init();
|
encoder->options = twolame_init();
|
||||||
if (encoder->options == nullptr) {
|
if (encoder->options == nullptr) {
|
||||||
|
@ -243,7 +243,7 @@ twolame_encoder_write(Encoder *_encoder,
|
||||||
assert(encoder->buffer_length == 0);
|
assert(encoder->buffer_length == 0);
|
||||||
|
|
||||||
const unsigned num_frames =
|
const unsigned num_frames =
|
||||||
length / audio_format_frame_size(&encoder->audio_format);
|
length / encoder->audio_format.GetFrameSize();
|
||||||
|
|
||||||
int bytes_out = twolame_encode_buffer_interleaved(encoder->options,
|
int bytes_out = twolame_encode_buffer_interleaved(encoder->options,
|
||||||
src, num_frames,
|
src, num_frames,
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "OggStream.hxx"
|
#include "OggStream.hxx"
|
||||||
#include "EncoderAPI.hxx"
|
#include "EncoderAPI.hxx"
|
||||||
#include "Tag.hxx"
|
#include "Tag.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "mpd_error.h"
|
#include "mpd_error.h"
|
||||||
|
|
||||||
#include <vorbis/vorbisenc.h>
|
#include <vorbis/vorbisenc.h>
|
||||||
|
@ -43,7 +43,7 @@ struct vorbis_encoder {
|
||||||
|
|
||||||
/* runtime information */
|
/* runtime information */
|
||||||
|
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
|
|
||||||
vorbis_dsp_state vd;
|
vorbis_dsp_state vd;
|
||||||
vorbis_block vb;
|
vorbis_block vb;
|
||||||
|
@ -202,14 +202,14 @@ vorbis_encoder_send_header(struct vorbis_encoder *encoder)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
vorbis_encoder_open(Encoder *_encoder,
|
vorbis_encoder_open(Encoder *_encoder,
|
||||||
struct audio_format *audio_format,
|
AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
|
struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
|
||||||
|
|
||||||
audio_format->format = SAMPLE_FORMAT_FLOAT;
|
audio_format.format = SampleFormat::FLOAT;
|
||||||
|
|
||||||
encoder->audio_format = *audio_format;
|
encoder->audio_format = audio_format;
|
||||||
|
|
||||||
if (!vorbis_encoder_reinit(encoder, error))
|
if (!vorbis_encoder_reinit(encoder, error))
|
||||||
return false;
|
return false;
|
||||||
|
@ -328,8 +328,7 @@ vorbis_encoder_write(Encoder *_encoder,
|
||||||
{
|
{
|
||||||
struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
|
struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
|
||||||
|
|
||||||
unsigned num_frames = length
|
unsigned num_frames = length / encoder->audio_format.GetFrameSize();
|
||||||
/ audio_format_frame_size(&encoder->audio_format);
|
|
||||||
|
|
||||||
/* this is for only 16-bit audio */
|
/* this is for only 16-bit audio */
|
||||||
|
|
||||||
|
|
|
@ -100,32 +100,32 @@ wave_encoder_finish(Encoder *_encoder)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
wave_encoder_open(Encoder *_encoder,
|
wave_encoder_open(Encoder *_encoder,
|
||||||
gcc_unused struct audio_format *audio_format,
|
AudioFormat &audio_format,
|
||||||
gcc_unused GError **error)
|
gcc_unused GError **error)
|
||||||
{
|
{
|
||||||
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
WaveEncoder *encoder = (WaveEncoder *)_encoder;
|
||||||
|
|
||||||
assert(audio_format_valid(audio_format));
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
encoder->bits = 8;
|
encoder->bits = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
encoder->bits = 16;
|
encoder->bits = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
encoder->bits = 24;
|
encoder->bits = 24;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
encoder->bits = 32;
|
encoder->bits = 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
encoder->bits = 16;
|
encoder->bits = 16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -136,10 +136,10 @@ wave_encoder_open(Encoder *_encoder,
|
||||||
|
|
||||||
/* create PCM wave header in initial buffer */
|
/* create PCM wave header in initial buffer */
|
||||||
fill_wave_header(header,
|
fill_wave_header(header,
|
||||||
audio_format->channels,
|
audio_format.channels,
|
||||||
encoder->bits,
|
encoder->bits,
|
||||||
audio_format->sample_rate,
|
audio_format.sample_rate,
|
||||||
(encoder->bits / 8) * audio_format->channels );
|
(encoder->bits / 8) * audio_format.channels);
|
||||||
fifo_buffer_append(encoder->buffer, sizeof(*header));
|
fifo_buffer_append(encoder->buffer, sizeof(*header));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -23,18 +23,11 @@
|
||||||
#include "FilterPlugin.hxx"
|
#include "FilterPlugin.hxx"
|
||||||
#include "FilterInternal.hxx"
|
#include "FilterInternal.hxx"
|
||||||
#include "FilterRegistry.hxx"
|
#include "FilterRegistry.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
class AutoConvertFilter final : public Filter {
|
class AutoConvertFilter final : public Filter {
|
||||||
/**
|
|
||||||
* The audio format being fed to the underlying filter. This
|
|
||||||
* plugin actually doesn't need this variable, we have it here
|
|
||||||
* just so our open() method doesn't return a stack pointer.
|
|
||||||
*/
|
|
||||||
audio_format child_audio_format;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The underlying filter.
|
* The underlying filter.
|
||||||
*/
|
*/
|
||||||
|
@ -52,46 +45,45 @@ public:
|
||||||
delete filter;
|
delete filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r);
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct audio_format *
|
AudioFormat
|
||||||
AutoConvertFilter::Open(audio_format &in_audio_format, GError **error_r)
|
AutoConvertFilter::Open(AudioFormat &in_audio_format, GError **error_r)
|
||||||
{
|
{
|
||||||
assert(audio_format_valid(&in_audio_format));
|
assert(in_audio_format.IsValid());
|
||||||
|
|
||||||
/* open the "real" filter */
|
/* open the "real" filter */
|
||||||
|
|
||||||
child_audio_format = in_audio_format;
|
const AudioFormat child_audio_format = in_audio_format;
|
||||||
const audio_format *out_audio_format =
|
AudioFormat out_audio_format = filter->Open(in_audio_format, error_r);
|
||||||
filter->Open(child_audio_format, error_r);
|
if (!out_audio_format.IsDefined())
|
||||||
if (out_audio_format == nullptr)
|
return out_audio_format;
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
/* need to convert? */
|
/* need to convert? */
|
||||||
|
|
||||||
if (!audio_format_equals(&child_audio_format, &in_audio_format)) {
|
if (in_audio_format != child_audio_format) {
|
||||||
/* yes - create a convert_filter */
|
/* yes - create a convert_filter */
|
||||||
|
|
||||||
convert = filter_new(&convert_filter_plugin, nullptr, error_r);
|
convert = filter_new(&convert_filter_plugin, nullptr, error_r);
|
||||||
if (convert == nullptr) {
|
if (convert == nullptr) {
|
||||||
filter->Close();
|
filter->Close();
|
||||||
return nullptr;
|
return AudioFormat::Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_format audio_format2 = in_audio_format;
|
AudioFormat audio_format2 = in_audio_format;
|
||||||
const audio_format *audio_format3 =
|
AudioFormat audio_format3 =
|
||||||
convert->Open(audio_format2, error_r);
|
convert->Open(audio_format2, error_r);
|
||||||
if (audio_format3 == nullptr) {
|
if (!audio_format3.IsDefined()) {
|
||||||
delete convert;
|
delete convert;
|
||||||
filter->Close();
|
filter->Close();
|
||||||
return nullptr;
|
return AudioFormat::Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(audio_format_equals(&audio_format2, &in_audio_format));
|
assert(audio_format2 == in_audio_format);
|
||||||
|
|
||||||
convert_filter_set(convert, child_audio_format);
|
convert_filter_set(convert, child_audio_format);
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "FilterPlugin.hxx"
|
#include "FilterPlugin.hxx"
|
||||||
#include "FilterInternal.hxx"
|
#include "FilterInternal.hxx"
|
||||||
#include "FilterRegistry.hxx"
|
#include "FilterRegistry.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ public:
|
||||||
children.emplace_back(name, filter);
|
children.emplace_back(name, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) override;
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
|
@ -96,43 +96,43 @@ ChainFilter::CloseUntil(const Filter *until)
|
||||||
gcc_unreachable();
|
gcc_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct audio_format *
|
static AudioFormat
|
||||||
chain_open_child(const char *name, Filter *filter,
|
chain_open_child(const char *name, Filter *filter,
|
||||||
const audio_format &prev_audio_format,
|
const AudioFormat &prev_audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
audio_format conv_audio_format = prev_audio_format;
|
AudioFormat conv_audio_format = prev_audio_format;
|
||||||
const audio_format *next_audio_format =
|
const AudioFormat next_audio_format =
|
||||||
filter->Open(conv_audio_format, error_r);
|
filter->Open(conv_audio_format, error_r);
|
||||||
if (next_audio_format == NULL)
|
if (!next_audio_format.IsDefined())
|
||||||
return NULL;
|
return next_audio_format;
|
||||||
|
|
||||||
if (!audio_format_equals(&conv_audio_format, &prev_audio_format)) {
|
if (conv_audio_format != prev_audio_format) {
|
||||||
struct audio_format_string s;
|
struct audio_format_string s;
|
||||||
|
|
||||||
filter->Close();
|
filter->Close();
|
||||||
g_set_error(error_r, filter_quark(), 0,
|
g_set_error(error_r, filter_quark(), 0,
|
||||||
"Audio format not supported by filter '%s': %s",
|
"Audio format not supported by filter '%s': %s",
|
||||||
name,
|
name,
|
||||||
audio_format_to_string(&prev_audio_format, &s));
|
audio_format_to_string(prev_audio_format, &s));
|
||||||
return NULL;
|
return AudioFormat::Undefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
return next_audio_format;
|
return next_audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
const audio_format *
|
AudioFormat
|
||||||
ChainFilter::Open(audio_format &in_audio_format, GError **error_r)
|
ChainFilter::Open(AudioFormat &in_audio_format, GError **error_r)
|
||||||
{
|
{
|
||||||
const audio_format *audio_format = &in_audio_format;
|
AudioFormat audio_format = in_audio_format;
|
||||||
|
|
||||||
for (auto &child : children) {
|
for (auto &child : children) {
|
||||||
audio_format = chain_open_child(child.name, child.filter,
|
audio_format = chain_open_child(child.name, child.filter,
|
||||||
*audio_format, error_r);
|
audio_format, error_r);
|
||||||
if (audio_format == NULL) {
|
if (!audio_format.IsDefined()) {
|
||||||
/* rollback, close all children */
|
/* rollback, close all children */
|
||||||
CloseUntil(child.filter);
|
CloseUntil(child.filter);
|
||||||
return NULL;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "pcm/PcmConvert.hxx"
|
#include "pcm/PcmConvert.hxx"
|
||||||
#include "util/Manual.hxx"
|
#include "util/Manual.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "poison.h"
|
#include "poison.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -36,27 +36,27 @@ class ConvertFilter final : public Filter {
|
||||||
* The input audio format; PCM data is passed to the filter()
|
* The input audio format; PCM data is passed to the filter()
|
||||||
* method in this format.
|
* method in this format.
|
||||||
*/
|
*/
|
||||||
audio_format in_audio_format;
|
AudioFormat in_audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The output audio format; the consumer of this plugin
|
* The output audio format; the consumer of this plugin
|
||||||
* expects PCM data in this format. This defaults to
|
* expects PCM data in this format. This defaults to
|
||||||
* #in_audio_format, and can be set with convert_filter_set().
|
* #in_audio_format, and can be set with convert_filter_set().
|
||||||
*/
|
*/
|
||||||
audio_format out_audio_format;
|
AudioFormat out_audio_format;
|
||||||
|
|
||||||
Manual<PcmConvert> state;
|
Manual<PcmConvert> state;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Set(const audio_format &_out_audio_format) {
|
void Set(const AudioFormat &_out_audio_format) {
|
||||||
assert(audio_format_valid(&in_audio_format));
|
assert(in_audio_format.IsValid());
|
||||||
assert(audio_format_valid(&out_audio_format));
|
assert(out_audio_format.IsValid());
|
||||||
assert(audio_format_valid(&_out_audio_format));
|
assert(_out_audio_format.IsValid());
|
||||||
|
|
||||||
out_audio_format = _out_audio_format;
|
out_audio_format = _out_audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) override;
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
|
@ -69,15 +69,15 @@ convert_filter_init(gcc_unused const struct config_param *param,
|
||||||
return new ConvertFilter();
|
return new ConvertFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct audio_format *
|
AudioFormat
|
||||||
ConvertFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
|
ConvertFilter::Open(AudioFormat &audio_format, gcc_unused GError **error_r)
|
||||||
{
|
{
|
||||||
assert(audio_format_valid(&audio_format));
|
assert(audio_format.IsValid());
|
||||||
|
|
||||||
in_audio_format = out_audio_format = audio_format;
|
in_audio_format = out_audio_format = audio_format;
|
||||||
state.Construct();
|
state.Construct();
|
||||||
|
|
||||||
return &in_audio_format;
|
return in_audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -93,15 +93,15 @@ const void *
|
||||||
ConvertFilter::FilterPCM(const void *src, size_t src_size,
|
ConvertFilter::FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r)
|
size_t *dest_size_r, GError **error_r)
|
||||||
{
|
{
|
||||||
if (audio_format_equals(&in_audio_format, &out_audio_format)) {
|
if (in_audio_format == out_audio_format) {
|
||||||
/* optimized special case: no-op */
|
/* optimized special case: no-op */
|
||||||
*dest_size_r = src_size;
|
*dest_size_r = src_size;
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
|
|
||||||
return state->Convert(&in_audio_format,
|
return state->Convert(in_audio_format,
|
||||||
src, src_size,
|
src, src_size,
|
||||||
&out_audio_format, dest_size_r,
|
out_audio_format, dest_size_r,
|
||||||
error_r);
|
error_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ const struct filter_plugin convert_filter_plugin = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
convert_filter_set(Filter *_filter, const audio_format &out_audio_format)
|
convert_filter_set(Filter *_filter, const AudioFormat out_audio_format)
|
||||||
{
|
{
|
||||||
ConvertFilter *filter = (ConvertFilter *)_filter;
|
ConvertFilter *filter = (ConvertFilter *)_filter;
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#define MPD_CONVERT_FILTER_PLUGIN_HXX
|
#define MPD_CONVERT_FILTER_PLUGIN_HXX
|
||||||
|
|
||||||
class Filter;
|
class Filter;
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the output audio format for the specified filter. You must
|
* Sets the output audio format for the specified filter. You must
|
||||||
|
@ -30,6 +30,6 @@ struct audio_format;
|
||||||
* the last in a chain.
|
* the last in a chain.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
convert_filter_set(Filter *filter, const audio_format &out_audio_format);
|
convert_filter_set(Filter *filter, AudioFormat out_audio_format);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "FilterInternal.hxx"
|
#include "FilterInternal.hxx"
|
||||||
#include "FilterRegistry.hxx"
|
#include "FilterRegistry.hxx"
|
||||||
#include "pcm/PcmBuffer.hxx"
|
#include "pcm/PcmBuffer.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "AudioCompress/compress.h"
|
#include "AudioCompress/compress.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
@ -34,7 +34,7 @@ class NormalizeFilter final : public Filter {
|
||||||
PcmBuffer buffer;
|
PcmBuffer buffer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) override;
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
|
@ -47,14 +47,14 @@ normalize_filter_init(gcc_unused const struct config_param *param,
|
||||||
return new NormalizeFilter();
|
return new NormalizeFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct audio_format *
|
AudioFormat
|
||||||
NormalizeFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
|
NormalizeFilter::Open(AudioFormat &audio_format, gcc_unused GError **error_r)
|
||||||
{
|
{
|
||||||
audio_format.format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
|
|
||||||
compressor = Compressor_new(0);
|
compressor = Compressor_new(0);
|
||||||
|
|
||||||
return &audio_format;
|
return audio_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -28,13 +28,14 @@
|
||||||
#include "FilterPlugin.hxx"
|
#include "FilterPlugin.hxx"
|
||||||
#include "FilterInternal.hxx"
|
#include "FilterInternal.hxx"
|
||||||
#include "FilterRegistry.hxx"
|
#include "FilterRegistry.hxx"
|
||||||
|
#include "AudioFormat.hxx"
|
||||||
#include "gcc.h"
|
#include "gcc.h"
|
||||||
|
|
||||||
class NullFilter final : public Filter {
|
class NullFilter final : public Filter {
|
||||||
public:
|
public:
|
||||||
virtual const audio_format *Open(audio_format &af,
|
virtual AudioFormat Open(AudioFormat &af,
|
||||||
gcc_unused GError **error_r) {
|
gcc_unused GError **error_r) {
|
||||||
return ⁡
|
return af;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Close() {}
|
virtual void Close() {}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "FilterPlugin.hxx"
|
#include "FilterPlugin.hxx"
|
||||||
#include "FilterInternal.hxx"
|
#include "FilterInternal.hxx"
|
||||||
#include "FilterRegistry.hxx"
|
#include "FilterRegistry.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "replay_gain_info.h"
|
#include "replay_gain_info.h"
|
||||||
#include "replay_gain_config.h"
|
#include "replay_gain_config.h"
|
||||||
#include "MixerControl.hxx"
|
#include "MixerControl.hxx"
|
||||||
|
@ -66,7 +66,7 @@ class ReplayGainFilter final : public Filter {
|
||||||
*/
|
*/
|
||||||
unsigned volume;
|
unsigned volume;
|
||||||
|
|
||||||
struct audio_format format;
|
AudioFormat format;
|
||||||
|
|
||||||
PcmBuffer buffer;
|
PcmBuffer buffer;
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ public:
|
||||||
*/
|
*/
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) override;
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
|
@ -159,12 +159,12 @@ replay_gain_filter_init(gcc_unused const struct config_param *param,
|
||||||
return new ReplayGainFilter();
|
return new ReplayGainFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
const audio_format *
|
AudioFormat
|
||||||
ReplayGainFilter::Open(audio_format &af, gcc_unused GError **error_r)
|
ReplayGainFilter::Open(AudioFormat &af, gcc_unused GError **error_r)
|
||||||
{
|
{
|
||||||
format = af;
|
format = af;
|
||||||
|
|
||||||
return &format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -196,7 +196,7 @@ ReplayGainFilter::FilterPCM(const void *src, size_t src_size,
|
||||||
memcpy(dest, src, src_size);
|
memcpy(dest, src, src_size);
|
||||||
|
|
||||||
bool success = pcm_volume(dest, src_size,
|
bool success = pcm_volume(dest, src_size,
|
||||||
sample_format(format.format),
|
format.format,
|
||||||
volume);
|
volume);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
g_set_error(error_r, replay_gain_quark(), 0,
|
g_set_error(error_r, replay_gain_quark(), 0,
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "ConfigQuark.hxx"
|
#include "ConfigQuark.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
#include "CheckAudioFormat.hxx"
|
#include "CheckAudioFormat.hxx"
|
||||||
#include "FilterPlugin.hxx"
|
#include "FilterPlugin.hxx"
|
||||||
#include "FilterInternal.hxx"
|
#include "FilterInternal.hxx"
|
||||||
|
@ -79,12 +79,12 @@ class RouteFilter final : public Filter {
|
||||||
/**
|
/**
|
||||||
* The actual input format of our signal, once opened
|
* The actual input format of our signal, once opened
|
||||||
*/
|
*/
|
||||||
struct audio_format input_format;
|
AudioFormat input_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The decided upon output format, once opened
|
* The decided upon output format, once opened
|
||||||
*/
|
*/
|
||||||
struct audio_format output_format;
|
AudioFormat output_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The size, in bytes, of each multichannel frame in the
|
* The size, in bytes, of each multichannel frame in the
|
||||||
|
@ -120,7 +120,7 @@ public:
|
||||||
*/
|
*/
|
||||||
bool Configure(const config_param *param, GError **error_r);
|
bool Configure(const config_param *param, GError **error_r);
|
||||||
|
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) override;
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
|
@ -241,12 +241,12 @@ route_filter_init(const config_param *param, GError **error_r)
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct audio_format *
|
AudioFormat
|
||||||
RouteFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
|
RouteFilter::Open(AudioFormat &audio_format, gcc_unused GError **error_r)
|
||||||
{
|
{
|
||||||
// Copy the input format for later reference
|
// Copy the input format for later reference
|
||||||
input_format = audio_format;
|
input_format = audio_format;
|
||||||
input_frame_size = audio_format_frame_size(&input_format);
|
input_frame_size = input_format.GetFrameSize();
|
||||||
|
|
||||||
// Decide on an output format which has enough channels,
|
// Decide on an output format which has enough channels,
|
||||||
// and is otherwise identical
|
// and is otherwise identical
|
||||||
|
@ -254,9 +254,9 @@ RouteFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
|
||||||
output_format.channels = min_output_channels;
|
output_format.channels = min_output_channels;
|
||||||
|
|
||||||
// Precalculate this simple value, to speed up allocation later
|
// Precalculate this simple value, to speed up allocation later
|
||||||
output_frame_size = audio_format_frame_size(&output_format);
|
output_frame_size = output_format.GetFrameSize();
|
||||||
|
|
||||||
return &output_format;
|
return output_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -271,8 +271,7 @@ RouteFilter::FilterPCM(const void *src, size_t src_size,
|
||||||
{
|
{
|
||||||
size_t number_of_frames = src_size / input_frame_size;
|
size_t number_of_frames = src_size / input_frame_size;
|
||||||
|
|
||||||
size_t bytes_per_frame_per_channel =
|
const size_t bytes_per_frame_per_channel = input_format.GetSampleSize();
|
||||||
audio_format_sample_size(&input_format);
|
|
||||||
|
|
||||||
// A moving pointer that always refers to channel 0 in the input, at the currently handled frame
|
// A moving pointer that always refers to channel 0 in the input, at the currently handled frame
|
||||||
const uint8_t *base_source = (const uint8_t *)src;
|
const uint8_t *base_source = (const uint8_t *)src;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "pcm/PcmVolume.hxx"
|
#include "pcm/PcmVolume.hxx"
|
||||||
#include "pcm/PcmBuffer.hxx"
|
#include "pcm/PcmBuffer.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -36,7 +36,7 @@ class VolumeFilter final : public Filter {
|
||||||
*/
|
*/
|
||||||
unsigned volume;
|
unsigned volume;
|
||||||
|
|
||||||
struct audio_format format;
|
AudioFormat format;
|
||||||
|
|
||||||
PcmBuffer buffer;
|
PcmBuffer buffer;
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public:
|
||||||
volume = _volume;
|
volume = _volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const audio_format *Open(audio_format &af, GError **error_r);
|
virtual AudioFormat Open(AudioFormat &af, GError **error_r) override;
|
||||||
virtual void Close();
|
virtual void Close();
|
||||||
virtual const void *FilterPCM(const void *src, size_t src_size,
|
virtual const void *FilterPCM(const void *src, size_t src_size,
|
||||||
size_t *dest_size_r, GError **error_r);
|
size_t *dest_size_r, GError **error_r);
|
||||||
|
@ -75,12 +75,12 @@ volume_filter_init(gcc_unused const struct config_param *param,
|
||||||
return new VolumeFilter();
|
return new VolumeFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct audio_format *
|
AudioFormat
|
||||||
VolumeFilter::Open(audio_format &audio_format, gcc_unused GError **error_r)
|
VolumeFilter::Open(AudioFormat &audio_format, gcc_unused GError **error_r)
|
||||||
{
|
{
|
||||||
format = audio_format;
|
format = audio_format;
|
||||||
|
|
||||||
return &format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -112,7 +112,7 @@ VolumeFilter::FilterPCM(const void *src, size_t src_size,
|
||||||
memcpy(dest, src, src_size);
|
memcpy(dest, src, src_size);
|
||||||
|
|
||||||
bool success = pcm_volume(dest, src_size,
|
bool success = pcm_volume(dest, src_size,
|
||||||
sample_format(format.format),
|
format.format,
|
||||||
volume);
|
volume);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
g_set_error(error_r, volume_quark(), 0,
|
g_set_error(error_r, volume_quark(), 0,
|
||||||
|
|
|
@ -233,26 +233,26 @@ alsa_test_default_device(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static snd_pcm_format_t
|
static snd_pcm_format_t
|
||||||
get_bitformat(enum sample_format sample_format)
|
get_bitformat(SampleFormat sample_format)
|
||||||
{
|
{
|
||||||
switch (sample_format) {
|
switch (sample_format) {
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
case SAMPLE_FORMAT_DSD:
|
case SampleFormat::DSD:
|
||||||
return SND_PCM_FORMAT_UNKNOWN;
|
return SND_PCM_FORMAT_UNKNOWN;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
return SND_PCM_FORMAT_S8;
|
return SND_PCM_FORMAT_S8;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
return SND_PCM_FORMAT_S16;
|
return SND_PCM_FORMAT_S16;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return SND_PCM_FORMAT_S24;
|
return SND_PCM_FORMAT_S24;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
return SND_PCM_FORMAT_S32;
|
return SND_PCM_FORMAT_S32;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return SND_PCM_FORMAT_FLOAT;
|
return SND_PCM_FORMAT_FLOAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,7 +324,7 @@ alsa_try_format_or_packed(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
alsa_output_try_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
alsa_output_try_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
||||||
enum sample_format sample_format,
|
SampleFormat sample_format,
|
||||||
bool *packed_r, bool *reverse_endian_r)
|
bool *packed_r, bool *reverse_endian_r)
|
||||||
{
|
{
|
||||||
snd_pcm_format_t alsa_format = get_bitformat(sample_format);
|
snd_pcm_format_t alsa_format = get_bitformat(sample_format);
|
||||||
|
@ -355,36 +355,36 @@ alsa_output_try_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
||||||
struct audio_format *audio_format,
|
AudioFormat &audio_format,
|
||||||
bool *packed_r, bool *reverse_endian_r)
|
bool *packed_r, bool *reverse_endian_r)
|
||||||
{
|
{
|
||||||
/* try the input format first */
|
/* try the input format first */
|
||||||
|
|
||||||
int err = alsa_output_try_format(pcm, hwparams,
|
int err = alsa_output_try_format(pcm, hwparams,
|
||||||
sample_format(audio_format->format),
|
audio_format.format,
|
||||||
packed_r, reverse_endian_r);
|
packed_r, reverse_endian_r);
|
||||||
|
|
||||||
/* if unsupported by the hardware, try other formats */
|
/* if unsupported by the hardware, try other formats */
|
||||||
|
|
||||||
static const enum sample_format probe_formats[] = {
|
static const SampleFormat probe_formats[] = {
|
||||||
SAMPLE_FORMAT_S24_P32,
|
SampleFormat::S24_P32,
|
||||||
SAMPLE_FORMAT_S32,
|
SampleFormat::S32,
|
||||||
SAMPLE_FORMAT_S16,
|
SampleFormat::S16,
|
||||||
SAMPLE_FORMAT_S8,
|
SampleFormat::S8,
|
||||||
SAMPLE_FORMAT_UNDEFINED,
|
SampleFormat::UNDEFINED,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned i = 0;
|
for (unsigned i = 0;
|
||||||
err == -EINVAL && probe_formats[i] != SAMPLE_FORMAT_UNDEFINED;
|
err == -EINVAL && probe_formats[i] != SampleFormat::UNDEFINED;
|
||||||
++i) {
|
++i) {
|
||||||
const enum sample_format mpd_format = probe_formats[i];
|
const SampleFormat mpd_format = probe_formats[i];
|
||||||
if (mpd_format == audio_format->format)
|
if (mpd_format == audio_format.format)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
err = alsa_output_try_format(pcm, hwparams, mpd_format,
|
err = alsa_output_try_format(pcm, hwparams, mpd_format,
|
||||||
packed_r, reverse_endian_r);
|
packed_r, reverse_endian_r);
|
||||||
if (err == 0)
|
if (err == 0)
|
||||||
audio_format->format = mpd_format;
|
audio_format.format = mpd_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -395,11 +395,11 @@ alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams,
|
||||||
* the configured settings and the audio format.
|
* the configured settings and the audio format.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
alsa_setup(AlsaOutput *ad, struct audio_format *audio_format,
|
alsa_setup(AlsaOutput *ad, AudioFormat &audio_format,
|
||||||
bool *packed_r, bool *reverse_endian_r, GError **error)
|
bool *packed_r, bool *reverse_endian_r, GError **error)
|
||||||
{
|
{
|
||||||
unsigned int sample_rate = audio_format->sample_rate;
|
unsigned int sample_rate = audio_format.sample_rate;
|
||||||
unsigned int channels = audio_format->channels;
|
unsigned int channels = audio_format.channels;
|
||||||
int err;
|
int err;
|
||||||
const char *cmd = NULL;
|
const char *cmd = NULL;
|
||||||
int retry = MPD_ALSA_RETRY_NR;
|
int retry = MPD_ALSA_RETRY_NR;
|
||||||
|
@ -443,7 +443,7 @@ configure_hw:
|
||||||
g_set_error(error, alsa_output_quark(), err,
|
g_set_error(error, alsa_output_quark(), err,
|
||||||
"ALSA device \"%s\" does not support format %s: %s",
|
"ALSA device \"%s\" does not support format %s: %s",
|
||||||
alsa_device(ad),
|
alsa_device(ad),
|
||||||
sample_format_to_string(sample_format(audio_format->format)),
|
sample_format_to_string(audio_format.format),
|
||||||
snd_strerror(-err));
|
snd_strerror(-err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -458,21 +458,21 @@ configure_hw:
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
g_set_error(error, alsa_output_quark(), err,
|
g_set_error(error, alsa_output_quark(), err,
|
||||||
"ALSA device \"%s\" does not support %i channels: %s",
|
"ALSA device \"%s\" does not support %i channels: %s",
|
||||||
alsa_device(ad), (int)audio_format->channels,
|
alsa_device(ad), (int)audio_format.channels,
|
||||||
snd_strerror(-err));
|
snd_strerror(-err));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
audio_format->channels = (int8_t)channels;
|
audio_format.channels = (int8_t)channels;
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams,
|
err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams,
|
||||||
&sample_rate, NULL);
|
&sample_rate, NULL);
|
||||||
if (err < 0 || sample_rate == 0) {
|
if (err < 0 || sample_rate == 0) {
|
||||||
g_set_error(error, alsa_output_quark(), err,
|
g_set_error(error, alsa_output_quark(), err,
|
||||||
"ALSA device \"%s\" does not support %u Hz audio",
|
"ALSA device \"%s\" does not support %u Hz audio",
|
||||||
alsa_device(ad), audio_format->sample_rate);
|
alsa_device(ad), audio_format.sample_rate);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
audio_format->sample_rate = sample_rate;
|
audio_format.sample_rate = sample_rate;
|
||||||
|
|
||||||
snd_pcm_uframes_t buffer_size_min, buffer_size_max;
|
snd_pcm_uframes_t buffer_size_min, buffer_size_max;
|
||||||
snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min);
|
snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min);
|
||||||
|
@ -603,22 +603,22 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
alsa_setup_dsd(AlsaOutput *ad, struct audio_format *audio_format,
|
alsa_setup_dsd(AlsaOutput *ad, const AudioFormat audio_format,
|
||||||
bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
|
bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
assert(ad->dsd_usb);
|
assert(ad->dsd_usb);
|
||||||
assert(audio_format->format == SAMPLE_FORMAT_DSD);
|
assert(audio_format.format == SampleFormat::DSD);
|
||||||
|
|
||||||
/* pass 24 bit to alsa_setup() */
|
/* pass 24 bit to alsa_setup() */
|
||||||
|
|
||||||
struct audio_format usb_format = *audio_format;
|
AudioFormat usb_format = audio_format;
|
||||||
usb_format.format = SAMPLE_FORMAT_S24_P32;
|
usb_format.format = SampleFormat::S24_P32;
|
||||||
usb_format.sample_rate /= 2;
|
usb_format.sample_rate /= 2;
|
||||||
|
|
||||||
const struct audio_format check = usb_format;
|
const AudioFormat check = usb_format;
|
||||||
|
|
||||||
if (!alsa_setup(ad, &usb_format, packed_r, reverse_endian_r, error_r))
|
if (!alsa_setup(ad, usb_format, packed_r, reverse_endian_r, error_r))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* if the device allows only 32 bit, shift all DSD-over-USB
|
/* if the device allows only 32 bit, shift all DSD-over-USB
|
||||||
|
@ -626,11 +626,11 @@ alsa_setup_dsd(AlsaOutput *ad, struct audio_format *audio_format,
|
||||||
the DSD-over-USB documentation does not specify whether
|
the DSD-over-USB documentation does not specify whether
|
||||||
this is legal, but there is anecdotical evidence that this
|
this is legal, but there is anecdotical evidence that this
|
||||||
is possible (and the only option for some devices) */
|
is possible (and the only option for some devices) */
|
||||||
*shift8_r = usb_format.format == SAMPLE_FORMAT_S32;
|
*shift8_r = usb_format.format == SampleFormat::S32;
|
||||||
if (usb_format.format == SAMPLE_FORMAT_S32)
|
if (usb_format.format == SampleFormat::S32)
|
||||||
usb_format.format = SAMPLE_FORMAT_S24_P32;
|
usb_format.format = SampleFormat::S24_P32;
|
||||||
|
|
||||||
if (!audio_format_equals(&usb_format, &check)) {
|
if (usb_format != check) {
|
||||||
/* no bit-perfect playback, which is required
|
/* no bit-perfect playback, which is required
|
||||||
for DSD over USB */
|
for DSD over USB */
|
||||||
g_set_error(error_r, alsa_output_quark(), 0,
|
g_set_error(error_r, alsa_output_quark(), 0,
|
||||||
|
@ -644,13 +644,13 @@ alsa_setup_dsd(AlsaOutput *ad, struct audio_format *audio_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
alsa_setup_or_dsd(AlsaOutput *ad, struct audio_format *audio_format,
|
alsa_setup_or_dsd(AlsaOutput *ad, AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
bool shift8 = false, packed, reverse_endian;
|
bool shift8 = false, packed, reverse_endian;
|
||||||
|
|
||||||
const bool dsd_usb = ad->dsd_usb &&
|
const bool dsd_usb = ad->dsd_usb &&
|
||||||
audio_format->format == SAMPLE_FORMAT_DSD;
|
audio_format.format == SampleFormat::DSD;
|
||||||
const bool success = dsd_usb
|
const bool success = dsd_usb
|
||||||
? alsa_setup_dsd(ad, audio_format,
|
? alsa_setup_dsd(ad, audio_format,
|
||||||
&shift8, &packed, &reverse_endian,
|
&shift8, &packed, &reverse_endian,
|
||||||
|
@ -660,14 +660,14 @@ alsa_setup_or_dsd(AlsaOutput *ad, struct audio_format *audio_format,
|
||||||
if (!success)
|
if (!success)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ad->pcm_export->Open(sample_format(audio_format->format),
|
ad->pcm_export->Open(audio_format.format,
|
||||||
audio_format->channels,
|
audio_format.channels,
|
||||||
dsd_usb, shift8, packed, reverse_endian);
|
dsd_usb, shift8, packed, reverse_endian);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
|
alsa_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||||
{
|
{
|
||||||
AlsaOutput *ad = (AlsaOutput *)ao;
|
AlsaOutput *ad = (AlsaOutput *)ao;
|
||||||
|
|
||||||
|
@ -688,8 +688,8 @@ alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **e
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ad->in_frame_size = audio_format_frame_size(audio_format);
|
ad->in_frame_size = audio_format.GetFrameSize();
|
||||||
ad->out_frame_size = ad->pcm_export->GetFrameSize(*audio_format);
|
ad->out_frame_size = ad->pcm_export->GetFrameSize(audio_format);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,18 +200,18 @@ ao_output_close(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ao_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
ao_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
ao_sample_format format = OUR_AO_FORMAT_INITIALIZER;
|
ao_sample_format format = OUR_AO_FORMAT_INITIALIZER;
|
||||||
AoOutput *ad = (AoOutput *)ao;
|
AoOutput *ad = (AoOutput *)ao;
|
||||||
|
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
format.bits = 8;
|
format.bits = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
format.bits = 16;
|
format.bits = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -219,14 +219,14 @@ ao_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
/* support for 24 bit samples in libao is currently
|
/* support for 24 bit samples in libao is currently
|
||||||
dubious, and until we have sorted that out,
|
dubious, and until we have sorted that out,
|
||||||
convert everything to 16 bit */
|
convert everything to 16 bit */
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
format.bits = 16;
|
format.bits = 16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
format.rate = audio_format->sample_rate;
|
format.rate = audio_format.sample_rate;
|
||||||
format.byte_format = AO_FMT_NATIVE;
|
format.byte_format = AO_FMT_NATIVE;
|
||||||
format.channels = audio_format->channels;
|
format.channels = audio_format.channels;
|
||||||
|
|
||||||
ad->device = ao_open_live(ad->driver, &format, ad->options);
|
ad->device = ao_open_live(ad->driver, &format, ad->options);
|
||||||
|
|
||||||
|
|
|
@ -227,12 +227,12 @@ fifo_output_finish(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
fifo_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
fifo_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
G_GNUC_UNUSED GError **error)
|
G_GNUC_UNUSED GError **error)
|
||||||
{
|
{
|
||||||
FifoOutput *fd = (FifoOutput *)ao;
|
FifoOutput *fd = (FifoOutput *)ao;
|
||||||
|
|
||||||
fd->timer = new Timer(*audio_format);
|
fd->timer = new Timer(audio_format);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,13 +131,13 @@ struct HttpdOutput final : private ServerSocket {
|
||||||
/**
|
/**
|
||||||
* Caller must lock the mutex.
|
* Caller must lock the mutex.
|
||||||
*/
|
*/
|
||||||
bool OpenEncoder(struct audio_format *audio_format,
|
bool OpenEncoder(AudioFormat &audio_format,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller must lock the mutex.
|
* Caller must lock the mutex.
|
||||||
*/
|
*/
|
||||||
bool Open(struct audio_format *audio_format, GError **error_r);
|
bool Open(AudioFormat &audio_format, GError **error_r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller must lock the mutex.
|
* Caller must lock the mutex.
|
||||||
|
|
|
@ -291,7 +291,7 @@ httpd_output_disable(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
HttpdOutput::OpenEncoder(struct audio_format *audio_format, GError **error)
|
HttpdOutput::OpenEncoder(AudioFormat &audio_format, GError **error)
|
||||||
{
|
{
|
||||||
if (!encoder_open(encoder, audio_format, error))
|
if (!encoder_open(encoder, audio_format, error))
|
||||||
return false;
|
return false;
|
||||||
|
@ -307,7 +307,7 @@ HttpdOutput::OpenEncoder(struct audio_format *audio_format, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
inline bool
|
||||||
HttpdOutput::Open(struct audio_format *audio_format, GError **error_r)
|
HttpdOutput::Open(AudioFormat &audio_format, GError **error_r)
|
||||||
{
|
{
|
||||||
assert(!open);
|
assert(!open);
|
||||||
assert(clients.empty());
|
assert(clients.empty());
|
||||||
|
@ -320,7 +320,7 @@ HttpdOutput::Open(struct audio_format *audio_format, GError **error_r)
|
||||||
/* initialize other attributes */
|
/* initialize other attributes */
|
||||||
|
|
||||||
clients_cnt = 0;
|
clients_cnt = 0;
|
||||||
timer = new Timer(*audio_format);
|
timer = new Timer(audio_format);
|
||||||
|
|
||||||
open = true;
|
open = true;
|
||||||
|
|
||||||
|
@ -328,7 +328,7 @@ HttpdOutput::Open(struct audio_format *audio_format, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
httpd_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
httpd_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
HttpdOutput *httpd = Cast(ao);
|
HttpdOutput *httpd = Cast(ao);
|
||||||
|
|
|
@ -67,7 +67,7 @@ struct JackOutput {
|
||||||
size_t ringbuffer_size;
|
size_t ringbuffer_size;
|
||||||
|
|
||||||
/* the current audio format */
|
/* the current audio format */
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
|
|
||||||
/* jack library stuff */
|
/* jack library stuff */
|
||||||
jack_port_t *ports[MAX_PORTS];
|
jack_port_t *ports[MAX_PORTS];
|
||||||
|
@ -203,18 +203,18 @@ mpd_jack_shutdown(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_audioformat(JackOutput *jd, struct audio_format *audio_format)
|
set_audioformat(JackOutput *jd, AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
audio_format->sample_rate = jack_get_sample_rate(jd->client);
|
audio_format.sample_rate = jack_get_sample_rate(jd->client);
|
||||||
|
|
||||||
if (jd->num_source_ports == 1)
|
if (jd->num_source_ports == 1)
|
||||||
audio_format->channels = 1;
|
audio_format.channels = 1;
|
||||||
else if (audio_format->channels > jd->num_source_ports)
|
else if (audio_format.channels > jd->num_source_ports)
|
||||||
audio_format->channels = 2;
|
audio_format.channels = 2;
|
||||||
|
|
||||||
if (audio_format->format != SAMPLE_FORMAT_S16 &&
|
if (audio_format.format != SampleFormat::S16 &&
|
||||||
audio_format->format != SAMPLE_FORMAT_S24_P32)
|
audio_format.format != SampleFormat::S24_P32)
|
||||||
audio_format->format = SAMPLE_FORMAT_S24_P32;
|
audio_format.format = SampleFormat::S24_P32;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -591,7 +591,7 @@ mpd_jack_start(JackOutput *jd, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format,
|
mpd_jack_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
JackOutput *jd = (JackOutput *)ao;
|
JackOutput *jd = (JackOutput *)ao;
|
||||||
|
@ -607,7 +607,7 @@ mpd_jack_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
set_audioformat(jd, audio_format);
|
set_audioformat(jd, audio_format);
|
||||||
jd->audio_format = *audio_format;
|
jd->audio_format = audio_format;
|
||||||
|
|
||||||
if (!mpd_jack_start(jd, error_r))
|
if (!mpd_jack_start(jd, error_r))
|
||||||
return false;
|
return false;
|
||||||
|
@ -684,12 +684,12 @@ mpd_jack_write_samples(JackOutput *jd, const void *src,
|
||||||
unsigned num_samples)
|
unsigned num_samples)
|
||||||
{
|
{
|
||||||
switch (jd->audio_format.format) {
|
switch (jd->audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
mpd_jack_write_samples_16(jd, (const int16_t*)src,
|
mpd_jack_write_samples_16(jd, (const int16_t*)src,
|
||||||
num_samples);
|
num_samples);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
mpd_jack_write_samples_24(jd, (const int32_t*)src,
|
mpd_jack_write_samples_24(jd, (const int32_t*)src,
|
||||||
num_samples);
|
num_samples);
|
||||||
break;
|
break;
|
||||||
|
@ -705,7 +705,7 @@ mpd_jack_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
JackOutput *jd = (JackOutput *)ao;
|
JackOutput *jd = (JackOutput *)ao;
|
||||||
const size_t frame_size = audio_format_frame_size(&jd->audio_format);
|
const size_t frame_size = jd->audio_format.GetFrameSize();
|
||||||
size_t space = 0, space1;
|
size_t space = 0, space1;
|
||||||
|
|
||||||
jd->pause = false;
|
jd->pause = false;
|
||||||
|
|
|
@ -66,13 +66,13 @@ null_finish(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
null_open(struct audio_output *ao, struct audio_format *audio_format,
|
null_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
gcc_unused GError **error)
|
gcc_unused GError **error)
|
||||||
{
|
{
|
||||||
NullOutput *nd = (NullOutput *)ao;
|
NullOutput *nd = (NullOutput *)ao;
|
||||||
|
|
||||||
if (nd->sync)
|
if (nd->sync)
|
||||||
nd->timer = new Timer(*audio_format);
|
nd->timer = new Timer(audio_format);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -316,30 +316,30 @@ osx_output_close(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
|
osx_output_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||||
{
|
{
|
||||||
OSXOutput *od = (OSXOutput *)ao;
|
OSXOutput *od = (OSXOutput *)ao;
|
||||||
|
|
||||||
AudioStreamBasicDescription stream_description;
|
AudioStreamBasicDescription stream_description;
|
||||||
stream_description.mSampleRate = audio_format->sample_rate;
|
stream_description.mSampleRate = audio_format.sample_rate;
|
||||||
stream_description.mFormatID = kAudioFormatLinearPCM;
|
stream_description.mFormatID = kAudioFormatLinearPCM;
|
||||||
stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
|
||||||
|
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
stream_description.mBitsPerChannel = 8;
|
stream_description.mBitsPerChannel = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
stream_description.mBitsPerChannel = 16;
|
stream_description.mBitsPerChannel = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
stream_description.mBitsPerChannel = 32;
|
stream_description.mBitsPerChannel = 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
audio_format->format = SAMPLE_FORMAT_S32;
|
audio_format.format = SampleFormat::S32;
|
||||||
stream_description.mBitsPerChannel = 32;
|
stream_description.mBitsPerChannel = 32;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -348,11 +348,10 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr
|
||||||
stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stream_description.mBytesPerPacket =
|
stream_description.mBytesPerPacket = audio_format.GetFrameSize();
|
||||||
audio_format_frame_size(audio_format);
|
|
||||||
stream_description.mFramesPerPacket = 1;
|
stream_description.mFramesPerPacket = 1;
|
||||||
stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
|
stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
|
||||||
stream_description.mChannelsPerFrame = audio_format->channels;
|
stream_description.mChannelsPerFrame = audio_format.channels;
|
||||||
|
|
||||||
ComponentResult result =
|
ComponentResult result =
|
||||||
AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
|
AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
|
||||||
|
@ -374,8 +373,8 @@ osx_output_open(struct audio_output *ao, struct audio_format *audio_format, GErr
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create a buffer of 1s */
|
/* create a buffer of 1s */
|
||||||
od->buffer = fifo_buffer_new(audio_format->sample_rate *
|
od->buffer = fifo_buffer_new(audio_format.sample_rate *
|
||||||
audio_format_frame_size(audio_format));
|
audio_format.GetFrameSize());
|
||||||
|
|
||||||
status = AudioOutputUnitStart(od->au);
|
status = AudioOutputUnitStart(od->au);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
|
|
|
@ -66,26 +66,26 @@ openal_output_quark(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALenum
|
static ALenum
|
||||||
openal_audio_format(struct audio_format *audio_format)
|
openal_audio_format(AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
/* note: cannot map SAMPLE_FORMAT_S8 to AL_FORMAT_STEREO8 or
|
/* note: cannot map SampleFormat::S8 to AL_FORMAT_STEREO8 or
|
||||||
AL_FORMAT_MONO8 since OpenAL expects unsigned 8 bit
|
AL_FORMAT_MONO8 since OpenAL expects unsigned 8 bit
|
||||||
samples, while MPD uses signed samples */
|
samples, while MPD uses signed samples */
|
||||||
|
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
if (audio_format->channels == 2)
|
if (audio_format.channels == 2)
|
||||||
return AL_FORMAT_STEREO16;
|
return AL_FORMAT_STEREO16;
|
||||||
if (audio_format->channels == 1)
|
if (audio_format.channels == 1)
|
||||||
return AL_FORMAT_MONO16;
|
return AL_FORMAT_MONO16;
|
||||||
|
|
||||||
/* fall back to mono */
|
/* fall back to mono */
|
||||||
audio_format->channels = 1;
|
audio_format.channels = 1;
|
||||||
return openal_audio_format(audio_format);
|
return openal_audio_format(audio_format);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* fall back to 16 bit */
|
/* fall back to 16 bit */
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
return openal_audio_format(audio_format);
|
return openal_audio_format(audio_format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ openal_finish(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
openal_open(struct audio_output *ao, struct audio_format *audio_format,
|
openal_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
OpenALOutput *od = (OpenALOutput *)ao;
|
OpenALOutput *od = (OpenALOutput *)ao;
|
||||||
|
@ -199,7 +199,7 @@ openal_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
od->filled = 0;
|
od->filled = 0;
|
||||||
od->frequency = audio_format->sample_rate;
|
od->frequency = audio_format.sample_rate;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct OssOutput {
|
||||||
* The current input audio format. This is needed to reopen
|
* The current input audio format. This is needed to reopen
|
||||||
* the device after cancel().
|
* the device after cancel().
|
||||||
*/
|
*/
|
||||||
struct audio_format audio_format;
|
AudioFormat audio_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current OSS audio format. This is needed to reopen the
|
* The current OSS audio format. This is needed to reopen the
|
||||||
|
@ -308,10 +308,10 @@ oss_try_ioctl(int fd, unsigned long request, int value,
|
||||||
* specified number is not supported.
|
* specified number is not supported.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
|
oss_setup_channels(int fd, AudioFormat &audio_format, GError **error_r)
|
||||||
{
|
{
|
||||||
const char *const msg = "Failed to set channel count";
|
const char *const msg = "Failed to set channel count";
|
||||||
int channels = audio_format->channels;
|
int channels = audio_format.channels;
|
||||||
enum oss_setup_result result =
|
enum oss_setup_result result =
|
||||||
oss_try_ioctl_r(fd, SNDCTL_DSP_CHANNELS, &channels, msg, error_r);
|
oss_try_ioctl_r(fd, SNDCTL_DSP_CHANNELS, &channels, msg, error_r);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -319,7 +319,7 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
|
||||||
if (!audio_valid_channel_count(channels))
|
if (!audio_valid_channel_count(channels))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
audio_format->channels = channels;
|
audio_format.channels = channels;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
@ -330,7 +330,7 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 1; i < 2; ++i) {
|
for (unsigned i = 1; i < 2; ++i) {
|
||||||
if (i == audio_format->channels)
|
if (i == audio_format.channels)
|
||||||
/* don't try that again */
|
/* don't try that again */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -342,7 +342,7 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
|
||||||
if (!audio_valid_channel_count(channels))
|
if (!audio_valid_channel_count(channels))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
audio_format->channels = channels;
|
audio_format.channels = channels;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
@ -362,11 +362,11 @@ oss_setup_channels(int fd, struct audio_format *audio_format, GError **error_r)
|
||||||
* specified sample rate is not supported.
|
* specified sample rate is not supported.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
oss_setup_sample_rate(int fd, struct audio_format *audio_format,
|
oss_setup_sample_rate(int fd, AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
const char *const msg = "Failed to set sample rate";
|
const char *const msg = "Failed to set sample rate";
|
||||||
int sample_rate = audio_format->sample_rate;
|
int sample_rate = audio_format.sample_rate;
|
||||||
enum oss_setup_result result =
|
enum oss_setup_result result =
|
||||||
oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
|
oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
|
||||||
msg, error_r);
|
msg, error_r);
|
||||||
|
@ -375,7 +375,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
|
||||||
if (!audio_valid_sample_rate(sample_rate))
|
if (!audio_valid_sample_rate(sample_rate))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
audio_format->sample_rate = sample_rate;
|
audio_format.sample_rate = sample_rate;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
@ -388,7 +388,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
|
||||||
static const int sample_rates[] = { 48000, 44100, 0 };
|
static const int sample_rates[] = { 48000, 44100, 0 };
|
||||||
for (unsigned i = 0; sample_rates[i] != 0; ++i) {
|
for (unsigned i = 0; sample_rates[i] != 0; ++i) {
|
||||||
sample_rate = sample_rates[i];
|
sample_rate = sample_rates[i];
|
||||||
if (sample_rate == (int)audio_format->sample_rate)
|
if (sample_rate == (int)audio_format.sample_rate)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result = oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
|
result = oss_try_ioctl_r(fd, SNDCTL_DSP_SPEED, &sample_rate,
|
||||||
|
@ -398,7 +398,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
|
||||||
if (!audio_valid_sample_rate(sample_rate))
|
if (!audio_valid_sample_rate(sample_rate))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
audio_format->sample_rate = sample_rate;
|
audio_format.sample_rate = sample_rate;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
@ -418,28 +418,28 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
|
||||||
* AFMT_QUERY if there is no direct counterpart.
|
* AFMT_QUERY if there is no direct counterpart.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
sample_format_to_oss(enum sample_format format)
|
sample_format_to_oss(SampleFormat format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
case SAMPLE_FORMAT_DSD:
|
case SampleFormat::DSD:
|
||||||
return AFMT_QUERY;
|
return AFMT_QUERY;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
return AFMT_S8;
|
return AFMT_S8;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
return AFMT_S16_NE;
|
return AFMT_S16_NE;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
#ifdef AFMT_S24_NE
|
#ifdef AFMT_S24_NE
|
||||||
return AFMT_S24_NE;
|
return AFMT_S24_NE;
|
||||||
#else
|
#else
|
||||||
return AFMT_QUERY;
|
return AFMT_QUERY;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
#ifdef AFMT_S32_NE
|
#ifdef AFMT_S32_NE
|
||||||
return AFMT_S32_NE;
|
return AFMT_S32_NE;
|
||||||
#else
|
#else
|
||||||
|
@ -452,47 +452,47 @@ sample_format_to_oss(enum sample_format format)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an OSS sample format to its MPD counterpart. Returns
|
* Convert an OSS sample format to its MPD counterpart. Returns
|
||||||
* SAMPLE_FORMAT_UNDEFINED if there is no direct counterpart.
|
* SampleFormat::UNDEFINED if there is no direct counterpart.
|
||||||
*/
|
*/
|
||||||
static enum sample_format
|
static SampleFormat
|
||||||
sample_format_from_oss(int format)
|
sample_format_from_oss(int format)
|
||||||
{
|
{
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case AFMT_S8:
|
case AFMT_S8:
|
||||||
return SAMPLE_FORMAT_S8;
|
return SampleFormat::S8;
|
||||||
|
|
||||||
case AFMT_S16_NE:
|
case AFMT_S16_NE:
|
||||||
return SAMPLE_FORMAT_S16;
|
return SampleFormat::S16;
|
||||||
|
|
||||||
#ifdef AFMT_S24_PACKED
|
#ifdef AFMT_S24_PACKED
|
||||||
case AFMT_S24_PACKED:
|
case AFMT_S24_PACKED:
|
||||||
return SAMPLE_FORMAT_S24_P32;
|
return SampleFormat::S24_P32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AFMT_S24_NE
|
#ifdef AFMT_S24_NE
|
||||||
case AFMT_S24_NE:
|
case AFMT_S24_NE:
|
||||||
return SAMPLE_FORMAT_S24_P32;
|
return SampleFormat::S24_P32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef AFMT_S32_NE
|
#ifdef AFMT_S32_NE
|
||||||
case AFMT_S32_NE:
|
case AFMT_S32_NE:
|
||||||
return SAMPLE_FORMAT_S32;
|
return SampleFormat::S32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return SAMPLE_FORMAT_UNDEFINED;
|
return SampleFormat::UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Probe one sample format.
|
* Probe one sample format.
|
||||||
*
|
*
|
||||||
* @return the selected sample format or SAMPLE_FORMAT_UNDEFINED on
|
* @return the selected sample format or SampleFormat::UNDEFINED on
|
||||||
* error
|
* error
|
||||||
*/
|
*/
|
||||||
static enum oss_setup_result
|
static enum oss_setup_result
|
||||||
oss_probe_sample_format(int fd, enum sample_format sample_format,
|
oss_probe_sample_format(int fd, SampleFormat sample_format,
|
||||||
enum sample_format *sample_format_r,
|
SampleFormat *sample_format_r,
|
||||||
int *oss_format_r,
|
int *oss_format_r,
|
||||||
#ifdef AFMT_S24_PACKED
|
#ifdef AFMT_S24_PACKED
|
||||||
PcmExport &pcm_export,
|
PcmExport &pcm_export,
|
||||||
|
@ -509,7 +509,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
|
||||||
"Failed to set sample format", error_r);
|
"Failed to set sample format", error_r);
|
||||||
|
|
||||||
#ifdef AFMT_S24_PACKED
|
#ifdef AFMT_S24_PACKED
|
||||||
if (result == UNSUPPORTED && sample_format == SAMPLE_FORMAT_S24_P32) {
|
if (result == UNSUPPORTED && sample_format == SampleFormat::S24_P32) {
|
||||||
/* if the driver doesn't support padded 24 bit, try
|
/* if the driver doesn't support padded 24 bit, try
|
||||||
packed 24 bit */
|
packed 24 bit */
|
||||||
oss_format = AFMT_S24_PACKED;
|
oss_format = AFMT_S24_PACKED;
|
||||||
|
@ -523,7 +523,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
sample_format = sample_format_from_oss(oss_format);
|
sample_format = sample_format_from_oss(oss_format);
|
||||||
if (sample_format == SAMPLE_FORMAT_UNDEFINED)
|
if (sample_format == SampleFormat::UNDEFINED)
|
||||||
return UNSUPPORTED;
|
return UNSUPPORTED;
|
||||||
|
|
||||||
*sample_format_r = sample_format;
|
*sample_format_r = sample_format;
|
||||||
|
@ -544,16 +544,16 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
|
||||||
* specified format is not supported.
|
* specified format is not supported.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
oss_setup_sample_format(int fd, struct audio_format *audio_format,
|
oss_setup_sample_format(int fd, AudioFormat &audio_format,
|
||||||
int *oss_format_r,
|
int *oss_format_r,
|
||||||
#ifdef AFMT_S24_PACKED
|
#ifdef AFMT_S24_PACKED
|
||||||
PcmExport &pcm_export,
|
PcmExport &pcm_export,
|
||||||
#endif
|
#endif
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
enum sample_format mpd_format;
|
SampleFormat mpd_format;
|
||||||
enum oss_setup_result result =
|
enum oss_setup_result result =
|
||||||
oss_probe_sample_format(fd, sample_format(audio_format->format),
|
oss_probe_sample_format(fd, audio_format.format,
|
||||||
&mpd_format, oss_format_r,
|
&mpd_format, oss_format_r,
|
||||||
#ifdef AFMT_S24_PACKED
|
#ifdef AFMT_S24_PACKED
|
||||||
pcm_export,
|
pcm_export,
|
||||||
|
@ -561,7 +561,7 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
|
||||||
error_r);
|
error_r);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
audio_format->format = mpd_format;
|
audio_format.format = mpd_format;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
@ -577,17 +577,17 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
|
||||||
/* the requested sample format is not available - probe for
|
/* the requested sample format is not available - probe for
|
||||||
other formats supported by MPD */
|
other formats supported by MPD */
|
||||||
|
|
||||||
static const enum sample_format sample_formats[] = {
|
static const SampleFormat sample_formats[] = {
|
||||||
SAMPLE_FORMAT_S24_P32,
|
SampleFormat::S24_P32,
|
||||||
SAMPLE_FORMAT_S32,
|
SampleFormat::S32,
|
||||||
SAMPLE_FORMAT_S16,
|
SampleFormat::S16,
|
||||||
SAMPLE_FORMAT_S8,
|
SampleFormat::S8,
|
||||||
SAMPLE_FORMAT_UNDEFINED /* sentinel */
|
SampleFormat::UNDEFINED /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unsigned i = 0; sample_formats[i] != SAMPLE_FORMAT_UNDEFINED; ++i) {
|
for (unsigned i = 0; sample_formats[i] != SampleFormat::UNDEFINED; ++i) {
|
||||||
mpd_format = sample_formats[i];
|
mpd_format = sample_formats[i];
|
||||||
if (mpd_format == audio_format->format)
|
if (mpd_format == audio_format.format)
|
||||||
/* don't try that again */
|
/* don't try that again */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -599,7 +599,7 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
|
||||||
error_r);
|
error_r);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case SUCCESS:
|
case SUCCESS:
|
||||||
audio_format->format = mpd_format;
|
audio_format.format = mpd_format;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
|
@ -619,7 +619,7 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
|
||||||
* Sets up the OSS device which was opened before.
|
* Sets up the OSS device which was opened before.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
oss_setup(OssOutput *od, struct audio_format *audio_format,
|
oss_setup(OssOutput *od, AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
return oss_setup_channels(od->fd, audio_format, error_r) &&
|
return oss_setup_channels(od->fd, audio_format, error_r) &&
|
||||||
|
@ -687,7 +687,7 @@ oss_reopen(OssOutput *od, GError **error_r)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
oss_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
oss_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
OssOutput *od = (OssOutput *)ao;
|
OssOutput *od = (OssOutput *)ao;
|
||||||
|
@ -705,7 +705,7 @@ oss_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
od->audio_format = *audio_format;
|
od->audio_format = audio_format;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,7 +95,7 @@ pipe_output_finish(struct audio_output *ao)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pipe_output_open(struct audio_output *ao,
|
pipe_output_open(struct audio_output *ao,
|
||||||
G_GNUC_UNUSED struct audio_format *audio_format,
|
G_GNUC_UNUSED AudioFormat &audio_format,
|
||||||
G_GNUC_UNUSED GError **error)
|
G_GNUC_UNUSED GError **error)
|
||||||
{
|
{
|
||||||
PipeOutput *pd = (PipeOutput *)ao;
|
PipeOutput *pd = (PipeOutput *)ao;
|
||||||
|
|
|
@ -578,7 +578,7 @@ pulse_output_setup_stream(PulseOutput *po, const pa_sample_spec *ss,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
pulse_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
pulse_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
PulseOutput *po = (PulseOutput *)ao;
|
PulseOutput *po = (PulseOutput *)ao;
|
||||||
|
@ -615,11 +615,11 @@ pulse_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
|
|
||||||
/* MPD doesn't support the other pulseaudio sample formats, so
|
/* MPD doesn't support the other pulseaudio sample formats, so
|
||||||
we just force MPD to send us everything as 16 bit */
|
we just force MPD to send us everything as 16 bit */
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
|
|
||||||
ss.format = PA_SAMPLE_S16NE;
|
ss.format = PA_SAMPLE_S16NE;
|
||||||
ss.rate = audio_format->sample_rate;
|
ss.rate = audio_format.sample_rate;
|
||||||
ss.channels = audio_format->channels;
|
ss.channels = audio_format.channels;
|
||||||
|
|
||||||
/* create a stream .. */
|
/* create a stream .. */
|
||||||
|
|
||||||
|
|
|
@ -192,7 +192,7 @@ RecorderOutput::EncoderToFile(GError **error_r)
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
recorder_output_open(struct audio_output *ao,
|
recorder_output_open(struct audio_output *ao,
|
||||||
struct audio_format *audio_format,
|
AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
RecorderOutput *recorder = (RecorderOutput *)ao;
|
RecorderOutput *recorder = (RecorderOutput *)ao;
|
||||||
|
|
|
@ -144,39 +144,41 @@ roar_finish(struct audio_output *ao)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
roar_use_audio_format(struct roar_audio_info *info,
|
roar_use_audio_format(struct roar_audio_info *info,
|
||||||
struct audio_format *audio_format)
|
AudioFormat &audio_format)
|
||||||
{
|
{
|
||||||
info->rate = audio_format->sample_rate;
|
info->rate = audio_format.sample_rate;
|
||||||
info->channels = audio_format->channels;
|
info->channels = audio_format.channels;
|
||||||
info->codec = ROAR_CODEC_PCM_S;
|
info->codec = ROAR_CODEC_PCM_S;
|
||||||
|
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
case SampleFormat::UNDEFINED:
|
||||||
|
case SampleFormat::FLOAT:
|
||||||
|
case SampleFormat::DSD:
|
||||||
info->bits = 16;
|
info->bits = 16;
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
info->bits = 8;
|
info->bits = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
info->bits = 16;
|
info->bits = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
info->bits = 32;
|
info->bits = 32;
|
||||||
audio_format->format = SAMPLE_FORMAT_S32;
|
audio_format.format = SampleFormat::S32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
info->bits = 32;
|
info->bits = 32;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
roar_open(struct audio_output *ao, struct audio_format *audio_format, GError **error)
|
roar_open(struct audio_output *ao, AudioFormat &audio_format, GError **error)
|
||||||
{
|
{
|
||||||
RoarOutput *self = (RoarOutput *)ao;
|
RoarOutput *self = (RoarOutput *)ao;
|
||||||
const ScopeLock protect(self->mutex);
|
const ScopeLock protect(self->mutex);
|
||||||
|
|
|
@ -116,9 +116,8 @@ inline bool
|
||||||
ShoutOutput::Configure(const config_param *param, GError **error_r)
|
ShoutOutput::Configure(const config_param *param, GError **error_r)
|
||||||
{
|
{
|
||||||
|
|
||||||
const struct audio_format *audio_format =
|
const AudioFormat audio_format = base.config_audio_format;
|
||||||
&base.config_audio_format;
|
if (!audio_format.IsFullyDefined()) {
|
||||||
if (!audio_format_fully_defined(audio_format)) {
|
|
||||||
g_set_error(error_r, shout_output_quark(), 0,
|
g_set_error(error_r, shout_output_quark(), 0,
|
||||||
"Need full audio format specification");
|
"Need full audio format specification");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -269,10 +268,10 @@ ShoutOutput::Configure(const config_param *param, GError **error_r)
|
||||||
char temp[11];
|
char temp[11];
|
||||||
memset(temp, 0, sizeof(temp));
|
memset(temp, 0, sizeof(temp));
|
||||||
|
|
||||||
snprintf(temp, sizeof(temp), "%u", audio_format->channels);
|
snprintf(temp, sizeof(temp), "%u", audio_format.channels);
|
||||||
shout_set_audio_info(shout_conn, SHOUT_AI_CHANNELS, temp);
|
shout_set_audio_info(shout_conn, SHOUT_AI_CHANNELS, temp);
|
||||||
|
|
||||||
snprintf(temp, sizeof(temp), "%u", audio_format->sample_rate);
|
snprintf(temp, sizeof(temp), "%u", audio_format.sample_rate);
|
||||||
|
|
||||||
shout_set_audio_info(shout_conn, SHOUT_AI_SAMPLERATE, temp);
|
shout_set_audio_info(shout_conn, SHOUT_AI_SAMPLERATE, temp);
|
||||||
|
|
||||||
|
@ -428,7 +427,7 @@ shout_connect(ShoutOutput *sd, GError **error)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
my_shout_open_device(struct audio_output *ao, struct audio_format *audio_format,
|
my_shout_open_device(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
ShoutOutput *sd = (ShoutOutput *)ao;
|
ShoutOutput *sd = (ShoutOutput *)ao;
|
||||||
|
|
|
@ -113,7 +113,7 @@ solaris_output_finish(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
solaris_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
solaris_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
SolarisOutput *so = (SolarisOutput *)ao;
|
SolarisOutput *so = (SolarisOutput *)ao;
|
||||||
|
@ -122,7 +122,7 @@ solaris_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
|
|
||||||
/* support only 16 bit mono/stereo for now; nothing else has
|
/* support only 16 bit mono/stereo for now; nothing else has
|
||||||
been tested */
|
been tested */
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
|
|
||||||
/* open the device in non-blocking mode */
|
/* open the device in non-blocking mode */
|
||||||
|
|
||||||
|
@ -150,8 +150,8 @@ solaris_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.play.sample_rate = audio_format->sample_rate;
|
info.play.sample_rate = audio_format.sample_rate;
|
||||||
info.play.channels = audio_format->channels;
|
info.play.channels = audio_format.channels;
|
||||||
info.play.precision = 16;
|
info.play.precision = 16;
|
||||||
info.play.encoding = AUDIO_ENCODING_LINEAR;
|
info.play.encoding = AUDIO_ENCODING_LINEAR;
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ winmm_output_finish(struct audio_output *ao)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
winmm_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
winmm_output_open(struct audio_output *ao, AudioFormat &audio_format,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
WinmmOutput *wo = (WinmmOutput *)ao;
|
WinmmOutput *wo = (WinmmOutput *)ao;
|
||||||
|
@ -154,30 +154,32 @@ winmm_output_open(struct audio_output *ao, struct audio_format *audio_format,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (audio_format->format) {
|
switch (audio_format.format) {
|
||||||
case SAMPLE_FORMAT_S8:
|
case SampleFormat::S8:
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
case SAMPLE_FORMAT_UNDEFINED:
|
case SampleFormat::FLOAT:
|
||||||
|
case SampleFormat::DSD:
|
||||||
|
case SampleFormat::UNDEFINED:
|
||||||
/* we havn't tested formats other than S16 */
|
/* we havn't tested formats other than S16 */
|
||||||
audio_format->format = SAMPLE_FORMAT_S16;
|
audio_format.format = SampleFormat::S16;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audio_format->channels > 2)
|
if (audio_format.channels > 2)
|
||||||
/* same here: more than stereo was not tested */
|
/* same here: more than stereo was not tested */
|
||||||
audio_format->channels = 2;
|
audio_format.channels = 2;
|
||||||
|
|
||||||
WAVEFORMATEX format;
|
WAVEFORMATEX format;
|
||||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
format.nChannels = audio_format->channels;
|
format.nChannels = audio_format.channels;
|
||||||
format.nSamplesPerSec = audio_format->sample_rate;
|
format.nSamplesPerSec = audio_format.sample_rate;
|
||||||
format.nBlockAlign = audio_format_frame_size(audio_format);
|
format.nBlockAlign = audio_format.GetFrameSize();
|
||||||
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
|
||||||
format.wBitsPerSample = audio_format_sample_size(audio_format) * 8;
|
format.wBitsPerSample = audio_format.GetSampleSize() * 8;
|
||||||
format.cbSize = 0;
|
format.cbSize = 0;
|
||||||
|
|
||||||
MMRESULT result = waveOutOpen(&wo->handle, wo->device_id, &format,
|
MMRESULT result = waveOutOpen(&wo->handle, wo->device_id, &format,
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "PcmChannels.hxx"
|
#include "PcmChannels.hxx"
|
||||||
#include "PcmFormat.hxx"
|
#include "PcmFormat.hxx"
|
||||||
#include "pcm_pack.h"
|
#include "pcm_pack.h"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
@ -48,46 +48,46 @@ PcmConvert::Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const int16_t *
|
inline const int16_t *
|
||||||
PcmConvert::Convert16(const audio_format *src_format,
|
PcmConvert::Convert16(const AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format, size_t *dest_size_r,
|
const AudioFormat dest_format, size_t *dest_size_r,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
const int16_t *buf;
|
const int16_t *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
assert(dest_format->format == SAMPLE_FORMAT_S16);
|
assert(dest_format.format == SampleFormat::S16);
|
||||||
|
|
||||||
buf = pcm_convert_to_16(format_buffer, dither,
|
buf = pcm_convert_to_16(format_buffer, dither,
|
||||||
sample_format(src_format->format),
|
src_format.format,
|
||||||
src_buffer, src_size,
|
src_buffer, src_size,
|
||||||
&len);
|
&len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %s to 16 bit is not implemented",
|
"Conversion from %s to 16 bit is not implemented",
|
||||||
sample_format_to_string(sample_format(src_format->format)));
|
sample_format_to_string(src_format.format));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_format->channels != dest_format->channels) {
|
if (src_format.channels != dest_format.channels) {
|
||||||
buf = pcm_convert_channels_16(channels_buffer,
|
buf = pcm_convert_channels_16(channels_buffer,
|
||||||
dest_format->channels,
|
dest_format.channels,
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
buf, len, &len);
|
buf, len, &len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %u to %u channels "
|
"Conversion from %u to %u channels "
|
||||||
"is not implemented",
|
"is not implemented",
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
dest_format->channels);
|
dest_format.channels);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_format->sample_rate != dest_format->sample_rate) {
|
if (src_format.sample_rate != dest_format.sample_rate) {
|
||||||
buf = resampler.Resample16(dest_format->channels,
|
buf = resampler.Resample16(dest_format.channels,
|
||||||
src_format->sample_rate, buf, len,
|
src_format.sample_rate, buf, len,
|
||||||
dest_format->sample_rate, &len,
|
dest_format.sample_rate, &len,
|
||||||
error_r);
|
error_r);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -98,45 +98,45 @@ PcmConvert::Convert16(const audio_format *src_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const int32_t *
|
inline const int32_t *
|
||||||
PcmConvert::Convert24(const audio_format *src_format,
|
PcmConvert::Convert24(const AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format, size_t *dest_size_r,
|
const AudioFormat dest_format, size_t *dest_size_r,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
const int32_t *buf;
|
const int32_t *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
assert(dest_format->format == SAMPLE_FORMAT_S24_P32);
|
assert(dest_format.format == SampleFormat::S24_P32);
|
||||||
|
|
||||||
buf = pcm_convert_to_24(format_buffer,
|
buf = pcm_convert_to_24(format_buffer,
|
||||||
sample_format(src_format->format),
|
src_format.format,
|
||||||
src_buffer, src_size, &len);
|
src_buffer, src_size, &len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %s to 24 bit is not implemented",
|
"Conversion from %s to 24 bit is not implemented",
|
||||||
sample_format_to_string(sample_format(src_format->format)));
|
sample_format_to_string(src_format.format));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_format->channels != dest_format->channels) {
|
if (src_format.channels != dest_format.channels) {
|
||||||
buf = pcm_convert_channels_24(channels_buffer,
|
buf = pcm_convert_channels_24(channels_buffer,
|
||||||
dest_format->channels,
|
dest_format.channels,
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
buf, len, &len);
|
buf, len, &len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %u to %u channels "
|
"Conversion from %u to %u channels "
|
||||||
"is not implemented",
|
"is not implemented",
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
dest_format->channels);
|
dest_format.channels);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_format->sample_rate != dest_format->sample_rate) {
|
if (src_format.sample_rate != dest_format.sample_rate) {
|
||||||
buf = resampler.Resample24(dest_format->channels,
|
buf = resampler.Resample24(dest_format.channels,
|
||||||
src_format->sample_rate, buf, len,
|
src_format.sample_rate, buf, len,
|
||||||
dest_format->sample_rate, &len,
|
dest_format.sample_rate, &len,
|
||||||
error_r);
|
error_r);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -147,45 +147,45 @@ PcmConvert::Convert24(const audio_format *src_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const int32_t *
|
inline const int32_t *
|
||||||
PcmConvert::Convert32(const audio_format *src_format,
|
PcmConvert::Convert32(const AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format, size_t *dest_size_r,
|
const AudioFormat dest_format, size_t *dest_size_r,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
const int32_t *buf;
|
const int32_t *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
assert(dest_format->format == SAMPLE_FORMAT_S32);
|
assert(dest_format.format == SampleFormat::S32);
|
||||||
|
|
||||||
buf = pcm_convert_to_32(format_buffer,
|
buf = pcm_convert_to_32(format_buffer,
|
||||||
sample_format(src_format->format),
|
src_format.format,
|
||||||
src_buffer, src_size, &len);
|
src_buffer, src_size, &len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %s to 32 bit is not implemented",
|
"Conversion from %s to 32 bit is not implemented",
|
||||||
sample_format_to_string(sample_format(src_format->format)));
|
sample_format_to_string(src_format.format));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_format->channels != dest_format->channels) {
|
if (src_format.channels != dest_format.channels) {
|
||||||
buf = pcm_convert_channels_32(channels_buffer,
|
buf = pcm_convert_channels_32(channels_buffer,
|
||||||
dest_format->channels,
|
dest_format.channels,
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
buf, len, &len);
|
buf, len, &len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %u to %u channels "
|
"Conversion from %u to %u channels "
|
||||||
"is not implemented",
|
"is not implemented",
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
dest_format->channels);
|
dest_format.channels);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_format->sample_rate != dest_format->sample_rate) {
|
if (src_format.sample_rate != dest_format.sample_rate) {
|
||||||
buf = resampler.Resample32(dest_format->channels,
|
buf = resampler.Resample32(dest_format.channels,
|
||||||
src_format->sample_rate, buf, len,
|
src_format.sample_rate, buf, len,
|
||||||
dest_format->sample_rate, &len,
|
dest_format.sample_rate, &len,
|
||||||
error_r);
|
error_r);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -196,41 +196,41 @@ PcmConvert::Convert32(const audio_format *src_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const float *
|
inline const float *
|
||||||
PcmConvert::ConvertFloat(const audio_format *src_format,
|
PcmConvert::ConvertFloat(const AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format, size_t *dest_size_r,
|
const AudioFormat dest_format, size_t *dest_size_r,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
const float *buffer = (const float *)src_buffer;
|
const float *buffer = (const float *)src_buffer;
|
||||||
size_t size = src_size;
|
size_t size = src_size;
|
||||||
|
|
||||||
assert(dest_format->format == SAMPLE_FORMAT_FLOAT);
|
assert(dest_format.format == SampleFormat::FLOAT);
|
||||||
|
|
||||||
/* convert to float now */
|
/* convert to float now */
|
||||||
|
|
||||||
buffer = pcm_convert_to_float(format_buffer,
|
buffer = pcm_convert_to_float(format_buffer,
|
||||||
sample_format(src_format->format),
|
src_format.format,
|
||||||
buffer, size, &size);
|
buffer, size, &size);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %s to float is not implemented",
|
"Conversion from %s to float is not implemented",
|
||||||
sample_format_to_string(sample_format(src_format->format)));
|
sample_format_to_string(src_format.format));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert channels */
|
/* convert channels */
|
||||||
|
|
||||||
if (src_format->channels != dest_format->channels) {
|
if (src_format.channels != dest_format.channels) {
|
||||||
buffer = pcm_convert_channels_float(channels_buffer,
|
buffer = pcm_convert_channels_float(channels_buffer,
|
||||||
dest_format->channels,
|
dest_format.channels,
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
buffer, size, &size);
|
buffer, size, &size);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"Conversion from %u to %u channels "
|
"Conversion from %u to %u channels "
|
||||||
"is not implemented",
|
"is not implemented",
|
||||||
src_format->channels,
|
src_format.channels,
|
||||||
dest_format->channels);
|
dest_format.channels);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,11 +238,11 @@ PcmConvert::ConvertFloat(const audio_format *src_format,
|
||||||
/* resample with float, because this is the best format for
|
/* resample with float, because this is the best format for
|
||||||
libsamplerate */
|
libsamplerate */
|
||||||
|
|
||||||
if (src_format->sample_rate != dest_format->sample_rate) {
|
if (src_format.sample_rate != dest_format.sample_rate) {
|
||||||
buffer = resampler.ResampleFloat(dest_format->channels,
|
buffer = resampler.ResampleFloat(dest_format.channels,
|
||||||
src_format->sample_rate,
|
src_format.sample_rate,
|
||||||
buffer, size,
|
buffer, size,
|
||||||
dest_format->sample_rate,
|
dest_format.sample_rate,
|
||||||
&size, error_r);
|
&size, error_r);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -253,16 +253,16 @@ PcmConvert::ConvertFloat(const audio_format *src_format,
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *
|
const void *
|
||||||
PcmConvert::Convert(const audio_format *src_format,
|
PcmConvert::Convert(AudioFormat src_format,
|
||||||
const void *src, size_t src_size,
|
const void *src, size_t src_size,
|
||||||
const audio_format *dest_format,
|
const AudioFormat dest_format,
|
||||||
size_t *dest_size_r,
|
size_t *dest_size_r,
|
||||||
GError **error_r)
|
GError **error_r)
|
||||||
{
|
{
|
||||||
struct audio_format float_format;
|
AudioFormat float_format;
|
||||||
if (src_format->format == SAMPLE_FORMAT_DSD) {
|
if (src_format.format == SampleFormat::DSD) {
|
||||||
size_t f_size;
|
size_t f_size;
|
||||||
const float *f = dsd.ToFloat(src_format->channels,
|
const float *f = dsd.ToFloat(src_format.channels,
|
||||||
false, (const uint8_t *)src,
|
false, (const uint8_t *)src,
|
||||||
src_size, &f_size);
|
src_size, &f_size);
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
|
@ -271,31 +271,31 @@ PcmConvert::Convert(const audio_format *src_format,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
float_format = *src_format;
|
float_format = src_format;
|
||||||
float_format.format = SAMPLE_FORMAT_FLOAT;
|
float_format.format = SampleFormat::FLOAT;
|
||||||
|
|
||||||
src_format = &float_format;
|
src_format = float_format;
|
||||||
src = f;
|
src = f;
|
||||||
src_size = f_size;
|
src_size = f_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (sample_format(dest_format->format)) {
|
switch (dest_format.format) {
|
||||||
case SAMPLE_FORMAT_S16:
|
case SampleFormat::S16:
|
||||||
return Convert16(src_format, src, src_size,
|
return Convert16(src_format, src, src_size,
|
||||||
dest_format, dest_size_r,
|
dest_format, dest_size_r,
|
||||||
error_r);
|
error_r);
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S24_P32:
|
case SampleFormat::S24_P32:
|
||||||
return Convert24(src_format, src, src_size,
|
return Convert24(src_format, src, src_size,
|
||||||
dest_format, dest_size_r,
|
dest_format, dest_size_r,
|
||||||
error_r);
|
error_r);
|
||||||
|
|
||||||
case SAMPLE_FORMAT_S32:
|
case SampleFormat::S32:
|
||||||
return Convert32(src_format, src, src_size,
|
return Convert32(src_format, src, src_size,
|
||||||
dest_format, dest_size_r,
|
dest_format, dest_size_r,
|
||||||
error_r);
|
error_r);
|
||||||
|
|
||||||
case SAMPLE_FORMAT_FLOAT:
|
case SampleFormat::FLOAT:
|
||||||
return ConvertFloat(src_format, src, src_size,
|
return ConvertFloat(src_format, src, src_size,
|
||||||
dest_format, dest_size_r,
|
dest_format, dest_size_r,
|
||||||
error_r);
|
error_r);
|
||||||
|
@ -303,7 +303,7 @@ PcmConvert::Convert(const audio_format *src_format,
|
||||||
default:
|
default:
|
||||||
g_set_error(error_r, pcm_convert_quark(), 0,
|
g_set_error(error_r, pcm_convert_quark(), 0,
|
||||||
"PCM conversion to %s is not implemented",
|
"PCM conversion to %s is not implemented",
|
||||||
sample_format_to_string(sample_format(dest_format->format)));
|
sample_format_to_string(dest_format.format));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
struct audio_format;
|
struct AudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This object is statically allocated (within another struct), and
|
* This object is statically allocated (within another struct), and
|
||||||
|
@ -71,34 +71,34 @@ public:
|
||||||
* ignore errors
|
* ignore errors
|
||||||
* @return the destination buffer, or NULL on error
|
* @return the destination buffer, or NULL on error
|
||||||
*/
|
*/
|
||||||
const void *Convert(const audio_format *src_format,
|
const void *Convert(AudioFormat src_format,
|
||||||
const void *src, size_t src_size,
|
const void *src, size_t src_size,
|
||||||
const audio_format *dest_format,
|
AudioFormat dest_format,
|
||||||
size_t *dest_size_r,
|
size_t *dest_size_r,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const int16_t *Convert16(const audio_format *src_format,
|
const int16_t *Convert16(AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format,
|
AudioFormat dest_format,
|
||||||
size_t *dest_size_r,
|
size_t *dest_size_r,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
const int32_t *Convert24(const audio_format *src_format,
|
const int32_t *Convert24(AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format,
|
AudioFormat dest_format,
|
||||||
size_t *dest_size_r,
|
size_t *dest_size_r,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
const int32_t *Convert32(const audio_format *src_format,
|
const int32_t *Convert32(AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format,
|
AudioFormat dest_format,
|
||||||
size_t *dest_size_r,
|
size_t *dest_size_r,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
|
|
||||||
const float *ConvertFloat(const audio_format *src_format,
|
const float *ConvertFloat(AudioFormat src_format,
|
||||||
const void *src_buffer, size_t src_size,
|
const void *src_buffer, size_t src_size,
|
||||||
const audio_format *dest_format,
|
AudioFormat dest_format,
|
||||||
size_t *dest_size_r,
|
size_t *dest_size_r,
|
||||||
GError **error_r);
|
GError **error_r);
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "PcmDsdUsb.hxx"
|
#include "PcmDsdUsb.hxx"
|
||||||
#include "PcmBuffer.hxx"
|
#include "PcmBuffer.hxx"
|
||||||
#include "audio_format.h"
|
#include "AudioFormat.hxx"
|
||||||
|
|
||||||
G_GNUC_CONST
|
G_GNUC_CONST
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
|
|
|
@ -27,21 +27,21 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PcmExport::Open(enum sample_format sample_format, unsigned _channels,
|
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
||||||
bool _dsd_usb, bool _shift8, bool _pack, bool _reverse_endian)
|
bool _dsd_usb, bool _shift8, bool _pack, bool _reverse_endian)
|
||||||
{
|
{
|
||||||
assert(audio_valid_sample_format(sample_format));
|
assert(audio_valid_sample_format(sample_format));
|
||||||
assert(!_dsd_usb || audio_valid_channel_count(_channels));
|
assert(!_dsd_usb || audio_valid_channel_count(_channels));
|
||||||
|
|
||||||
channels = _channels;
|
channels = _channels;
|
||||||
dsd_usb = _dsd_usb && sample_format == SAMPLE_FORMAT_DSD;
|
dsd_usb = _dsd_usb && sample_format == SampleFormat::DSD;
|
||||||
if (dsd_usb)
|
if (dsd_usb)
|
||||||
/* after the conversion to DSD-over-USB, the DSD
|
/* after the conversion to DSD-over-USB, the DSD
|
||||||
samples are stuffed inside fake 24 bit samples */
|
samples are stuffed inside fake 24 bit samples */
|
||||||
sample_format = SAMPLE_FORMAT_S24_P32;
|
sample_format = SampleFormat::S24_P32;
|
||||||
|
|
||||||
shift8 = _shift8 && sample_format == SAMPLE_FORMAT_S24_P32;
|
shift8 = _shift8 && sample_format == SampleFormat::S24_P32;
|
||||||
pack24 = _pack && sample_format == SAMPLE_FORMAT_S24_P32;
|
pack24 = _pack && sample_format == SampleFormat::S24_P32;
|
||||||
|
|
||||||
assert(!shift8 || !pack24);
|
assert(!shift8 || !pack24);
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ PcmExport::Open(enum sample_format sample_format, unsigned _channels,
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
PcmExport::GetFrameSize(const struct audio_format &audio_format) const
|
PcmExport::GetFrameSize(const AudioFormat &audio_format) const
|
||||||
{
|
{
|
||||||
if (pack24)
|
if (pack24)
|
||||||
/* packed 24 bit samples (3 bytes per sample) */
|
/* packed 24 bit samples (3 bytes per sample) */
|
||||||
|
@ -71,7 +71,7 @@ PcmExport::GetFrameSize(const struct audio_format &audio_format) const
|
||||||
bytes per sample) */
|
bytes per sample) */
|
||||||
return channels * 4;
|
return channels * 4;
|
||||||
|
|
||||||
return audio_format_frame_size(&audio_format);
|
return audio_format.GetFrameSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *
|
const void *
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue