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/aiff.h"
28 #include <libraries/iffparse.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
36 #define ZERO MKBADDR(NULL)
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')
61 #define AIFC_VERSION1 0xA2805140
71 #define AIFF_COMP_NONE MAKE_ID('N','O','N','E')
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
) {
95 exp
= (exp
& 0x7fff) - 0x3fff;
96 if (exp
< 0) return 0;
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
) {
110 AIFF_STREAM
*stream
= NULL
;
120 file
= Open(filename
, MODE_OLDFILE
);
125 stream
= AllocVec(sizeof(*stream
), MEMF_CLEAR
);
127 SetIoErr(ERROR_NO_FREE_STORE
);
131 stream
->close
= AIFF_close
;
132 stream
->read
= AIFF_read
;
135 if (FRead(file
, &header
, 1, sizeof(header
)) != sizeof(header
)) {
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
);
147 if (FRead(file
, &chunk
, 1, sizeof(chunk
)) != sizeof(chunk
)) {
150 wbe32(&chunk
.id
, chunk
.id
);
151 wbe32(&chunk
.size
, chunk
.size
);
154 if (chunk
.size
!= sizeof(fver
)) {
155 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
158 if (FRead(file
, &fver
, 1, sizeof(fver
)) != sizeof(fver
)) {
161 if (rbe32(&fver
.timestamp
) != AIFC_VERSION1
) {
162 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
167 if (chunk
.size
!= 18 && chunk
.size
!= 22) {
168 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
171 if (FRead(file
, &comm
, 1, chunk
.size
) != chunk
.size
) {
174 if (rbe16(&comm
.channels
) != 2 ||
175 extended2long(comm
.frequency
) != 44100 ||
176 rbe16(&comm
.bitspersample
) != 16)
178 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
181 if (chunk
.size
== 22 && comm
.compression
!= AIFF_COMP_NONE
) {
182 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
185 stream
->length
= rbe32(&comm
.frames
) * 4UL;
188 if (chunk
.size
< sizeof(ssnd
)) {
189 SetIoErr(ERROR_OBJECT_WRONG_TYPE
);
192 if (FRead(file
, &ssnd
, 1, sizeof(ssnd
)) != sizeof(ssnd
)) {
195 if (ssnd
.dataoffset
&&
196 !ChangeFilePosition(file
, rbe32(&ssnd
.dataoffset
), OFFSET_CURRENT
))
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()) {
210 if (!ChangeFilePosition(file
, (chunk
.size
+1)&~1, OFFSET_CURRENT
)) {
224 static void AIFF_close(AIFF_STREAM
*stream
) {
231 static LONG
AIFF_read(AIFF_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
) {
232 BPTR file
= stream
->file
;
235 if (offset
>= stream
->length
) {
236 memset(buffer
, 0, length
);
239 if (!ChangeFilePosition(file
, stream
->offset
+ offset
, OFFSET_BEGINNING
)) {
242 if ((offset
+ length
) > stream
->length
) {
243 read_length
= stream
->length
;
245 read_length
= length
;
247 bytes_read
= FRead(file
, buffer
, 1, read_length
);
248 if (bytes_read
< 0) {
251 swab2(buffer
, buffer
, bytes_read
);
252 memset((uint8
*)buffer
+ bytes_read
, 0, length
- bytes_read
);