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/mp3_mpg123.h"
28 #include <proto/exec.h>
29 #include <proto/dos.h>
37 #define ZERO MKBADDR(NULL)
38 #define MPG123_SEEK_SET SEEK_SET
39 #define MPG123_SEEK_CUR SEEK_CUR
40 #define MPG123_SEEK_END SEEK_END
42 static void MP3_close(MP3_STREAM
*stream
);
43 static LONG
MP3_read(MP3_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
);
45 ssize_t
mpg123_r_read(void *handle
, void *buffer
, size_t length
);
46 off_t
mpg123_r_lseek(void *handle
, off_t offset
, int whence
);
47 void mpg123_cleanup(void *handle
);
49 MP3_STREAM
*MP3_open(CONST_STRPTR filename
) {
51 MP3_STREAM
*stream
= NULL
;
52 LONG error
= NO_ERROR
;
54 file
= Open(filename
, MODE_OLDFILE
);
60 stream
= AllocVec(sizeof(*stream
), MEMF_ANY
|MEMF_CLEAR
);
62 error
= ERROR_NO_FREE_STORE
;
66 stream
->close
= MP3_close
;
67 stream
->read
= MP3_read
;
70 stream
->mh
= mpg123_new(NULL
, NULL
);
72 error
= ERROR_NO_FREE_STORE
;
76 if (mpg123_format_none(stream
->mh
) != MPG123_OK
||
77 mpg123_format(stream
->mh
, 44100, MPG123_STEREO
,
78 MPG123_ENC_SIGNED_16
) != MPG123_OK
||
79 mpg123_replace_reader_handle(stream
->mh
, mpg123_r_read
,
80 mpg123_r_lseek
, mpg123_cleanup
) != MPG123_OK
||
81 mpg123_open_handle(stream
->mh
, stream
) != MPG123_OK
)
83 error
= ERROR_OBJECT_WRONG_TYPE
;
87 stream
->total_samples
= mpg123_length(stream
->mh
);
88 if (stream
->total_samples
== MPG123_ERR
) {
89 error
= ERROR_OBJECT_WRONG_TYPE
;
92 stream
->length
= stream
->total_samples
<< 2;
102 static void MP3_close(MP3_STREAM
*stream
) {
104 mpg123_delete(stream
->mh
);
110 static LONG
MP3_read(MP3_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
) {
111 LONG sample_offset
= offset
>> 2;
112 LONG samples_to_read
= length
>> 2;
117 if (sample_offset
>= stream
->total_samples
) {
118 memset(buffer
, 0, length
);
121 if (mpg123_tell(stream
->mh
) != sample_offset
) {
122 LONG curr_sample_offset
;
124 curr_sample_offset
= mpg123_seek(stream
->mh
, sample_offset
,
126 if (curr_sample_offset
< 0) {
128 } else if (curr_sample_offset
< sample_offset
) {
129 LONG seek_len
, do_len
;
130 seek_len
= (sample_offset
- curr_sample_offset
) << 2;
132 while (seek_len
> 0) {
133 if (seek_len
< length
) do_len
= seek_len
;
134 res
= mpg123_read(stream
->mh
, buffer
, do_len
, &bytes_read
);
135 if (bytes_read
> 0) {
136 seek_len
-= bytes_read
;
138 if (res
== MPG123_DONE
) {
142 if (res
!= MPG123_OK
) {
146 } else if (curr_sample_offset
> sample_offset
) {
150 while (samples_to_read
) {
152 memset(dst
, 0, samples_to_read
<< 2);
153 dst
+= (samples_to_read
<< 1);
156 res
= mpg123_read(stream
->mh
, (UBYTE
*)dst
, samples_to_read
<< 2, &bytes_read
);
157 samples_read
= bytes_read
>> 2;
158 if (samples_read
> 0) {
160 for (sample
= 0; sample
< samples_read
; sample
++) {
161 wle16(dst
, *dst
); dst
++;
162 wle16(dst
, *dst
); dst
++;
164 samples_to_read
-= samples_read
;
166 if (res
== MPG123_DONE
) {
170 if (res
!= MPG123_OK
&& res
!= MPG123_NEW_FORMAT
) {
174 return (IPTR
)dst
- (IPTR
)buffer
;
177 ssize_t
mpg123_r_read(void *handle
, void *buffer
, size_t length
) {
178 MP3_STREAM
*stream
= handle
;
179 BPTR file
= stream
->file
;
180 return Read(file
, buffer
, length
);
183 off_t
mpg123_r_lseek(void *handle
, off_t offset
, int whence
) {
184 MP3_STREAM
*stream
= handle
;
185 BPTR file
= stream
->file
;
189 case MPG123_SEEK_SET
:
190 mode
= OFFSET_BEGINNING
;
192 case MPG123_SEEK_CUR
:
193 mode
= OFFSET_CURRENT
;
195 case MPG123_SEEK_END
:
201 if (!ChangeFilePosition(file
, offset
, mode
)) {
204 res
= GetFilePosition(file
);
205 if (res
>= 0LL && res
<= 0x7fffffffLL
) {
212 void mpg123_cleanup(void *handle
) {