WaveEncoderPlugin.cxx 5.66 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2014 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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.
 */

20
#include "config.h"
21
#include "WaveEncoderPlugin.hxx"
22
#include "../EncoderAPI.hxx"
23
#include "system/ByteOrder.hxx"
24 25
#include "util/Manual.hxx"
#include "util/DynamicFifoBuffer.hxx"
26 27 28 29

#include <assert.h>
#include <string.h>

30
struct WaveEncoder {
31
	Encoder encoder;
32 33
	unsigned bits;

34
	Manual<DynamicFifoBuffer<uint8_t>> buffer;
35

36
	WaveEncoder():encoder(wave_encoder_plugin) {}
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
};

struct wave_header {
	uint32_t id_riff;
	uint32_t riff_size;
	uint32_t id_wave;
	uint32_t id_fmt;
	uint32_t fmt_size;
	uint16_t format;
	uint16_t channels;
	uint32_t freq;
	uint32_t byterate;
	uint16_t blocksize;
	uint16_t bits;
	uint32_t id_data;
	uint32_t data_size;
};

static void
56
fill_wave_header(struct wave_header *header, int channels, int bits,
57 58 59 60 61
		int freq, int block_size)
{
	int data_size = 0x0FFFFFFF;

	/* constants */
62 63 64 65
	header->id_riff = ToLE32(0x46464952);
	header->id_wave = ToLE32(0x45564157);
	header->id_fmt = ToLE32(0x20746d66);
	header->id_data = ToLE32(0x61746164);
66 67

        /* wave format */
68 69 70 71 72 73
	header->format = ToLE16(1); // PCM_FORMAT
	header->channels = ToLE16(channels);
	header->bits = ToLE16(bits);
	header->freq = ToLE32(freq);
	header->blocksize = ToLE16(block_size);
	header->byterate = ToLE32(freq * block_size);
74 75

        /* chunk sizes (fake data length) */
76 77 78
	header->fmt_size = ToLE32(16);
	header->data_size = ToLE32(data_size);
	header->riff_size = ToLE32(4 + (8 + 16) + (8 + data_size));
79 80
}

81
static Encoder *
82
wave_encoder_init(gcc_unused const config_param &param,
83
		  gcc_unused Error &error)
84
{
85
	WaveEncoder *encoder = new WaveEncoder();
86 87 88 89
	return &encoder->encoder;
}

static void
90
wave_encoder_finish(Encoder *_encoder)
91
{
92
	WaveEncoder *encoder = (WaveEncoder *)_encoder;
93

94
	delete encoder;
95 96 97
}

static bool
98
wave_encoder_open(Encoder *_encoder,
99
		  AudioFormat &audio_format,
100
		  gcc_unused Error &error)
101
{
102
	WaveEncoder *encoder = (WaveEncoder *)_encoder;
103

104
	assert(audio_format.IsValid());
105

106 107
	switch (audio_format.format) {
	case SampleFormat::S8:
108 109 110
		encoder->bits = 8;
		break;

111
	case SampleFormat::S16:
112 113 114
		encoder->bits = 16;
		break;

115
	case SampleFormat::S24_P32:
116 117 118
		encoder->bits = 24;
		break;

119
	case SampleFormat::S32:
120 121 122 123
		encoder->bits = 32;
		break;

	default:
124
		audio_format.format = SampleFormat::S16;
125 126 127
		encoder->bits = 16;
		break;
	}
128

129 130 131 132 133
	encoder->buffer.Construct(8192);

	auto range = encoder->buffer->Write();
	assert(range.size >= sizeof(wave_header));
	wave_header *header = (wave_header *)range.data;
134

135
	/* create PCM wave header in initial buffer */
136
	fill_wave_header(header,
137
			 audio_format.channels,
138
			 encoder->bits,
139 140
			 audio_format.sample_rate,
			 (encoder->bits / 8) * audio_format.channels);
141 142

	encoder->buffer->Append(sizeof(*header));
143 144 145 146

	return true;
}

147
static void
148
wave_encoder_close(Encoder *_encoder)
149
{
150
	WaveEncoder *encoder = (WaveEncoder *)_encoder;
151

152
	encoder->buffer.Destruct();
153 154
}

155
static size_t
156
pcm16_to_wave(uint16_t *dst16, const uint16_t *src16, size_t length)
157
{
158 159
	size_t cnt = length >> 1;
	while (cnt > 0) {
160
		*dst16++ = ToLE16(*src16++);
161
		cnt--;
162 163 164 165
	}
	return length;
}

166
static size_t
167
pcm32_to_wave(uint32_t *dst32, const uint32_t *src32, size_t length)
168
{
169 170
	size_t cnt = length >> 2;
	while (cnt > 0){
171
		*dst32++ = ToLE32(*src32++);
172
		cnt--;
173 174 175 176
	}
	return length;
}

177
static size_t
178
pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length)
179
{
180 181
	uint32_t value;
	uint8_t *dst_old = dst8;
182

183 184
	length = length >> 2;
	while (length > 0){
185 186 187 188
		value = *src32++;
		*dst8++ = (value) & 0xFF;
		*dst8++ = (value >> 8) & 0xFF;
		*dst8++ = (value >> 16) & 0xFF;
189
		length--;
190 191
	}
	//correct buffer length
192
	return (dst8 - dst_old);
193 194 195
}

static bool
196
wave_encoder_write(Encoder *_encoder,
197
		   const void *src, size_t length,
198
		   gcc_unused Error &error)
199
{
200
	WaveEncoder *encoder = (WaveEncoder *)_encoder;
201

202
	uint8_t *dst = encoder->buffer->Write(length);
203

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
	if (IsLittleEndian()) {
		switch (encoder->bits) {
		case 8:
		case 16:
		case 32:// optimized cases
			memcpy(dst, src, length);
			break;
		case 24:
			length = pcm24_to_wave(dst, (const uint32_t *)src, length);
			break;
		}
	} else {
		switch (encoder->bits) {
		case 8:
			memcpy(dst, src, length);
			break;
		case 16:
			length = pcm16_to_wave((uint16_t *)dst,
					       (const uint16_t *)src, length);
			break;
		case 24:
			length = pcm24_to_wave(dst, (const uint32_t *)src, length);
			break;
		case 32:
			length = pcm32_to_wave((uint32_t *)dst,
					       (const uint32_t *)src, length);
			break;
		}
232 233
	}

234
	encoder->buffer->Append(length);
235 236 237 238
	return true;
}

static size_t
239
wave_encoder_read(Encoder *_encoder, void *dest, size_t length)
240
{
241
	WaveEncoder *encoder = (WaveEncoder *)_encoder;
242

243
	return encoder->buffer->Read((uint8_t *)dest, length);
244 245
}

246
static const char *
247
wave_encoder_get_mime_type(gcc_unused Encoder *_encoder)
248
{
249
	return "audio/wav";
250 251
}

252
const EncoderPlugin wave_encoder_plugin = {
253 254 255 256 257 258 259 260 261 262 263 264
	"wave",
	wave_encoder_init,
	wave_encoder_finish,
	wave_encoder_open,
	wave_encoder_close,
	nullptr,
	nullptr,
	nullptr,
	nullptr,
	wave_encoder_write,
	wave_encoder_read,
	wave_encoder_get_mime_type,
265
};