A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 293 lines 8.9 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005 David Bryant 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#include "plugin.h" 22#ifdef RB_PROFILE 23#include "lib/profile_plugin.h" 24#endif 25 26#include <codecs/libwavpack/wavpack.h> 27 28 29 30#define SAMPLES_PER_BLOCK 22050 31 32static char *audiobuf; 33static ssize_t audiobuflen; 34 35static struct wav_header { 36 char ckID [4]; /* RIFF chuck header */ 37 int32_t ckSize; 38 char formType [4]; 39 40 char fmt_ckID [4]; /* format chunk header */ 41 int32_t fmt_ckSize; 42 ushort FormatTag, NumChannels; 43 uint32_t SampleRate, BytesPerSecond; 44 ushort BlockAlign, BitsPerSample; 45 46 char data_ckID [4]; /* data chunk header */ 47 int32_t data_ckSize; 48} raw_header, native_header; 49 50#define WAV_HEADER_FORMAT "4L44LSSLLSS4L" 51 52static void wvupdate (int32_t start_tick, 53 int32_t sample_rate, 54 uint32_t total_samples, 55 uint32_t samples_converted, 56 uint32_t bytes_read, 57 uint32_t bytes_written) 58{ 59 int32_t elapsed_ticks = *rb->current_tick - start_tick; 60 int compression = 0, progress = 0, realtime = 0; 61 62 if (total_samples) 63 progress = (int)(((int64_t) samples_converted * 100 + 64 (total_samples/2)) / total_samples); 65 66 if (elapsed_ticks) 67 realtime = (int)(((int64_t) samples_converted * 100 * HZ / 68 sample_rate + (elapsed_ticks/2)) / elapsed_ticks); 69 70 if (bytes_read) 71 compression = (int)(((int64_t)(bytes_read - bytes_written) * 100 + 72 (bytes_read/2)) / bytes_read); 73 74 rb->lcd_putsf(0, 2, "elapsed time: %ld secs", 75 (long)(elapsed_ticks + (HZ/2)) / HZ); 76 rb->lcd_putsf(0, 4, "progress: %d%%", progress); 77 rb->lcd_putsf(0, 6, "realtime: %d%% ", realtime); 78 rb->lcd_putsf(0, 8, "compression: %d%% ", compression); 79 80 rb->lcd_update(); 81} 82 83#define TEMP_SAMPLES 4096 84 85static int32_t temp_buffer [TEMP_SAMPLES] IDATA_ATTR; 86 87static int wav2wv(const char *infile) 88{ 89 int in_fd, out_fd, num_chans, error = false, last_buttons; 90 uint32_t total_bytes_read = 0, total_bytes_written = 0; 91 uint32_t total_samples, samples_remaining; 92 int32_t *input_buffer = (int32_t *) audiobuf; 93 unsigned char *output_buffer = (unsigned char *)(audiobuf + 0x100000); 94 char outfile[MAX_PATH]; 95 const char *inextension; 96 char *outextension; 97 WavpackConfig config; 98 WavpackContext *wpc; 99 int32_t start_tick; 100 101 rb->lcd_clear_display(); 102 rb->lcd_puts_scroll(0, 0, (unsigned char *)infile); 103 rb->lcd_update(); 104 105 last_buttons = rb->button_status (); 106 start_tick = *rb->current_tick; 107 inextension = infile + rb->strlen(infile) - 3; 108 if (rb->strcasecmp (inextension, "wav")) { 109 rb->splash(HZ*2, "only for wav files!"); 110 return 1; 111 } 112 113 in_fd = rb->open(infile, O_RDONLY); 114 115 if (in_fd < 0) { 116 rb->splash(HZ*2, "could not open file!"); 117 return true; 118 } 119 120 if (rb->read (in_fd, &raw_header, sizeof (raw_header)) != sizeof (raw_header)) { 121 rb->splash(HZ*2, "could not read file!"); 122 rb->close (in_fd); 123 return true; 124 } 125 126 total_bytes_read += sizeof (raw_header); 127 rb->memcpy (&native_header, &raw_header, sizeof (raw_header)); 128 little_endian_to_native (&native_header, WAV_HEADER_FORMAT); 129 130 if (rb->strncmp (native_header.ckID, "RIFF", 4) || 131 rb->strncmp (native_header.fmt_ckID, "fmt ", 4) || 132 rb->strncmp (native_header.data_ckID, "data", 4) || 133 native_header.FormatTag != 1 || native_header.BitsPerSample != 16) { 134 rb->splash(HZ*2, "incompatible wav file!"); 135 rb->close (in_fd); 136 return true; 137 } 138 139 wpc = WavpackOpenFileOutput (); 140 141 rb->memset (&config, 0, sizeof (config)); 142 config.bits_per_sample = 16; 143 config.bytes_per_sample = 2; 144 config.sample_rate = native_header.SampleRate; 145 num_chans = config.num_channels = native_header.NumChannels; 146 total_samples = native_header.data_ckSize / native_header.BlockAlign; 147 148/* config.flags |= CONFIG_HIGH_FLAG; */ 149 150 if (!WavpackSetConfiguration (wpc, &config, total_samples)) { 151 rb->splash(HZ*2, "internal error!"); 152 rb->close (in_fd); 153 return true; 154 } 155 156 WavpackAddWrapper (wpc, &raw_header, sizeof (raw_header)); 157 158 rb->strcpy(outfile, infile); 159 outextension = outfile + rb->strlen(outfile) - 3; 160 outextension[1] = outextension[2]; 161 outextension[2] = 0; 162 out_fd = rb->creat(outfile, 0666); 163 164 if (out_fd < 0) { 165 rb->splash(HZ*2, "could not create file!"); 166 rb->close (in_fd); 167 return true; 168 } 169 170 wvupdate (start_tick, native_header.SampleRate, total_samples, 0, 0, 0); 171 172 for (samples_remaining = total_samples; samples_remaining;) { 173 uint32_t samples_count, samples_to_pack, bytes_count; 174 int cnt, buttons; 175 int32_t value, *lp; 176 signed char *cp; 177 178 samples_count = SAMPLES_PER_BLOCK; 179 180 if (samples_count > samples_remaining) 181 samples_count = samples_remaining; 182 183 bytes_count = samples_count * num_chans * 2; 184 185 if (rb->read (in_fd, input_buffer, bytes_count) != (int32_t) bytes_count) { 186 rb->splash(HZ*2, "could not read file!"); 187 error = true; 188 break; 189 } 190 191 total_bytes_read += bytes_count; 192 WavpackStartBlock (wpc, output_buffer, output_buffer + 0x100000); 193 samples_to_pack = samples_count; 194 cp = (signed char *) input_buffer; 195 196 while (samples_to_pack) { 197 uint32_t samples_this_pass = TEMP_SAMPLES / num_chans; 198 199 if (samples_this_pass > samples_to_pack) 200 samples_this_pass = samples_to_pack; 201 202 lp = temp_buffer; 203 cnt = samples_this_pass; 204 205 if (num_chans == 2) 206 while (cnt--) { 207 value = *cp++ & 0xff; 208 value += *cp++ << 8; 209 *lp++ = value; 210 value = *cp++ & 0xff; 211 value += *cp++ << 8; 212 *lp++ = value; 213 } 214 else 215 while (cnt--) { 216 value = *cp++ & 0xff; 217 value += *cp++ << 8; 218 *lp++ = value; 219 } 220 221 if (!WavpackPackSamples (wpc, temp_buffer, samples_this_pass)) { 222 rb->splash(HZ*2, "internal error!"); 223 error = true; 224 break; 225 } 226 227 samples_to_pack -= samples_this_pass; 228 } 229 230 if (error) 231 break; 232 233 bytes_count = WavpackFinishBlock (wpc); 234 235 if (rb->write (out_fd, output_buffer, bytes_count) != (int32_t) bytes_count) { 236 rb->splash(HZ*2, "could not write file!"); 237 error = true; 238 break; 239 } 240 241 total_bytes_written += bytes_count; 242 samples_remaining -= samples_count; 243 244 wvupdate (start_tick, native_header.SampleRate, total_samples, 245 total_samples - samples_remaining, total_bytes_read, total_bytes_written); 246 247 buttons = rb->button_status (); 248 249 if (last_buttons == BUTTON_NONE && buttons != BUTTON_NONE) { 250 rb->splash(HZ*2, "operation aborted!"); 251 error = true; 252 break; 253 } 254 else 255 last_buttons = buttons; 256 } 257 258 rb->close (out_fd); 259 rb->close (in_fd); 260 261 if (error) { 262 rb->remove (outfile); 263 } 264 else 265 rb->splash(HZ*3, "operation successful"); 266 267 rb->reload_directory(); 268 return error; 269} 270 271enum plugin_status plugin_start(const void *parameter) 272{ 273 if (!parameter) 274 return PLUGIN_ERROR; 275 276 audiobuf = rb->plugin_get_audio_buffer((size_t *)&audiobuflen); 277 278 if (audiobuflen < 0x200000) { 279 rb->splash(HZ*2, "not enough memory!"); 280 return PLUGIN_ERROR; 281 } 282 283#ifdef HAVE_ADJUSTABLE_CPU_FREQ 284 rb->cpu_boost(true); 285#endif 286 287 wav2wv (parameter); 288 289#ifdef HAVE_ADJUSTABLE_CPU_FREQ 290 rb->cpu_boost(false); 291#endif 292 return PLUGIN_OK; 293}