revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / wavpack.c
blob78adb10c704752252d86b739960c51094e026d26
1 /* Copyright 2007-2012 Fredrik Wikstrom. All rights reserved.
2 **
3 ** Redistribution and use in source and binary forms, with or without
4 ** modification, are permitted provided that the following conditions
5 ** are met:
6 **
7 ** 1. Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 **
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>
32 #include <string.h>
33 #include <stdio.h>
34 #include "endian.h"
35 #include "support.h"
37 #define NO_ERROR 0
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 = {
61 WAVPACK_read_bytes,
62 WAVPACK_get_pos,
63 WAVPACK_set_pos_abs,
64 WAVPACK_set_pos_rel,
65 WAVPACK_push_back_byte,
66 WAVPACK_get_length,
67 WAVPACK_can_seek,
68 WAVPACK_write_bytes
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;
81 int flags = 0;
82 int mode;
83 int channels;
84 uint32_t sample_rate;
85 int bits_per_sample;
87 stream = AllocVec(sizeof(*stream), MEMF_CLEAR);
88 if (!stream) {
89 error = ERROR_NO_FREE_STORE;
90 goto error;
92 stream->close = WAVPACK_close;
93 stream->read = WAVPACK_read;
95 stream->wv_file = Open(wv_filename, MODE_OLDFILE);
96 if (!stream->wv_file) {
97 error = IoErr();
98 goto error;
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) {
104 flags |= OPEN_WVC;
106 if (cuesheet) {
107 flags |= OPEN_TAGS;
110 stream->wpc = WavpackOpenFileInputEx((WavpackStreamReader *)&reader,
111 (APTR)stream->wv_file, (APTR)stream->wvc_file, error_buffer, flags, 0);
112 if (!stream->wpc) {
113 error = ERROR_OBJECT_WRONG_TYPE;
114 goto error;
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;
126 goto error;
128 stream->length = stream->total_samples << 2;
130 stream->pcm = AllocVec(PCM_BUFFER_SIZE * 2 * sizeof(int32_t), MEMF_ANY);
131 if (!stream->pcm) {
132 error = ERROR_NO_FREE_STORE;
133 goto error;
136 return stream;
138 error:
139 WAVPACK_close(stream);
140 SetIoErr(error);
141 return NULL;
144 static void strip_file_extension (STRPTR name, CONST_STRPTR ext) {
145 int32 len = strlen(name) - strlen(ext);
146 if (len >= 0) {
147 name += len;
148 if (!Stricmp(name, ext)) {
149 *name = 0;
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);
158 if (fib) {
159 if (ExamineFH(file, fib)) {
160 Strlcpy(buffer, fib->fib_FileName, size);
161 strip_file_extension(buffer, ".wv");
162 Strlcat(buffer, ".wvc", size);
163 } else {
164 error = IoErr();
166 FreeDosObject(DOS_FIB, fib);
167 } else {
168 error = ERROR_NO_FREE_STORE;
170 return error;
173 static void WAVPACK_close(WAVPACK_STREAM *stream) {
174 if (stream) {
175 if (stream->wpc) {
176 WavpackCloseFile(stream->wpc);
178 FreeVec(stream->pcm);
179 Close(stream->wv_file);
180 Close(stream->wvc_file);
181 FreeVec(stream);
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;
188 LONG samples_read;
189 LONG sample;
190 int32_t *src;
191 WORD *dst = buffer;
192 if (stream->wpc == NULL) {
193 TEXT error_buffer[80];
194 int flags = 0;
195 if (stream->wvc_file) {
196 flags |= OPEN_WVC;
198 stream->wpc = WavpackOpenFileInputEx((WavpackStreamReader *)&reader,
199 (APTR)stream->wv_file, (APTR)stream->wvc_file, error_buffer, flags, 0);
200 if (!stream->wpc) {
201 return 0;
204 if (WavpackGetSampleIndex(stream->wpc) != sample_offset) {
205 if (!WavpackSeekSample(stream->wpc, sample_offset)) {
206 WavpackCloseFile(stream->wpc);
207 stream->wpc = NULL;
208 return 0;
211 while (samples_to_read) {
212 if (samples_to_read < PCM_BUFFER_SIZE)
213 samples_read = samples_to_read;
214 else
215 samples_read = PCM_BUFFER_SIZE;
216 samples_read = WavpackUnpackSamples(stream->wpc, stream->pcm, samples_read);
217 if (samples_read == 0) {
218 break;
220 src = stream->pcm;
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);
228 return length;
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;
248 switch (mode) {
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);
252 default: return !0;
256 static int WAVPACK_push_back_byte(void *id, int c) {
257 BPTR file = (BPTR)id;
258 if (c == -1) return -1;
259 SetIoErr(NO_ERROR);
260 if (UnGetC(file, c) != c || (c == FALSE && IoErr())) {
261 return -1;
263 return c;
266 static uint32_t WAVPACK_get_length(void *id) {
267 BPTR file = (BPTR)id;
268 QUAD size;
269 if (file == ZERO) return 0;
270 if ((size = GetFileSize(file)) == -1 && IoErr()) {
271 return 0;
273 return size;
276 static int WAVPACK_can_seek(void *id) {
277 BPTR file = (BPTR)id;
278 if (file == ZERO) return FALSE;
279 return TRUE;
282 static int32_t WAVPACK_write_bytes(void *id, void *data, int32_t bcount) {
283 return 0;