Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
Mohamed Tarek | a67deef | 2009-11-18 01:00:43 +0000 | [diff] [blame] | 8 | * $Id$ |
| 9 | * |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 10 | * Copyright (C) 2009 Mohamed Tarek |
| 11 | * |
| 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. |
| 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
| 21 | |
| 22 | #include <string.h> |
| 23 | |
| 24 | #include "logf.h" |
| 25 | #include "codeclib.h" |
| 26 | #include "inttypes.h" |
| 27 | #include "libcook/cook.h" |
| 28 | |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 29 | CODEC_HEADER |
| 30 | |
Nils Wallménius | 6325ef9 | 2010-07-25 22:24:53 +0000 | [diff] [blame] | 31 | static RMContext rmctx; |
| 32 | static RMPacket pkt; |
| 33 | static COOKContext q IBSS_ATTR; |
| 34 | static int32_t rm_outbuf[2048]; |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 35 | |
| 36 | static void init_rm(RMContext *rmctx) |
| 37 | { |
Maurus Cuelenaere | 851b0e3 | 2009-07-08 17:18:59 +0000 | [diff] [blame] | 38 | memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 39 | } |
| 40 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 41 | /* this is called for each file to process */ |
| 42 | enum codec_status codec_run(void) |
| 43 | { |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 44 | static size_t buff_size; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 45 | int datasize, res, consumed, i, time_offset; |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 46 | uint8_t *bit_buffer; |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 47 | uint16_t fs,sps,h; |
| 48 | uint32_t packet_count; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 49 | int scrambling_unit_size, num_units; |
Michael Sevakis | 85e4025 | 2011-02-20 15:27:10 +0000 | [diff] [blame] | 50 | size_t resume_offset; |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 51 | intptr_t param = 0; |
| 52 | enum codec_command_action action = CODEC_ACTION_NULL; |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 53 | |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 54 | if (codec_init()) { |
| 55 | DEBUGF("codec init failed\n"); |
| 56 | return CODEC_ERROR; |
| 57 | } |
Michael Sevakis | 85e4025 | 2011-02-20 15:27:10 +0000 | [diff] [blame] | 58 | |
Michael Sevakis | 85e4025 | 2011-02-20 15:27:10 +0000 | [diff] [blame] | 59 | resume_offset = ci->id3->offset; |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 60 | |
| 61 | codec_set_replaygain(ci->id3); |
| 62 | ci->memset(&rmctx,0,sizeof(RMContext)); |
| 63 | ci->memset(&pkt,0,sizeof(RMPacket)); |
| 64 | ci->memset(&q,0,sizeof(COOKContext)); |
| 65 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 66 | ci->seek_buffer(0); |
| 67 | |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 68 | init_rm(&rmctx); |
| 69 | |
| 70 | ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); |
Andree Buschmann | 3d6faa0 | 2010-02-21 19:47:05 +0000 | [diff] [blame] | 71 | /* cook's sample representation is 21.11 |
| 72 | * DSP_SET_SAMPLE_DEPTH = 11 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 26 */ |
| 73 | ci->configure(DSP_SET_SAMPLE_DEPTH, 26); |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 74 | ci->configure(DSP_SET_STEREO_MODE, rmctx.nb_channels == 1 ? |
Andree Buschmann | 3d6faa0 | 2010-02-21 19:47:05 +0000 | [diff] [blame] | 75 | STEREO_MONO : STEREO_NONINTERLEAVED); |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 76 | |
| 77 | packet_count = rmctx.nb_packets; |
| 78 | rmctx.audio_framesize = rmctx.block_align; |
| 79 | rmctx.block_align = rmctx.sub_packet_size; |
| 80 | fs = rmctx.audio_framesize; |
| 81 | sps= rmctx.block_align; |
| 82 | h = rmctx.sub_packet_h; |
| 83 | scrambling_unit_size = h*fs; |
| 84 | |
| 85 | res =cook_decode_init(&rmctx, &q); |
| 86 | if(res < 0) { |
| 87 | DEBUGF("failed to initialize cook decoder\n"); |
| 88 | return CODEC_ERROR; |
| 89 | } |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 90 | |
Mohamed Tarek | 9669bbc | 2009-11-18 00:41:46 +0000 | [diff] [blame] | 91 | /* check for a mid-track resume and force a seek time accordingly */ |
| 92 | if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { |
| 93 | resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; |
| 94 | num_units = (int)resume_offset / scrambling_unit_size; |
| 95 | /* put number of subpackets to skip in resume_offset */ |
| 96 | resume_offset /= (sps + PACKET_HEADER_SIZE); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 97 | param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); |
| 98 | action = CODEC_ACTION_SEEK_TIME; |
Mohamed Tarek | 9669bbc | 2009-11-18 00:41:46 +0000 | [diff] [blame] | 99 | } |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 100 | |
| 101 | ci->set_elapsed(0); |
| 102 | ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); |
| 103 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 104 | /* The main decoder loop */ |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 105 | seek_start : |
| 106 | while(packet_count) |
| 107 | { |
| 108 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); |
| 109 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); |
| 110 | if(consumed < 0) { |
| 111 | DEBUGF("rm_get_packet failed\n"); |
| 112 | return CODEC_ERROR; |
| 113 | } |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 114 | |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 115 | for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 116 | { |
| 117 | if (action == CODEC_ACTION_NULL) |
| 118 | action = ci->get_command(¶m); |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 119 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 120 | if (action == CODEC_ACTION_HALT) |
| 121 | return CODEC_OK; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 122 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 123 | if (action == CODEC_ACTION_SEEK_TIME) { |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 124 | /* Do not allow seeking beyond the file's length */ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 125 | if ((unsigned) param > ci->id3->length) { |
| 126 | ci->set_elapsed(ci->id3->length); |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 127 | ci->seek_complete(); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 128 | return CODEC_OK; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 129 | } |
| 130 | |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 131 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 132 | packet_count = rmctx.nb_packets; |
| 133 | rmctx.audio_pkt_cnt = 0; |
| 134 | rmctx.frame_number = 0; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 135 | |
| 136 | /* Seek to the start of the track */ |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 137 | if (param == 0) { |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 138 | ci->set_elapsed(0); |
| 139 | ci->seek_complete(); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 140 | action = CODEC_ACTION_NULL; |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 141 | goto seek_start; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 142 | } |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 143 | num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 144 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); |
| 145 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); |
| 146 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); |
| 147 | if(consumed < 0) { |
| 148 | DEBUGF("rm_get_packet failed\n"); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 149 | ci->seek_complete(); |
| 150 | return CODEC_ERROR; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 151 | } |
| 152 | packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 153 | rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate)); |
| 154 | while(rmctx.audiotimestamp > (unsigned) param) { |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 155 | rmctx.audio_pkt_cnt = 0; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 156 | ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); |
| 157 | bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); |
| 158 | consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 159 | packet_count += rmctx.audio_pkt_cnt; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 160 | num_units--; |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 161 | } |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 162 | time_offset = param - rmctx.audiotimestamp; |
Mohamed Tarek | b5b9cb0 | 2009-07-13 10:06:19 +0000 | [diff] [blame] | 163 | i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); |
| 164 | ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); |
| 165 | ci->seek_complete(); |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 166 | } |
| 167 | |
| 168 | action = CODEC_ACTION_NULL; |
| 169 | |
Andree Buschmann | 3d6faa0 | 2010-02-21 19:47:05 +0000 | [diff] [blame] | 170 | res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align); |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 171 | rmctx.frame_number++; |
| 172 | |
| 173 | /* skip the first two frames; no valid audio */ |
| 174 | if(rmctx.frame_number < 3) continue; |
| 175 | |
| 176 | if(res != rmctx.block_align) { |
| 177 | DEBUGF("codec error\n"); |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 178 | return CODEC_ERROR; |
| 179 | } |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 180 | |
Andree Buschmann | 3d6faa0 | 2010-02-21 19:47:05 +0000 | [diff] [blame] | 181 | ci->pcmbuf_insert(rm_outbuf, |
| 182 | rm_outbuf+q.samples_per_channel, |
| 183 | q.samples_per_channel); |
Mohamed Tarek | edf3af2 | 2009-07-12 14:36:06 +0000 | [diff] [blame] | 184 | ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 185 | } |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 186 | packet_count -= rmctx.audio_pkt_cnt; |
| 187 | rmctx.audio_pkt_cnt = 0; |
| 188 | ci->advance_buffer(consumed); |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 189 | } |
Mohamed Tarek | d259568 | 2009-07-08 20:23:24 +0000 | [diff] [blame] | 190 | |
Michael Sevakis | c537d59 | 2011-04-27 03:08:23 +0000 | [diff] [blame^] | 191 | return CODEC_OK; |
Mohamed Tarek | e184ef1 | 2009-07-06 22:40:45 +0000 | [diff] [blame] | 192 | } |