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/vorbis.h"
28 #include <proto/exec.h>
29 #include <proto/dos.h>
36 #define ZERO MKBADDR(NULL)
37 #define OGG_SEEK_SET SEEK_SET
38 #define OGG_SEEK_CUR SEEK_CUR
39 #define OGG_SEEK_END SEEK_END
41 #define ID_OggS MAKE_ID('O','g','g','S')
43 BOOL
VORBIS_header(CONST_APTR p
) {
44 return rbe32(p
) == ID_OggS
;
47 static void VORBIS_close(VORBIS_STREAM
*stream
);
48 static LONG
VORBIS_read(VORBIS_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
);
50 static size_t ogg_read (APTR buffer
, size_t size
, size_t nitems
, APTR file
);
51 static int ogg_seek (APTR file
, ogg_int64_t offset
, int mode
);
52 static long ogg_tell (APTR file
);
54 static const ov_callbacks callbacks
= {
61 VORBIS_STREAM
*VORBIS_open(CONST_STRPTR filename
) {
63 VORBIS_STREAM
*stream
= NULL
;
65 LONG error
= NO_ERROR
;
67 file
= Open(filename
, MODE_OLDFILE
);
73 stream
= AllocVec(sizeof(*stream
), MEMF_CLEAR
);
75 error
= ERROR_NO_FREE_STORE
;
79 stream
->close
= VORBIS_close
;
80 stream
->read
= VORBIS_read
;
83 stream
->vf
= AllocVec(sizeof(OggVorbis_File
), MEMF_CLEAR
);
85 error
= ERROR_NO_FREE_STORE
;
89 if (ov_open_callbacks(stream
, stream
->vf
, NULL
, 0, callbacks
) < 0) {
90 error
= ERROR_OBJECT_WRONG_TYPE
;
96 vi
= ov_info(stream
->vf
, stream
->bs
);
97 if (vi
->channels
!= 2 || vi
->rate
!= 44100) {
98 error
= ERROR_OBJECT_WRONG_TYPE
;
102 stream
->total_samples
= ov_pcm_total(stream
->vf
, stream
->bs
);
103 stream
->length
= stream
->total_samples
<< 2;
108 VORBIS_close(stream
);
113 static void VORBIS_close(VORBIS_STREAM
*stream
) {
116 ov_clear(stream
->vf
);
124 static LONG
VORBIS_read(VORBIS_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
) {
125 LONG sample_offset
= offset
>> 2;
126 LONG bytes_to_read
= length
;
129 if (sample_offset
>= stream
->total_samples
) {
130 memset(buffer
, 0, length
);
133 if (ov_pcm_tell(stream
->vf
) != sample_offset
) {
135 if (ov_pcm_seek(stream
->vf
, sample_offset
) < 0) {
139 while (bytes_to_read
> 0) {
141 memset(dst
, 0, bytes_to_read
);
142 dst
+= bytes_to_read
;
145 bytes_read
= ov_read(stream
->vf
, dst
, bytes_to_read
, 0, 2, 1, &stream
->bs
);
146 if (bytes_read
< 0) {
149 if (bytes_read
== 0) {
153 bytes_to_read
-= bytes_read
;
156 return (LONG
)dst
- (LONG
)buffer
;
159 static size_t ogg_read (APTR buffer
, size_t size
, size_t nitems
, APTR handle
) {
160 VORBIS_STREAM
*stream
= handle
;
162 items_read
= FRead(stream
->file
, buffer
, size
, nitems
);
163 return items_read
== -1 ? 0 : items_read
;
166 static int ogg_seek (APTR handle
, ogg_int64_t offset
, int mode
) {
167 VORBIS_STREAM
*stream
= handle
;
170 mode
= OFFSET_BEGINNING
;
173 mode
= OFFSET_CURRENT
;
181 return !ChangeFilePosition(stream
->file
, offset
, mode
) ? -1 : 0;
184 static long ogg_tell (APTR handle
) {
185 VORBIS_STREAM
*stream
= handle
;
186 return GetFilePosition(stream
->file
);