-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmppdec.c
executable file
·1795 lines (1590 loc) · 68.9 KB
/
mppdec.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
*
* Main Decoder Loop
*
*
* (C) Copyright 1999-2001 Andree Buschmann. All rights reserved.
* (C) Copyright 2001-2003 Frank Klemm. All rights reserved.
*
* For licencing see the licencing file which is part of this package.
*
*
* Principles:
* Current decoder uses the so called pull model. The decoder is started, take full
* control of the current thread and pulls input data when it need input data and
* writes the decoded data to the destination when it has decoded data.
* A decoder using this principle is difficult to use by other programs, because it can't
* be controlled by another program, it can only control other programs.
*
* Most work for changing this model must be done in Decode() and DecodeFile().
*
* History:
* 1999-2003 programmed by Frank Klemm and Andree Buschmann
* 2003-02-02 the file got an header
*
* Global functions:
* - main()
* - but also some remaining global variables
*
* TODO:
* - removal of global variables
* - multithreading support
* - fast forward using skip information instead of decoding (although seeking speed is hard disk read speed limited on current computers).
* - usage of IO and AudioIO lib for input and output
* - push pull transformation
*
*/
#include <time.h>
#include <string.h>
#include <errno.h>
#include "mppdec.h"
// global variables (ugly, not killed yet)
quant_t QQ [MAXCH] [32] [36]; // quantized matrixed subband samples
Float YY [MAXCH] [36] [32]; // scaled dematrixed subband samples
Float VV [MAXCH] [1024 + 64*(VIRT_SHIFT-1)]; // 1st stage of the subband synthesizer
scf_t SCF_Index[MAXCH] [32] [ 3]; // scale factors for transforming QQ -> YY
res_t Res [MAXCH] [32]; // sample resolution for decoding Bitstream -> QQ
Bool_t MS_Band [32]; // dematrixing information for transforming QQ -> YY
static Int V_offset [MAXCH];
static Uint MS_bits = 0; // 0: all is LR coded, 1: MS or LR coding per subband
Bool_t IS_used = 0; // is IS used (if yes, a fixed number of subbands is IS coded)
static Float Scale = 1.; // user defined scale factor
static Bool_t ClipPrev = 0; // if set, clipping is prevented if needed information is available
static int ReplayGainType = 0; // 0: no additional gain, 1: CD based gain correction, 2: title based gain correction
Bool_t TrueGaplessPresent = 0; // is true gapless used?
Int LastValidSamples = 0; // number of valid samples within last frame
Uint DUMPSELECT = 0;
unsigned int SampleFreq = 44100;
static int Channels = 2;
static const Uint16_t
sftable [4] = { 44100, 48000, 37800, 32000 };
#if defined MAKE_16BIT || defined MAKE_24BIT || defined MAKE_32BIT
static int Bits = SAMPLE_SIZE;
static int NoiseShapeType = 0;
static Float Dither = -1; // Dithering if not Noise shaping
#endif
static Uint StreamVersion;
static Ulong InputBuffRead;
#ifdef USE_ASM
static SyntheseFilter16_t
Synthese_Filter_16;
#endif
Bool_t output_endianess = LITTLE_ENDIAN;
Ulong errors = 0;
const char About [] = "MPC Decoder " MPPDEC_VERSION " " BUILD " " COPYRIGHT;
const char CompileFlags [] = COMPILER_FLAGS;
const char Date [] = __DATE__ " " __TIME__;
/**********************************************************************************************************************************
*
* Functions: helper functions for Decode()
*
* PrintTime():
* computes a 12 character long time string (10 ms precision) from a given
* sample count. An optional character can be prefixed.
* FrameSize():
* Read the size of the next frame in bits from the bit stream.
* ReadAndVerifyFrame():
* Reads a frame and verify the correct contents by checking the decoded length by the length read via FrameSize().
* This is not a secure test (especially for SV8), but typical errors you find on hard disks and which occured
* using FTP or HTTP downstream can be recognized.
* Argument IgnoreErrors can be used to read known defect frames (SV4/5 last frame ist mostly corrupted),
* the last two arguments are only used to write a useful error message.
* Requantize():
* Compute subband samples from quantized subband samples. Do also MS dematrixing.
* Arguments MinBand and MaxBand are handling the stuff which bands are MS and which are IS encoded.
* These are all AB names and should be replaced by useful names.
*/
static const char*
PrintTime ( UintMax_t samples,
int sign )
{
static char ret [16];
Ulong tmp = (Ulong)( UintMAX_FP(samples) * 100.f / SampleFreq + 0.5 ); // unit: 1/100th second
Uint hour = (Uint) ( tmp / 360000 );
Uint min = (Uint) ( tmp / 6000 % 60 );
Uint sec = (Uint) ( tmp / 100 % 60 );
Uint csec = (Uint) ( tmp % 100 );
if ( hour > 9 )
sprintf ( ret, "%c%2u:%02u", sign, hour, min );
else if ( hour > 0 )
sprintf ( ret, " %c%1u:%02u", sign, hour, min );
else if ( min > 9 )
sprintf ( ret, " %c%2u", sign, min );
else
sprintf ( ret, " %c%1u", sign, min );
sprintf ( ret + 6, ":%02u.%02u", sec, csec );
return ret;
}
static Uint
FrameSize ( int StreamVersion )
{
if ( StreamVersion & 0x08 )
return BitstreamBE_read (16) * 8;
else
return BitstreamLE_read (20);
}
static int
ReadAndVerifyFrame ( int StreamVersion,
int IgnoreErrors,
Ulong CurrentFrame,
Ulong FrameCount )
{
Uint32_t CurrBlkSize;
Uint32_t StartBitPos;
Uint32_t EndBitPos;
CurrBlkSize = FrameSize (StreamVersion);
StartBitPos = BitsRead ();
Read_Bitstream ( StreamVersion, MS_bits, Channels ); // decode bitstream (see decode.c)
EndBitPos = BitsRead ();
// check skip information against value determined by decoding (buggy for CBR)
if ( EndBitPos - StartBitPos != CurrBlkSize && !IgnoreErrors ) {
errors++;
if ( BitsRead() < InputBuffRead * (Ulong)(CHAR_BIT * sizeof(*InputBuff)) )
stderr_printf ( "\n\n"PROG_NAME": broken frame %lu/%lu (decoded size=%lu, size in stream=%lu)\a\n\n",
CurrentFrame, FrameCount, (Ulong)(EndBitPos - StartBitPos), (Ulong)CurrBlkSize );
else
stderr_printf ("\n\n"PROG_NAME": unexpected end of file after frame %lu/%lu\a\n\n", CurrentFrame, FrameCount );
return -1;
}
return 0;
}
static void
Requantize ( const Bool_t* MSBand,
int ISused,
int MinBand,
int MaxBand,
int StreamVersion )
{
if ( ISused ) {
Requantize_MidSideStereo ( MinBand-1, MS_Band, StreamVersion );
Requantize_IntensityStereo ( MinBand, MaxBand );
}
else {
Requantize_MidSideStereo ( MaxBand, MSBand, StreamVersion );
}
}
/**********************************************************************************************************************************
*
* Function: Decode()
*
* This is the main decoder loop, which decodes the file frame by frame.
*
* This function has the following things to do:
* - Read the stream frame by frame
* - refill the bitstream buffer, so there's always enough data in the buffer to decode a frame (even when it is a monster frame with 34 kbits).
* - requantization and synthesis of the PCM signal
* - Outputing some messages from time to time about the progress of decoding
* - compensation of analysis+synthesis filter delay (481 samples).
* - last block handling, so the decoded file is exactly as long as the source file.
*
* Some remarks (please read this and ask when you don't understand something!):
* - analysis + synthesis filter together has a delay of exactly 481 samples - MP1/MP2 has the same delay
* - all windowed transform based codecs (Musepack is also one) have such a delay
* - that musepack has not such a delay is that only one encoder and one decoder exist, which do compensate this perfectly,
* it is not a property of musepack as proecess itself.
* - decoder discards the first 481 samples of the decoded PCM signal of the first block.
* The remaining blocks are decoded fully, the last block must generate 481 samples more than the
* bitstreams says.
* - Original AB stream syntax:
* + header, contains number N of frames in the file
* + N frames
* + 11 bits, how many samples R the last frame contains without the delay compensation
* - two bugs
* + when R is 1152, it was encoded as 0. Decoded file was 1152 samples too short
* + in the worst case the last frame must produce 1152+481 samples. AB assumed,
* that a single encoded frame can produce 1152+481 samples, but it can't.
* From the mathematical point it can only produce 1152 samples, from the practical 1152+160...170,
* after 1152+240 samples the output amplitude has dropped by 6 dB, after 1152+481 samples by 100 dB.
* + So version 1.01 and above encode an additional frame after these 11 bits when the last frame
* must produce more than 1152 samples.
* - Current stream syntax:
* + header, contains number N of frames in the file
* + N frames
* + 11 bits, how many samples R the last frame contains without the delay compensation
* + optional frame, when R+481 > 1152
* - That such an additional frame CAN be possible, is marked in the header by a special bit.
* - In this case the 11 bit word R is also stored in the header, but currently not used in SV7.
* (but can be used to determine the exact length of the file by only reading the header,
* otherwise you must read the whole file).
* - This fixes the problem of these gaps without breaking compatibility.
*
* Nevertheless Musepack is not absolutely gapless. For an absolutely gapless lossy encoder
* you have still the problem of swinging in and out of the analysis and synthesis filter.
* You can see this effect when you feed pure DC to any encoder. To solve this problem there
* are two ways:
* - start and end must be encoded lossless
* - you must also feed the encoder with the end samples of the predecessor and the beginning
* of the sucessor. From the mathematical view 481 samples are enough, from the practical
* 240...256 samples (-96...-100 dB).
* - current pre SV8 encoder can be called via:
* mppenc *.wav destdir
* which can handle this problem perfectly (when the GUI calls the program right).
* Currently this code is not programmed.
* - when this method is used, 481+481 samples from the first block must be discarded.
* 1152-481-481=190 samples remaining. May be I discard the whole first block in the decoder
* and adjust the encoder so this gives the right result.
* - SV7 contains a lot of implicit information about this process. It SV8 they shoudl bes tored explicitely.
* Should this be done:
* - in the audioframes internally
* - or as additional information between the frames?
*/
static UintMax_t
Decode ( FILE_T OutputFile,
FILE_T InputFile,
Uint32_t TotalFrames,
UintMax_t Start,
UintMax_t Duration,
size_t valid_end )
{
IntSample_t Stream [ BLK_SIZE * MAXCH ];
size_t ring;
size_t valid;
Uint32_t FrameNo;
UintMax_t ret = 0;
time_t T = time (NULL);
ENTER(3);
memset ( Stream, 0, sizeof Stream );
for ( FrameNo = 0; FrameNo < TotalFrames && Duration > 0; FrameNo++ ) { // decode frame by frame, note some differences in decoding the last frame (TotalFrames-1)
ring = InputCnt;
if ( ReadAndVerifyFrame ( StreamVersion, FrameNo == TotalFrames-1 && StreamVersion <= 5, FrameNo, TotalFrames ) < 0 ) {
LEAVE(3);
return ret;
}
// reload data if more than 50% of the buffer is decoded
if ( (ring ^ InputCnt) & IBUFSIZE2 )
InputBuffRead += READ ( InputFile, InputBuff + (ring & IBUFSIZE2), IBUFSIZE2 * 4 ) / 4;
// Subband synthesizer
if ( Start <= BLK_SIZE ) {
if ( Scale != 0. ) {
Requantize ( MS_Band, IS_used, Min_Band, Max_Band, StreamVersion );
Synthese_Filter ( Stream + 0, V_offset+0, VV [0], YY [0], Channels, 0 );
Synthese_Filter ( Stream + 1, V_offset+1, VV [1], YY [1], Channels, 1 );
}
// write PCM data to destination (except the data in the last frame, this is done behind the for loop
if ( FrameNo < TotalFrames-1 ) {
valid = BLK_SIZE - Start;
if ( valid > Duration )
valid = Duration;
ret += Write_PCM ( OutputFile, Stream + Start * Channels, valid * Channels ) / Channels;
Duration -= valid;
Start = 0;
}
}
else {
Start -= BLK_SIZE;
}
// output report if a real time second is over sinse the last report
if ( (Int)(time (NULL) - T) >= 0 ) {
T += 1;
stderr_printf ("\r%s/", PrintTime ( Start ? Start : ret, Start ? '-' : ' ' ) );
stderr_printf ("%s %s (%4.1f%%)", PrintTime ( (UintMax_t)TotalFrames * BLK_SIZE, ' ') + 1, Start ? "jumping" : "decoded", 100. * FrameNo / TotalFrames );
}
}
if ( Duration > 0 ) { // write PCM data to destination for the last frame
switch ( StreamVersion ) { // reconstruct exact size for SV6 and higher (for SV4...5 this is unknown)
default:
assert (0);
case 0x04:
case 0x05:
valid_end = 0;
break;
case 0x06:
case 0x07:
case 0x17:
valid_end = (Int) BitstreamLE_read (11);
if (valid_end == 0)
valid_end = BLK_SIZE; // Old encoder writes a 0 instead of a 1152, Bugfix
/* fall through */
case 0xFF:
valid_end += DECODER_DELAY - Start;
if ( valid_end > Duration ) valid_end = Duration;
if ( Start + valid_end > BLK_SIZE ) {
// write out data for the last frame
if ( Start < BLK_SIZE ) {
ret += Write_PCM ( OutputFile, Stream + Start * Channels, (size_t)((BLK_SIZE - Start) * Channels) ) / Channels;
valid_end -= BLK_SIZE - Start;
Start = 0;
}
else {
Start -= BLK_SIZE;
}
if ( ! TrueGaplessPresent ) {
memset ( YY, 0, sizeof YY );
}
else {
if ( ReadAndVerifyFrame ( StreamVersion, 0, FrameNo, TotalFrames ) < 0 ) {
LEAVE(3);
return ret;
}
if ( Scale != 0. )
Requantize ( MS_Band, IS_used, Min_Band, Max_Band, StreamVersion );
}
Synthese_Filter ( Stream + 0, V_offset+0, VV [0], YY [0], Channels, 0 );
Synthese_Filter ( Stream + 1, V_offset+1, VV [1], YY [1], Channels, 1 );
}
break;
}
// write PCM data to destination from the "very last" frame
ret += Write_PCM ( OutputFile, Stream + Start * Channels, valid_end * Channels ) / Channels;
}
stderr_printf ("\r%s", PrintTime ( ret, (char)' ' ) ); // time report
LEAVE(3);
return ret;
}
/**********************************************************************************************************************************
*
* Functions: helper functions for DecodeFile()
*
* JumpID3v2():
* Determines the size of a ID3v2 tag without footer and with Run Length Restriction.
* This si a very special kind of ID3v2 tags, but it looks like all ID3v2 tags in reality
* have this propertity. <JOKE>Generate some other ID3v2 files and check how clean current ID3v2 readers are</JOKE>.
* Function returns 0 on error and the total size of the tag otherwise.
* Function should only be called when a tag is available, because it read a unpredictable amount of data from the stream, so you must reset the bitstream decoder after a wrong call of this function.
* EncoderName():
* Returns a version string of the used encoder for encoding the stream (1.06 and above).
* ProfileName():
* Return a encoder profile name as string.
*/
static Int32_t
JumpID3v2 ( void )
{
Int32_t ret = 10;
if ( (BitstreamLE_read (32) & 0xFFFFFF) != 0x334449L )
return 0;
if ( BitstreamLE_read (1) )
return 0;
ret += BitstreamLE_read (7) << 14;
if ( BitstreamLE_read (1) )
return 0;
ret += BitstreamLE_read (7) << 21;
BitstreamLE_read (1);
if ( BitstreamLE_read (1) )
ret += 10;
BitstreamLE_read (14);
BitstreamLE_read (16);
if ( BitstreamLE_read (1) )
return 0;
ret += BitstreamLE_read (7) << 0;
if ( BitstreamLE_read (1) )
return 0;
ret += BitstreamLE_read (7) << 7;
return ret;
}
static const char*
EncoderName ( int encoderno ) // odd version numbers are alpha, even are beta, dividable by 10 are release versions
{
static char Name [32];
if ( encoderno <= 0 )
Name [0] = '\0';
else if ( encoderno % 10 == 0 )
sprintf ( Name, " (Release %u.%u)", encoderno/100, encoderno/10%10 );
else if ( (encoderno & 1) == 0 )
sprintf ( Name, " (Beta %u.%02u)", encoderno/100, encoderno%100 );
else
sprintf ( Name, " (--Alpha-- %u.%02u)", encoderno/100, encoderno%100 );
return Name;
}
static const char*
ProfileName ( Uint profile ) // profile is 0...15, where 1, 5...15 is currently used
{
static const char na [] = "n.a.";
static const char* Names [] = {
na , "Unstable/Experimental", na , na ,
na , "below 'Telephone'" , "below 'Telephone'", "'Telephone'" ,
"'Thumb'" , "'Radio'" , "'Standard'" , "'Xtreme'" ,
"'Insane'", "'BrainDead'" , "above 'BrainDead'", "above 'BrainDead'",
};
return profile >= sizeof(Names)/sizeof(*Names) ? na : Names [profile];
}
/**********************************************************************************************************************************
*
* Function: DecodeFile()
*
* This function do all the header analysing stuff, calls then Decode() and pretends at the end about the decoding speed.
*
* This function has the following things to do:
* - Inits bitstream decoder + fills bitstream decoder buffer for the first time
* - Analyse first 32 bit of the bitsream to determine file type
* - Gives a lot of useful, but unnecessary messages when the input file seems to be a non musepack file and returns.
* - analyse the header of SV4, SV5, SV6, SV7.0, SV7.1 and current experimental SV8 and initializes some
* global variables.
* - Calls two tag analysing functions and if they report success, it prints most important tag information on stderr.
* - Tag analysing functions also return the file size, this is used to calculate and print the bitrate for VBR files.
* - Analysing of replaygain/clip prevention and printing of results.
* These results are used to call Init_QuantTab(), i.e. SCF scalers are adjusted for replaygain/clip prevention.
* So you don't need any CPU power to do replaygain/clip prevention.
* - Compute Start + Duration from seconds into samples, do the special percent handling for negative values.
* - Resets some arrays.
* - Call Decode()
* - Calculate Decoding speed and print result.
*
*/
static UintMax_t
DecodeFile ( FILE_T OutputFile,
FILE_T InputFile,
Double Start,
Double Duration )
{
Int MaxBandDesired = 0;
Uint32_t TotalFrames = 0;
UintMax_t DecodedSamples = 0;
Uint Profile = (Uint)-1;
Float AverageBitrate;
static TagInfo_t taginfo;
clock_t T;
Int32_t ID3v2;
Uint16_t PeakTitle = 0;
Uint16_t PeakAlbum = 0;
Uint16_t Peak;
Uint16_t tmp;
Int16_t GainTitle = 0;
Int16_t GainAlbum = 0;
Int16_t Gain;
int Encoder;
Bool_t SecurePeakTitle = 0;
Float ReplayGain; // 0...1...+oo
Float ClipCorr; // 0...1
size_t HeaderLen;
ENTER(2);
// Fill the bitstream buffer for the first time
resume:
Bitstream_init ();
InputBuffRead = READ ( InputFile, InputBuff, IBUFSIZE * 4 ) / 4;
// Test the first 4 bytes ("MP+": SV7+, "ID3": ID3V2, other: may be SV4...6)
switch ( BitstreamLE_preview (32) ) {
case (Uint32_t)0x01334449L: /* ID3 V2.1...2.4 */
case (Uint32_t)0x02334449L:
case (Uint32_t)0x03334449L:
case (Uint32_t)0x04334449L:
stderr_printf ("\n"PROG_NAME": Stream was corrupted by an ID3 Version 2 tagger\n\n" );
ID3v2 = JumpID3v2 ();
if ( SEEK ( InputFile, ID3v2, SEEK_SET ) < 0 ) {
stderr_printf ( "\n\nSorry, recovering fails.\n\a" );
return 0;
}
sleep (1);
stderr_printf ("\b\b\b\b, ignore %lu words and %u bits ...\n\a", (unsigned long)ID3v2 >> 2, (int)(ID3v2&3) << 3 );
goto resume;
case (Uint32_t)0x072B504DL: /* MP+ SV7 */
case (Uint32_t)0x172B504DL: /* MP+ SV7.1 */
StreamVersion = (Int) BitstreamLE_read (8);
(void) BitstreamLE_read (24);
break;
case (Uint32_t)0xFF2B504DL: /* MP+ SVF.F */
(void) BitstreamBE_read (24);
StreamVersion = (Int) BitstreamBE_read (8);
break;
case (Uint32_t)0x2043414DL: /* MAC */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "Monkey's Audio" );
return 0;
case (Uint32_t)0x7961722E: /* Real Audio */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "Real Audio" );
return 0;
case (Uint32_t)0x46464952L: /* WAV */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "Microsoft WAVE" );
return 0;
case (Uint32_t)0x43614C66L: /* FLAC */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "FLAC" );
return 0;
case (Uint32_t)0x4341504CL: /* LPAC */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "LPAC" );
return 0;
case (Uint32_t)0x37414B52L: /* RKAU */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "RKAU" );
return 0;
case (Uint32_t)0x676B6A61L: /* Shorten */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "Shorten" );
return 0;
case (Uint32_t)0x040A5A53L: /* SZIP 1.12 */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "szip" );
return 0;
case (Uint32_t)0x5367674FL: /* OggS */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "Ogg Stream" );
return 0;
case (Uint32_t)0x46494441L: /* AAC-ADIF */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "AAC Audio Data Interchange Format" );
return 0;
case (Uint32_t)0x75B22630L: /* MS WMA */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "MS Windows Media Audio" );
return 0;
case (Uint32_t)0xBA010000L: /* MPEG system stream */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "MPEG system stream/VOB" );
return 0;
case (Uint32_t)0x0180FE7FL: /* DTS */
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "Digital Theater System" );
return 0;
default:
StreamVersion = (Uint32_t) BitstreamLE_preview (32);
if ( ( StreamVersion & 0x00FFFFFF ) == (Uint32_t)0x002B504DL ) {
StreamVersion >>= 24;
stderr_printf ( "\n"PROG_NAME": Input File seems to be a MPC file StreamVersion %u.%u\nVisit http://www.uni-jena.de/~pfk/mpc/ and update your software.\n\n", StreamVersion & 15, StreamVersion >> 4 );
return 0;
}
if ( ( (BitstreamLE_preview (32)) & 0x0000FFFF ) == (Uint32_t)0x0000770BL ) {
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "AC3/Dolby Digital" );
return 0;
}
if ( ( (BitstreamLE_preview (32)) & 0x0000E6FF ) == (Uint32_t)0x0000E6FFL ) {
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "MPEG Layer 1" );
return 0;
}
if ( ( (BitstreamLE_preview (32)) & 0x0000E6FF ) == (Uint32_t)0x0000E4FFL ) {
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "MPEG Layer 2" );
return 0;
}
if ( ( (BitstreamLE_preview (32)) & 0x0000E6FF ) == (Uint32_t)0x0000E2FFL ) {
stderr_printf ("\n"PROG_NAME": Input File is a %s file\n", "MPEG Layer 3" );
return 0;
}
StreamVersion = (Int) (BitstreamLE_preview (21) & 0x3FF);
if ( StreamVersion < 4 || StreamVersion > 6 ) {
stderr_printf ("\n"PROG_NAME": Input File is not a MPC file, neither SV 4...6 nor SV 7 (SV %u)\n", StreamVersion );
return 0;
}
break;
}
// decode the header for SV4...6 or SV7 or SV8
switch ( StreamVersion ) {
case 0x04:
case 0x05:
case 0x06:
Bitrate = (Int) BitstreamLE_read ( 9);
IS_used = (Int) BitstreamLE_read ( 1);
MS_bits = (Uint) BitstreamLE_read ( 1);
StreamVersion = (Int) BitstreamLE_read (10);
MaxBandDesired = (Int) BitstreamLE_read ( 5);
if ( BitstreamLE_read (6) != 1 ) {
fprintf ( stderr, "Blocksize of != 1 is not supported any longer\n" );
return 0;
}
TotalFrames = BitstreamLE_read ( StreamVersion < 5 ? 16 : 32 );
SampleFreq = 44100;
Encoder = -1;
Channels = 2;
if ( StreamVersion >= 4 && StreamVersion <= 6 )
break;
default: // it should be impossible to execute the following code
stderr_printf ("\n"PROG_NAME": Internal error\n" );
stderr_printf ("\n"PROG_NAME": Not a MPC file, neither SV 4...6 nor SV 7 (SV %u.%u)\n", StreamVersion & 15, StreamVersion >> 4 );
return 0;
case 0x07:
case 0x17:
Bitrate = 0;
Channels = 2;
TotalFrames = BitstreamLE_read (32);
IS_used = (Int) BitstreamLE_read ( 1);
MS_bits = (Uint) BitstreamLE_read ( 1);
MaxBandDesired = (Int) BitstreamLE_read ( 6);
// reading the profile
Profile = (Int) BitstreamLE_read (4);
(void) BitstreamLE_read ( 2);
SampleFreq = sftable [ BitstreamLE_read ( 2) ];
// reading peak and gain values from the file (or use useful values if they are absent)
PeakTitle = (Uint16_t)(1.18 * (Uint32_t)BitstreamLE_read (16));
GainTitle = BitstreamLE_read (16);
tmp = BitstreamLE_read (16);
if ( SecurePeakTitle = (tmp != 0) )
PeakTitle = tmp;
GainAlbum = BitstreamLE_read (16);
PeakAlbum = BitstreamLE_read (16);
if ( PeakAlbum == 0 )
PeakAlbum = PeakTitle;
// reading true gapless
TrueGaplessPresent = BitstreamLE_read ( 1);
LastValidSamples = BitstreamLE_read (11);
(void) BitstreamLE_read (20);
// reserved bytes for future use
Encoder = BitstreamLE_read ( 8);
break;
case 0xFF:
Bitrate = 0;
TrueGaplessPresent = 1;
HeaderLen = (Uint16_t) BitstreamBE_read (16);
Profile = (Uint8_t) BitstreamBE_read ( 8);
Encoder = (Uint8_t) BitstreamBE_read ( 8);
TotalFrames = (Uint32_t) BitstreamBE_read (32);
// reading peak and gain values from the file (or use useful values if they are absent)
SecurePeakTitle = 1;
PeakTitle = (Uint16_t) BitstreamBE_read (16);
GainTitle = (Int16_t) BitstreamBE_read (16);
PeakAlbum = (Uint16_t) BitstreamBE_read (16);
GainAlbum = (Int16_t) BitstreamBE_read (16);
if ( PeakAlbum == 0 )
PeakAlbum = PeakTitle;
MaxBandDesired = (Uint) BitstreamBE_read ( 6);
MS_bits = (Uint) BitstreamBE_read ( 4);
(void) BitstreamBE_read ( 6);
LastValidSamples = (Uint) BitstreamBE_read (16);
Channels = (Uint8_t) BitstreamBE_read ( 8);
(void) BitstreamBE_read (24);
SampleFreq = (Uint16_t) BitstreamBE_read (16);
(void) BitstreamBE_read (16);
for ( ; HeaderLen > 26; HeaderLen-- )
(void) BitstreamBE_read ( 8);
break;
}
// check for ID3V1(.1) tags or APE tags, output information if available
if ( Read_ID3V1_Tags ( InputFile, &taginfo ) || Read_APE_Tags ( InputFile, &taginfo ) ) {
#define GET(x) ( taginfo.x ? taginfo.x : "" )
#define HAVE_GENRE ( GET(Genre)[0] != '?' && GET(Genre)[0] != '\0' )
#define HAVE_YEAR ( GET(Year)[0] != '\0' )
stderr_printf ("\n %s: %s ", GET(Artist), GET(Album) );
stderr_printf ( HAVE_GENRE || HAVE_YEAR ? " (" : "" );
stderr_printf ( HAVE_GENRE ? "%0.0s" : "%s", GET(Genre) );
stderr_printf ( HAVE_GENRE && HAVE_YEAR ? ", " : "" );
stderr_printf ( "%s", GET(Year) );
stderr_printf ( HAVE_GENRE || HAVE_YEAR ? ")\n" : "\n" );
stderr_printf (" %s %s", GET(Track), GET(Title) );
stderr_printf ( GET(Comment)[0] != '\0' ? " (%s)\n" : "%s\n", GET(Comment) );
#undef GET
#undef HAVE_GENRE
#undef HAVE_YEAR
}
// calculate bitrate for informational purpose
if ( Bitrate == 0 ) {
AverageBitrate = ( SampleFreq / 1000. / BLK_SIZE * 8 ) * taginfo.FileSize / TotalFrames ;
}
else {
AverageBitrate = Bitrate;
}
stderr_printf ("\n");
if ( AverageBitrate > 0. )
stderr_printf ("%7.1f kbps,", AverageBitrate );
// Output total time, Streamversion, Profile
stderr_printf ("%s, SV %u.%u, Profile %s%s", PrintTime ((UintMax_t)TotalFrames * BLK_SIZE, ' ') + 1, StreamVersion & 15, StreamVersion >> 4, ProfileName(Profile), EncoderName(Encoder) );
// Choose the select type of Peak and Gain values
switch ( ReplayGainType ) {
case 0: // no replay gain, use title peak for clipping prevention
Gain = 0;
Peak = PeakTitle;
break;
case 1: // no replay gain, use album peak for clipping prevention
Gain = 0;
Peak = PeakAlbum;
break;
default: // title replay gain
Gain = GainTitle;
Peak = PeakTitle;
break;
case 3: // album replay gain
Gain = GainAlbum;
Peak = PeakAlbum;
break;
}
// calculate the multiplier from the original integer peak and gain data
ReplayGain = (Float) exp ( (M_LN10/2000.) * (Int16_t)Gain );
ClipCorr = (Float) (32767. / ( (Uint32_t)Peak + 1 )); // avoid divide by 0
// Perform or not perform clipping prevention, that is here the question
if ( ClipPrev ) {
stderr_printf (", ClipDamp " );
if ( Peak == 0 ) {
stderr_printf ("1 ???" );
ClipCorr = 1.f;
}
else if ( ReplayGain * fabs(Scale) > ClipCorr ) {
stderr_printf (".%04d%s", (int)(1.e4 * ClipCorr / (ReplayGain * Scale) + 0.5), SecurePeakTitle ? "" : "?" );
ClipCorr = ClipCorr / (ReplayGain * Scale);
}
else {
stderr_printf ("1%s", SecurePeakTitle ? "" : "?" );
ClipCorr = 1.f;
}
}
else {
ClipCorr = 1.f;
}
// report replay gain if != 1.
if ( ReplayGain != 1. )
stderr_printf (", Gain %.4f", ReplayGain );
stderr_printf ("\n\n");
// init subband structure (MaxBandDesired, StreamVersion, bitrate) and Scale factors
Init_QuantTab ( MaxBandDesired, IS_used, ClipCorr * ReplayGain * Scale, StreamVersion );
// calculate Start and Duration if they are given in precent as negative values
if ( Start < 0. )
Start *= TotalFrames * -(0.01 * BLK_SIZE / SampleFreq);
if ( Duration < 0. )
Duration *= TotalFrames * -(0.01 * BLK_SIZE / SampleFreq);
// reset arrays to avoid HF noise if recent MaxBand > current MaxBand
memset ( YY , 0, sizeof YY );
memset ( QQ , 0, sizeof QQ );
memset ( VV , 0, sizeof VV );
memset ( V_offset, 0, sizeof V_offset );
// decoding kernel with time measurement
T = clock ();
DecodedSamples = Decode ( OutputFile, InputFile, TotalFrames,
floor (Start * SampleFreq + 0.5) + DECODER_DELAY,
Duration <= 0. ? 1.e18 : floor (Duration * SampleFreq + 0.5),
LastValidSamples );
T = clock () - T;
#ifdef __TURBOC__ // wraps around at midnight
if ( (Long)T < 0 ) {
T += (time_t) (86400. * CLOCKS_PER_SEC);
}
#endif
// output at the end of a decoded title
(void) stderr_printf ( " (runtime: %.2f s speed: %.2fx)\n", (Double) (T * (1. / CLOCKS_PER_SEC )),
T ? (Double) ((CLOCKS_PER_SEC/(Float)SampleFreq) * UintMAX_FP(DecodedSamples) / T) : (Double)0. );
LEAVE(2);
return DecodedSamples;
}
/**********************************************************************************************************************************
*
* Function: Create_Extention()
*
* Creates a output file name by a given destination path, the input file name and a given extention
*
* - Path is taken
* - a directory separator is appended
* - the file name of the source file is taken
* - and the extention is added.
*
* Decoding the source file bar.mpc with the path foo will create the destination file
* foo/bar.mpc.wav . The double extention mpc.wav is intended, on my computer such "lossy" WAV files has
* always such extentions.
*
* foo.wav Original
* foo.mpc Encoded file, normal behave can be to overwrite existing output files, you still have the original file.
* foo.mpc.wav 1st generation decoded file, no danger to overwite foo.wav and you see it is a "lossy" WAV file.
* foo.mpc.mpc 2nd generation encoded file
* ...
*/
static char*
Create_Extention ( const char* Path,
const char* Name,
const char* Extention )
{
static char ret [PATHLEN_MAX + 3];
char* p = strrchr ( Name, PATH_SEP );
if ( p != NULL )
Name = p + 1;
if ( strlen(Path) + strlen(Name) + strlen(Extention) > sizeof(ret) - 3 ) {
stderr_printf (PROG_NAME":\tTarget buffer for new file name too short,\n\tincrease PATHLEN_MAX and recompile.\n\a" );
exit (4);
}
sprintf ( ret, "%s%c%s.%s", Path, PATH_SEP, Name, Extention );
return ret;
}
/**********************************************************************************************************************************
*
* Function: Unintended_OutputFile()
*
* Checks the sense of using a file name as an output file.
*
* - Identifier starting with http:// or ftp:// are very likely not a useful output file, because the program do not support writing via http or ftp
* - When file can be opened, there's at least no danger to use the file as output file, because it is (besides from some races) not possible to destroy data.
* - When the first 3 bytes of the file are "MP+", it is very likely that this is not an intended output file
* - When the file ends with a path separator, it also can't be an input file.
* - When the file ends with one of the below mentioned extentions, it is also not a candidate for an file with PCM data.
*
* This is pure heuristic, but saves you from damaging files. And I don't found any case, where this automatic
* made nonsense.
*
*/
static Int
Unintended_OutputFile ( const char* Name )
{
static char* BadExt [] = { "MPC", "MPP", "MP+", "M3U", "PAC", "APE", "OFR", "RKA", "AC3", "MP4", "MPT", "MP3", "MP2", "MP1", "MP3PRO", "OGG", "AAC", "LQT", "SHN", "FLA", "FLAC", "MOD", "LA", "VOB", "MPEG", "MPG", "AVI", "AU", "MOD", "MIDI", "MID", "VQF", "WMA", "WMV" };
char buff [3];
FILE_T fp;
int i;
#ifdef USE_HTTP
if ( 0 == strncasecmp (Name, "http://", 7) || 0 == strncasecmp (Name, "ftp://", 6) ) // HTTP/FTP: not possible
return 1;
#endif
if ( (fp = OPEN ( Name )) == INVALID_FILEDESC ) // file not exist: no danger
return 0;
READ ( fp, buff, 3 );
CLOSE (fp);
if ( memcmp (buff, "MP+", 3) == 0 )
return 1; // Destination is very likely a MPC file (SV7+)
if ( strlen (Name) < 1 )
return 0;
if ( Name[strlen(Name)-1] == PATH_SEP ) // Ends with a path separator
return 1;
Name = strrchr ( Name, '.' );
if ( Name == NULL )
return 0; // No dot in the path, no extention
for ( i = 0; i < sizeof(BadExt)/sizeof(*BadExt); i++ ) // Known extentions
if ( 0 == strcasecmp ( Name+1, BadExt [i] ) )
return 1;
return 0;
}
/**********************************************************************************************************************************
*
* Function: RandomizeList()
* SortList()
*
* Randomizes/Sorts rests of the argument line pointed by argv.
*
* Bug: also options are randomized/sorted.
*
*/
static void
RandomizeList ( const char** argv )
{
int argc;
int i;
int j;
const char* tmp;
for ( argc = 0; argv[argc] != NULL; argc++ )
;
srand ( time (NULL) );
for ( i = 0; i < argc; i++ ) {
j = rand() % argc;
tmp = argv[i];
argv[i] = argv[j];
argv[j] = tmp;
}
}
static int Cdecl
cmpfn ( const void* p1, const void* p2 )
{
return strcmp ( *((const char**)p1), *((const char**)p2) );
}
static void
SortList ( const char** argv )
{
int argc;
for ( argc = 0; argv[argc] != NULL; argc++ )
;
qsort ( (void*)argv, argc, sizeof(*argv), cmpfn );
}