revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / diskimage / audio / aiff.c
blobe0d7fc3b740d23adb21edcfe5cafd290acb57ccd
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/aiff.h"
28 #include <libraries/iffparse.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <string.h>
32 #include "endian.h"
33 #include "support.h"
35 #define NO_ERROR 0
36 #define ZERO MKBADDR(NULL)
38 #pragma pack(1)
40 typedef struct {
41 ULONG id;
42 ULONG size;
43 ULONG type;
44 } iff_header_t;
46 typedef struct {
47 ULONG id;
48 ULONG size;
49 } iff_chunk_t;
51 #define ID_AIFF MAKE_ID('A','I','F','F')
52 #define ID_AIFC MAKE_ID('A','I','F','C')
53 #define ID_FVER MAKE_ID('F','V','E','R')
54 #define ID_COMM MAKE_ID('C','O','M','M')
55 #define ID_SSND MAKE_ID('S','S','N','D')
57 typedef struct {
58 ULONG timestamp;
59 } aiff_fver_t;
61 #define AIFC_VERSION1 0xA2805140
63 typedef struct {
64 UWORD channels;
65 ULONG frames;
66 UWORD bitspersample;
67 UWORD frequency[5];
68 ULONG compression;
69 } aiff_comm_t;
71 #define AIFF_COMP_NONE MAKE_ID('N','O','N','E')
73 typedef struct {
74 ULONG dataoffset;
75 ULONG blocksize;
76 } aiff_ssnd_t;
78 #pragma pack()
80 BOOL AIFF_header(CONST_APTR p) {
81 const iff_header_t *header = p;
82 return rbe32(&header->id) == ID_FORM && (rbe32(&header->type) == ID_AIFF || rbe32(&header->type) == ID_AIFC);
85 static inline LONG extended2long (UWORD *ext) {
86 ULONG man;
87 WORD exp;
88 LONG sign;
89 exp = rbe16(ext++);
90 man = rbe32(ext);
91 if (exp & 0x8000)
92 sign = -1;
93 else
94 sign = 1;
95 exp = (exp & 0x7fff) - 0x3fff;
96 if (exp < 0) return 0;
97 exp -= 31;
98 if (exp > 0)
99 man = 0x7fffffff;
100 else
101 man >>= -exp;
102 return sign * man;
105 static void AIFF_close(AIFF_STREAM *stream);
106 static LONG AIFF_read(AIFF_STREAM *stream, APTR buffer, ULONG offset, ULONG length);
108 AIFF_STREAM *AIFF_open(CONST_STRPTR filename) {
109 BPTR file = ZERO;
110 AIFF_STREAM *stream = NULL;
111 iff_header_t header;
112 iff_chunk_t chunk;
113 aiff_fver_t fver;
114 aiff_comm_t comm;
115 aiff_ssnd_t ssnd;
116 LONG done = FALSE;
118 SetIoErr(NO_ERROR);
120 file = Open(filename, MODE_OLDFILE);
121 if (!file) {
122 goto error;
125 stream = AllocVec(sizeof(*stream), MEMF_CLEAR);
126 if (!stream) {
127 SetIoErr(ERROR_NO_FREE_STORE);
128 Close(file);
129 goto error;
131 stream->close = AIFF_close;
132 stream->read = AIFF_read;
133 stream->file = file;
135 if (FRead(file, &header, 1, sizeof(header)) != sizeof(header)) {
136 goto error;
138 wbe32(&header.id, header.id);
139 wbe32(&header.size, header.size);
140 wbe32(&header.type, header.type);
141 if (header.id != ID_FORM || (header.type != ID_AIFF && header.type != ID_AIFC)) {
142 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
143 goto error;
146 while (!done) {
147 if (FRead(file, &chunk, 1, sizeof(chunk)) != sizeof(chunk)) {
148 goto error;
150 wbe32(&chunk.id, chunk.id);
151 wbe32(&chunk.size, chunk.size);
152 switch (chunk.id) {
153 case ID_FVER:
154 if (chunk.size != sizeof(fver)) {
155 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
156 goto error;
158 if (FRead(file, &fver, 1, sizeof(fver)) != sizeof(fver)) {
159 goto error;
161 if (rbe32(&fver.timestamp) != AIFC_VERSION1) {
162 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
163 goto error;
165 break;
166 case ID_COMM:
167 if (chunk.size != 18 && chunk.size != 22) {
168 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
169 goto error;
171 if (FRead(file, &comm, 1, chunk.size) != chunk.size) {
172 goto error;
174 if (rbe16(&comm.channels) != 2 ||
175 extended2long(comm.frequency) != 44100 ||
176 rbe16(&comm.bitspersample) != 16)
178 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
179 goto error;
181 if (chunk.size == 22 && comm.compression != AIFF_COMP_NONE) {
182 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
183 goto error;
185 stream->length = rbe32(&comm.frames) * 4UL;
186 break;
187 case ID_SSND:
188 if (chunk.size < sizeof(ssnd)) {
189 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
190 goto error;
192 if (FRead(file, &ssnd, 1, sizeof(ssnd)) != sizeof(ssnd)) {
193 goto error;
195 if (ssnd.dataoffset &&
196 !ChangeFilePosition(file, rbe32(&ssnd.dataoffset), OFFSET_CURRENT))
198 goto error;
200 stream->offset = GetFilePosition(file);
201 if (stream->length == 0) {
202 stream->length = chunk.size - rbe32(&ssnd.dataoffset);
204 if ((LONG)stream->offset == -1 && IoErr()) {
205 goto error;
207 done = TRUE;
208 break;
209 default:
210 if (!ChangeFilePosition(file, (chunk.size+1)&~1, OFFSET_CURRENT)) {
211 goto error;
213 break;
217 return stream;
219 error:
220 AIFF_close(stream);
221 return NULL;
224 static void AIFF_close(AIFF_STREAM *stream) {
225 if (stream) {
226 Close(stream->file);
227 FreeVec(stream);
231 static LONG AIFF_read(AIFF_STREAM *stream, APTR buffer, ULONG offset, ULONG length) {
232 BPTR file = stream->file;
233 LONG read_length;
234 LONG bytes_read;
235 if (offset >= stream->length) {
236 memset(buffer, 0, length);
237 return length;
239 if (!ChangeFilePosition(file, stream->offset + offset, OFFSET_BEGINNING)) {
240 return 0;
242 if ((offset + length) > stream->length) {
243 read_length = stream->length;
244 } else {
245 read_length = length;
247 bytes_read = FRead(file, buffer, 1, read_length);
248 if (bytes_read < 0) {
249 return 0;
251 swab2(buffer, buffer, bytes_read);
252 memset((uint8 *)buffer + bytes_read, 0, length - bytes_read);
253 return length;