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