comparison src/shnplug/shn.c @ 1305:51bf0e431e02

Add SHNplug.
author William Pitcock <nenolod@atheme-project.org>
date Fri, 20 Jul 2007 10:29:54 -0500
parents
children 761e17b23e0c
comparison
equal deleted inserted replaced
1300:c198ae31bb74 1305:51bf0e431e02
1 /* shn.c - main functions for xmms-shn
2 * Copyright (C) 2000-2007 Jason Jordan <shnutils@freeshell.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 /*
20 * $Id: shn.c,v 1.38 2007/03/23 05:49:48 jason Exp $
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <math.h>
26 #include <glib.h>
27 #include <audacious/util.h>
28 #include <audacious/configdb.h>
29 #include "shorten.h"
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 static void shn_about(void);
36 static void shn_configure(void);
37 static void shn_init(void);
38 static int shn_is_our_fd(char *, VFSFile *fd);
39 static void shn_play(InputPlayback *);
40 static void shn_stop(InputPlayback *);
41 static void shn_seek(InputPlayback *, int);
42 static void shn_pause(InputPlayback *, short);
43 static void shn_get_file_info(char *,char **,int *);
44 static void shn_display_file_info(char *);
45
46 gchar *shn_fmts[] = { "shn", NULL };
47
48 InputPlugin shn_ip =
49 {
50 NULL,
51 NULL,
52 "SHN Player " VERSION,
53 shn_init,
54 shn_about,
55 shn_configure,
56 NULL,
57 NULL,
58 shn_play,
59 shn_stop,
60 shn_pause,
61 shn_seek,
62 NULL,
63 NULL,
64 NULL,
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 NULL,
70 NULL,
71 shn_get_file_info,
72 shn_display_file_info,
73 NULL,
74 NULL,
75 NULL,
76 NULL,
77 shn_is_our_fd,
78 shn_fmts,
79 };
80
81 InputPlugin *shn_iplist[] = { &shn_ip, NULL };
82
83 DECLARE_PLUGIN(shnplug, NULL, NULL, shn_iplist, NULL, NULL, NULL, NULL);
84
85 shn_file *shnfile;
86 shn_config shn_cfg;
87
88 static pthread_t decode_thread;
89 static gboolean audio_error = FALSE;
90
91 static void shn_init()
92 {
93 ConfigDb *cfg;
94
95 shn_cfg.error_output_method = ERROR_OUTPUT_DEVNULL;
96 shn_cfg.error_output_method_config_name = "error_output_method";
97 shn_cfg.seek_tables_path = NULL;
98 shn_cfg.seek_tables_path_config_name = "seek_tables_path";
99 shn_cfg.relative_seek_tables_path = NULL;
100 shn_cfg.relative_seek_tables_path_config_name = "relative_seek_tables_path";
101 shn_cfg.verbose = 0;
102 shn_cfg.verbose_config_name = "verbose";
103 shn_cfg.swap_bytes = 0;
104 shn_cfg.swap_bytes_config_name = "swap_bytes";
105 shn_cfg.load_textfiles = FALSE;
106 shn_cfg.load_textfiles_config_name = "load_textfiles";
107 shn_cfg.textfile_extensions = NULL;
108 shn_cfg.textfile_extensions_config_name = "textfile_extensions";
109
110 if ((cfg = bmp_cfg_db_open()) != 0)
111 {
112 bmp_cfg_db_get_int(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.error_output_method_config_name, &shn_cfg.error_output_method);
113 bmp_cfg_db_get_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.verbose_config_name, &shn_cfg.verbose);
114 if (!bmp_cfg_db_get_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.seek_tables_path_config_name, &shn_cfg.seek_tables_path))
115 shn_cfg.seek_tables_path = g_strdup(g_get_home_dir());
116 if (!bmp_cfg_db_get_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.relative_seek_tables_path_config_name, &shn_cfg.relative_seek_tables_path))
117 shn_cfg.relative_seek_tables_path = g_strdup("");
118 bmp_cfg_db_get_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.swap_bytes_config_name, &shn_cfg.swap_bytes);
119 bmp_cfg_db_get_bool(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.load_textfiles_config_name, &shn_cfg.load_textfiles);
120 if (!bmp_cfg_db_get_string(cfg, XMMS_SHN_VERSION_TAG, shn_cfg.textfile_extensions_config_name, &shn_cfg.textfile_extensions))
121 shn_cfg.textfile_extensions = g_strdup("txt,nfo");
122 bmp_cfg_db_close(cfg);
123 }
124 }
125
126 static void shn_about()
127 {
128 shn_display_about();
129 }
130
131 static void shn_configure()
132 {
133 shn_display_configure();
134 }
135
136 int init_decode_state(shn_file *this_shn)
137 {
138 if (this_shn->decode_state)
139 {
140 if (this_shn->decode_state->getbuf)
141 {
142 free(this_shn->decode_state->getbuf);
143 this_shn->decode_state->getbuf = NULL;
144 }
145
146 if (this_shn->decode_state->writebuf)
147 {
148 free(this_shn->decode_state->writebuf);
149 this_shn->decode_state->writebuf = NULL;
150 }
151
152 if (this_shn->decode_state->writefub)
153 {
154 free(this_shn->decode_state->writefub);
155 this_shn->decode_state->writefub = NULL;
156 }
157
158 free(this_shn->decode_state);
159 this_shn->decode_state = NULL;
160 }
161
162 if (!(this_shn->decode_state = malloc(sizeof(shn_decode_state))))
163 {
164 shn_debug("Could not allocate memory for decode state data structure");
165 return 0;
166 }
167
168 this_shn->decode_state->getbuf = NULL;
169 this_shn->decode_state->getbufp = NULL;
170 this_shn->decode_state->nbitget = 0;
171 this_shn->decode_state->nbyteget = 0;
172 this_shn->decode_state->gbuffer = 0;
173 this_shn->decode_state->writebuf = NULL;
174 this_shn->decode_state->writefub = NULL;
175 this_shn->decode_state->nwritebuf = 0;
176
177 this_shn->vars.bytes_in_buf = 0;
178
179 return 1;
180 }
181
182 int get_wave_header(shn_file *this_shn)
183 {
184 slong **buffer = NULL, **offset = NULL;
185 slong lpcqoffset = 0;
186 int version = FORMAT_VERSION, bitshift = 0;
187 int ftype = TYPE_EOF;
188 char *magic = MAGIC;
189 int blocksize = DEFAULT_BLOCK_SIZE, nchan = DEFAULT_NCHAN;
190 int i, chan, nwrap, nskip = DEFAULT_NSKIP;
191 int *qlpc = NULL, maxnlpc = DEFAULT_MAXNLPC, nmean = UNDEFINED_UINT;
192 int cmd;
193 int internal_ftype;
194 int cklen;
195 int retval = 0;
196
197 if (!init_decode_state(this_shn))
198 return 0;
199
200 /***********************/
201 /* EXTRACT starts here */
202 /***********************/
203
204 /* read magic number */
205 #ifdef STRICT_FORMAT_COMPATABILITY
206 if(FORMAT_VERSION < 2)
207 {
208 for(i = 0; i < strlen(magic); i++) {
209 if(getc_exit(this_shn->vars.fd) != magic[i])
210 return 0;
211 this_shn->vars.bytes_read++;
212 }
213
214 /* get version number */
215 version = getc_exit(this_shn->vars.fd);
216 this_shn->vars.bytes_read++;
217 }
218 else
219 #endif /* STRICT_FORMAT_COMPATABILITY */
220 {
221 int nscan = 0;
222
223 version = MAX_VERSION + 1;
224 while(version > MAX_VERSION)
225 {
226 int byte = vfs_getc(this_shn->vars.fd);
227 this_shn->vars.bytes_read++;
228 if(byte == EOF)
229 return 0;
230 if(magic[nscan] != '\0' && byte == magic[nscan])
231 nscan++;
232 else
233 if(magic[nscan] == '\0' && byte <= MAX_VERSION)
234 version = byte;
235 else
236 {
237 if(byte == magic[0])
238 nscan = 1;
239 else
240 {
241 nscan = 0;
242 }
243 version = MAX_VERSION + 1;
244 }
245 }
246 }
247
248 /* check version number */
249 if(version > MAX_SUPPORTED_VERSION)
250 return 0;
251
252 /* set up the default nmean, ignoring the command line state */
253 nmean = (version < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN;
254
255 /* initialise the variable length file read for the compressed stream */
256 var_get_init(this_shn);
257 if (this_shn->vars.fatal_error)
258 return 0;
259
260 /* initialise the fixed length file write for the uncompressed stream */
261 fwrite_type_init(this_shn);
262
263 /* get the internal file type */
264 internal_ftype = UINT_GET(TYPESIZE, this_shn);
265
266 /* has the user requested a change in file type? */
267 if(internal_ftype != ftype) {
268 if(ftype == TYPE_EOF) {
269 ftype = internal_ftype; /* no problems here */
270 }
271 else { /* check that the requested conversion is valid */
272 if(internal_ftype == TYPE_AU1 || internal_ftype == TYPE_AU2 ||
273 internal_ftype == TYPE_AU3 || ftype == TYPE_AU1 ||ftype == TYPE_AU2 || ftype == TYPE_AU3)
274 {
275 retval = 0;
276 goto got_enough_data;
277 }
278 }
279 }
280
281 nchan = UINT_GET(CHANSIZE, this_shn);
282 this_shn->vars.actual_nchan = nchan;
283
284 /* get blocksize if version > 0 */
285 if(version > 0)
286 {
287 int byte;
288 blocksize = UINT_GET((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2),this_shn);
289 maxnlpc = UINT_GET(LPCQSIZE, this_shn);
290 this_shn->vars.actual_maxnlpc = maxnlpc;
291 nmean = UINT_GET(0, this_shn);
292 this_shn->vars.actual_nmean = nmean;
293 nskip = UINT_GET(NSKIPSIZE, this_shn);
294 for(i = 0; i < nskip; i++)
295 {
296 byte = uvar_get(XBYTESIZE,this_shn);
297 }
298 }
299 else
300 blocksize = DEFAULT_BLOCK_SIZE;
301
302 nwrap = MAX(NWRAP, maxnlpc);
303
304 /* grab some space for the input buffer */
305 buffer = long2d((ulong) nchan, (ulong) (blocksize + nwrap),this_shn);
306 if (this_shn->vars.fatal_error)
307 return 0;
308 offset = long2d((ulong) nchan, (ulong) MAX(1, nmean),this_shn);
309 if (this_shn->vars.fatal_error) {
310 if (buffer) {
311 free(buffer);
312 buffer = NULL;
313 }
314 return 0;
315 }
316
317 for(chan = 0; chan < nchan; chan++)
318 {
319 for(i = 0; i < nwrap; i++)
320 buffer[chan][i] = 0;
321 buffer[chan] += nwrap;
322 }
323
324 if(maxnlpc > 0) {
325 qlpc = (int*) pmalloc((ulong) (maxnlpc * sizeof(*qlpc)),this_shn);
326 if (this_shn->vars.fatal_error) {
327 if (buffer) {
328 free(buffer);
329 buffer = NULL;
330 }
331 if (offset) {
332 free(offset);
333 buffer = NULL;
334 }
335 return 0;
336 }
337 }
338
339 if(version > 1)
340 lpcqoffset = V2LPCQOFFSET;
341
342 init_offset(offset, nchan, MAX(1, nmean), internal_ftype);
343
344 /* get commands from file and execute them */
345 chan = 0;
346 while(1)
347 {
348 this_shn->vars.reading_function_code = 1;
349 cmd = uvar_get(FNSIZE,this_shn);
350 this_shn->vars.reading_function_code = 0;
351
352 switch(cmd)
353 {
354 case FN_ZERO:
355 case FN_DIFF0:
356 case FN_DIFF1:
357 case FN_DIFF2:
358 case FN_DIFF3:
359 case FN_QLPC:
360 {
361 slong coffset, *cbuffer = buffer[chan];
362 int resn = 0, nlpc, j;
363
364 if(cmd != FN_ZERO)
365 {
366 resn = uvar_get(ENERGYSIZE,this_shn);
367 if (this_shn->vars.fatal_error) {
368 retval = 0;
369 goto got_enough_data;
370 }
371 /* this is a hack as version 0 differed in definition of var_get */
372 if(version == 0)
373 resn--;
374 }
375
376 /* find mean offset : N.B. this code duplicated */
377 if(nmean == 0)
378 coffset = offset[chan][0];
379 else
380 {
381 slong sum = (version < 2) ? 0 : nmean / 2;
382 for(i = 0; i < nmean; i++)
383 sum += offset[chan][i];
384 if(version < 2)
385 coffset = sum / nmean;
386 else
387 coffset = ROUNDEDSHIFTDOWN(sum / nmean, bitshift);
388 }
389
390 switch(cmd)
391 {
392 case FN_ZERO:
393 for(i = 0; i < blocksize; i++)
394 cbuffer[i] = 0;
395 break;
396 case FN_DIFF0:
397 for(i = 0; i < blocksize; i++) {
398 cbuffer[i] = var_get(resn,this_shn) + coffset;
399 if (this_shn->vars.fatal_error) {
400 retval = 0;
401 goto got_enough_data;
402 }
403 }
404 break;
405 case FN_DIFF1:
406 for(i = 0; i < blocksize; i++) {
407 cbuffer[i] = var_get(resn,this_shn) + cbuffer[i - 1];
408 if (this_shn->vars.fatal_error) {
409 retval = 0;
410 goto got_enough_data;
411 }
412 }
413 break;
414 case FN_DIFF2:
415 for(i = 0; i < blocksize; i++) {
416 cbuffer[i] = var_get(resn,this_shn) + (2 * cbuffer[i - 1] - cbuffer[i - 2]);
417 if (this_shn->vars.fatal_error) {
418 retval = 0;
419 goto got_enough_data;
420 }
421 }
422 break;
423 case FN_DIFF3:
424 for(i = 0; i < blocksize; i++) {
425 cbuffer[i] = var_get(resn,this_shn) + 3 * (cbuffer[i - 1] - cbuffer[i - 2]) + cbuffer[i - 3];
426 if (this_shn->vars.fatal_error) {
427 retval = 0;
428 goto got_enough_data;
429 }
430 }
431 break;
432 case FN_QLPC:
433 nlpc = uvar_get(LPCQSIZE,this_shn);
434 if (this_shn->vars.fatal_error) {
435 retval = 0;
436 goto got_enough_data;
437 }
438
439 for(i = 0; i < nlpc; i++) {
440 qlpc[i] = var_get(LPCQUANT,this_shn);
441 if (this_shn->vars.fatal_error) {
442 retval = 0;
443 goto got_enough_data;
444 }
445 }
446 for(i = 0; i < nlpc; i++)
447 cbuffer[i - nlpc] -= coffset;
448 for(i = 0; i < blocksize; i++)
449 {
450 slong sum = lpcqoffset;
451
452 for(j = 0; j < nlpc; j++)
453 sum += qlpc[j] * cbuffer[i - j - 1];
454 cbuffer[i] = var_get(resn,this_shn) + (sum >> LPCQUANT);
455 if (this_shn->vars.fatal_error) {
456 retval = 0;
457 goto got_enough_data;
458 }
459 }
460 if(coffset != 0)
461 for(i = 0; i < blocksize; i++)
462 cbuffer[i] += coffset;
463 break;
464 }
465
466 /* store mean value if appropriate : N.B. Duplicated code */
467 if(nmean > 0)
468 {
469 slong sum = (version < 2) ? 0 : blocksize / 2;
470
471 for(i = 0; i < blocksize; i++)
472 sum += cbuffer[i];
473
474 for(i = 1; i < nmean; i++)
475 offset[chan][i - 1] = offset[chan][i];
476 if(version < 2)
477 offset[chan][nmean - 1] = sum / blocksize;
478 else
479 offset[chan][nmean - 1] = (sum / blocksize) << bitshift;
480 }
481
482 if (0 == chan) {
483 this_shn->vars.initial_file_position = this_shn->vars.last_file_position_no_really;
484 goto got_enough_data;
485 }
486
487 /* do the wrap */
488 for(i = -nwrap; i < 0; i++)
489 cbuffer[i] = cbuffer[i + blocksize];
490
491 fix_bitshift(cbuffer, blocksize, bitshift, internal_ftype);
492
493 if(chan == nchan - 1)
494 {
495 fwrite_type(buffer, ftype, nchan, blocksize, this_shn);
496 this_shn->vars.bytes_in_buf = 0;
497 }
498
499 chan = (chan + 1) % nchan;
500 break;
501 }
502 break;
503
504 case FN_BLOCKSIZE:
505 UINT_GET((int) (log((double) blocksize) / M_LN2), this_shn);
506 break;
507
508 case FN_VERBATIM:
509 cklen = uvar_get(VERBATIM_CKSIZE_SIZE,this_shn);
510
511 while (cklen--) {
512 if (this_shn->vars.bytes_in_header >= OUT_BUFFER_SIZE) {
513 shn_debug("Unexpectedly large header - " PACKAGE " can only handle a maximum of %d bytes",OUT_BUFFER_SIZE);
514 goto got_enough_data;
515 }
516 this_shn->vars.bytes_in_buf = 0;
517 this_shn->vars.header[this_shn->vars.bytes_in_header++] = (char)uvar_get(VERBATIM_BYTE_SIZE,this_shn);
518 }
519 retval = 1;
520 break;
521
522 case FN_BITSHIFT:
523 bitshift = uvar_get(BITSHIFTSIZE,this_shn);
524 this_shn->vars.actual_bitshift = bitshift;
525 break;
526
527 default:
528 goto got_enough_data;
529 }
530 }
531
532 got_enough_data:
533
534 /* wind up */
535 var_get_quit(this_shn);
536 fwrite_type_quit(this_shn);
537
538 if (buffer) free((void *) buffer);
539 if (offset) free((void *) offset);
540 if(maxnlpc > 0 && qlpc)
541 free((void *) qlpc);
542
543 this_shn->vars.bytes_in_buf = 0;
544
545 return retval;
546 }
547
548 void shn_unload(shn_file *this_shn)
549 {
550 int this_shn_is_shnfile = (this_shn == shnfile) ? 1 : 0;
551
552 if (this_shn)
553 {
554 if (this_shn->vars.fd)
555 {
556 vfs_fclose(this_shn->vars.fd);
557 this_shn->vars.fd = NULL;
558 }
559
560 if (this_shn->decode_state)
561 {
562 if (this_shn->decode_state->getbuf)
563 {
564 free(this_shn->decode_state->getbuf);
565 this_shn->decode_state->getbuf = NULL;
566 }
567
568 if (this_shn->decode_state->writebuf)
569 {
570 free(this_shn->decode_state->writebuf);
571 this_shn->decode_state->writebuf = NULL;
572 }
573
574 if (this_shn->decode_state->writefub)
575 {
576 free(this_shn->decode_state->writefub);
577 this_shn->decode_state->writefub = NULL;
578 }
579
580 free(this_shn->decode_state);
581 this_shn->decode_state = NULL;
582 }
583
584 if (this_shn->seek_table)
585 {
586 free(this_shn->seek_table);
587 this_shn->seek_table = NULL;
588 }
589
590 free(this_shn);
591 this_shn = NULL;
592 if (this_shn_is_shnfile)
593 shnfile = NULL;
594 }
595 }
596
597 shn_file *load_shn(InputPlayback *playback, char *filename, VFSFile *fd)
598 {
599 shn_file *tmp_file;
600 shn_seek_entry *first_seek_table;
601
602 shn_debug("Loading file: '%s'", filename);
603
604 if (!(tmp_file = malloc(sizeof(shn_file))))
605 {
606 shn_debug("Could not allocate memory for SHN data structure");
607 return NULL;
608 }
609
610 memset(tmp_file, 0, sizeof(shn_file));
611
612 tmp_file->vars.fd = NULL;
613 tmp_file->vars.seek_to = -1;
614 tmp_file->vars.eof = 0;
615 tmp_file->vars.going = 0;
616 tmp_file->vars.playback = playback;
617 tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
618 tmp_file->vars.bytes_in_buf = 0;
619 tmp_file->vars.bytes_in_header = 0;
620 tmp_file->vars.reading_function_code = 0;
621 tmp_file->vars.initial_file_position = 0;
622 tmp_file->vars.last_file_position = 0;
623 tmp_file->vars.last_file_position_no_really = 0;
624 tmp_file->vars.bytes_read = 0;
625 tmp_file->vars.actual_bitshift = 0;
626 tmp_file->vars.actual_maxnlpc = 0;
627 tmp_file->vars.actual_nmean = 0;
628 tmp_file->vars.actual_nchan = 0;
629 tmp_file->vars.seek_offset = 0;
630
631 tmp_file->decode_state = NULL;
632
633 tmp_file->wave_header.filename = filename;
634 tmp_file->wave_header.wave_format = 0;
635 tmp_file->wave_header.channels = 0;
636 tmp_file->wave_header.block_align = 0;
637 tmp_file->wave_header.bits_per_sample = 0;
638 tmp_file->wave_header.samples_per_sec = 0;
639 tmp_file->wave_header.avg_bytes_per_sec = 0;
640 tmp_file->wave_header.rate = 0;
641 tmp_file->wave_header.header_size = 0;
642 tmp_file->wave_header.data_size = 0;
643 tmp_file->wave_header.file_has_id3v2_tag = 0;
644 tmp_file->wave_header.id3v2_tag_size = 0;
645
646 tmp_file->seek_header.version = NO_SEEK_TABLE;
647 tmp_file->seek_header.shnFileSize = 0;
648
649 tmp_file->seek_trailer.seekTableSize = 0;
650
651 tmp_file->seek_table = NULL;
652
653 if (!fd)
654 {
655 if (!(tmp_file->vars.fd = shn_open_and_discard_id3v2_tag(filename,&tmp_file->wave_header.file_has_id3v2_tag,&tmp_file->wave_header.id3v2_tag_size)))
656 {
657 shn_debug("Could not open file: '%s'",filename);
658 shn_unload(tmp_file);
659 return NULL;
660 }
661 }
662 else
663 tmp_file->vars.fd = fd;
664
665 if (0 == get_wave_header(tmp_file))
666 {
667 shn_debug("Unable to read WAVE header from file '%s'",filename);
668 shn_unload(tmp_file);
669 return NULL;
670 }
671
672 if (tmp_file->wave_header.file_has_id3v2_tag)
673 {
674 vfs_fseek(tmp_file->vars.fd,tmp_file->wave_header.id3v2_tag_size,SEEK_SET);
675 tmp_file->vars.bytes_read += tmp_file->wave_header.id3v2_tag_size;
676 tmp_file->vars.seek_offset = tmp_file->wave_header.id3v2_tag_size;
677 }
678 else
679 {
680 vfs_fseek(tmp_file->vars.fd,0,SEEK_SET);
681 }
682
683 if (0 == shn_verify_header(tmp_file))
684 {
685 shn_debug("Invalid WAVE header in file: '%s'",filename);
686 shn_unload(tmp_file);
687 return NULL;
688 }
689
690 if (tmp_file->decode_state)
691 {
692 free(tmp_file->decode_state);
693 tmp_file->decode_state = NULL;
694 }
695
696 shn_load_seek_table(tmp_file,filename);
697
698 if (NO_SEEK_TABLE != tmp_file->vars.seek_table_entries)
699 {
700 /* verify seek tables */
701
702 first_seek_table = (shn_seek_entry *)tmp_file->seek_table;
703
704 if (tmp_file->vars.actual_bitshift != shn_uchar_to_ushort_le(first_seek_table->data+22))
705 {
706 /* initial bitshift value in the file does not match the first bitshift value of the first seektable entry - seeking is broken */
707 shn_debug("Broken seek table detected (invalid bitshift) - seeking disabled for this file.");
708 tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
709 }
710 else if (tmp_file->vars.actual_nchan > 2)
711 {
712 /* nchan is greater than the number of such entries stored in a seek table entry - seeking won't work */
713 shn_debug("Broken seek table detected (nchan %d not in range [1 .. 2]) - seeking disabled for this file.",tmp_file->vars.actual_nchan);
714 tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
715 }
716 else if (tmp_file->vars.actual_maxnlpc > 3)
717 {
718 /* maxnlpc is greater than the number of such entries stored in a seek table entry - seeking won't work */
719 shn_debug("Broken seek table detected (maxnlpc %d not in range [0 .. 3]) - seeking disabled for this file.",tmp_file->vars.actual_maxnlpc);
720 tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
721 }
722 else if (tmp_file->vars.actual_nmean > 4)
723 {
724 /* nmean is greater than the number of such entries stored in a seek table entry - seeking won't work */
725 shn_debug("Broken seek table detected (nmean %d not in range [0 .. 4]) - seeking disabled for this file.",tmp_file->vars.actual_nmean);
726 tmp_file->vars.seek_table_entries = NO_SEEK_TABLE;
727 }
728 else
729 {
730 /* seek table appears to be valid - now adjust byte offsets in seek table to match the file */
731 tmp_file->vars.seek_offset += tmp_file->vars.initial_file_position - shn_uchar_to_ulong_le(first_seek_table->data+8);
732
733 if (0 != tmp_file->vars.seek_offset)
734 {
735 shn_debug("Adjusting seek table offsets by %ld bytes due to mismatch between seek table values and input file - seeking might not work correctly.",
736 tmp_file->vars.seek_offset);
737 }
738 }
739 }
740
741 shn_debug("Successfully loaded file: '%s'",filename);
742
743 return tmp_file;
744 }
745
746 static int shn_is_our_fd(char *fn, VFSFile *fd)
747 {
748 char data[4];
749
750 if (vfs_fread((void *)data,1,4,fd) != 4)
751 return FALSE;
752
753 if (memcmp(data,MAGIC,4))
754 return FALSE;
755
756 #if 0
757 if (!(tmp_file = load_shn(NULL, filename, fd)))
758 return FALSE;
759
760 shn_unload(tmp_file);
761 #endif
762
763 return TRUE;
764 }
765
766 void swap_bytes(shn_file *this_shn,int bytes)
767 {
768 int i;
769 uchar tmp;
770
771 for (i=0;i<bytes;i=i+2) {
772 tmp = this_shn->vars.buffer[i+1];
773 this_shn->vars.buffer[i+1] = this_shn->vars.buffer[i];
774 this_shn->vars.buffer[i] = tmp;
775 }
776 }
777
778 void write_and_wait(shn_file *this_shn,int block_size)
779 {
780 int bytes_to_write,bytes_in_block,i;
781 InputPlayback *playback = this_shn->vars.playback;
782
783 if (this_shn->vars.bytes_in_buf < block_size)
784 return;
785
786 bytes_in_block = min(this_shn->vars.bytes_in_buf, block_size);
787
788 if (bytes_in_block <= 0)
789 return;
790
791 bytes_to_write = bytes_in_block;
792 while ((bytes_to_write + bytes_in_block) <= this_shn->vars.bytes_in_buf)
793 bytes_to_write += bytes_in_block;
794
795 shn_ip.add_vis_pcm(shn_ip.output->written_time(), (this_shn->wave_header.bits_per_sample == 16) ? FMT_S16_LE : FMT_U8,
796 this_shn->wave_header.channels, bytes_to_write, this_shn->vars.buffer);
797
798 while(shn_ip.output->buffer_free() < bytes_to_write && playback->playing && this_shn->vars.seek_to == -1)
799 xmms_usleep(10000);
800
801 if(playback->playing && this_shn->vars.seek_to == -1) {
802 if (shn_cfg.swap_bytes)
803 swap_bytes(this_shn, bytes_to_write);
804 shn_ip.output->write_audio(this_shn->vars.buffer, bytes_to_write);
805 } else
806 return;
807
808 /* shift data from end of buffer to the front */
809 this_shn->vars.bytes_in_buf -= bytes_to_write;
810
811 for(i=0;i<this_shn->vars.bytes_in_buf;i++)
812 this_shn->vars.buffer[i] = this_shn->vars.buffer[i+bytes_to_write];
813 }
814
815 static void *play_loop_shn(void *arg)
816 {
817 slong **buffer = NULL, **offset = NULL;
818 slong lpcqoffset = 0;
819 int version = FORMAT_VERSION, bitshift = 0;
820 int ftype = TYPE_EOF;
821 char *magic = MAGIC;
822 int blocksize = DEFAULT_BLOCK_SIZE, nchan = DEFAULT_NCHAN;
823 int i, chan, nwrap, nskip = DEFAULT_NSKIP;
824 int *qlpc = NULL, maxnlpc = DEFAULT_MAXNLPC, nmean = UNDEFINED_UINT;
825 int cmd;
826 int internal_ftype;
827 shn_file *this_shn = shnfile;
828 int blk_size;
829 int cklen;
830 uchar tmp;
831 ulong seekto_offset;
832 InputPlayback *playback = this_shn->vars.playback;
833
834 restart:
835
836 this_shn->vars.bytes_in_buf = 0;
837
838 if (!init_decode_state(this_shn))
839 goto exit_thread;
840
841 blk_size = 512 * (this_shn->wave_header.bits_per_sample / 8) * this_shn->wave_header.channels;
842
843 /***********************/
844 /* EXTRACT starts here */
845 /***********************/
846
847 /* read magic number */
848 #ifdef STRICT_FORMAT_COMPATABILITY
849 if(FORMAT_VERSION < 2)
850 {
851 for(i = 0; i < strlen(magic); i++)
852 if(getc_exit(this_shn->vars.fd) != magic[i]) {
853 shn_error_fatal(this_shn,"Bad magic number");
854 goto exit_thread;
855 }
856
857 /* get version number */
858 version = getc_exit(this_shn->vars.fd);
859 }
860 else
861 #endif /* STRICT_FORMAT_COMPATABILITY */
862 {
863 int nscan = 0;
864
865 version = MAX_VERSION + 1;
866 while(version > MAX_VERSION)
867 {
868 int byte = vfs_getc(this_shn->vars.fd);
869 if(byte == EOF) {
870 shn_error_fatal(this_shn,"No magic number");
871 goto exit_thread;
872 }
873 if(magic[nscan] != '\0' && byte == magic[nscan])
874 nscan++;
875 else
876 if(magic[nscan] == '\0' && byte <= MAX_VERSION)
877 version = byte;
878 else
879 {
880 if(byte == magic[0])
881 nscan = 1;
882 else
883 {
884 nscan = 0;
885 }
886 version = MAX_VERSION + 1;
887 }
888 }
889 }
890
891 /* check version number */
892 if(version > MAX_SUPPORTED_VERSION) {
893 shn_error_fatal(this_shn,"Can't decode version %d", version);
894 goto exit_thread;
895 }
896
897 /* set up the default nmean, ignoring the command line state */
898 nmean = (version < 2) ? DEFAULT_V0NMEAN : DEFAULT_V2NMEAN;
899
900 /* initialise the variable length file read for the compressed stream */
901 var_get_init(this_shn);
902 if (this_shn->vars.fatal_error)
903 goto exit_thread;
904
905 /* initialise the fixed length file write for the uncompressed stream */
906 fwrite_type_init(this_shn);
907
908 /* get the internal file type */
909 internal_ftype = UINT_GET(TYPESIZE, this_shn);
910
911 /* has the user requested a change in file type? */
912 if(internal_ftype != ftype) {
913 if(ftype == TYPE_EOF)
914 ftype = internal_ftype; /* no problems here */
915 else /* check that the requested conversion is valid */
916 if(internal_ftype == TYPE_AU1 || internal_ftype == TYPE_AU2 ||
917 internal_ftype == TYPE_AU3 || ftype == TYPE_AU1 ||ftype == TYPE_AU2 || ftype == TYPE_AU3) {
918 shn_error_fatal(this_shn,"Not able to perform requested output format conversion");
919 goto cleanup;
920 }
921 }
922
923 nchan = UINT_GET(CHANSIZE, this_shn);
924
925 /* get blocksize if version > 0 */
926 if(version > 0)
927 {
928 int byte;
929 blocksize = UINT_GET((int) (log((double) DEFAULT_BLOCK_SIZE) / M_LN2),this_shn);
930 maxnlpc = UINT_GET(LPCQSIZE, this_shn);
931 nmean = UINT_GET(0, this_shn);
932 nskip = UINT_GET(NSKIPSIZE, this_shn);
933 for(i = 0; i < nskip; i++)
934 {
935 byte = uvar_get(XBYTESIZE,this_shn);
936 }
937 }
938 else
939 blocksize = DEFAULT_BLOCK_SIZE;
940
941 nwrap = MAX(NWRAP, maxnlpc);
942
943 /* grab some space for the input buffer */
944 buffer = long2d((ulong) nchan, (ulong) (blocksize + nwrap),this_shn);
945 if (this_shn->vars.fatal_error)
946 goto exit_thread;
947 offset = long2d((ulong) nchan, (ulong) MAX(1, nmean),this_shn);
948 if (this_shn->vars.fatal_error) {
949 if (buffer) {
950 free(buffer);
951 buffer = NULL;
952 }
953 goto exit_thread;
954 }
955
956 for(chan = 0; chan < nchan; chan++)
957 {
958 for(i = 0; i < nwrap; i++)
959 buffer[chan][i] = 0;
960 buffer[chan] += nwrap;
961 }
962
963 if(maxnlpc > 0) {
964 qlpc = (int*) pmalloc((ulong) (maxnlpc * sizeof(*qlpc)),this_shn);
965 if (this_shn->vars.fatal_error) {
966 if (buffer) {
967 free(buffer);
968 buffer = NULL;
969 }
970 if (offset) {
971 free(offset);
972 buffer = NULL;
973 }
974 goto exit_thread;
975 }
976 }
977
978 if(version > 1)
979 lpcqoffset = V2LPCQOFFSET;
980
981 init_offset(offset, nchan, MAX(1, nmean), internal_ftype);
982
983 /* get commands from file and execute them */
984 chan = 0;
985 while(1)
986 {
987 cmd = uvar_get(FNSIZE,this_shn);
988 if (this_shn->vars.fatal_error)
989 goto cleanup;
990
991 switch(cmd)
992 {
993 case FN_ZERO:
994 case FN_DIFF0:
995 case FN_DIFF1:
996 case FN_DIFF2:
997 case FN_DIFF3:
998 case FN_QLPC:
999 {
1000 slong coffset, *cbuffer = buffer[chan];
1001 int resn = 0, nlpc, j;
1002
1003 if(cmd != FN_ZERO)
1004 {
1005 resn = uvar_get(ENERGYSIZE,this_shn);
1006 if (this_shn->vars.fatal_error)
1007 goto cleanup;
1008 /* this is a hack as version 0 differed in definition of var_get */
1009 if(version == 0)
1010 resn--;
1011 }
1012
1013 /* find mean offset : N.B. this code duplicated */
1014 if(nmean == 0)
1015 coffset = offset[chan][0];
1016 else
1017 {
1018 slong sum = (version < 2) ? 0 : nmean / 2;
1019 for(i = 0; i < nmean; i++)
1020 sum += offset[chan][i];
1021 if(version < 2)
1022 coffset = sum / nmean;
1023 else
1024 coffset = ROUNDEDSHIFTDOWN(sum / nmean, bitshift);
1025 }
1026
1027 switch(cmd)
1028 {
1029 case FN_ZERO:
1030 for(i = 0; i < blocksize; i++)
1031 cbuffer[i] = 0;
1032 break;
1033 case FN_DIFF0:
1034 for(i = 0; i < blocksize; i++) {
1035 cbuffer[i] = var_get(resn,this_shn) + coffset;
1036 if (this_shn->vars.fatal_error)
1037 goto cleanup;
1038 }
1039 break;
1040 case FN_DIFF1:
1041 for(i = 0; i < blocksize; i++) {
1042 cbuffer[i] = var_get(resn,this_shn) + cbuffer[i - 1];
1043 if (this_shn->vars.fatal_error)
1044 goto cleanup;
1045 }
1046 break;
1047 case FN_DIFF2:
1048 for(i = 0; i < blocksize; i++) {
1049 cbuffer[i] = var_get(resn,this_shn) + (2 * cbuffer[i - 1] - cbuffer[i - 2]);
1050 if (this_shn->vars.fatal_error)
1051 goto cleanup;
1052 }
1053 break;
1054 case FN_DIFF3:
1055 for(i = 0; i < blocksize; i++) {
1056 cbuffer[i] = var_get(resn,this_shn) + 3 * (cbuffer[i - 1] - cbuffer[i - 2]) + cbuffer[i - 3];
1057 if (this_shn->vars.fatal_error)
1058 goto cleanup;
1059 }
1060 break;
1061 case FN_QLPC:
1062 nlpc = uvar_get(LPCQSIZE,this_shn);
1063 if (this_shn->vars.fatal_error)
1064 goto cleanup;
1065
1066 for(i = 0; i < nlpc; i++) {
1067 qlpc[i] = var_get(LPCQUANT,this_shn);
1068 if (this_shn->vars.fatal_error)
1069 goto cleanup;
1070 }
1071 for(i = 0; i < nlpc; i++)
1072 cbuffer[i - nlpc] -= coffset;
1073 for(i = 0; i < blocksize; i++)
1074 {
1075 slong sum = lpcqoffset;
1076
1077 for(j = 0; j < nlpc; j++)
1078 sum += qlpc[j] * cbuffer[i - j - 1];
1079 cbuffer[i] = var_get(resn,this_shn) + (sum >> LPCQUANT);
1080 if (this_shn->vars.fatal_error)
1081 goto cleanup;
1082 }
1083 if(coffset != 0)
1084 for(i = 0; i < blocksize; i++)
1085 cbuffer[i] += coffset;
1086 break;
1087 }
1088
1089 /* store mean value if appropriate : N.B. Duplicated code */
1090 if(nmean > 0)
1091 {
1092 slong sum = (version < 2) ? 0 : blocksize / 2;
1093
1094 for(i = 0; i < blocksize; i++)
1095 sum += cbuffer[i];
1096
1097 for(i = 1; i < nmean; i++)
1098 offset[chan][i - 1] = offset[chan][i];
1099 if(version < 2)
1100 offset[chan][nmean - 1] = sum / blocksize;
1101 else
1102 offset[chan][nmean - 1] = (sum / blocksize) << bitshift;
1103 }
1104
1105 /* do the wrap */
1106 for(i = -nwrap; i < 0; i++)
1107 cbuffer[i] = cbuffer[i + blocksize];
1108
1109 fix_bitshift(cbuffer, blocksize, bitshift, internal_ftype);
1110
1111 if(chan == nchan - 1)
1112 {
1113 if (!playback->playing || this_shn->vars.fatal_error)
1114 goto cleanup;
1115
1116 fwrite_type(buffer, ftype, nchan, blocksize, this_shn);
1117
1118 write_and_wait(this_shn,blk_size);
1119
1120 if (this_shn->vars.seek_to != -1)
1121 {
1122 shn_seek_entry *seek_info;
1123 int j;
1124
1125 shn_debug("Seeking to %d:%02d",this_shn->vars.seek_to/60,this_shn->vars.seek_to%60);
1126
1127 seek_info = shn_seek_entry_search(this_shn->seek_table,this_shn->vars.seek_to * (ulong)this_shn->wave_header.samples_per_sec,0,
1128 (ulong)(this_shn->vars.seek_table_entries - 1),this_shn->vars.seek_resolution);
1129
1130 /* loop through number of channels in this file */
1131 for (i=0;i<nchan;i++) {
1132 /* load the three sample buffer values for this channel */
1133 for (j=0;j<3;j++)
1134 buffer[i][j-3] = shn_uchar_to_slong_le(seek_info->data+32+12*i-4*j);
1135
1136 /* load the variable number of offset history values for this channel */
1137 for (j=0;j<MAX(1,nmean);j++)
1138 offset[i][j] = shn_uchar_to_slong_le(seek_info->data+48+16*i+4*j);
1139 }
1140
1141 bitshift = shn_uchar_to_ushort_le(seek_info->data+22);
1142
1143 seekto_offset = shn_uchar_to_ulong_le(seek_info->data+8) + this_shn->vars.seek_offset;
1144
1145 vfs_fseek(this_shn->vars.fd,(slong)seekto_offset,SEEK_SET);
1146 vfs_fread((uchar*) this_shn->decode_state->getbuf, 1, BUFSIZ, this_shn->vars.fd);
1147
1148 this_shn->decode_state->getbufp = this_shn->decode_state->getbuf + shn_uchar_to_ushort_le(seek_info->data+14);
1149 this_shn->decode_state->nbitget = shn_uchar_to_ushort_le(seek_info->data+16);
1150 this_shn->decode_state->nbyteget = shn_uchar_to_ushort_le(seek_info->data+12);
1151 this_shn->decode_state->gbuffer = shn_uchar_to_ulong_le(seek_info->data+18);
1152
1153 this_shn->vars.bytes_in_buf = 0;
1154
1155 shn_ip.output->flush(this_shn->vars.seek_to * 1000);
1156 this_shn->vars.seek_to = -1;
1157 }
1158
1159 }
1160 chan = (chan + 1) % nchan;
1161 break;
1162 }
1163
1164 break;
1165
1166 case FN_QUIT:
1167 /* empty out last of buffer */
1168 write_and_wait(this_shn,this_shn->vars.bytes_in_buf);
1169
1170 playback->eof = TRUE;
1171
1172 while (1)
1173 {
1174 if (!playback->playing)
1175 goto finish;
1176 if (this_shn->vars.seek_to != -1)
1177 {
1178 var_get_quit(this_shn);
1179 fwrite_type_quit(this_shn);
1180
1181 if (buffer) free((void *) buffer);
1182 if (offset) free((void *) offset);
1183 if(maxnlpc > 0 && qlpc)
1184 free((void *) qlpc);
1185
1186 vfs_fseek(this_shn->vars.fd,0,SEEK_SET);
1187 goto restart;
1188 }
1189 else
1190 xmms_usleep(10000);
1191 }
1192
1193 goto cleanup;
1194 break;
1195
1196 case FN_BLOCKSIZE:
1197 blocksize = UINT_GET((int) (log((double) blocksize) / M_LN2), this_shn);
1198 if (this_shn->vars.fatal_error)
1199 goto cleanup;
1200 break;
1201 case FN_BITSHIFT:
1202 bitshift = uvar_get(BITSHIFTSIZE,this_shn);
1203 if (this_shn->vars.fatal_error)
1204 goto cleanup;
1205 break;
1206 case FN_VERBATIM:
1207 cklen = uvar_get(VERBATIM_CKSIZE_SIZE,this_shn);
1208 if (this_shn->vars.fatal_error)
1209 goto cleanup;
1210
1211 while (cklen--) {
1212 tmp = (uchar)uvar_get(VERBATIM_BYTE_SIZE,this_shn);
1213 if (this_shn->vars.fatal_error)
1214 goto cleanup;
1215 }
1216
1217 break;
1218
1219 default:
1220 shn_error_fatal(this_shn,"Sanity check fails trying to decode function: %d",cmd);
1221 goto cleanup;
1222 }
1223 }
1224
1225 cleanup:
1226
1227 write_and_wait(this_shn,this_shn->vars.bytes_in_buf);
1228 shn_ip.output->buffer_free();
1229 shn_ip.output->buffer_free();
1230 xmms_usleep(10000);
1231
1232 finish:
1233
1234 this_shn->vars.seek_to = -1;
1235 playback->eof = TRUE;
1236
1237 /* wind up */
1238 var_get_quit(this_shn);
1239 fwrite_type_quit(this_shn);
1240
1241 if (buffer) free((void *) buffer);
1242 if (offset) free((void *) offset);
1243 if(maxnlpc > 0 && qlpc)
1244 free((void *) qlpc);
1245
1246 exit_thread:
1247
1248 pthread_exit(NULL);
1249 }
1250
1251 static void shn_play(InputPlayback *playback)
1252 {
1253 char *name, *temp;
1254 char *filename = playback->filename;
1255
1256 audio_error = FALSE;
1257
1258 if (!(shnfile = load_shn(playback, playback->filename, NULL)))
1259 {
1260 shn_debug("Could not load file for playing: '%s'", playback->filename);
1261 return;
1262 }
1263
1264 vfs_fseek(shnfile->vars.fd,0,SEEK_SET);
1265
1266 playback->playing = TRUE;
1267
1268 if (shn_ip.output->open_audio((shnfile->wave_header.bits_per_sample == 16) ? FMT_S16_LE : FMT_U8, shnfile->wave_header.samples_per_sec, shnfile->wave_header.channels) == 0)
1269 {
1270 audio_error = TRUE;
1271 shn_debug("Could not open audio device for playback (check your output plugin configuration)");
1272 return;
1273 }
1274 temp = strrchr(filename, '/');
1275 if (!temp)
1276 temp = filename;
1277 else
1278 temp++;
1279 name = malloc(strlen(temp) + 1);
1280 strcpy(name, temp);
1281 if (shn_filename_contains_a_dot(name))
1282 *(strrchr(name,'.')) = '\0';
1283 shn_ip.set_info(name, 1000 * shnfile->wave_header.length, 8 * shnfile->wave_header.rate, shnfile->wave_header.samples_per_sec, shnfile->wave_header.channels);
1284 free(name);
1285 shnfile->vars.seek_to = -1;
1286 pthread_create(&decode_thread, NULL, play_loop_shn, NULL);
1287 }
1288
1289 static void shn_stop(InputPlayback *playback)
1290 {
1291 int was_fatal;
1292 char error_msg[BUF_SIZE];
1293
1294 if (!shnfile)
1295 return;
1296
1297 if ((was_fatal = shnfile->vars.fatal_error))
1298 shn_snprintf(error_msg,BUF_SIZE,"%s.\nAffected file was:\n%s",shnfile->vars.fatal_error_msg,shnfile->wave_header.filename);
1299
1300 if (playback->playing || was_fatal)
1301 {
1302 playback->playing = FALSE;
1303 pthread_join(decode_thread, NULL);
1304 shn_ip.output->close_audio();
1305 shn_unload(shnfile);
1306 }
1307
1308 if (was_fatal)
1309 shn_error(error_msg);
1310 }
1311
1312 static void shn_pause(InputPlayback *playback, short p)
1313 {
1314 playback->output->pause(p);
1315 }
1316
1317 static void shn_seek(InputPlayback *playback, int time)
1318 {
1319 if (NULL == shnfile)
1320 return;
1321
1322 if (shnfile->vars.seek_table_entries == NO_SEEK_TABLE)
1323 {
1324 shn_error("Cannot seek to %d:%02d because there is no seek information for this file.",time/60,time%60);
1325 return;
1326 }
1327
1328 shnfile->vars.seek_to = time;
1329
1330 while (shnfile->vars.seek_to != -1)
1331 xmms_usleep(10000);
1332 }
1333
1334 static void shn_get_file_info(char *filename, char **title, int *length)
1335 {
1336 char *name, *temp;
1337 shn_file *tmp_file;
1338
1339 temp = strrchr(filename, '/');
1340 if (!temp)
1341 temp = filename;
1342 else
1343 temp++;
1344
1345 name = g_malloc(strlen(temp) + 1);
1346 strcpy(name, temp);
1347
1348 if (shn_filename_contains_a_dot(name))
1349 *(strrchr(name,'.')) = '\0';
1350
1351 *title = name;
1352
1353 *length = 0;
1354
1355 if (!(tmp_file = load_shn(NULL, filename, NULL)))
1356 {
1357 shn_debug("Could not get information from file: '%s'",filename);
1358 return;
1359 }
1360
1361 *length = 1000 * tmp_file->wave_header.length;
1362
1363 shn_unload(tmp_file);
1364 }
1365
1366 static void shn_display_file_info(char *filename)
1367 {
1368 shn_file *tmp_file;
1369
1370 if (!(tmp_file = load_shn(NULL, filename, NULL)))
1371 {
1372 shn_debug("Could not get information from file: '%s'",filename);
1373 return;
1374 }
1375
1376 shn_display_info(tmp_file);
1377
1378 shn_unload(tmp_file);
1379 }