Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2005 Thom Johansen |
| 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame] | 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. |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
| 21 | |
Thom Johansen | c91e0bb | 2005-10-13 11:32:52 +0000 | [diff] [blame] | 22 | #include "codeclib.h" |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 23 | #include <codecs/libmusepack/mpcdec.h> |
| 24 | #include <codecs/libmusepack/internal.h> |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 25 | |
Jens Arnold | b8749fd | 2006-01-18 00:05:14 +0000 | [diff] [blame] | 26 | CODEC_HEADER |
| 27 | |
Nils Wallménius | 6325ef9 | 2010-07-25 22:24:53 +0000 | [diff] [blame] | 28 | static MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH] IBSS_ATTR; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 29 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 30 | /* Our implementations of the mpc_reader callback functions. */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 31 | static mpc_int32_t read_impl(mpc_reader *reader, void *ptr, mpc_int32_t size) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 32 | { |
Andree Buschmann | a3541c0 | 2010-06-21 18:45:34 +0000 | [diff] [blame] | 33 | (void)reader; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 34 | return ((mpc_int32_t)(ci->read_filebuf(ptr, size))); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 35 | } |
| 36 | |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 37 | static mpc_bool_t seek_impl(mpc_reader *reader, mpc_int32_t offset) |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 38 | { |
Andree Buschmann | a3541c0 | 2010-06-21 18:45:34 +0000 | [diff] [blame] | 39 | (void)reader; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 40 | return ci->seek_buffer(offset); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 41 | } |
| 42 | |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 43 | static mpc_int32_t tell_impl(mpc_reader *reader) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 44 | { |
Andree Buschmann | a3541c0 | 2010-06-21 18:45:34 +0000 | [diff] [blame] | 45 | (void)reader; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 46 | return ci->curpos; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 47 | } |
| 48 | |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 49 | static mpc_int32_t get_size_impl(mpc_reader *reader) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 50 | { |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 51 | (void)reader; |
Andree Buschmann | a3541c0 | 2010-06-21 18:45:34 +0000 | [diff] [blame] | 52 | return ci->filesize; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 53 | } |
| 54 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 55 | /* this is the codec entry point */ |
| 56 | enum codec_status codec_main(enum codec_entry_call_reason reason) |
| 57 | { |
| 58 | if (reason == CODEC_LOAD) { |
| 59 | /* musepack's sample representation is 18.14 |
| 60 | * DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */ |
| 61 | ci->configure(DSP_SET_SAMPLE_DEPTH, 29); |
| 62 | } |
| 63 | |
| 64 | return CODEC_OK; |
| 65 | } |
| 66 | |
| 67 | /* this is called for each file to process */ |
| 68 | enum codec_status codec_run(void) |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 69 | { |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 70 | mpc_int64_t samplesdone; |
Andree Buschmann | 1f725eb | 2010-03-14 13:32:16 +0000 | [diff] [blame] | 71 | uint32_t frequency; /* 0.1 kHz accuracy */ |
| 72 | uint32_t elapsed_time; /* milliseconds */ |
| 73 | uint32_t byterate; /* bytes per second */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 74 | mpc_status status; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 75 | mpc_reader reader; |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 76 | mpc_streaminfo info; |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 77 | mpc_frame_info frame; |
| 78 | mpc_demux *demux = NULL; |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 79 | intptr_t param; |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 80 | |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 81 | frame.buffer = sample_buffer; |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 82 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 83 | /* Create a decoder instance */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 84 | reader.read = read_impl; |
| 85 | reader.seek = seek_impl; |
| 86 | reader.tell = tell_impl; |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 87 | reader.get_size = get_size_impl; |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 88 | |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 89 | if (codec_init()) |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 90 | return CODEC_ERROR; |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 91 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 92 | /* Prep position */ |
| 93 | ci->seek_buffer(0); |
Magnus Holmgren | 87842ca | 2008-02-24 19:12:15 +0000 | [diff] [blame] | 94 | |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 95 | /* Initialize demux/decoder. */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 96 | demux = mpc_demux_init(&reader); |
| 97 | if (NULL == demux) |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 98 | return CODEC_ERROR; |
| 99 | |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 100 | /* Read file's streaminfo data. */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 101 | mpc_demux_get_info(demux, &info); |
| 102 | |
Andree Buschmann | 1f725eb | 2010-03-14 13:32:16 +0000 | [diff] [blame] | 103 | byterate = (mpc_uint32_t)(info.average_bitrate) / 8; |
Andree Buschmann | f4ac757 | 2009-04-20 19:16:48 +0000 | [diff] [blame] | 104 | frequency = info.sample_freq / 100; /* 0.1 kHz accuracy */ |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 105 | ci->configure(DSP_SWITCH_FREQUENCY, info.sample_freq); |
Andree Buschmann | 1f725eb | 2010-03-14 13:32:16 +0000 | [diff] [blame] | 106 | |
| 107 | /* Remark: rockbox offset is the file offset in bytes. So, estimate the |
| 108 | * sample seek position from the file offset, the sampling frequency and |
| 109 | * the bitrate. As the saved position is exactly calculated the reverse way |
| 110 | * there is no loss of information except rounding. */ |
| 111 | samplesdone = 100 * ((mpc_uint64_t)(ci->id3->offset * frequency) / byterate); |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 112 | |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 113 | /* Set up digital signal processing for correct number of channels */ |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 114 | /* NOTE: current musepack format only allows for stereo files |
| 115 | but code is here to handle other configurations anyway */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 116 | if (info.channels == 2) |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 117 | ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 118 | else if (info.channels == 1) |
Michael Sevakis | 97f369a | 2007-02-10 16:34:16 +0000 | [diff] [blame] | 119 | ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 120 | else |
| 121 | return CODEC_ERROR; |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 122 | |
Thom Johansen | d5eefe8 | 2005-11-04 21:35:08 +0000 | [diff] [blame] | 123 | codec_set_replaygain(ci->id3); |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 124 | |
Adam Boot | a5d7309 | 2007-04-06 21:48:17 +0000 | [diff] [blame] | 125 | /* Resume to saved sample offset. */ |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 126 | if (samplesdone > 0) |
| 127 | { |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 128 | if (mpc_demux_seek_sample(demux, samplesdone) == MPC_STATUS_OK) |
| 129 | { |
Andree Buschmann | f4ac757 | 2009-04-20 19:16:48 +0000 | [diff] [blame] | 130 | elapsed_time = (samplesdone*10)/frequency; |
| 131 | ci->set_elapsed(elapsed_time); |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 132 | } |
| 133 | else |
| 134 | { |
Adam Boot | a5d7309 | 2007-04-06 21:48:17 +0000 | [diff] [blame] | 135 | samplesdone = 0; |
| 136 | } |
Adam Boot | a5d7309 | 2007-04-06 21:48:17 +0000 | [diff] [blame] | 137 | } |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 138 | |
Thom Johansen | 8b2531b | 2005-06-22 22:02:11 +0000 | [diff] [blame] | 139 | /* This is the decoding loop. */ |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 140 | do |
| 141 | { |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 142 | enum codec_command_action action = ci->get_command(¶m); |
| 143 | |
| 144 | if (action == CODEC_ACTION_HALT) |
| 145 | return CODEC_OK; |
| 146 | |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 147 | /* Complete seek handler. */ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 148 | if (action == CODEC_ACTION_SEEK_TIME) |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 149 | { |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 150 | mpc_int64_t new_offset = (param/10)*frequency; |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 151 | if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK) |
| 152 | { |
Thom Johansen | 7410120 | 2005-11-06 19:12:27 +0000 | [diff] [blame] | 153 | samplesdone = new_offset; |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 154 | } |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 155 | |
| 156 | elapsed_time = (samplesdone*10)/frequency; |
| 157 | ci->set_elapsed(elapsed_time); |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 158 | ci->seek_complete(); |
| 159 | } |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 160 | |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 161 | /* Decode one frame. */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 162 | status = mpc_demux_decode(demux, &frame); |
Thom Johansen | 3d98ecf | 2005-10-10 19:56:40 +0000 | [diff] [blame] | 163 | ci->yield(); |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 164 | if (frame.bits == -1) |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 165 | { |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 166 | /* Decoding error, exit decoding loop. */ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 167 | return (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR; |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 168 | } |
| 169 | else |
| 170 | { |
Andree Buschmann | fc1fab4 | 2010-06-23 06:25:18 +0000 | [diff] [blame] | 171 | /* Decoding passed, insert samples to PCM buffer. */ |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 172 | ci->pcmbuf_insert(frame.buffer, |
| 173 | frame.buffer + MPC_FRAME_LENGTH, |
| 174 | frame.samples); |
| 175 | samplesdone += frame.samples; |
Andree Buschmann | f4ac757 | 2009-04-20 19:16:48 +0000 | [diff] [blame] | 176 | elapsed_time = (samplesdone*10)/frequency; |
| 177 | ci->set_elapsed(elapsed_time); |
Andree Buschmann | 1f725eb | 2010-03-14 13:32:16 +0000 | [diff] [blame] | 178 | /* Remark: rockbox offset is the file offset in bytes. So estimate |
| 179 | * this offset from the samples, sampling frequency and bitrate */ |
| 180 | ci->set_offset( (samplesdone * byterate)/(frequency*100) ); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 181 | } |
Andree Buschmann | b3d9578 | 2010-03-07 19:34:44 +0000 | [diff] [blame] | 182 | } while (true); |
Dave Chapman | 2f2d7d4 | 2005-06-11 12:40:27 +0000 | [diff] [blame] | 183 | } |