Commit 17293886 authored by Max Kellermann's avatar Max Kellermann

pcm_export: convert to C++

parent c654c763
...@@ -316,7 +316,7 @@ libevent_a_SOURCES = \ ...@@ -316,7 +316,7 @@ libevent_a_SOURCES = \
libpcm_a_SOURCES = \ libpcm_a_SOURCES = \
src/pcm/pcm_buffer.c src/pcm/pcm_buffer.h \ src/pcm/pcm_buffer.c src/pcm/pcm_buffer.h \
src/pcm/pcm_export.c src/pcm/pcm_export.h \ src/pcm/PcmExport.cxx src/pcm/PcmExport.hxx \
src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \ src/pcm/PcmConvert.cxx src/pcm/PcmConvert.hxx \
src/pcm/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h \ src/pcm/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h \
src/pcm/pcm_dsd.c src/pcm/pcm_dsd.h \ src/pcm/pcm_dsd.c src/pcm/pcm_dsd.h \
...@@ -1301,6 +1301,7 @@ test_run_convert_LDADD = \ ...@@ -1301,6 +1301,7 @@ test_run_convert_LDADD = \
$(GLIB_LIBS) $(GLIB_LIBS)
test_run_output_LDADD = $(MPD_LIBS) \ test_run_output_LDADD = $(MPD_LIBS) \
$(PCM_LIBS) \
$(OUTPUT_LIBS) \ $(OUTPUT_LIBS) \
$(ENCODER_LIBS) \ $(ENCODER_LIBS) \
libmixer_plugins.a \ libmixer_plugins.a \
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
#include "AlsaOutputPlugin.hxx" #include "AlsaOutputPlugin.hxx"
#include "output_api.h" #include "output_api.h"
#include "MixerList.hxx" #include "MixerList.hxx"
#include "pcm/pcm_export.h" #include "pcm/PcmExport.hxx"
#include "util/Manual.hxx"
#include <glib.h> #include <glib.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
...@@ -48,7 +49,7 @@ typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer, ...@@ -48,7 +49,7 @@ typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer,
struct AlsaOutput { struct AlsaOutput {
struct audio_output base; struct audio_output base;
struct pcm_export_state pcm_export; Manual<PcmExport> pcm_export;
/** /**
* The configured name of the ALSA device; empty for the * The configured name of the ALSA device; empty for the
...@@ -202,7 +203,7 @@ alsa_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r) ...@@ -202,7 +203,7 @@ alsa_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r)
{ {
AlsaOutput *ad = (AlsaOutput *)ao; AlsaOutput *ad = (AlsaOutput *)ao;
pcm_export_init(&ad->pcm_export); ad->pcm_export.Construct();
return true; return true;
} }
...@@ -211,7 +212,7 @@ alsa_output_disable(struct audio_output *ao) ...@@ -211,7 +212,7 @@ alsa_output_disable(struct audio_output *ao)
{ {
AlsaOutput *ad = (AlsaOutput *)ao; AlsaOutput *ad = (AlsaOutput *)ao;
pcm_export_deinit(&ad->pcm_export); ad->pcm_export.Destruct();
} }
static bool static bool
...@@ -659,8 +660,7 @@ alsa_setup_or_dsd(AlsaOutput *ad, struct audio_format *audio_format, ...@@ -659,8 +660,7 @@ alsa_setup_or_dsd(AlsaOutput *ad, struct audio_format *audio_format,
if (!success) if (!success)
return false; return false;
pcm_export_open(&ad->pcm_export, ad->pcm_export->Open(sample_format(audio_format->format),
sample_format(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;
...@@ -689,8 +689,7 @@ alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **e ...@@ -689,8 +689,7 @@ alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **e
} }
ad->in_frame_size = audio_format_frame_size(audio_format); ad->in_frame_size = audio_format_frame_size(audio_format);
ad->out_frame_size = pcm_export_frame_size(&ad->pcm_export, ad->out_frame_size = ad->pcm_export->GetFrameSize(*audio_format);
audio_format);
return true; return true;
} }
...@@ -809,7 +808,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size, ...@@ -809,7 +808,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
assert(size % ad->in_frame_size == 0); assert(size % ad->in_frame_size == 0);
chunk = pcm_export(&ad->pcm_export, chunk, size, &size); chunk = ad->pcm_export->Export(chunk, size, size);
assert(size % ad->out_frame_size == 0); assert(size % ad->out_frame_size == 0);
...@@ -822,8 +821,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size, ...@@ -822,8 +821,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
% ad->period_frames; % ad->period_frames;
size_t bytes_written = ret * ad->out_frame_size; size_t bytes_written = ret * ad->out_frame_size;
return pcm_export_source_size(&ad->pcm_export, return ad->pcm_export->CalcSourceSize(bytes_written);
bytes_written);
} }
if (ret < 0 && ret != -EAGAIN && ret != -EINTR && if (ret < 0 && ret != -EAGAIN && ret != -EINTR &&
......
...@@ -52,14 +52,15 @@ ...@@ -52,14 +52,15 @@
#endif #endif
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
#include "pcm/pcm_export.h" #include "pcm/PcmExport.hxx"
#include "util/Manual.hxx"
#endif #endif
struct oss_data { struct oss_data {
struct audio_output base; struct audio_output base;
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
struct pcm_export_state pcm_export; Manual<PcmExport> pcm_export;
#endif #endif
int fd; int fd;
...@@ -241,7 +242,7 @@ oss_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r) ...@@ -241,7 +242,7 @@ oss_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r)
{ {
struct oss_data *od = (struct oss_data *)ao; struct oss_data *od = (struct oss_data *)ao;
pcm_export_init(&od->pcm_export); od->pcm_export.Construct();
return true; return true;
} }
...@@ -250,7 +251,7 @@ oss_output_disable(struct audio_output *ao) ...@@ -250,7 +251,7 @@ oss_output_disable(struct audio_output *ao)
{ {
struct oss_data *od = (struct oss_data *)ao; struct oss_data *od = (struct oss_data *)ao;
pcm_export_deinit(&od->pcm_export); od->pcm_export.Destruct();
} }
#endif #endif
...@@ -502,7 +503,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format, ...@@ -502,7 +503,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
enum sample_format *sample_format_r, enum sample_format *sample_format_r,
int *oss_format_r, int *oss_format_r,
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
struct pcm_export_state *pcm_export, PcmExport &pcm_export,
#endif #endif
GError **error_r) GError **error_r)
{ {
...@@ -537,7 +538,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format, ...@@ -537,7 +538,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format,
*oss_format_r = oss_format; *oss_format_r = oss_format;
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
pcm_export_open(pcm_export, sample_format, 0, false, false, pcm_export.Open(sample_format, 0, false, false,
oss_format == AFMT_S24_PACKED, oss_format == AFMT_S24_PACKED,
oss_format == AFMT_S24_PACKED && oss_format == AFMT_S24_PACKED &&
G_BYTE_ORDER != G_LITTLE_ENDIAN); G_BYTE_ORDER != G_LITTLE_ENDIAN);
...@@ -554,7 +555,7 @@ static bool ...@@ -554,7 +555,7 @@ static bool
oss_setup_sample_format(int fd, struct audio_format *audio_format, oss_setup_sample_format(int fd, struct audio_format *audio_format,
int *oss_format_r, int *oss_format_r,
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
struct pcm_export_state *pcm_export, PcmExport &pcm_export,
#endif #endif
GError **error_r) GError **error_r)
{ {
...@@ -633,7 +634,7 @@ oss_setup(struct oss_data *od, struct audio_format *audio_format, ...@@ -633,7 +634,7 @@ oss_setup(struct oss_data *od, struct audio_format *audio_format,
oss_setup_sample_rate(od->fd, audio_format, error_r) && oss_setup_sample_rate(od->fd, audio_format, error_r) &&
oss_setup_sample_format(od->fd, audio_format, &od->oss_format, oss_setup_sample_format(od->fd, audio_format, &od->oss_format,
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
&od->pcm_export, od->pcm_export,
#endif #endif
error_r); error_r);
} }
...@@ -747,14 +748,14 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size, ...@@ -747,14 +748,14 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
return 0; return 0;
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
chunk = pcm_export(&od->pcm_export, chunk, size, &size); chunk = od->pcm_export->Export(chunk, size, size);
#endif #endif
while (true) { while (true) {
ret = write(od->fd, chunk, size); ret = write(od->fd, chunk, size);
if (ret > 0) { if (ret > 0) {
#ifdef AFMT_S24_PACKED #ifdef AFMT_S24_PACKED
ret = pcm_export_source_size(&od->pcm_export, ret); ret = od->pcm_export->CalcSourceSize(ret);
#endif #endif
return ret; return ret;
} }
......
/* /*
* Copyright (C) 2003-2012 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
...@@ -18,95 +18,79 @@ ...@@ -18,95 +18,79 @@
*/ */
#include "config.h" #include "config.h"
#include "pcm_export.h" #include "PcmExport.hxx"
extern "C" {
#include "pcm_dsd_usb.h" #include "pcm_dsd_usb.h"
#include "pcm_pack.h" #include "pcm_pack.h"
#include "util/byte_reverse.h" #include "util/byte_reverse.h"
void
pcm_export_init(struct pcm_export_state *state)
{
pcm_buffer_init(&state->reverse_buffer);
pcm_buffer_init(&state->pack_buffer);
pcm_buffer_init(&state->dsd_buffer);
}
void pcm_export_deinit(struct pcm_export_state *state)
{
pcm_buffer_deinit(&state->reverse_buffer);
pcm_buffer_deinit(&state->pack_buffer);
pcm_buffer_deinit(&state->dsd_buffer);
} }
void void
pcm_export_open(struct pcm_export_state *state, PcmExport::Open(enum sample_format sample_format, unsigned _channels,
enum sample_format 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));
state->channels = channels; channels = _channels;
state->dsd_usb = dsd_usb && sample_format == SAMPLE_FORMAT_DSD; dsd_usb = _dsd_usb && sample_format == SAMPLE_FORMAT_DSD;
if (state->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 = SAMPLE_FORMAT_S24_P32;
state->shift8 = shift8 && sample_format == SAMPLE_FORMAT_S24_P32; shift8 = _shift8 && sample_format == SAMPLE_FORMAT_S24_P32;
state->pack24 = pack && sample_format == SAMPLE_FORMAT_S24_P32; pack24 = _pack && sample_format == SAMPLE_FORMAT_S24_P32;
assert(!state->shift8 || !state->pack24); assert(!shift8 || !pack24);
state->reverse_endian = 0; reverse_endian = 0;
if (reverse_endian) { if (_reverse_endian) {
size_t sample_size = state->pack24 size_t sample_size = pack24
? 3 ? 3
: sample_format_size(sample_format); : sample_format_size(sample_format);
assert(sample_size <= 0xff); assert(sample_size <= 0xff);
if (sample_size > 1) if (sample_size > 1)
state->reverse_endian = sample_size; reverse_endian = sample_size;
} }
} }
size_t size_t
pcm_export_frame_size(const struct pcm_export_state *state, PcmExport::GetFrameSize(const struct audio_format &audio_format) const
const struct audio_format *audio_format)
{ {
assert(state != NULL); if (pack24)
assert(audio_format != NULL);
if (state->pack24)
/* packed 24 bit samples (3 bytes per sample) */ /* packed 24 bit samples (3 bytes per sample) */
return audio_format->channels * 3; return audio_format.channels * 3;
if (state->dsd_usb) if (dsd_usb)
/* the DSD-over-USB draft says that DSD 1-bit samples /* the DSD-over-USB draft says that DSD 1-bit samples
are enclosed within 24 bit samples, and MPD's are enclosed within 24 bit samples, and MPD's
representation of 24 bit is padded to 32 bit (4 representation of 24 bit is padded to 32 bit (4
bytes per sample) */ bytes per sample) */
return audio_format->channels * 4; return channels * 4;
return audio_format_frame_size(audio_format); return audio_format_frame_size(&audio_format);
} }
const void * const void *
pcm_export(struct pcm_export_state *state, const void *data, size_t size, PcmExport::Export(const void *data, size_t size, size_t &dest_size_r)
size_t *dest_size_r)
{ {
if (state->dsd_usb) if (dsd_usb)
data = pcm_dsd_to_usb(&state->dsd_buffer, state->channels, data = pcm_dsd_to_usb(&dsd_buffer, channels,
data, size, &size); (const uint8_t *)data, size, &size);
if (state->pack24) { if (pack24) {
assert(size % 4 == 0); assert(size % 4 == 0);
const size_t num_samples = size / 4; const size_t num_samples = size / 4;
const size_t dest_size = num_samples * 3; const size_t dest_size = num_samples * 3;
const uint8_t *src8 = data, *src_end8 = src8 + size; const uint8_t *src8 = (const uint8_t *)data;
uint8_t *dest = pcm_buffer_get(&state->pack_buffer, dest_size); const uint8_t *src_end8 = src8 + size;
uint8_t *dest = (uint8_t *)
pcm_buffer_get(&pack_buffer, dest_size);
assert(dest != NULL); assert(dest != NULL);
pcm_pack_24(dest, (const int32_t *)src8, pcm_pack_24(dest, (const int32_t *)src8,
...@@ -114,14 +98,16 @@ pcm_export(struct pcm_export_state *state, const void *data, size_t size, ...@@ -114,14 +98,16 @@ pcm_export(struct pcm_export_state *state, const void *data, size_t size,
data = dest; data = dest;
size = dest_size; size = dest_size;
} else if (state->shift8) { } else if (shift8) {
assert(size % 4 == 0); assert(size % 4 == 0);
const uint8_t *src8 = data, *src_end8 = src8 + size; const uint8_t *src8 = (const uint8_t *)data;
const uint8_t *src_end8 = src8 + size;
const uint32_t *src = (const uint32_t *)src8; const uint32_t *src = (const uint32_t *)src8;
const uint32_t *const src_end = (const uint32_t *)src_end8; const uint32_t *const src_end = (const uint32_t *)src_end8;
uint32_t *dest = pcm_buffer_get(&state->pack_buffer, size); uint32_t *dest = (uint32_t *)
pcm_buffer_get(&pack_buffer, size);
data = dest; data = dest;
while (src < src_end) while (src < src_end)
...@@ -129,30 +115,32 @@ pcm_export(struct pcm_export_state *state, const void *data, size_t size, ...@@ -129,30 +115,32 @@ pcm_export(struct pcm_export_state *state, const void *data, size_t size,
} }
if (state->reverse_endian > 0) { if (reverse_endian > 0) {
assert(state->reverse_endian >= 2); assert(reverse_endian >= 2);
void *dest = pcm_buffer_get(&state->reverse_buffer, size); uint8_t *dest = (uint8_t *)
pcm_buffer_get(&reverse_buffer, size);
assert(dest != NULL); assert(dest != NULL);
const uint8_t *src = data, *src_end = src + size; const uint8_t *src = (const uint8_t *)data;
reverse_bytes(dest, src, src_end, state->reverse_endian); const uint8_t *src_end = src + size;
reverse_bytes(dest, src, src_end, reverse_endian);
data = dest; data = dest;
} }
*dest_size_r = size; dest_size_r = size;
return data; return data;
} }
size_t size_t
pcm_export_source_size(const struct pcm_export_state *state, size_t size) PcmExport::CalcSourceSize(size_t size) const
{ {
if (state->pack24) if (pack24)
/* 32 bit to 24 bit conversion (4 to 3 bytes) */ /* 32 bit to 24 bit conversion (4 to 3 bytes) */
size = (size / 3) * 4; size = (size / 3) * 4;
if (state->dsd_usb) if (dsd_usb)
/* DSD over USB doubles the transport size */ /* DSD over USB doubles the transport size */
size /= 2; size /= 2;
......
/* /*
* Copyright (C) 2003-2012 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,15 +17,13 @@ ...@@ -17,15 +17,13 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#ifndef PCM_EXPORT_H #ifndef PCM_EXPORT_HXX
#define PCM_EXPORT_H #define PCM_EXPORT_HXX
#include "check.h" #include "check.h"
#include "pcm_buffer.h" #include "pcm_buffer.h"
#include "audio_format.h" #include "audio_format.h"
#include <stdbool.h>
struct audio_format; struct audio_format;
/** /**
...@@ -33,7 +31,7 @@ struct audio_format; ...@@ -33,7 +31,7 @@ struct audio_format;
* outside of MPD. It has a few more options to tweak the binary * outside of MPD. It has a few more options to tweak the binary
* representation which are not supported by the pcm_convert library. * representation which are not supported by the pcm_convert library.
*/ */
struct pcm_export_state { struct PcmExport {
/** /**
* The buffer is used to convert DSD samples to the * The buffer is used to convert DSD samples to the
* DSD-over-USB format. * DSD-over-USB format.
...@@ -85,25 +83,20 @@ struct pcm_export_state { ...@@ -85,25 +83,20 @@ struct pcm_export_state {
* sample (2 or bigger). * sample (2 or bigger).
*/ */
uint8_t reverse_endian; uint8_t reverse_endian;
};
#ifdef __cplusplus PcmExport() {
extern "C" { pcm_buffer_init(&reverse_buffer);
#endif pcm_buffer_init(&pack_buffer);
pcm_buffer_init(&dsd_buffer);
/** }
* Initialize a #pcm_export_state object.
*/
void
pcm_export_init(struct pcm_export_state *state);
/** ~PcmExport() {
* Deinitialize a #pcm_export_state object and free allocated memory. pcm_buffer_deinit(&reverse_buffer);
*/ pcm_buffer_deinit(&pack_buffer);
void pcm_buffer_deinit(&dsd_buffer);
pcm_export_deinit(struct pcm_export_state *state); }
/** /**
* Open the #pcm_export_state object. * Open the #pcm_export_state object.
* *
* There is no "close" method. This function may be called multiple * There is no "close" method. This function may be called multiple
...@@ -113,20 +106,16 @@ pcm_export_deinit(struct pcm_export_state *state); ...@@ -113,20 +106,16 @@ pcm_export_deinit(struct pcm_export_state *state);
* *
* @param channels the number of channels; ignored unless dsd_usb is set * @param channels the number of channels; ignored unless dsd_usb is set
*/ */
void void Open(enum sample_format sample_format, unsigned channels,
pcm_export_open(struct pcm_export_state *state,
enum sample_format sample_format, unsigned channels,
bool dsd_usb, bool shift8, bool pack, bool reverse_endian); bool dsd_usb, bool shift8, bool pack, bool reverse_endian);
/** /**
* Calculate the size of one output frame. * Calculate the size of one output frame.
*/ */
G_GNUC_PURE gcc_pure
size_t size_t GetFrameSize(const struct audio_format &audio_format) const;
pcm_export_frame_size(const struct pcm_export_state *state,
const struct audio_format *audio_format);
/** /**
* Export a PCM buffer. * Export a PCM buffer.
* *
* @param state an initialized and open pcm_export_state object * @param state an initialized and open pcm_export_state object
...@@ -135,21 +124,16 @@ pcm_export_frame_size(const struct pcm_export_state *state, ...@@ -135,21 +124,16 @@ pcm_export_frame_size(const struct pcm_export_state *state,
* @param dest_size_r returns the number of bytes of the destination buffer * @param dest_size_r returns the number of bytes of the destination buffer
* @return the destination buffer (may be a pointer to the source buffer) * @return the destination buffer (may be a pointer to the source buffer)
*/ */
const void * const void *Export(const void *src, size_t src_size,
pcm_export(struct pcm_export_state *state, const void *src, size_t src_size, size_t &dest_size_r);
size_t *dest_size_r);
/** /**
* Converts the number of consumed bytes from the pcm_export() * Converts the number of consumed bytes from the pcm_export()
* destination buffer to the according number of bytes from the * destination buffer to the according number of bytes from the
* pcm_export() source buffer. * pcm_export() source buffer.
*/ */
G_GNUC_PURE gcc_pure
size_t size_t CalcSourceSize(size_t dest_size) const;
pcm_export_source_size(const struct pcm_export_state *state, size_t dest_size); };
#ifdef __cplusplus
}
#endif
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment