1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
14 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
15 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 ** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 ** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 ** POSSIBILITY OF SUCH DAMAGE.
27 #include "audio/wavpack.h"
28 #include <libraries/iffparse.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/utility.h>
38 #define ZERO MKBADDR(NULL)
39 #define WAVPACK_SEEK_SET SEEK_SET
40 #define WAVPACK_SEEK_CUR SEEK_CUR
41 #define WAVPACK_SEEK_END SEEK_END
43 #define ID_wvpk MAKE_ID('w','v','p','k')
45 #define PCM_BUFFER_SIZE 588
47 BOOL
WAVPACK_header(CONST_APTR p
) {
48 return rbe32(p
) == ID_wvpk
;
51 static int32_t WAVPACK_read_bytes(void *id
, void *data
, int32_t bcount
);
52 static uint32_t WAVPACK_get_pos(void *id
);
53 static int WAVPACK_set_pos_abs(void *id
, uint32_t pos
);
54 static int WAVPACK_set_pos_rel(void *id
, int32_t delta
, int mode
);
55 static int WAVPACK_push_back_byte(void *id
, int c
);
56 static uint32_t WAVPACK_get_length(void *id
);
57 static int WAVPACK_can_seek(void *id
);
58 static int32_t WAVPACK_write_bytes(void *id
, void *data
, int32_t bcount
);
60 static const WavpackStreamReader reader
= {
65 WAVPACK_push_back_byte
,
71 static LONG
WAVPACK_get_wvc_filename (BPTR file
, STRPTR buffer
, LONG size
);
73 static void WAVPACK_close(WAVPACK_STREAM
*stream
);
74 static LONG
WAVPACK_read(WAVPACK_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
);
76 WAVPACK_STREAM
*WAVPACK_open(CONST_STRPTR wv_filename
, BOOL cuesheet
) {
77 WAVPACK_STREAM
*stream
= NULL
;
78 TEXT wvc_filename
[512];
79 TEXT error_buffer
[80];
80 LONG error
= NO_ERROR
;
87 stream
= AllocVec(sizeof(*stream
), MEMF_CLEAR
);
89 error
= ERROR_NO_FREE_STORE
;
92 stream
->close
= WAVPACK_close
;
93 stream
->read
= WAVPACK_read
;
95 stream
->wv_file
= Open(wv_filename
, MODE_OLDFILE
);
96 if (!stream
->wv_file
) {
100 error
= WAVPACK_get_wvc_filename(stream
->wv_file
, wvc_filename
, sizeof(wvc_filename
));
101 if (error
!= NO_ERROR
) goto error
;
102 stream
->wvc_file
= Open(wvc_filename
, MODE_OLDFILE
);
103 if (stream
->wvc_file
) {
110 stream
->wpc
= WavpackOpenFileInputEx((WavpackStreamReader
*)&reader
,
111 (APTR
)stream
->wv_file
, (APTR
)stream
->wvc_file
, error_buffer
, flags
, 0);
113 error
= ERROR_OBJECT_WRONG_TYPE
;
117 mode
= WavpackGetMode(stream
->wpc
);
118 channels
= WavpackGetNumChannels(stream
->wpc
);
119 sample_rate
= WavpackGetSampleRate(stream
->wpc
);
120 bits_per_sample
= WavpackGetBitsPerSample(stream
->wpc
);
121 stream
->total_samples
= WavpackGetNumSamples(stream
->wpc
);
122 if ((mode
& MODE_FLOAT
) || channels
!= 2 || sample_rate
!= 44100 ||
123 bits_per_sample
!= 16 || stream
->total_samples
<= 0)
125 error
= ERROR_OBJECT_WRONG_TYPE
;
128 stream
->length
= stream
->total_samples
<< 2;
130 stream
->pcm
= AllocVec(PCM_BUFFER_SIZE
* 2 * sizeof(int32_t), MEMF_ANY
);
132 error
= ERROR_NO_FREE_STORE
;
139 WAVPACK_close(stream
);
144 static void strip_file_extension (STRPTR name
, CONST_STRPTR ext
) {
145 int32 len
= strlen(name
) - strlen(ext
);
148 if (!Stricmp(name
, ext
)) {
154 static LONG
WAVPACK_get_wvc_filename (BPTR file
, STRPTR buffer
, LONG size
) {
155 struct FileInfoBlock
*fib
;
156 int32 error
= NO_ERROR
;
157 fib
= AllocDosObject(DOS_FIB
, NULL
);
159 if (ExamineFH(file
, fib
)) {
160 Strlcpy(buffer
, fib
->fib_FileName
, size
);
161 strip_file_extension(buffer
, ".wv");
162 Strlcat(buffer
, ".wvc", size
);
166 FreeDosObject(DOS_FIB
, fib
);
168 error
= ERROR_NO_FREE_STORE
;
173 static void WAVPACK_close(WAVPACK_STREAM
*stream
) {
176 WavpackCloseFile(stream
->wpc
);
178 FreeVec(stream
->pcm
);
179 Close(stream
->wv_file
);
180 Close(stream
->wvc_file
);
185 static LONG
WAVPACK_read(WAVPACK_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
) {
186 LONG sample_offset
= offset
>> 2;
187 LONG samples_to_read
= length
>> 2;
192 if (stream
->wpc
== NULL
) {
193 TEXT error_buffer
[80];
195 if (stream
->wvc_file
) {
198 stream
->wpc
= WavpackOpenFileInputEx((WavpackStreamReader
*)&reader
,
199 (APTR
)stream
->wv_file
, (APTR
)stream
->wvc_file
, error_buffer
, flags
, 0);
204 if (WavpackGetSampleIndex(stream
->wpc
) != sample_offset
) {
205 if (!WavpackSeekSample(stream
->wpc
, sample_offset
)) {
206 WavpackCloseFile(stream
->wpc
);
211 while (samples_to_read
) {
212 if (samples_to_read
< PCM_BUFFER_SIZE
)
213 samples_read
= samples_to_read
;
215 samples_read
= PCM_BUFFER_SIZE
;
216 samples_read
= WavpackUnpackSamples(stream
->wpc
, stream
->pcm
, samples_read
);
217 if (samples_read
== 0) {
221 for (sample
= 0; sample
< samples_read
; sample
++) {
222 wle16(dst
, (UWORD
)*src
); src
++; dst
++;
223 wle16(dst
, (UWORD
)*src
); src
++; dst
++;
225 samples_to_read
-= samples_read
;
227 memset(dst
, 0, samples_to_read
<< 2);
231 static int32_t WAVPACK_read_bytes(void *id
, void *data
, int32_t bcount
) {
232 BPTR file
= (BPTR
)id
;
233 return FRead(file
, data
, 1, bcount
);
236 static uint32_t WAVPACK_get_pos(void *id
) {
237 BPTR file
= (BPTR
)id
;
238 return GetFilePosition(file
);
241 static int WAVPACK_set_pos_abs(void *id
, uint32_t pos
) {
242 BPTR file
= (BPTR
)id
;
243 return !ChangeFilePosition(file
, pos
, OFFSET_BEGINNING
);
246 static int WAVPACK_set_pos_rel(void *id
, int32_t delta
, int mode
) {
247 BPTR file
= (BPTR
)id
;
249 case WAVPACK_SEEK_SET
: return !ChangeFilePosition(file
, delta
, OFFSET_BEGINNING
);
250 case WAVPACK_SEEK_CUR
: return !ChangeFilePosition(file
, delta
, OFFSET_CURRENT
);
251 case WAVPACK_SEEK_END
: return !ChangeFilePosition(file
, delta
, OFFSET_END
);
256 static int WAVPACK_push_back_byte(void *id
, int c
) {
257 BPTR file
= (BPTR
)id
;
258 if (c
== -1) return -1;
260 if (UnGetC(file
, c
) != c
|| (c
== FALSE
&& IoErr())) {
266 static uint32_t WAVPACK_get_length(void *id
) {
267 BPTR file
= (BPTR
)id
;
269 if (file
== ZERO
) return 0;
270 if ((size
= GetFileSize(file
)) == -1 && IoErr()) {
276 static int WAVPACK_can_seek(void *id
) {
277 BPTR file
= (BPTR
)id
;
278 if (file
== ZERO
) return FALSE
;
282 static int32_t WAVPACK_write_bytes(void *id
, void *data
, int32_t bcount
) {