1 /* -*- linux-c -*-
2 Copyright (C) 2007 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: dec_wavpack.c 1245 2012-02-04 10:33:30Z assworth $
19 */
20
21 #include <config.h>
22
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <math.h>
29
30 #include "../metadata.h"
31 #include "../metadata_ape.h"
32 #include "../rb.h"
33 #include "file_decoder.h"
34 #include "dec_wavpack.h"
35
36
37 extern size_t sample_size;
38
39
40 int
decode_wavpack(decoder_t * dec)41 decode_wavpack(decoder_t * dec) {
42
43 file_decoder_t * fdec = dec->fdec;
44 wavpack_pdata_t * pd = (wavpack_pdata_t *)dec->pdata;
45
46 int32_t buffer[WAVPACK_BUFSIZE];
47 uint i, j;
48
49 float fval[fdec->fileinfo.channels];
50
51 pd->last_decoded_samples = WavpackUnpackSamples(pd->wpc, buffer,
52 WAVPACK_BUFSIZE / fdec->fileinfo.channels);
53
54 /* Actual floating point data is output into an integer, will have to deal with that */
55 if (WavpackGetMode (pd->wpc) & MODE_FLOAT) {
56
57 int num_samples = pd->last_decoded_samples * fdec->fileinfo.channels;
58 int32_t * buffer_pointer = buffer;
59
60 while (num_samples--) {
61 float data = * (float*) buffer_pointer;
62 data *= pd->scale_factor_float;
63
64 if (data > pd->scale_factor_float)
65 data = pd->scale_factor_float;
66 if (data < -(pd->scale_factor_float))
67 data = -(pd->scale_factor_float);
68
69 *buffer_pointer++ = (int32_t) data;
70 }
71 }
72
73 if (pd->last_decoded_samples == 0)
74 return 1;
75
76 for (i = 0; i < pd->last_decoded_samples * fdec->fileinfo.channels; i += fdec->fileinfo.channels) {
77 for (j = 0; j < fdec->fileinfo.channels; j++) {
78
79 fval[j] = buffer[i+j] * fdec->voladj_lin / pd->scale_factor_float;
80
81 if (fval[j] < -1.0f) {
82 fval[j] = -1.0f;
83 } else if (fval[j] > 1.0f) {
84 fval[j] = 1.0f;
85 }
86 }
87 rb_write(pd->rb, (char *)fval, fdec->fileinfo.channels * sample_size);
88 }
89
90 return 0;
91 }
92
93
94 decoder_t *
wavpack_decoder_init(file_decoder_t * fdec)95 wavpack_decoder_init(file_decoder_t * fdec) {
96
97 decoder_t * dec = NULL;
98
99 if ((dec = calloc(1, sizeof(decoder_t))) == NULL) {
100 fprintf(stderr, "dec_wavpack.c: wavpack_decoder_new() failed: calloc error\n");
101 return NULL;
102 }
103
104 dec->fdec = fdec;
105
106 if ((dec->pdata = calloc(1, sizeof(wavpack_pdata_t))) == NULL) {
107 fprintf(stderr, "dec_wavpack.c: wavpack_decoder_new() failed: calloc error\n");
108 return NULL;
109 }
110
111 dec->init = wavpack_decoder_init;
112 dec->destroy = wavpack_decoder_destroy;
113 dec->open = wavpack_decoder_open;
114 dec->send_metadata = wavpack_decoder_send_metadata;
115 dec->close = wavpack_decoder_close;
116 dec->read = wavpack_decoder_read;
117 dec->seek = wavpack_decoder_seek;
118
119 return dec;
120 }
121
122
123 void
wavpack_decoder_destroy(decoder_t * dec)124 wavpack_decoder_destroy(decoder_t * dec) {
125
126 free(dec->pdata);
127 free(dec);
128 }
129
130
131 int
wavpack_decoder_open(decoder_t * dec,char * filename)132 wavpack_decoder_open(decoder_t * dec, char * filename) {
133
134 file_decoder_t * fdec = dec->fdec;
135 wavpack_pdata_t * pd = (wavpack_pdata_t *)dec->pdata;
136 int i, corrected_bits_per_sample;
137 metadata_t * meta;
138
139 /* More than 2 channels doesn't work */
140 /* Normalize is for floating point data only, it gets scaled to -1.0 and 1.0,
141 not replaygain related or anything */
142 /* Opening hybrid correction file if possible */
143 pd->flags = OPEN_2CH_MAX | OPEN_TAGS | OPEN_NORMALIZE | OPEN_WVC;
144
145 strcpy(pd->error, "No Error");
146 pd->wpc = WavpackOpenFileInput(filename, pd->error, pd->flags, 0);
147
148 /* The decoder can actually do something with the file */
149 if (pd->wpc != NULL) {
150 fdec->fileinfo.channels = WavpackGetReducedChannels(pd->wpc);
151 fdec->fileinfo.sample_rate = WavpackGetSampleRate(pd->wpc);
152 fdec->fileinfo.total_samples = WavpackGetNumSamples(pd->wpc);
153 fdec->fileinfo.bps = WavpackGetBitsPerSample(pd->wpc) * fdec->fileinfo.sample_rate
154 * fdec->fileinfo.channels;
155 pd->bits_per_sample = WavpackGetBitsPerSample(pd->wpc);
156
157 pd->rb = rb_create(fdec->fileinfo.channels * sample_size * RB_WAVPACK_SIZE);
158
159 pd->end_of_file = 0;
160
161 /* It's best to calculate the scale factor in advance and store it */
162 pd->scale_factor_float = 1;
163 /* Anything other than 8, 16, 24 or 32 bits is padded to the nearest one */
164 if (WavpackGetMode (pd->wpc) & MODE_FLOAT) {
165 corrected_bits_per_sample = 32;
166 } else {
167 corrected_bits_per_sample = ceil(pd->bits_per_sample/8.0f) * 8;
168 }
169
170 for (i = 1; i < corrected_bits_per_sample; i++) {
171 pd->scale_factor_float *= 2;
172 }
173
174 strcpy(dec->format_str, "WavPack");
175 fdec->file_lib = WAVPACK_LIB;
176
177 meta = metadata_new();
178 meta_ape_send_metadata(meta, fdec);
179 return DECODER_OPEN_SUCCESS;
180 }
181
182 return DECODER_OPEN_BADLIB;
183 }
184
185
186 void
wavpack_decoder_send_metadata(decoder_t * dec)187 wavpack_decoder_send_metadata(decoder_t * dec) {
188 }
189
190
191 void
wavpack_decoder_close(decoder_t * dec)192 wavpack_decoder_close(decoder_t * dec) {
193 wavpack_pdata_t * pd = (wavpack_pdata_t *)dec->pdata;
194
195 WavpackCloseFile(pd->wpc);
196 rb_free(pd->rb);
197 }
198
199
200 unsigned int
wavpack_decoder_read(decoder_t * dec,float * dest,int num)201 wavpack_decoder_read(decoder_t * dec, float * dest, int num) {
202
203 file_decoder_t * fdec = dec->fdec;
204 wavpack_pdata_t * pd = (wavpack_pdata_t *)dec->pdata;
205
206 while ((rb_read_space(pd->rb) < num * fdec->fileinfo.channels * sample_size) &&
207 (pd->end_of_file == 0)) {
208
209 pd->end_of_file = decode_wavpack(dec);
210 }
211
212 uint actual_num = 0;
213 uint n_avail = rb_read_space(pd->rb) / (fdec->fileinfo.channels * sample_size);
214
215 if ( num > n_avail ) {
216 actual_num = n_avail;
217 } else {
218 actual_num = num;
219 }
220
221 rb_read(pd->rb, (char *)dest, actual_num * sample_size * fdec->fileinfo.channels);
222
223 return actual_num;
224 }
225
226
227 void
wavpack_decoder_seek(decoder_t * dec,unsigned long long seek_to_pos)228 wavpack_decoder_seek(decoder_t * dec, unsigned long long seek_to_pos) {
229
230 file_decoder_t * fdec = dec->fdec;
231 wavpack_pdata_t * pd = (wavpack_pdata_t *)dec->pdata;
232 char flush_dest;
233
234 if (WavpackSeekSample(pd->wpc, seek_to_pos) == 1) {
235 fdec->samples_left = fdec->fileinfo.total_samples - seek_to_pos;
236 /* Empty ringbuffer */
237 while (rb_read_space(pd->rb))
238 rb_read(pd->rb, &flush_dest, sizeof(char));
239 } else {
240 fprintf(stderr, "wavpack_decoder_seek: warning: WavpackSeekSample() failed\n");
241 }
242 }
243
244
245
246 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
247