1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (c) 2010 Yoshihisa Uchida
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include "codecs/libpcm/support_formats.h"
28 * SMAF (Synthetic music Mobile Application Format)
31 * [1] YAMAHA Corporation, Synthetic music Mobile Application Format Ver.3.05, 2002
35 SMAF_AUDIO_TRACK_CHUNK
= 0, /* PCM Audio Track */
36 SMAF_SCORE_TRACK_CHUNK
, /* Score Track */
39 /* SMAF supported codec formats */
41 SMAF_FORMAT_UNSUPPORT
= 0, /* unsupported format */
42 SMAF_FORMAT_SIGNED_PCM
, /* 2's complement PCM */
43 SMAF_FORMAT_UNSIGNED_PCM
, /* Offset Binary PCM */
44 SMAF_FORMAT_ADPCM
, /* YAMAHA ADPCM */
47 static const int support_formats
[2][3] = {
48 {SMAF_FORMAT_SIGNED_PCM
, SMAF_FORMAT_ADPCM
, SMAF_FORMAT_UNSUPPORT
},
49 {SMAF_FORMAT_SIGNED_PCM
, SMAF_FORMAT_UNSIGNED_PCM
, SMAF_FORMAT_ADPCM
},
52 static const struct pcm_entry pcm_codecs
[] = {
53 { SMAF_FORMAT_SIGNED_PCM
, get_linear_pcm_codec
},
54 { SMAF_FORMAT_UNSIGNED_PCM
, get_linear_pcm_codec
},
55 { SMAF_FORMAT_ADPCM
, get_yamaha_adpcm_codec
},
60 static const int basebits
[4] = { 4, 8, 12, 16 };
62 #define PCM_SAMPLE_SIZE (2048*2)
64 static int32_t samples
[PCM_SAMPLE_SIZE
] IBSS_ATTR
;
66 static const struct pcm_codec
*get_codec(uint32_t formattag
)
70 for (i
= 0; i
< NUM_FORMATS
; i
++)
72 if (pcm_codecs
[i
].format_tag
== formattag
)
74 if (pcm_codecs
[i
].get_codec
)
75 return pcm_codecs
[i
].get_codec();
82 static unsigned int get_be32(const uint8_t *buf
)
84 return (buf
[0] << 24) | (buf
[1] << 16) | (buf
[2] << 8) | buf
[3];
87 static int convert_smaf_channels(unsigned int ch
)
92 static int convert_smaf_audio_format(unsigned int chunk
, unsigned int audio_format
)
94 int idx
= (audio_format
& 0x70) >> 4;
97 return support_formats
[chunk
][idx
];
99 DEBUGF("CODEC_ERROR: unsupport audio format: %d\n", audio_format
);
100 return SMAF_FORMAT_UNSUPPORT
;
103 static int convert_smaf_audio_basebit(unsigned int basebit
)
106 return basebits
[basebit
];
108 DEBUGF("CODEC_ERROR: illegal basebit: %d\n", basebit
);
112 static unsigned int search_chunk(const unsigned char *name
, int nlen
, off_t
*pos
)
114 const unsigned char *buf
;
115 unsigned int chunksize
;
120 buf
= ci
->request_buffer(&size
, 8);
124 chunksize
= get_be32(buf
+ 4);
125 ci
->advance_buffer(8);
127 if (memcmp(buf
, name
, nlen
) == 0)
130 ci
->advance_buffer(chunksize
);
133 DEBUGF("CODEC_ERROR: missing '%s' chunk\n", name
);
137 static bool parse_audio_track(struct pcm_format
*fmt
, unsigned int chunksize
, off_t
*pos
)
139 const unsigned char *buf
;
142 /* search PCM Audio Track Chunk */
143 ci
->advance_buffer(chunksize
);
145 if (search_chunk("ATR", 3, pos
) == 0)
147 DEBUGF("CODEC_ERROR: missing PCM Audio Track Chunk\n");
156 * +2: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: frequency
157 * +3: bit 4-7: base bit
161 * Note: If PCM Audio Track does not include Sequence Data Chunk,
162 * tmp+6 is the start position of Wave Data Chunk.
164 buf
= ci
->request_buffer(&size
, 6);
167 DEBUGF("CODEC_ERROR: smaf is too small\n");
171 fmt
->formattag
= convert_smaf_audio_format(SMAF_AUDIO_TRACK_CHUNK
, buf
[2]);
172 fmt
->channels
= convert_smaf_channels(buf
[2]);
173 fmt
->bitspersample
= convert_smaf_audio_basebit(buf
[3] >> 4);
175 /* search Wave Data Chunk */
176 ci
->advance_buffer(6);
178 fmt
->numbytes
= search_chunk("Awa", 3, pos
);
179 if (fmt
->numbytes
== 0)
181 DEBUGF("CODEC_ERROR: missing Wave Data Chunk\n");
188 static bool parse_score_track(struct pcm_format
*fmt
, off_t
*pos
)
190 const unsigned char *buf
;
191 unsigned int chunksize
;
194 /* parse Optional Data Chunk */
195 buf
= ci
->request_buffer(&size
, 13);
198 DEBUGF("CODEC_ERROR: smaf is too small\n");
202 if (memcmp(buf
+ 5, "OPDA", 4) != 0)
204 DEBUGF("CODEC_ERROR: missing Optional Data Chunk\n");
208 /* Optional Data Chunk size */
209 chunksize
= get_be32(buf
+ 9);
211 /* search Score Track Chunk */
212 ci
->advance_buffer(13 + chunksize
);
213 *pos
+= (13 + chunksize
);
214 if (search_chunk("MTR", 3, pos
) == 0)
216 DEBUGF("CODEC_ERROR: missing Score Track Chunk\n");
222 * usually, next chunk ('M***') found within 40 bytes.
224 buf
= ci
->request_buffer(&size
, 40);
227 DEBUGF("CODEC_ERROR: smaf is too small\n");
232 while (size
< 40 && buf
[size
] != 'M')
237 DEBUGF("CODEC_ERROR: missing Score Track Stream PCM Data Chunk");
241 /* search Score Track Stream PCM Data Chunk */
242 ci
->advance_buffer(size
);
244 if (search_chunk("Mtsp", 4, pos
) == 0)
246 DEBUGF("CODEC_ERROR: missing Score Track Stream PCM Data Chunk\n");
251 * parse Score Track Stream Wave Data Chunk
253 * +4-7: chunk size (WaveType(3bytes) + wave data count)
254 * +8: bit 7 0:mono/1:stereo, bit 4-6 format, bit 0-3: base bit
255 * +9: frequency (MSB)
256 * +10: frequency (LSB)
258 buf
= ci
->request_buffer(&size
, 9);
261 DEBUGF("CODEC_ERROR: smaf is too small\n");
265 if (memcmp(buf
, "Mwa", 3) != 0)
267 DEBUGF("CODEC_ERROR: missing Score Track Stream Wave Data Chunk\n");
271 fmt
->formattag
= convert_smaf_audio_format(SMAF_SCORE_TRACK_CHUNK
, buf
[8]);
272 fmt
->channels
= convert_smaf_channels(buf
[8]);
273 fmt
->bitspersample
= convert_smaf_audio_basebit(buf
[8] & 0xf);
274 fmt
->numbytes
= get_be32(buf
+ 4) - 3;
280 static bool parse_header(struct pcm_format
*fmt
, off_t
*pos
)
282 const unsigned char *buf
;
283 unsigned int chunksize
;
286 ci
->memset(fmt
, 0, sizeof(struct pcm_format
));
288 /* check File Chunk and Contents Info Chunk */
289 buf
= ci
->request_buffer(&size
, 16);
292 DEBUGF("CODEC_ERROR: smaf is too small\n");
296 if ((memcmp(buf
, "MMMD", 4) != 0) || (memcmp(buf
+ 8, "CNTI", 4) != 0))
298 DEBUGF("CODEC_ERROR: does not smaf format\n");
302 chunksize
= get_be32(buf
+ 12);
303 ci
->advance_buffer(16);
307 if (!parse_audio_track(fmt
, chunksize
, pos
))
310 else if (!parse_score_track(fmt
, pos
))
313 /* data signess (default signed) */
314 fmt
->is_signed
= (fmt
->formattag
!= SMAF_FORMAT_UNSIGNED_PCM
);
316 /* data is always big endian */
317 fmt
->is_little_endian
= false;
322 static struct pcm_format format
;
323 static uint32_t bytesdone
;
325 static uint8_t *read_buffer(size_t *realsize
)
327 uint8_t *buffer
= (uint8_t *)ci
->request_buffer(realsize
, format
.chunksize
);
328 if (bytesdone
+ (*realsize
) > format
.numbytes
)
329 *realsize
= format
.numbytes
- bytesdone
;
330 bytesdone
+= *realsize
;
331 ci
->advance_buffer(*realsize
);
335 enum codec_status
codec_main(void)
337 int status
= CODEC_OK
;
338 uint32_t decodedsamples
;
343 off_t firstblockposn
; /* position of the first block in file */
344 const struct pcm_codec
*codec
;
346 /* Generic codec initialisation */
347 ci
->configure(DSP_SET_SAMPLE_DEPTH
, PCM_OUTPUT_DEPTH
-1);
351 status
= CODEC_ERROR
;
355 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
358 codec_set_replaygain(ci
->id3
);
360 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
361 bytesdone
= ci
->id3
->offset
;
366 if (!parse_header(&format
, &firstblockposn
))
368 status
= CODEC_ERROR
;
372 codec
= get_codec(format
.formattag
);
375 DEBUGF("CODEC_ERROR: unsupport audio format: 0x%x\n", (int)format
.formattag
);
376 status
= CODEC_ERROR
;
380 if (!codec
->set_format(&format
))
382 status
= CODEC_ERROR
;
386 /* check chunksize */
387 if ((format
.chunksize
/ format
.blockalign
) * format
.samplesperblock
* format
.channels
389 format
.chunksize
= (PCM_SAMPLE_SIZE
/ format
.blockalign
) * format
.blockalign
;
390 if (format
.chunksize
== 0)
392 DEBUGF("CODEC_ERROR: chunksize is 0\n");
393 status
= CODEC_ERROR
;
397 ci
->configure(DSP_SWITCH_FREQUENCY
, ci
->id3
->frequency
);
399 if (format
.channels
== 2) {
400 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_INTERLEAVED
);
401 } else if (format
.channels
== 1) {
402 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
404 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
405 status
= CODEC_ERROR
;
409 ci
->seek_buffer(firstblockposn
);
412 /* make sure we're at the correct offset */
413 if (bytesdone
> (uint32_t) firstblockposn
)
415 /* Round down to previous block */
416 struct pcm_pos
*newpos
= codec
->get_seek_pos(bytesdone
- firstblockposn
,
417 PCM_SEEK_POS
, &read_buffer
);
419 if (newpos
->pos
> format
.numbytes
)
421 if (ci
->seek_buffer(firstblockposn
+ newpos
->pos
))
423 bytesdone
= newpos
->pos
;
424 decodedsamples
= newpos
->samples
;
430 /* already where we need to be */
434 /* The main decoder loop */
437 while (!endofstream
) {
439 if (ci
->stop_codec
|| ci
->new_track
)
443 struct pcm_pos
*newpos
= codec
->get_seek_pos(ci
->seek_time
, PCM_SEEK_TIME
,
446 if (newpos
->pos
> format
.numbytes
)
448 if (ci
->seek_buffer(firstblockposn
+ newpos
->pos
))
450 bytesdone
= newpos
->pos
;
451 decodedsamples
= newpos
->samples
;
455 smafbuf
= (uint8_t *)ci
->request_buffer(&n
, format
.chunksize
);
458 break; /* End of stream */
460 if (bytesdone
+ n
> format
.numbytes
) {
461 n
= format
.numbytes
- bytesdone
;
465 status
= codec
->decode(smafbuf
, n
, samples
, &bufcount
);
466 if (status
== CODEC_ERROR
)
468 DEBUGF("codec error\n");
472 ci
->pcmbuf_insert(samples
, NULL
, bufcount
);
474 ci
->advance_buffer(n
);
476 decodedsamples
+= bufcount
;
477 if (bytesdone
>= format
.numbytes
)
480 ci
->set_elapsed(decodedsamples
*1000LL/ci
->id3
->frequency
);
485 if (ci
->request_next_track())