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_mpega.h"
28 #include <proto/exec.h>
29 #include <proto/dos.h>
30 #include <proto/mpega.h>
37 static const MPEGA_CTRL mpa_ctrl
= {
39 { FALSE
, { 1, 2, 44100 }, { 1, 2, 44100 } },
40 { FALSE
, { 1, 2, 44100 }, { 1, 2, 44100 } },
45 static void MP3_close(MP3_STREAM
*stream
);
46 static LONG
MP3_read(MP3_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
);
48 MP3_STREAM
*MP3_open(CONST_STRPTR filename
) {
49 MP3_STREAM
*stream
= NULL
;
50 LONG error
= NO_ERROR
;
52 stream
= AllocVec(sizeof(*stream
), MEMF_CLEAR
);
54 error
= ERROR_NO_FREE_STORE
;
57 stream
->close
= MP3_close
;
58 stream
->read
= MP3_read
;
60 stream
->stream
= MPEGA_open((STRPTR
)filename
, (MPEGA_CTRL
*)&mpa_ctrl
);
61 if (!stream
->stream
) {
62 error
= ERROR_OBJECT_NOT_FOUND
;
66 if (stream
->stream
->dec_frequency
!= 44100 ||
67 stream
->stream
->dec_channels
!= 2)
69 error
= ERROR_OBJECT_WRONG_TYPE
;
73 stream
->pcm
[0] = AllocVec(MPEGA_PCM_SIZE
* sizeof(WORD
), MEMF_ANY
);
74 stream
->pcm
[1] = AllocVec(MPEGA_PCM_SIZE
* sizeof(WORD
), MEMF_ANY
);
75 if (!stream
->pcm
[0] || !stream
->pcm
[1]) {
76 error
= ERROR_NO_FREE_STORE
;
80 stream
->length
= ((UQUAD
)stream
->stream
->ms_duration
* (44100ULL * 4ULL)) / 1000ULL;
90 static void MP3_close(MP3_STREAM
*stream
) {
92 if (stream
->stream
) MPEGA_close(stream
->stream
);
93 FreeVec(stream
->pcm
[0]);
94 FreeVec(stream
->pcm
[1]);
99 static LONG
MP3_read(MP3_STREAM
*stream
, APTR buffer
, ULONG offset
, ULONG length
) {
100 LONG sample_offset
= offset
>> 2;
101 LONG samples_to_read
= length
>> 2;
102 LONG samples_to_skip
;
106 if (sample_offset
>= stream
->first_sample_in_pcm
&&
107 sample_offset
< (stream
->first_sample_in_pcm
+ stream
->samples_in_pcm
))
109 samples_to_skip
= sample_offset
- stream
->first_sample_in_pcm
;
110 samples_read
= stream
->samples_in_pcm
;
111 sample_offset
= stream
->first_sample_in_pcm
+ samples_read
;
112 if (samples_read
> samples_to_skip
) {
113 if (samples_read
> (samples_to_skip
+ samples_to_read
)) {
114 samples_read
= samples_to_skip
+ samples_to_read
;
116 for (sample
= samples_to_skip
; sample
< samples_read
; sample
++) {
117 wle16(dst
, stream
->pcm
[0][sample
]); dst
++;
118 wle16(dst
, stream
->pcm
[1][sample
]); dst
++;
120 samples_read
-= samples_to_skip
;
122 samples_to_read
-= samples_read
;
124 samples_to_skip
-= samples_read
;
127 if (stream
->sample_offset
!= -1 && sample_offset
>= stream
->sample_offset
) {
128 samples_to_skip
= sample_offset
- stream
->sample_offset
;
129 sample_offset
= stream
->sample_offset
;
131 stream
->sample_offset
= -1;
133 if (MPEGA_seek(stream
->stream
, 0) < 0) {
134 return (LONG
)dst
- (LONG
)buffer
;
136 samples_to_skip
= sample_offset
;
137 stream
->sample_offset
= sample_offset
= 0;
139 while (samples_to_read
) {
141 memset(dst
, 0, samples_to_read
<< 2);
142 dst
+= (samples_to_read
<< 1);
145 stream
->first_sample_in_pcm
= 0;
146 stream
->samples_in_pcm
= 0;
147 samples_read
= MPEGA_decode_frame(stream
->stream
, stream
->pcm
);
148 if (samples_read
< 0) {
149 if (samples_read
== MPEGA_ERR_EOF
) {
153 stream
->sample_offset
= -1;
156 stream
->first_sample_in_pcm
= sample_offset
;
157 stream
->samples_in_pcm
= samples_read
;
158 sample_offset
+= samples_read
;
159 stream
->sample_offset
= sample_offset
;
160 if (samples_read
> samples_to_skip
) {
161 if (samples_read
> (samples_to_skip
+ samples_to_read
)) {
162 samples_read
= samples_to_skip
+ samples_to_read
;
164 for (sample
= samples_to_skip
; sample
< samples_read
; sample
++) {
165 wle16(dst
, stream
->pcm
[0][sample
]); dst
++;
166 wle16(dst
, stream
->pcm
[1][sample
]); dst
++;
168 samples_read
-= samples_to_skip
;
170 samples_to_read
-= samples_read
;
172 samples_to_skip
-= samples_read
;
175 return (LONG
)dst
- (LONG
)buffer
;