mirror of
https://github.com/cookiengineer/audacity
synced 2025-04-30 15:49:41 +02:00
352 lines
11 KiB
Perl
Executable File
352 lines
11 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
|
|
use warnings;
|
|
use strict;
|
|
|
|
use Digest::MD5 qw(md5_hex);
|
|
use Test::More tests => 77;
|
|
|
|
my $TWOLAME_CMD = $ENV{TWOLAME_CMD} || "../frontend/twolame";
|
|
my $STWOLAME_CMD = $ENV{STWOLAME_CMD} || "../simplefrontend/stwolame";
|
|
die "Error: twolame command not found: $TWOLAME_CMD" unless (-e $TWOLAME_CMD);
|
|
die "Error: stwolame command not found: $STWOLAME_CMD" unless (-e $STWOLAME_CMD);
|
|
|
|
|
|
my $encoding_parameters = [
|
|
{
|
|
# Test Case 1 (default settings)
|
|
'input_filename' => 'testcase-44100.wav',
|
|
'input_md5sum' => 'f50499fded70a74c810dbcadb3f28062',
|
|
'bitrate' => 192,
|
|
'samplerate' => 44100,
|
|
'version' => '1',
|
|
'mode' => 'stereo',
|
|
'psycmode' => 3,
|
|
'original' => 1,
|
|
'copyright' => 0,
|
|
'padding' => 0,
|
|
'protect' => 0,
|
|
'deemphasis' => 'n',
|
|
'total_frames' => 22,
|
|
'total_bytes' => 13772,
|
|
'total_samples' => 25344,
|
|
'output_md5sum' => '956f85e3647314750a1d3ed3fbf81ae3'
|
|
},
|
|
{
|
|
# Test Case 2 (toolame 0.2l default settings)
|
|
'input_filename' => 'testcase-44100.wav',
|
|
'input_md5sum' => 'f50499fded70a74c810dbcadb3f28062',
|
|
'bitrate' => 192,
|
|
'samplerate' => 44100,
|
|
'version' => '1',
|
|
'mode' => 'joint',
|
|
'psycmode' => 1,
|
|
'original' => 0,
|
|
'copyright' => 0,
|
|
'padding' => 1,
|
|
'protect' => 0,
|
|
'deemphasis' => 'n',
|
|
'total_frames' => 22,
|
|
'total_bytes' => 13792,
|
|
'total_samples' => 25344,
|
|
'output_md5sum' => 'fef3bb4926978e56822d33eaa89208d2'
|
|
},
|
|
{
|
|
# Test Case 3 (MPEG-2 test)
|
|
'input_filename' => 'testcase-22050.wav',
|
|
'input_md5sum' => 'a5ec3077c2138a1023bcd980aec8e4b4',
|
|
'bitrate' => 32,
|
|
'samplerate' => 22050,
|
|
'version' => '2',
|
|
'mode' => 'mono',
|
|
'psycmode' => 4,
|
|
'original' => 0,
|
|
'copyright' => 1,
|
|
'padding' => 1,
|
|
'protect' => 0,
|
|
'deemphasis' => '5',
|
|
'total_frames' => 11,
|
|
'total_bytes' => 2298,
|
|
'total_samples' => 12672,
|
|
'output_md5sum' => '3175f5332040aaad42b00823cd1ec913'
|
|
},
|
|
{
|
|
# Test Case 4 (error protection test)
|
|
'input_filename' => 'testcase-44100.wav',
|
|
'input_md5sum' => 'f50499fded70a74c810dbcadb3f28062',
|
|
'bitrate' => 192,
|
|
'samplerate' => 44100,
|
|
'version' => '1',
|
|
'mode' => 'stereo',
|
|
'psycmode' => 3,
|
|
'original' => 1,
|
|
'copyright' => 0,
|
|
'padding' => 0,
|
|
'protect' => 1,
|
|
'deemphasis' => 'n',
|
|
'total_frames' => 22,
|
|
'total_bytes' => 13772,
|
|
'total_samples' => 25344,
|
|
'output_md5sum' => '7e7aa8e3cfafdd1cd2eda53a9ab8bef3'
|
|
},
|
|
];
|
|
|
|
|
|
my $count = 1;
|
|
foreach my $params (@$encoding_parameters) {
|
|
my $INPUT_FILENAME = input_filepath($params->{input_filename});
|
|
my $OUTPUT_FILENAME = "testcase-$count.mp2";
|
|
|
|
die "Input file does not exist: $INPUT_FILENAME" unless (-e $INPUT_FILENAME);
|
|
is(md5_file($INPUT_FILENAME), $params->{input_md5sum}, "[$count] MD5sum of $INPUT_FILENAME");
|
|
|
|
my $result = system($TWOLAME_CMD,
|
|
'--quiet',
|
|
'--bitrate', $params->{bitrate},
|
|
'--mode', $params->{mode},
|
|
'--psyc-mode', $params->{psycmode},
|
|
$params->{copyright} ? '--copyright' : '--non-copyright',
|
|
$params->{original} ? '--original' : '--non-original',
|
|
$params->{protect} ? '--protect' : '',
|
|
$params->{padding} ? '--padding' : '',
|
|
'--deemphasis', $params->{deemphasis},
|
|
$INPUT_FILENAME, $OUTPUT_FILENAME
|
|
);
|
|
|
|
is($result, 0, "[$count] twolame response code");
|
|
|
|
my $info = mpeg_audio_info($OUTPUT_FILENAME);
|
|
is($info->{syncword}, 0xff, "[$count] MPEG Audio Header - Sync Word");
|
|
is($info->{version}, $params->{version}, "[$count] MPEG Audio Header - Version");
|
|
is($info->{layer}, 2, "[$count] MPEG Audio Header - Layer");
|
|
is($info->{mode}, $params->{mode}, "[$count] MPEG Audio Header - Mode");
|
|
is($info->{samplerate}, $params->{samplerate}, "[$count] MPEG Audio Header - Sample Rate");
|
|
is($info->{bitrate}, $params->{bitrate}, "[$count] MPEG Audio Header - Bitrate");
|
|
is($info->{copyright}, $params->{copyright}, "[$count] MPEG Audio Header - Copyright Flag");
|
|
is($info->{original}, $params->{original}, "[$count] MPEG Audio Header - Original Flag");
|
|
is($info->{protect}, $params->{protect}, "[$count] MPEG Audio Header - Error Protection Flag");
|
|
is($info->{deemphasis}, $params->{deemphasis}, "[$count] MPEG Audio Header - De-emphasis");
|
|
|
|
# FIXME: test that CRC is correct
|
|
|
|
is($info->{total_frames}, $params->{total_frames}, "[$count] total number of frames");
|
|
is($info->{total_bytes}, $params->{total_bytes}, "[$count] total number of bytes");
|
|
is($info->{total_samples}, $params->{total_samples}, "[$count] total number of samples");
|
|
|
|
is(filesize($OUTPUT_FILENAME), $params->{total_bytes}, , "[$count] file size of output file");
|
|
is(md5_file($OUTPUT_FILENAME), $params->{output_md5sum}, "[$count] md5sum of output file");
|
|
|
|
$count++;
|
|
}
|
|
|
|
|
|
# Test encoding from STDIN
|
|
SKIP: {
|
|
my $result = system("which sndfile-convert > /dev/null");
|
|
skip("sndfile-convert is not available", 5) unless ($result == 0);
|
|
|
|
my $INPUT_FILENAME = input_filepath('testcase-44100.wav');
|
|
$result = system("sndfile-convert -pcm16 $INPUT_FILENAME testcase.raw");
|
|
is($result, 0, "sndfile-convert to raw response code");
|
|
|
|
my $OUTPUT_FILENAME = 'testcase-stdin.mp2';
|
|
$result = system("$TWOLAME_CMD --quiet --raw-input - $OUTPUT_FILENAME < testcase.raw");
|
|
is($result, 0, "converting from STDIN - response code");
|
|
|
|
my $info = mpeg_audio_info($OUTPUT_FILENAME);
|
|
is($info->{total_frames}, 22, "converting from STDIN - total number of frames");
|
|
is($info->{total_bytes}, 13772, "converting from STDIN - total number of bytes");
|
|
is(md5_file($OUTPUT_FILENAME), '956f85e3647314750a1d3ed3fbf81ae3', "converting from STDIN - md5sum of output file");
|
|
}
|
|
|
|
|
|
# Test encoding using the simplefrontend
|
|
{
|
|
my $INPUT_FILENAME = input_filepath('testcase-44100.wav');
|
|
my $OUTPUT_FILENAME = 'testcase-simple.mp2';
|
|
my $result = system("../simplefrontend/stwolame $INPUT_FILENAME $OUTPUT_FILENAME");
|
|
is($result, 0, "converting using simplefrontend - response code");
|
|
|
|
my $info = mpeg_audio_info($OUTPUT_FILENAME);
|
|
is($info->{total_frames}, 22, "converting using simplefrontend - total number of frames");
|
|
is($info->{total_bytes}, 13772, "converting using simplefrontend - total number of bytes");
|
|
is(md5_file($OUTPUT_FILENAME), '956f85e3647314750a1d3ed3fbf81ae3', "converting using simplefrontend - md5sum of output file");
|
|
}
|
|
|
|
|
|
## END OF TESTS ##
|
|
|
|
sub input_filepath {
|
|
# Input test data files are in the same directory as the test script
|
|
my ($filename) = @_;
|
|
my $filepath = __FILE__;
|
|
$filepath =~ s/test.pl/$filename/;
|
|
return $filepath;
|
|
}
|
|
|
|
sub filesize {
|
|
return (stat(@_))[7];
|
|
}
|
|
|
|
sub md5_file {
|
|
my ($filename) = @_;
|
|
|
|
my $ctx = Digest::MD5->new;
|
|
|
|
open(FILE, $filename) or die "Failed to open file: $filename ($!)";
|
|
$ctx->addfile(*FILE);
|
|
close(FILE);
|
|
|
|
return $ctx->hexdigest;
|
|
}
|
|
|
|
sub mpeg_audio_info {
|
|
my ($filename) = @_;
|
|
my $info = undef;
|
|
|
|
open(MPAFILE, $filename) or die "Failed to open file: $filename ($!)";
|
|
|
|
until (eof(MPAFILE)) {
|
|
my $header = '';
|
|
my $bytes = read(MPAFILE, $header, 4);
|
|
if ($bytes != 4) {
|
|
warn "Failed to read MPEG Audio header";
|
|
last;
|
|
}
|
|
|
|
my $frame_info = parse_mpeg_header($header);
|
|
if ($frame_info->{syncword} != 0xff) {
|
|
warn "Lost MPEG Audio header sync";
|
|
last;
|
|
}
|
|
|
|
# Now read in the rest of the frame
|
|
my $buffer = '';
|
|
my $remaining = ($frame_info->{framesize}-4);
|
|
$bytes = read(MPAFILE, $buffer, $remaining);
|
|
if ($bytes != $remaining) {
|
|
warn "Failed to read remaining buts of MPEG Audio frame";
|
|
last;
|
|
}
|
|
|
|
if ($frame_info->{protect}) {
|
|
$frame_info->{crc} = unpack('n', $buffer);
|
|
}
|
|
|
|
$info = $frame_info unless ($info);
|
|
$info->{total_frames} += 1;
|
|
$info->{total_samples} += $frame_info->{samples};
|
|
$info->{total_bytes} += $frame_info->{framesize};
|
|
};
|
|
|
|
close(MPAFILE);
|
|
|
|
return $info;
|
|
}
|
|
|
|
sub parse_mpeg_header {
|
|
my ($buffer) = @_;
|
|
my $header = unpack('N', $buffer);
|
|
my $info = {};
|
|
|
|
my $bitrate_table = [
|
|
[ # MPEG 1
|
|
[0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448], # Layer 1
|
|
[0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384], # Layer 2
|
|
[0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320] # Layer 3
|
|
],
|
|
[ # MPEG 2
|
|
[0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256], # Layer 1
|
|
[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160], # Layer 2
|
|
[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] # Layer 3
|
|
],
|
|
[ # MPEG 2.5
|
|
[0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256], # Layer 1
|
|
[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160], # Layer 2
|
|
[0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160] # Layer 3
|
|
]
|
|
];
|
|
|
|
my $samplerate_table = [
|
|
[ 44100, 48000, 32000 ], # MPEG 1
|
|
[ 22050, 24000, 16000 ], # MPEG 2
|
|
[ 11025, 12000, 8000 ] # MPEG 2.5
|
|
];
|
|
|
|
$info->{syncword} = ($header >> 23) & 0xff;
|
|
|
|
my $version = (($header >> 19) & 0x03);
|
|
if ($version == 0x00) {
|
|
$info->{version} = '2.5'; # MPEG 2.5
|
|
} elsif ($version == 0x02) {
|
|
$info->{version} = '2'; # MPEG 2
|
|
} elsif ($version == 0x03) {
|
|
$info->{version} = '1'; # MPEG 1
|
|
} else {
|
|
$info->{version} = undef;
|
|
}
|
|
|
|
$info->{layer} = 4-(($header >> 17) & 0x03);
|
|
if ($info->{layer}==4) {
|
|
$info->{layer} = 0;
|
|
}
|
|
|
|
$info->{protect} = (($header >> 16) & 0x01) ? 0 : 1;
|
|
$info->{padding} = ($header >> 9) & 0x01;
|
|
$info->{extension} = ($header >> 8) & 0x01;
|
|
$info->{mode_ext} = ($header >> 4) & 0x03;
|
|
$info->{copyright} = ($header >> 3) & 0x01;
|
|
$info->{original} = ($header >> 2) & 0x01;
|
|
|
|
my $bitrate_index = ($header >> 12) & 0x0F;
|
|
my $samplerate_index = ($header >> 10) & 0x03;
|
|
if ($info->{layer} && $info->{version}) {
|
|
$info->{bitrate} = $bitrate_table->[$info->{version}-1]->[$info->{layer}-1][$bitrate_index];
|
|
$info->{samplerate} = $samplerate_table->[$info->{version}-1]->[$samplerate_index];
|
|
} else {
|
|
$info->{bitrate} = undef;
|
|
$info->{samplerate} = undef;
|
|
}
|
|
|
|
my $deemphasis = $header & 0x03;
|
|
if ($deemphasis == 0) {
|
|
$info->{deemphasis} = 'n'; # None
|
|
} elsif ($deemphasis == 1) {
|
|
$info->{deemphasis} = '5'; # 50/15 ms
|
|
} elsif ($deemphasis == 3) {
|
|
$info->{deemphasis} = 'c'; # CCITT J.17
|
|
} else {
|
|
$info->{deemphasis} = undef;
|
|
}
|
|
|
|
my $mode = ($header >> 6) & 0x03;
|
|
if ($mode == 0) {
|
|
$info->{mode} = 'stereo';
|
|
} elsif ($mode == 1) {
|
|
$info->{mode} = 'joint';
|
|
} elsif ($mode == 2) {
|
|
$info->{mode} = 'dual';
|
|
} elsif ($mode == 3) {
|
|
$info->{mode} = 'mono';
|
|
} else {
|
|
$info->{mode} = undef;
|
|
}
|
|
|
|
if ($info->{layer} == '1') {
|
|
$info->{samples} = 384;
|
|
} elsif ($info->{layer} == '2') {
|
|
$info->{samples} = 1152;
|
|
} elsif ($info->{layer} == '3') {
|
|
$info->{samples} = ($info->{version} eq '1') ? 1152 : 576;
|
|
}
|
|
|
|
if ($info->{samplerate}) {
|
|
$info->{framesize} = int(($info->{samples} * $info->{bitrate} * 1000 / $info->{samplerate}) / 8 + $info->{padding});
|
|
} else {
|
|
$info->{framesize} = undef;
|
|
}
|
|
|
|
return $info;
|
|
}
|
|
|