1 /* copyright: Steve Dekorte, 2002
2 * All rights reserved. See _BSDLicense.txt.
4 * user clones MP3Decoder and implements input and output methods
6 * input should return a buffer, output will have a buffer argument.
9 #include "IoMP3Decoder.h"
16 #define DATA(self) ((IoMP3DecoderData *)IoObject_dataPointer(self))
18 IoTag
*IoMP3Decoder_newTag(void *state
)
20 IoTag
*tag
= IoTag_newWithName_("MP3Decoder");
21 IoTag_state_(tag
, state
);
22 IoTag_cloneFunc_(tag
, (IoTagCloneFunc
*)IoMP3Decoder_rawClone
);
23 IoTag_markFunc_(tag
, (IoTagMarkFunc
*)IoMP3Decoder_mark
);
24 IoTag_freeFunc_(tag
, (IoTagFreeFunc
*)IoMP3Decoder_free
);
28 IoMP3Decoder
*IoMP3Decoder_proto(void *state
)
30 IoObject
*self
= IoObject_new(state
);
31 IoObject_tag_(self
, IoMP3Decoder_newTag(state
));
33 IoObject_setDataPointer_(self
, calloc(1, sizeof(IoMP3DecoderData
)));
35 //DATA(self)->outSound = 0x0;
36 DATA(self
)->willProcessMessage
= IoMessage_newWithName_label_(state
, IOSYMBOL("willProcess"), IOSYMBOL("[MP3Decoder]"));
37 DATA(self
)->didProcessMessage
= IoMessage_newWithName_label_(state
, IOSYMBOL("didProcess"), IOSYMBOL("[MP3Decoder]"));
38 DATA(self
)->inputBuffer
= IoSeq_new(state
);
39 DATA(self
)->outputBuffer
= IoSeq_new(state
);
40 DATA(self
)->tmpInputBa
= UArray_new();
42 IoState_registerProtoWithFunc_(state
, self
, IoMP3Decoder_proto
);
45 IoMethodTable methodTable
[] = {
46 {"start", IoMP3Decoder_start
},
47 {"stop", IoMP3Decoder_stop
},
48 {"inputBuffer", IoMP3Decoder_inputBuffer
},
49 {"outputBuffer", IoMP3Decoder_outputBuffer
},
53 IoObject_addMethodTable_(self
, methodTable
);
58 IoMP3Decoder
*IoMP3Decoder_rawClone(IoMP3Decoder
*proto
)
60 IoObject
*self
= IoObject_rawClonePrimitive(proto
);
61 IoObject_setDataPointer_(self
, calloc(1, sizeof(IoMP3DecoderData
)));
63 DATA(self
)->willProcessMessage
= DATA(proto
)->willProcessMessage
;
64 DATA(self
)->didProcessMessage
= DATA(proto
)->didProcessMessage
;
65 DATA(self
)->inputBuffer
= IOCLONE(DATA(proto
)->inputBuffer
);
66 DATA(self
)->outputBuffer
= IOCLONE(DATA(proto
)->outputBuffer
);
67 DATA(self
)->tmpInputBa
= UArray_new();
69 IoState_addValue_(IOSTATE
, self
);
73 IoMP3Decoder
*IoMP3Decoder_new(void *state
)
75 IoObject
*proto
= IoState_protoWithInitFunction_(state
, IoMP3Decoder_proto
);
76 return IOCLONE(proto
);
79 /* ----------------------------------------------------------- */
81 void IoMP3Decoder_free(IoMP3Decoder
*self
)
83 UArray_free(DATA(self
)->tmpInputBa
);
84 free(IoObject_dataPointer(self
));
87 void IoMP3Decoder_mark(IoMP3Decoder
*self
)
89 IoObject_shouldMark(DATA(self
)->inputBuffer
);
90 IoObject_shouldMark(DATA(self
)->outputBuffer
);
91 IoObject_shouldMark(DATA(self
)->willProcessMessage
);
92 IoObject_shouldMark(DATA(self
)->didProcessMessage
);
95 /* ----------------------------------------------------------- */
97 /* (re)fill the stream buffer which is to be decoded. */
99 static enum mad_flow
IoMP3Decoder_inputCallback(void *data
, struct mad_stream
*stream
)
101 IoMP3Decoder
*self
= data
;
102 struct mad_decoder
*decoder
= &(DATA(self
)->decoder
);
104 IoMessage_locals_performOn_(DATA(self
)->willProcessMessage
, self
, self
);
106 if (DATA(self
)->isRunning
)
108 UArray
*ba
= IoSeq_rawUArray(DATA(self
)->inputBuffer
);
110 UArray_removeRange(ba
, 0, DATA(self
)->lastInputPos
);
113 size_t size
= UArray_size(ba
);
114 UArray_setSize_(ba
, size
+ MAD_BUFFER_GUARD
);
115 memset(UArray_bytes(ba
) + size
, 0x0, MAD_BUFFER_GUARD
);
116 UArray_setSize_(ba
, size
);
119 if (UArray_size(ba
) == 0)
121 return MAD_FLOW_CONTINUE
;
124 DATA(self
)->lastInputPos
= UArray_size(ba
);
126 mad_stream_buffer(stream
, UArray_bytes(ba
), UArray_size(ba
));
129 return DATA(self
)->isRunning
? MAD_FLOW_CONTINUE
: MAD_FLOW_STOP
;
132 // This is the output callback function. It is called after each frame of
133 // MPEG audio data has been completely decoded. The purpose of this callback
134 // is to output (or play) the decoded PCM audio.
136 static enum mad_flow
IoMP3Decoder_outputCallback(void *data
,
137 struct mad_header
const *header
,
140 IoMP3Decoder
*self
= data
;
141 UArray
*ba
= IoSeq_rawUArray(DATA(self
)->outputBuffer
);
142 unsigned int oldSize
= UArray_size(ba
);
143 unsigned int newSize
= oldSize
+ (pcm
->length
* 2 * sizeof(float));
145 UArray_setSize_(ba
, newSize
);
147 if (!DATA(self
)->isRunning
)
149 return MAD_FLOW_STOP
;
152 // MAD data is in 4 byte signed ints
153 // and on separated (not interleaved channels)
154 // so we interleave them here
157 float *out
= (float *)(UArray_bytes(ba
) + oldSize
);
158 unsigned int nsamples
= pcm
->length
;
160 mad_fixed_t
const *left
= pcm
->samples
[0];
161 mad_fixed_t
const *right
= pcm
->samples
[1];
163 if (pcm
->channels
== 2)
165 // this would be much faster as a vector op
168 *out
= ((float)(*left
)) / INT_MAX
;
170 *out
= ((float)(*right
)) / INT_MAX
;
180 float f
= ((float)(*left
)) / INT_MAX
;
190 IoMessage_locals_performOn_(DATA(self
)->didProcessMessage
, self
, self
);
192 return DATA(self
)->isRunning
? MAD_FLOW_CONTINUE
: MAD_FLOW_STOP
;
196 * This is the error callback function. It is called whenever a decoding
197 * error occurs. The error is indicated by stream->error; the list of
198 * possible MAD_ERROR_* errors can be found in the mad.h (or
199 * libmad/stream.h) header file.
202 static enum mad_flow
IoMP3Decoder_errorCallback(void *data
,
203 struct mad_stream
*stream
,
204 struct mad_frame
*frame
)
206 //IoMP3Decoder *self = data;
208 fprintf(stderr
, "lbmad error %i (%s)\n", stream
->error
, mad_stream_errorstr(stream
));
211 IoState_error_(IOSTATE, 0x0, "MP3Decoder %s", mad_stream_errorstr(stream));
213 DATA(self)->isRunning = 0;
214 return MAD_FLOW_BREAK;
216 return MAD_FLOW_CONTINUE
;
219 IoObject
*IoMP3Decoder_start(IoMP3Decoder
*self
, IoObject
*locals
, IoMessage
*m
)
222 DATA(self
)->isRunning
= 1;
223 DATA(self
)->lastInputPos
= 0;
225 mad_decoder_init(&(DATA(self
)->decoder
), (void *)self
,
226 IoMP3Decoder_inputCallback
,
229 IoMP3Decoder_outputCallback
,
230 IoMP3Decoder_errorCallback
,
235 result
= mad_decoder_run(&(DATA(self
)->decoder
), MAD_DECODER_MODE_SYNC
);
237 mad_decoder_finish(&(DATA(self
)->decoder
));
239 /* release the decoder */
241 return IONUMBER(result
);
244 IoObject
*IoMP3Decoder_inputBuffer(IoMP3Decoder
*self
, IoObject
*locals
, IoMessage
*m
)
246 return DATA(self
)->inputBuffer
;
249 IoObject
*IoMP3Decoder_outputBuffer(IoMP3Decoder
*self
, IoObject
*locals
, IoMessage
*m
)
251 return DATA(self
)->outputBuffer
;
254 IoObject
*IoMP3Decoder_stop(IoMP3Decoder
*self
, IoObject
*locals
, IoMessage
*m
)
256 DATA(self
)->isRunning
= 0;
257 DATA(self
)->lastInputPos
= 0;
261 IoObject
*IoMP3Decoder_isRunning(IoMP3Decoder
*self
, IoObject
*locals
, IoMessage
*m
)
263 return IOBOOL(self
, DATA(self
)->isRunning
);