Initial commit of mpg123-1.29.3
This commit is contained in:
111
src/tests/Makemodule.am
Normal file
111
src/tests/Makemodule.am
Normal file
@@ -0,0 +1,111 @@
|
||||
# Module for non-recursive mpg123 build system.
|
||||
|
||||
TESTS += \
|
||||
src/tests/decode_fixed.sh \
|
||||
src/tests/seek_whence.sh \
|
||||
src/tests/seek_accuracy.sh \
|
||||
src/tests/resample_total \
|
||||
src/tests/text \
|
||||
src/tests/textprint \
|
||||
src/tests/plain_id3.sh
|
||||
|
||||
if !HAVE_SYNTH16
|
||||
XFAIL_TESTS += src/tests/decode_fixed.sh
|
||||
endif
|
||||
|
||||
# Those are created by test scrips. Could add targets?
|
||||
clean-local: clean-local-check
|
||||
.PHONY: clean-local-check
|
||||
clean-local-check:
|
||||
rm -f src/tests/sweepsweep.mp3 src/tests/stripsweep.mp3 src/tests/plain_id3.out.txt
|
||||
|
||||
# Why do I have to repeat the test scripts here?
|
||||
EXTRA_DIST += \
|
||||
src/tests/testtext.sh \
|
||||
src/tests/decode_fixed.sh \
|
||||
src/tests/seek_whence.sh \
|
||||
src/tests/seek_accuracy.sh \
|
||||
src/tests/plain_id3.sh \
|
||||
src/tests/plain_id3.txt \
|
||||
src/tests/sweep.mp3
|
||||
|
||||
check_PROGRAMS += \
|
||||
src/tests/decode_fixed \
|
||||
src/tests/seek_whence \
|
||||
src/tests/seek_accuracy \
|
||||
src/tests/resample_total \
|
||||
src/tests/text \
|
||||
src/tests/textprint \
|
||||
src/tests/plain_id3
|
||||
|
||||
EXTRA_PROGRAMS += \
|
||||
src/tests/volume \
|
||||
src/tests/decode_fixed \
|
||||
src/tests/seek_whence \
|
||||
src/tests/seek_accuracy \
|
||||
src/tests/noise \
|
||||
src/tests/sweeper
|
||||
|
||||
src_tests_volume_SOURCES = \
|
||||
src/tests/volume.c
|
||||
src_tests_volume_LDADD = \
|
||||
src/libsyn123/libsyn123.la
|
||||
|
||||
src_tests_decode_fixed_SOURCES = \
|
||||
src/tests/decode_fixed.c
|
||||
src_tests_decode_fixed_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libmpg123/libmpg123.la
|
||||
|
||||
src_tests_seek_whence_SOURCES = \
|
||||
src/tests/seek_whence.c
|
||||
src_tests_seek_whence_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libmpg123/libmpg123.la
|
||||
|
||||
src_tests_seek_accuracy_SOURCES = \
|
||||
src/tests/seek_accuracy.c
|
||||
src_tests_seek_accuracy_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libmpg123/libmpg123.la
|
||||
|
||||
src_tests_noise_SOURCES = \
|
||||
src/tests/noise.c \
|
||||
src/libmpg123/dither.h \
|
||||
src/libmpg123/dither_impl.h
|
||||
src_tests_noise_LDADD = \
|
||||
src/compat/libcompat.la
|
||||
|
||||
src_tests_sweeper_SOURCES = \
|
||||
src/tests/sweeper.c
|
||||
src_tests_sweeper_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libsyn123/libsyn123.la \
|
||||
src/libout123/libout123.la
|
||||
|
||||
src_tests_resample_total_SOURCES = \
|
||||
src/tests/resample_total.c
|
||||
src_tests_resample_total_LDADD = \
|
||||
src/libsyn123/libsyn123.la
|
||||
|
||||
src_tests_text_SOURCES = \
|
||||
src/tests/text.c \
|
||||
src/tests/testtext.h
|
||||
src_tests_text_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libmpg123/libmpg123.la
|
||||
|
||||
src_tests_textprint_SOURCES =\
|
||||
src/tests/textprint.c \
|
||||
src/local.c \
|
||||
src/genre.c
|
||||
|
||||
src_tests_textprint_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libmpg123/libmpg123.la
|
||||
|
||||
src_tests_plain_id3_SOURCES = \
|
||||
src/tests/plain_id3.c
|
||||
src_tests_plain_id3_LDADD = \
|
||||
src/compat/libcompat.la \
|
||||
src/libmpg123/libmpg123.la
|
||||
63
src/tests/decode_fixed.c
Normal file
63
src/tests/decode_fixed.c
Normal file
@@ -0,0 +1,63 @@
|
||||
#include "compat.h"
|
||||
#include <mpg123.h>
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
int work(mpg123_handle *mh, int ch, int enc)
|
||||
{
|
||||
int16_t buffer[16348];
|
||||
long rate;
|
||||
int channels, encoding;
|
||||
if(mpg123_getformat(mh, &rate, &channels, &encoding) != MPG123_OK)
|
||||
return 1;
|
||||
if(channels != ch || encoding != enc)
|
||||
{
|
||||
error("channel/encoding mismatch");
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "openend fixed track with %ld %d %d\n"
|
||||
, rate, channels, encoding );
|
||||
int ret;
|
||||
size_t done;
|
||||
while( (ret=mpg123_read(mh, buffer, sizeof(buffer), &done)) == MPG123_OK)
|
||||
{
|
||||
if(!done)
|
||||
continue;
|
||||
fprintf(stderr, "Got first sample %d and last sample %d out of %zu\n"
|
||||
, buffer[0], buffer[done/sizeof(*buffer)-1], done/sizeof(*buffer) );
|
||||
unintr_write(STDOUT_FILENO, buffer, done);
|
||||
}
|
||||
if(ret != MPG123_DONE)
|
||||
{
|
||||
merror( "wrong mpg123_read() return value %d (%s, %s)"
|
||||
, ret, mpg123_plain_strerror(ret), mpg123_strerror(mh) );
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 1;
|
||||
int enc = MPG123_ENC_SIGNED_16;
|
||||
if(!mpg123_feature2(MPG123_FEATURE_OUTPUT_16BIT))
|
||||
{
|
||||
error("Libmpg123 doesn't do 16 bit output, cannot test.");
|
||||
return 1;
|
||||
}
|
||||
if(argc < 2)
|
||||
{
|
||||
printf("Gimme a MPEG file name...\n");
|
||||
return 0;
|
||||
}
|
||||
// Intentionally no error checking here. Let's see how the lib deals with it.
|
||||
mpg123_handle *mh = mpg123_new(NULL, NULL);
|
||||
// Try to set decoder to generic to avoid memory sanitizer freaking out about
|
||||
// asssembly synth routines.
|
||||
mpg123_decoder(mh, "generic");
|
||||
// Let's fix it to mono.
|
||||
if(mpg123_open_fixed(mh, argv[1], MPG123_MONO, enc) == MPG123_OK)
|
||||
ret = work(mh, 1, enc);
|
||||
mpg123_delete(mh);
|
||||
return ret;
|
||||
}
|
||||
22
src/tests/decode_fixed.sh
Executable file
22
src/tests/decode_fixed.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -x
|
||||
sweep="$srcdir/src/tests/sweep.mp3"
|
||||
sweepsweep="src/tests/sweepsweep.mp3"
|
||||
stripsweep="src/tests/stripsweep.mp3"
|
||||
|
||||
echo "Test successful decoding as such:"
|
||||
c1=$(src/tests/decode_fixed "$sweep" | wc -c)
|
||||
|
||||
echo "Test that track is decoded only once:"
|
||||
cat "$sweep" "$sweep" > "$sweepsweep"
|
||||
c2=$(src/tests/decode_fixed "$sweepsweep" | wc -c)
|
||||
test "$c1" = "$c2"
|
||||
|
||||
echo "Test that stripped track is decoded twice:"
|
||||
src/mpg123-strip -n < "$sweepsweep" > "$stripsweep"
|
||||
c3=$(src/tests/decode_fixed "$stripsweep" | wc -c)
|
||||
# Needs to be even larger as gapless info vanished.
|
||||
test "$c3" -gt "$(($c2*2))"
|
||||
|
||||
echo PASS
|
||||
56
src/tests/noise.c
Normal file
56
src/tests/noise.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "config.h"
|
||||
#include "compat.h"
|
||||
#include "dither.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* Directly include the code for testing, avoiding
|
||||
build of same object with and without libtool. */
|
||||
#include "../libmpg123/dither_impl.h"
|
||||
|
||||
const char *typenames[] = { "white", "tpdf", "highpass_tpdf" };
|
||||
enum mpg123_noise_type types[] = { mpg123_white_noise, mpg123_tpdf_noise, mpg123_highpass_tpdf_noise };
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
size_t i;
|
||||
size_t count = DITHERSIZE;
|
||||
float *table;
|
||||
enum mpg123_noise_type type = mpg123_highpass_tpdf_noise;
|
||||
|
||||
fprintf(stderr, "Note: You could give two optional arguments: noise type and table size (number count).\n");
|
||||
if(argc > 1)
|
||||
{
|
||||
const char *typename = argv[1];
|
||||
for(i=0; i<sizeof(typenames)/sizeof(char*); ++i)
|
||||
if(strcmp(typename, typenames[i]) == 0)
|
||||
{
|
||||
type = types[i];
|
||||
break;
|
||||
}
|
||||
|
||||
if(i == sizeof(typenames)/sizeof(char*))
|
||||
{
|
||||
error("Unknown noise type!");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(argc > 2)
|
||||
{
|
||||
count = (size_t) atol(argv[2]);
|
||||
}
|
||||
|
||||
table = malloc(sizeof(float)*count);
|
||||
if(table == NULL)
|
||||
{
|
||||
error("Cannot allocate memory for noise table!");
|
||||
return -2;
|
||||
}
|
||||
|
||||
mpg123_noise(table, count, type);
|
||||
for(i=0; i<count; ++i)
|
||||
printf("%g\n", table[i]);
|
||||
|
||||
free(table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
109
src/tests/plain_id3.c
Normal file
109
src/tests/plain_id3.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/* Just printing out ID3 tags with plain data from libmpg123 and explicitly called conversion routine. */
|
||||
|
||||
#include "compat.h"
|
||||
#include <mpg123.h>
|
||||
#include "debug.h"
|
||||
|
||||
int test_whence(const char* path, int scan_before)
|
||||
{
|
||||
int err = MPG123_OK;
|
||||
mpg123_handle* mh = NULL;
|
||||
off_t length, pos;
|
||||
|
||||
mh = mpg123_new(NULL, &err );
|
||||
if(mh == NULL) return -1;
|
||||
|
||||
err = mpg123_open(mh, path );
|
||||
if(err != MPG123_OK) return -1;
|
||||
|
||||
if(scan_before) mpg123_scan(mh);
|
||||
|
||||
pos = mpg123_seek( mh, 0, SEEK_END);
|
||||
if(pos < 0){ error1("seek failed: %s", mpg123_strerror(mh)); return -1; }
|
||||
|
||||
pos = mpg123_tell(mh);
|
||||
length = mpg123_length(mh);
|
||||
|
||||
/* Later: Read samples and compare different whence values with identical seek positions. */
|
||||
|
||||
mpg123_close(mh);
|
||||
mpg123_delete(mh);
|
||||
|
||||
fprintf(stdout, "length %"OFF_P" vs. pos %"OFF_P"\n", length, pos);
|
||||
|
||||
return (pos == length) ? 0 : -1;
|
||||
}
|
||||
|
||||
void print_field(const char *name, mpg123_string *sb)
|
||||
{
|
||||
const unsigned char *sbp = (unsigned char*)sb->p;
|
||||
enum mpg123_text_encoding enc;
|
||||
mpg123_string printer;
|
||||
mpg123_init_string(&printer);
|
||||
printf("\n=== %s ===\n", name);
|
||||
if(sb->fill == 0)
|
||||
{
|
||||
printf("Oh, empty. Totally.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
enc = mpg123_enc_from_id3(sbp[0]);
|
||||
|
||||
printf("From encoding: %i (in ID3: %i)\n", enc, (int)sbp[0]) ;
|
||||
if(mpg123_store_utf8(&printer, enc, sbp+1, sb->fill-1))
|
||||
{
|
||||
/* Not caring for multiple strings separated via null bytes here. */
|
||||
printf("Value: %s\n", printer.p);
|
||||
}
|
||||
else error("Conversion failed!");
|
||||
mpg123_free_string(&printer);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int err;
|
||||
int ret = 0;
|
||||
mpg123_handle *mh;
|
||||
mpg123_id3v2 *id3;
|
||||
|
||||
if(argc < 2)
|
||||
{
|
||||
printf("Gimme a MPEG file name...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mpg123_init();
|
||||
mh = mpg123_new(NULL, &err);
|
||||
if(err != MPG123_OK) goto badend;
|
||||
|
||||
mpg123_param(mh, MPG123_ADD_FLAGS, MPG123_PLAIN_ID3TEXT, 0.);
|
||||
|
||||
err = mpg123_open(mh, argv[1]);
|
||||
if(err != MPG123_OK) goto badend;
|
||||
|
||||
err = mpg123_scan(mh);
|
||||
if(err != MPG123_OK) goto badend;
|
||||
|
||||
err = mpg123_id3(mh, NULL, &id3);
|
||||
if(err != MPG123_OK) goto badend;
|
||||
|
||||
if(id3 == NULL)
|
||||
{
|
||||
error("No ID3 data found.");
|
||||
goto badend;
|
||||
}
|
||||
|
||||
print_field("artist", id3->artist);
|
||||
print_field("title", id3->title);
|
||||
print_field("album", id3->album);
|
||||
print_field("comment", id3->comment);
|
||||
|
||||
goto end;
|
||||
badend:
|
||||
ret = -1;
|
||||
end:
|
||||
mpg123_delete(mh);
|
||||
mpg123_exit();
|
||||
return ret;
|
||||
}
|
||||
15
src/tests/plain_id3.sh
Executable file
15
src/tests/plain_id3.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
export LC_ALL=C
|
||||
|
||||
sweep="$srcdir/src/tests/sweep.mp3"
|
||||
out=src/tests/plain_id3.out.txt
|
||||
ref="$srcdir/src/tests/plain_id3.txt"
|
||||
|
||||
src/tests/plain_id3 "$sweep" > src/tests/plain_id3.out.txt
|
||||
|
||||
if ! diff -q "$ref" "$out"; then
|
||||
exit 1
|
||||
fi
|
||||
echo PASS
|
||||
17
src/tests/plain_id3.txt
Normal file
17
src/tests/plain_id3.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
=== artist ===
|
||||
From encoding: 6 (in ID3: 1)
|
||||
Value: Dä mäintääner du tout les jours
|
||||
|
||||
=== title ===
|
||||
From encoding: 6 (in ID3: 1)
|
||||
Value: mpg123 test sweep
|
||||
|
||||
=== album ===
|
||||
From encoding: 6 (in ID3: 1)
|
||||
Value: The Greatest
|
||||
Test Suite
|
||||
|
||||
=== comment ===
|
||||
From encoding: 6 (in ID3: 1)
|
||||
Value: I got some wide chars.
|
||||
27
src/tests/resample_total.c
Normal file
27
src/tests/resample_total.c
Normal file
@@ -0,0 +1,27 @@
|
||||
// Those select the specific syn123 functions, without
|
||||
// this, the native wrapper is used, hopefully matching off_t.
|
||||
//#define _FILE_OFFSET_BITS 64
|
||||
//#define _FILE_OFFSET_BITS 32
|
||||
#include <syn123.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
const long arate = 8000;
|
||||
const long brate = 48000;
|
||||
const off_t ins = 12637;
|
||||
const off_t outs = 75822;
|
||||
|
||||
int main()
|
||||
{
|
||||
off_t outs2 = syn123_resample_total(arate,brate,ins);
|
||||
off_t ins2 = syn123_resample_intotal(arate,brate,outs);
|
||||
int err = 0;
|
||||
if(outs2 != outs && ++err)
|
||||
fprintf(stderr, "total mismatch: %ld != %ld\n"
|
||||
, (long)outs2, (long)outs );
|
||||
if(ins2 != ins && ++err)
|
||||
fprintf(stderr, "intotal mismatch: %ld != %ld\n"
|
||||
, (long)ins2, (long)ins );
|
||||
printf("%s\n", err ? "FAIL" : "PASS");
|
||||
return err;
|
||||
}
|
||||
286
src/tests/seek_accuracy.c
Normal file
286
src/tests/seek_accuracy.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
seek-accuracy: Take some given mpeg file and validate that seeks are indeed accurate.
|
||||
|
||||
copyright 2009-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Thomas Orgis
|
||||
|
||||
arguments: decoder preframes testfile.mpeg
|
||||
*/
|
||||
|
||||
#include <mpg123.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include "mpg123.h"
|
||||
#include "compat.h"
|
||||
|
||||
#define SAMPLES 187
|
||||
/* Cannot use the const value as fixed array size:-( */
|
||||
const size_t samples = SAMPLES;
|
||||
|
||||
/* Use getlopt.c in future? But heck, don't bloat. */
|
||||
enum theargs
|
||||
{
|
||||
arg_binname = 0
|
||||
,arg_decoder
|
||||
,arg_preframes
|
||||
,arg_file
|
||||
,arg_total
|
||||
};
|
||||
|
||||
const char* filename;
|
||||
int channels;
|
||||
mpg123_handle *m;
|
||||
size_t first_sample_errs = 0;
|
||||
|
||||
|
||||
int check_seeking(size_t *errs);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
size_t errs[2] = {0, 0};
|
||||
size_t errs_ntom[2] = {0, 0};
|
||||
const char* decoder = "auto";
|
||||
const char* preframes = "10";
|
||||
|
||||
if(argc < arg_total)
|
||||
{
|
||||
if(argc < 2)
|
||||
{
|
||||
/* Would at least need a file to use ... */
|
||||
fprintf(stderr, "\nUsage: %s <decoder> <preframes> <mpeg audio file>\n\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
/* silently use defaults plus given file */
|
||||
filename = argv[argc-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
decoder = argv[arg_decoder];
|
||||
preframes = argv[arg_preframes];
|
||||
filename = argv[arg_file];
|
||||
}
|
||||
m = mpg123_new(decoder, NULL);
|
||||
// Try to set decoder to generic to avoid memory sanitizer freaking out about
|
||||
// asssembly synth routines.
|
||||
mpg123_decoder(m, "generic");
|
||||
mpg123_param(m, MPG123_RESYNC_LIMIT, -1, 0);
|
||||
mpg123_param(m, MPG123_REMOVE_FLAGS, MPG123_GAPLESS, 0);
|
||||
|
||||
if(mpg123_param(m, MPG123_PREFRAMES, atol(preframes), 0) == MPG123_OK)
|
||||
fprintf(stderr,"Testing library with preframes set to %li\n", atol(preframes));
|
||||
|
||||
ret = check_seeking(errs);
|
||||
|
||||
if(ret == 0)
|
||||
{
|
||||
fprintf(stderr,"Now with NtoM resampling to 33333 Hz!");
|
||||
mpg123_param(m, MPG123_FORCE_RATE, 33333, 0);
|
||||
ret = check_seeking(errs_ntom);
|
||||
}
|
||||
else fprintf(stderr, "Some failure occured! Unable to test properly!");
|
||||
|
||||
fprintf(stderr,"\n");
|
||||
fprintf(stderr,"1to1 indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs[0],(size_p)samples);
|
||||
fprintf(stderr,"1to1 non-indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs[1],(size_p)samples);
|
||||
fprintf(stderr,"NtoM indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs_ntom[0],(size_p)samples);
|
||||
fprintf(stderr,"NtoM non-indexed seek errors: %"SIZE_P" / %"SIZE_P"\n", (size_p)errs_ntom[1],(size_p)samples);
|
||||
fprintf(stderr,"Errors in getting first sample again: %"SIZE_P"\n", first_sample_errs);
|
||||
fprintf(stderr,"\n");
|
||||
|
||||
if(ret == 0)
|
||||
{
|
||||
|
||||
if(first_sample_errs == 0 && errs[0] == 0 && errs[1] == 0 && errs_ntom[0] == 0 && errs_ntom[1] == 0)
|
||||
{
|
||||
printf("Congratulations, all seeks were accurate!\n");
|
||||
printf("But be warned: Not _all_ sample offsets have been tested. This result just means that the basic mechanism of sample-accurate seeking seems to work.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("There have been some errors. For layer 3 files, this may be due to too low MPG123_PREFRAMES.\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
}
|
||||
else fprintf(stderr, "Some bad failure during checking!\n");
|
||||
|
||||
mpg123_delete(m);
|
||||
mpg123_exit();
|
||||
|
||||
printf("%s\n", ret ? "FAIL" : "PASS");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int open_file()
|
||||
{
|
||||
if( mpg123_open(m, filename) == MPG123_OK
|
||||
&&
|
||||
mpg123_getformat(m, NULL, &channels, NULL) == MPG123_OK )
|
||||
{
|
||||
fprintf(stderr,"Channels: %i\n", channels);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"Opening file failed: %s\n", mpg123_strerror(m));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Operation:
|
||||
Read through the whole file and remember selected samples and their position.
|
||||
Then, seek to the positions selectively and compare.
|
||||
Second mode: Check if this is identical to fresh decoding and seek (without frame index table)... less important now, focusing on the first one.
|
||||
*/
|
||||
|
||||
struct seeko
|
||||
{
|
||||
off_t position[SAMPLES];
|
||||
short left[SAMPLES];
|
||||
short right[SAMPLES];
|
||||
};
|
||||
|
||||
/* select some positions to check seek accuracy on */
|
||||
void fix_positions(struct seeko *so, off_t length)
|
||||
{
|
||||
off_t step = (length-1)/(samples-1);
|
||||
size_t i;
|
||||
/* simple fixed stepping, in order (one could shuffle this) */
|
||||
for(i=0; i<samples-1; ++i)
|
||||
so->position[i] = i*step;
|
||||
|
||||
/* plus the last one! */
|
||||
so->position[samples-1] = length-1;
|
||||
}
|
||||
|
||||
int collect(struct seeko *so)
|
||||
{
|
||||
off_t pos_count = 0;
|
||||
off_t length;
|
||||
int err = MPG123_OK;
|
||||
size_t posi = 0;
|
||||
mpg123_scan(m);
|
||||
length = mpg123_length(m);
|
||||
fprintf(stderr,"Estimated length: %"OFF_P"\n", (off_p)length);
|
||||
/* Compute the interesting positions */
|
||||
fix_positions(so, length);
|
||||
/*
|
||||
Default format is always 16bit int, rate does not matter.
|
||||
Let's just get the channel count and not bother.
|
||||
*/
|
||||
while(err == MPG123_OK)
|
||||
{
|
||||
short buff[1024]; /* choosing a non-divider of mpeg frame size on purpose */
|
||||
size_t got = 0;
|
||||
off_t buffsamples;
|
||||
err = mpg123_read(m, (unsigned char*)buff, 1024*sizeof(short), &got);
|
||||
buffsamples = got/(channels*sizeof(short));
|
||||
while(so->position[posi] < pos_count+buffsamples)
|
||||
{
|
||||
size_t i = (so->position[posi]-pos_count)*channels;
|
||||
fprintf(stderr,"got sample %"SIZE_P" (%"OFF_P")\n", (size_p)posi, (off_p)so->position[posi]);
|
||||
so->left[posi] = buff[i];
|
||||
if(channels == 2)
|
||||
so->right[posi] = buff[i+1];
|
||||
|
||||
if(++posi >= samples) break;
|
||||
}
|
||||
if(posi >= samples) break;
|
||||
|
||||
pos_count += buffsamples;
|
||||
}
|
||||
if(posi < samples && (err != MPG123_DONE && err != MPG123_OK))
|
||||
{
|
||||
fprintf(stderr,"An error occured (not done)?: %s\n", mpg123_strerror(m));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We allow some minimal difference ... for subtle floating point effects. */
|
||||
int same(short a, short b)
|
||||
{
|
||||
return (abs(a-b) <= 2);
|
||||
}
|
||||
|
||||
int check_sample(struct seeko *so, size_t i)
|
||||
{
|
||||
short buf[2]; /* at max one left and right sample */
|
||||
size_t got = 0;
|
||||
|
||||
if(mpg123_seek(m, so->position[i], SEEK_SET) != so->position[i])
|
||||
{
|
||||
fprintf(stderr,"Error seeking to %"OFF_P": %s\n", (off_p)so->position[i], mpg123_strerror(m));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( mpg123_read(m, (unsigned char*)buf, channels*sizeof(short), &got) != MPG123_OK
|
||||
||
|
||||
got/sizeof(short) != channels )
|
||||
{
|
||||
fprintf(stderr,"Error occured on reading sample %"SIZE_P"! (%s)\n", (size_p)i, mpg123_strerror(m));
|
||||
return -1;
|
||||
}
|
||||
if(same(buf[0], so->left[i]) && (channels == 1 || same(buf[1], so->right[i])))
|
||||
{
|
||||
fprintf(stderr,"sample %"SIZE_P" PASS\n", (size_p)i);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(channels == 1) fprintf(stderr,"sample %"SIZE_P" FAIL (%i != %i)\n", (size_p)i, buf[0], so->left[i]);
|
||||
else fprintf(stderr,"sample %"SIZE_P" FAIL (%i != %i || %i != %i)\n", (size_p)i, buf[0], so->left[i], buf[1], so->right[i]);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t check_positions(struct seeko *so)
|
||||
{
|
||||
size_t i;
|
||||
size_t errs = 0;
|
||||
fprintf(stderr,"Seeking and comparing...\n");
|
||||
for(i=0; i<samples; ++i)
|
||||
{
|
||||
if(i == samples/2)
|
||||
{
|
||||
fprintf(stderr,"a little scan in between\n");
|
||||
mpg123_scan(m);
|
||||
}
|
||||
if(check_sample(so, i) != 0)
|
||||
++errs;
|
||||
}
|
||||
fprintf(stderr,"Check the first one again, seeking back from the end.\n");
|
||||
if(check_sample(so, 0) != 0)
|
||||
++first_sample_errs;
|
||||
|
||||
return errs;
|
||||
}
|
||||
|
||||
int check_seeking(size_t *errs)
|
||||
{
|
||||
struct seeko so;
|
||||
int ret = 0;
|
||||
|
||||
/* First opening. */
|
||||
if(open_file() != 0) return -1;
|
||||
|
||||
fprintf(stderr,"Collecting samples...\n");
|
||||
ret = collect(&so);
|
||||
if(ret != 0) return ret;
|
||||
|
||||
errs[0] = check_positions(&so);
|
||||
|
||||
fprintf(stderr,"With fresh opening (empty seek index):\n");
|
||||
if(open_file() != 0) return -1;
|
||||
|
||||
errs[1] = check_positions(&so);
|
||||
|
||||
fprintf(stderr,"Another fresh Opening to see if first sample works:\n");
|
||||
if(open_file() != 0) return -1;
|
||||
if(check_sample(&so, 0) != 0)
|
||||
++first_sample_errs;
|
||||
|
||||
return ret;
|
||||
}
|
||||
2
src/tests/seek_accuracy.sh
Executable file
2
src/tests/seek_accuracy.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec src/tests/seek_accuracy "$srcdir/src/tests/sweep.mp3"
|
||||
56
src/tests/seek_whence.c
Normal file
56
src/tests/seek_whence.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "compat.h"
|
||||
#include <mpg123.h>
|
||||
#include "debug.h"
|
||||
|
||||
int test_whence(const char* path, int scan_before)
|
||||
{
|
||||
int err = MPG123_OK;
|
||||
mpg123_handle* mh = NULL;
|
||||
off_t length, pos;
|
||||
|
||||
mh = mpg123_new(NULL, &err );
|
||||
if(mh == NULL) return -1;
|
||||
|
||||
err = mpg123_open(mh, path );
|
||||
if(err != MPG123_OK) return -1;
|
||||
|
||||
if(scan_before) mpg123_scan(mh);
|
||||
|
||||
pos = mpg123_seek( mh, 0, SEEK_END);
|
||||
if(pos < 0){ error1("seek failed: %s", mpg123_strerror(mh)); return -1; }
|
||||
|
||||
pos = mpg123_tell(mh);
|
||||
length = mpg123_length(mh);
|
||||
|
||||
/* Later: Read samples and compare different whence values with identical seek positions. */
|
||||
|
||||
mpg123_close(mh);
|
||||
mpg123_delete(mh);
|
||||
|
||||
fprintf(stdout, "length %"OFF_P" vs. pos %"OFF_P"\n", length, pos);
|
||||
|
||||
return (pos == length) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int err = 0, errsum = 0;
|
||||
if(argc < 2)
|
||||
{
|
||||
printf("Gimme a MPEG file name...\n");
|
||||
return 0;
|
||||
}
|
||||
mpg123_init();
|
||||
fprintf(stderr, "End seek without (explicit) scanning: ");
|
||||
err = test_whence(argv[1], 0);
|
||||
fprintf(stdout, "%s\n", err == 0 ? "PASS" : "FAIL");
|
||||
errsum += err;
|
||||
fprintf(stderr, "End seek with explicit scanning: ");
|
||||
err = test_whence(argv[1], 1);
|
||||
fprintf(stdout, "%s\n", err == 0 ? "PASS" : "FAIL");
|
||||
errsum += err;
|
||||
mpg123_exit();
|
||||
printf("%s\n", errsum ? "FAIL" : "PASS");
|
||||
return errsum;
|
||||
}
|
||||
2
src/tests/seek_whence.sh
Executable file
2
src/tests/seek_whence.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
exec src/tests/seek_whence "$srcdir/src/tests/sweep.mp3"
|
||||
BIN
src/tests/sweep.mp3
Normal file
BIN
src/tests/sweep.mp3
Normal file
Binary file not shown.
149
src/tests/sweeper.c
Normal file
149
src/tests/sweeper.c
Normal file
@@ -0,0 +1,149 @@
|
||||
#include <syn123.h>
|
||||
#include <out123.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
static long block_rate(long rate, double speed, double factor, off_t bi)
|
||||
{
|
||||
static long maxrate = -1;
|
||||
if(maxrate < 0)
|
||||
maxrate = syn123_resample_maxrate();
|
||||
double foutrate = (double)rate/(speed*pow(factor, bi));
|
||||
long outrate = foutrate > maxrate ? maxrate : (long)foutrate;
|
||||
return outrate > 0 ? outrate : 1;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
if(argc < 7)
|
||||
{
|
||||
fprintf( stderr
|
||||
, "Usage: %s <rate> <freq> <block> <speed> <speedfactor> <smooth>"
|
||||
" [duration [outfile]]\n"
|
||||
, argv[0] );
|
||||
return 1;
|
||||
}
|
||||
long rate = atol(argv[1]);
|
||||
double freq = atof(argv[2]);
|
||||
long block = atol(argv[3]);
|
||||
double speed = atof(argv[4]);
|
||||
double factor = atof(argv[5]);
|
||||
if(factor < 1e-10)
|
||||
{
|
||||
fprintf(stderr, "Funny. Give me a speed factor properly > 0!\n");
|
||||
return -6;
|
||||
}
|
||||
int smooth = atoi(argv[6]);
|
||||
double duration = argc > 7 ? atof(argv[7]) : 5;
|
||||
// Trivially ensuring that it's > 0, playing a bit longer than required.
|
||||
// Could cut things in the end, if I really care.
|
||||
off_t out_limit = (off_t)(duration*rate)/block+1;
|
||||
char *outfile = argc > 8 ? argv[8] : NULL;
|
||||
syn123_handle *syn = syn123_new(rate, 1, MPG123_ENC_FLOAT_32, 0, NULL);
|
||||
if(!syn)
|
||||
return -1;
|
||||
out123_handle *out = out123_new();
|
||||
if(!out)
|
||||
return -2;
|
||||
if(out123_open(out, outfile ? "wav" : NULL, outfile))
|
||||
return -3;
|
||||
if(out123_start(out, rate, 1, MPG123_ENC_FLOAT_32))
|
||||
return -3;
|
||||
if(syn123_setup_waves(syn, 1, NULL, &freq, NULL, NULL, NULL))
|
||||
return -4;
|
||||
off_t bi = 0;
|
||||
// Biggest output rate to plan for.
|
||||
long firstrate = block_rate(rate, speed, factor, 0);
|
||||
long lastrate = block_rate(rate, speed, factor, (out_limit-1));
|
||||
long maxrate = firstrate > lastrate ? firstrate : lastrate;
|
||||
long minrate = firstrate < lastrate ? firstrate : lastrate;
|
||||
fprintf(stderr, "rate %ld to [%ld;%ld]\n", rate, minrate, maxrate);
|
||||
// Need to add 1 to incount to account for rates in between.
|
||||
// A slightly lower rate than maxrate might cause an increase in
|
||||
// the max incount for that rate, resulting in _more_ outcount
|
||||
// than the lower incount for the maxrate.
|
||||
size_t maxoutblock = syn123_resample_count( rate, maxrate
|
||||
, syn123_resample_incount(rate, maxrate, block)+1 );
|
||||
size_t maxinblock = syn123_resample_incount(rate, minrate, block);
|
||||
fprintf( stderr, "maxinblock %zu, maxoutblock %zu\n"
|
||||
, maxinblock, maxoutblock );
|
||||
if(!maxoutblock || !maxinblock)
|
||||
return -7;
|
||||
float *outbuf = malloc(sizeof(float)*maxoutblock);
|
||||
float *inbuf = malloc(sizeof(float)*maxinblock);
|
||||
if(!outbuf || !inbuf)
|
||||
return -13;
|
||||
|
||||
off_t intotal = 0;
|
||||
off_t outtotal = 0;
|
||||
while(bi < out_limit)
|
||||
{
|
||||
long outrate = block_rate(rate, speed, factor, bi);
|
||||
fprintf(stderr, "block %"OFF_P" rate %ld\n", (off_p)bi, outrate);
|
||||
if(syn123_setup_resample(syn, rate, outrate, 1, 0, smooth))
|
||||
{
|
||||
ret = -11;
|
||||
break;
|
||||
}
|
||||
// Determine how many input samples to feed to get block output samples.
|
||||
ssize_t inblock = syn123_resample_inexpect(syn, block);
|
||||
if(inblock <= 0 || inblock > maxinblock)
|
||||
{
|
||||
fprintf(stderr, "bad inblock: %zd\n", inblock);
|
||||
ret = -15;
|
||||
break;
|
||||
}
|
||||
ssize_t outblock = syn123_resample_expect(syn, inblock);
|
||||
fprintf(stderr, "in %zu out %zu\n", inblock, outblock);
|
||||
if(outblock <= 0 || outblock > maxoutblock || outblock < block)
|
||||
{
|
||||
fprintf(stderr, "bad outblock: %zd\n", outblock);
|
||||
ret = -16;
|
||||
break;
|
||||
}
|
||||
size_t bytes = syn123_read(syn, inbuf, sizeof(float)*inblock);
|
||||
if(bytes != sizeof(float)*inblock)
|
||||
{
|
||||
ret = -14;
|
||||
break;
|
||||
}
|
||||
size_t outsamples = syn123_resample(syn, outbuf, inbuf, inblock);
|
||||
if(outsamples != outblock)
|
||||
{
|
||||
fprintf( stderr, "output prediction wrong in block %"
|
||||
PRIiMAX": %zu != %zu\n", bi, outsamples, outblock );
|
||||
ret = -17;
|
||||
break;
|
||||
}
|
||||
intotal += inblock;
|
||||
outtotal += outblock;
|
||||
//fprintf( stderr, "ratio: %f %"OFF_P":%"OFF_P" to %"OFF_P":%"OFF_P"\n"
|
||||
//, (double)intotal/outtotal, (off_p)intotal
|
||||
//, (off_p)syn123_resample_intotal(rate, outrate, outtotal)
|
||||
//, (off_p)outtotal, (off_p)syn123_resample_total(rate, outrate, intotal) );
|
||||
syn123_amp(outbuf, MPG123_ENC_FLOAT_32, outsamples, syn123_db2lin(-12), 0, NULL, NULL);
|
||||
if(out123_play(out, outbuf, sizeof(float)*outsamples) != sizeof(float)*outsamples)
|
||||
{
|
||||
ret = -10;
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
float spacer[100];
|
||||
if(outsamples)
|
||||
{
|
||||
for(unsigned int i=0; i<sizeof(spacer)/sizeof(float); ++i)
|
||||
spacer[i] = outbuf[outsamples-1];
|
||||
}
|
||||
else
|
||||
memset(spacer, 0, sizeof(spacer));
|
||||
out123_play(out, spacer, sizeof(spacer));
|
||||
#endif
|
||||
++bi;
|
||||
}
|
||||
free(outbuf);
|
||||
free(inbuf);
|
||||
out123_del(out);
|
||||
syn123_del(syn);
|
||||
return ret;
|
||||
}
|
||||
34
src/tests/testtext.h
Normal file
34
src/tests/testtext.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Test strings generated by testtext.sh, using data from test.txt */
|
||||
|
||||
const unsigned char latin1[] =
|
||||
{ 0x47, 0x72, 0x6f, 0xdf, 0x65, 0x72, 0x20, 0x4d, 0xe4, 0x7a, 0x65, 0x6e, 0x2c, 0x20, 0x7a, 0x65, 0x69, 0x67, 0x65, 0x20, 0x64, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x46, 0x6c, 0xfc, 0x67, 0x65, 0x6c, 0x20, 0xf6, 0x66, 0x74, 0x65, 0x72, 0x20, 0x6d, 0x61, 0x6c, 0x21, 0x20, 0x46, 0x61, 0x6b, 0x74, 0x6f, 0x72, 0x20, 0xbc, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x74, 0x65, 0x2e, 0x0a,
|
||||
0x00 };
|
||||
|
||||
const unsigned char cp1252[] =
|
||||
{ 0x47, 0x72, 0x6f, 0xdf, 0x65, 0x72, 0x20, 0x4d, 0xe4, 0x7a, 0x65, 0x6e, 0x2c, 0x20, 0x7a, 0x65, 0x69, 0x67, 0x65, 0x20, 0x64, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x46, 0x6c, 0xfc, 0x67, 0x65, 0x6c, 0x20, 0xf6, 0x66, 0x74, 0x65, 0x72, 0x20, 0x6d, 0x61, 0x6c, 0x21, 0x20, 0x46, 0x61, 0x6b, 0x74, 0x6f, 0x72, 0x20, 0xbc, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x74, 0x65, 0x2e, 0x0a,
|
||||
0x00 };
|
||||
|
||||
const unsigned char utf8[] =
|
||||
{ 0x47, 0x72, 0x6f, 0xc3, 0x9f, 0x65, 0x72, 0x20, 0x4d, 0xc3, 0xa4, 0x7a, 0x65, 0x6e, 0x2c, 0x20, 0x7a, 0x65, 0x69, 0x67, 0x65, 0x20, 0x64, 0x65, 0x69, 0x6e, 0x65, 0x20, 0x46, 0x6c, 0xc3, 0xbc, 0x67, 0x65, 0x6c, 0x20, 0xc3, 0xb6, 0x66, 0x74, 0x65, 0x72, 0x20, 0x6d, 0x61, 0x6c, 0x21, 0x20, 0x46, 0x61, 0x6b, 0x74, 0x6f, 0x72, 0x20, 0xc2, 0xbc, 0x2c, 0x20, 0x62, 0x69, 0x74, 0x74, 0x65, 0x2e, 0x0a,
|
||||
0x00 };
|
||||
|
||||
const unsigned char utf16[] =
|
||||
{ 0xff, 0xfe, 0x47, 0x00, 0x72, 0x00, 0x6f, 0x00, 0xdf, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4d, 0x00, 0xe4, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6c, 0x00, 0xfc, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0xf6, 0x00, 0x66, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x21, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0xbc, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x0a, 0x00,
|
||||
0x00, 0x00 };
|
||||
|
||||
const unsigned char utf16bom_le[] =
|
||||
{ 0xff, 0xfe, 0x47, 0x00, 0x72, 0x00, 0x6f, 0x00, 0xdf, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4d, 0x00, 0xe4, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6c, 0x00, 0xfc, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0xf6, 0x00, 0x66, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x21, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0xbc, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x0a, 0x00,
|
||||
0x00, 0x00 };
|
||||
|
||||
const unsigned char utf16le[] =
|
||||
{ 0x47, 0x00, 0x72, 0x00, 0x6f, 0x00, 0xdf, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4d, 0x00, 0xe4, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6c, 0x00, 0xfc, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0xf6, 0x00, 0x66, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x21, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0xbc, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x0a, 0x00,
|
||||
0x00, 0x00 };
|
||||
|
||||
const unsigned char utf16bom_be[] =
|
||||
{ 0xfe, 0xff, 0x00, 0x47, 0x00, 0x72, 0x00, 0x6f, 0x00, 0xdf, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4d, 0x00, 0xe4, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6c, 0x00, 0xfc, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0xf6, 0x00, 0x66, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x21, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0xbc, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x0a,
|
||||
0x00, 0x00 };
|
||||
|
||||
const unsigned char utf16be[] =
|
||||
{ 0x00, 0x47, 0x00, 0x72, 0x00, 0x6f, 0x00, 0xdf, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x4d, 0x00, 0xe4, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x7a, 0x00, 0x65, 0x00, 0x69, 0x00, 0x67, 0x00, 0x65, 0x00, 0x20, 0x00, 0x64, 0x00, 0x65, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x20, 0x00, 0x46, 0x00, 0x6c, 0x00, 0xfc, 0x00, 0x67, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x20, 0x00, 0xf6, 0x00, 0x66, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x20, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x21, 0x00, 0x20, 0x00, 0x46, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0xbc, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x74, 0x00, 0x65, 0x00, 0x2e, 0x00, 0x0a,
|
||||
0x00, 0x00 };
|
||||
|
||||
36
src/tests/testtext.sh
Executable file
36
src/tests/testtext.sh
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/bin/sh
|
||||
|
||||
testtext="test.txt"
|
||||
|
||||
echo "/* Test strings generated by $0, using data from $testtext */"
|
||||
echo
|
||||
|
||||
for i in latin1 cp1252 utf8 utf16 utf16bom_le utf16le utf16bom_be utf16be
|
||||
do
|
||||
enc=$i
|
||||
bom=
|
||||
case $i in
|
||||
utf16bom_be)
|
||||
enc=utf16be
|
||||
bom="0xfe, 0xff, ";
|
||||
;;
|
||||
utf16bom_le*)
|
||||
enc=utf16le
|
||||
bom="0xff, 0xfe, ";
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "const unsigned char ${i}[] = "
|
||||
echo -n "{ $bom"
|
||||
iconv -f utf8 -t $enc < "$testtext" | hexdump -v -e '1/1 "0x%02x, "'
|
||||
echo
|
||||
case $i in
|
||||
latin1|utf8|cp1252)
|
||||
echo " 0x00 };"
|
||||
;;
|
||||
utf16*)
|
||||
echo " 0x00, 0x00 };"
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
done
|
||||
80
src/tests/text.c
Normal file
80
src/tests/text.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
text: Test text transformations in libmpg123 (conversion to UTF-8).
|
||||
|
||||
copyright 2009 by the mpg123 project - free software under the terms of the LGPL 2.1
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Thomas Orgis
|
||||
|
||||
arguments: decoder testfile.mpeg
|
||||
*/
|
||||
|
||||
#include <mpg123.h>
|
||||
#include <compat.h>
|
||||
|
||||
#include "testtext.h"
|
||||
|
||||
int string_good(mpg123_string *sb)
|
||||
{
|
||||
/* Let's accept additional null bytes... */
|
||||
if(sb->fill >= sizeof(utf8) && memcmp(utf8, sb->p, sizeof(utf8)) == 0
|
||||
&& (sb->fill <= sizeof(utf8) || sb->p[sizeof(utf8)] == 0) )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int check_string(const char* name, enum mpg123_text_encoding enc, const unsigned char* source, size_t source_size)
|
||||
{
|
||||
int ret = 0;
|
||||
mpg123_string sb;
|
||||
mpg123_init_string(&sb);
|
||||
printf("Conversion of %s: ", name);
|
||||
if( mpg123_store_utf8(&sb, enc, source, source_size)
|
||||
&& string_good(&sb) )
|
||||
{
|
||||
printf("PASS\n");
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("FAIL (%"SIZE_P" vs. %"SIZE_P")\n", (size_p)sb.fill, (size_p)sizeof(utf8));
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
mpg123_free_string(&sb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We test: latin1, cp1252, utf8 and all of utf16be/le with and without BOM.
|
||||
Everything should succeed -- except utf16le without BOM. */
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
mpg123_string trans_utf16le;
|
||||
|
||||
mpg123_init_string(&trans_utf16le);
|
||||
|
||||
/* First, all conversions that should work. */
|
||||
ret += check_string("latin1", mpg123_text_latin1, latin1, sizeof(latin1));
|
||||
ret += check_string("cp1252", mpg123_text_cp1252, cp1252, sizeof(cp1252));
|
||||
ret += check_string("utf8", mpg123_text_utf8, utf8, sizeof(utf8));
|
||||
ret += check_string("utf16bom_be", mpg123_text_utf16bom, utf16bom_be, sizeof(utf16bom_be));
|
||||
ret += check_string("utf16bom_le", mpg123_text_utf16, utf16bom_le, sizeof(utf16bom_le));
|
||||
ret += check_string("utf16be", mpg123_text_utf16be, utf16be, sizeof(utf16be));
|
||||
|
||||
/* Now test the non-supported string. */
|
||||
printf("Let's see what happens with a non-BOM little endian UTF-16 string: ");
|
||||
mpg123_store_utf8(&trans_utf16le, mpg123_text_utf16, utf16le, sizeof(utf16le));
|
||||
if(string_good(&trans_utf16le))
|
||||
{
|
||||
++ret;
|
||||
printf("FAIL\n");
|
||||
}
|
||||
else printf("PASS\n");
|
||||
|
||||
mpg123_free_string(&trans_utf16le);
|
||||
|
||||
printf("\n%s\n", ret == 0 ? "PASS" : "FAIL");
|
||||
|
||||
return ret;
|
||||
}
|
||||
196
src/tests/textprint.c
Normal file
196
src/tests/textprint.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
textprint: Test filtering of text before terminal printout.
|
||||
|
||||
copyright 2019-2020 by the mpg123 project
|
||||
free software under the terms of the LGPL 2.1
|
||||
|
||||
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
||||
initially written by Thomas Orgis
|
||||
*/
|
||||
|
||||
#include "mpg123app.h"
|
||||
#include "local.h"
|
||||
|
||||
// A number of UTF-8 strings to test.
|
||||
|
||||
struct test_string
|
||||
{
|
||||
const char* in; // UTF-8 input including control chars etc.
|
||||
const char* ascii; // output reduced to ASCII
|
||||
const char* utf8hack; // output in UTF-8 without controls, hacked
|
||||
const char* utf8full; // output in UTF-8 only including printing chars
|
||||
size_t chars; // number of apparent characters (for utf8hack)
|
||||
size_t width; // proper printing width
|
||||
};
|
||||
|
||||
// const char *bla = "..." is not constant enoug to server as initializer.
|
||||
#define simple_string "Just a plain string without trouble."
|
||||
#define simple_width 36
|
||||
// o-Umlaut and a random Chinese character
|
||||
#define utf_string "St\xc3\xb6rt mein \xe7\x8c\x95?"
|
||||
#define utf_string_ascii "St?rt mein ??"
|
||||
#define utf_width 14
|
||||
#define utf_chars 13
|
||||
|
||||
const struct test_string test_input[] =
|
||||
{
|
||||
{
|
||||
.in=simple_string
|
||||
, .ascii=simple_string
|
||||
, .utf8hack=simple_string
|
||||
, .utf8full=simple_string
|
||||
, .chars=simple_width
|
||||
, .width=simple_width
|
||||
}
|
||||
, {
|
||||
.in="U\xcc\x88""bel\nist mir."
|
||||
, .ascii="U?bel ist mir."
|
||||
, .utf8hack="U\xcc\x88""bel ist mir."
|
||||
, .utf8full="U\xcc\x88""bel ist mir."
|
||||
, .chars=14
|
||||
, .width=13
|
||||
}
|
||||
, {
|
||||
.in=utf_string
|
||||
, .ascii=utf_string_ascii
|
||||
, .utf8hack=utf_string
|
||||
, .utf8full=utf_string
|
||||
, .chars=utf_chars
|
||||
, .width=utf_width
|
||||
}
|
||||
, {
|
||||
.in="Gimme\x0a some\x0a\x0d""con\302\237tr\xc3\xb6l!\x7f\x7f""b \033]0;xtermed\x07"
|
||||
, .ascii="Gimme some contr?l!b ]0;xtermed"
|
||||
, .utf8hack="Gimme some contr\xc3\xb6l!b ]0;xtermed"
|
||||
, .utf8full="Gimme some contr\xc3\xb6l!b ]0;xtermed"
|
||||
, .chars=33
|
||||
, .width=33
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
char *dst = NULL;
|
||||
const size_t test_count = sizeof(test_input)/sizeof(*test_input);
|
||||
int err = 0;
|
||||
|
||||
// First, without any locale check, we should work like in C locale.
|
||||
// Only ASCII is safe.
|
||||
fprintf(stderr, "Testing plain ASCII world.\n");
|
||||
for(size_t t=0; t<test_count; ++t)
|
||||
{
|
||||
int lerr = 0;
|
||||
fprintf(stderr, "string %zu: ", t);
|
||||
size_t w = utf8outstr(&dst, test_input[t].in, 1);
|
||||
size_t l = strlen(test_input[t].ascii);
|
||||
if(!dst)
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(conversion failed) ");
|
||||
}
|
||||
else if(w == l)
|
||||
{
|
||||
if(strcmp(test_input[t].ascii, dst))
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(mismatch) ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(bad length %zu != %zu) ", w, l);
|
||||
}
|
||||
err += lerr;
|
||||
fprintf(stderr, "%s\n", lerr ? "FAIL" : "PASS");
|
||||
}
|
||||
|
||||
// Now, the internal UTF-8 sanitation is employed, assuming no working
|
||||
// locale to help us.
|
||||
utf8env = 1;
|
||||
utf8loc = 0;
|
||||
fprintf(stderr, "Testing hacked UTF-8 world.\n");
|
||||
for(size_t t=0; t<test_count; ++t)
|
||||
{
|
||||
int lerr = 0;
|
||||
fprintf(stderr, "string %zu: ", t);
|
||||
size_t w = utf8outstr(&dst, test_input[t].in, 1);
|
||||
size_t l = test_input[t].chars;
|
||||
if(!dst)
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(conversion failed) ");
|
||||
}
|
||||
else if(w == l)
|
||||
{
|
||||
if(strcmp(test_input[t].utf8hack, dst))
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(mismatch) ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(bad length %zu != %zu) ", w, l);
|
||||
}
|
||||
err += lerr;
|
||||
fprintf(stderr, "%s\n", lerr ? "FAIL" : "PASS");
|
||||
}
|
||||
|
||||
#if defined(HAVE_MBSTOWCS) && defined(HAVE_WCSWIDTH) && \
|
||||
defined(HAVE_ISWPRINT) && defined(HAVE_WCSTOMBS)
|
||||
// Finally, proper UTF-8 handling including iswprint() shall be undertaken.
|
||||
// The test is skipped if there is no UTF-8 locale to work with.
|
||||
utf8env = 0;
|
||||
utf8loc = 0;
|
||||
utf8force = 1;
|
||||
check_locale();
|
||||
if(utf8env && utf8loc)
|
||||
{
|
||||
fprintf(stderr, "Got locale, testing proper workings.\n");
|
||||
for(size_t t=0; t<test_count; ++t)
|
||||
{
|
||||
int lerr = 0;
|
||||
fprintf(stderr, "string %zu: ", t);
|
||||
size_t w = utf8outstr(&dst, test_input[t].in, 1);
|
||||
size_t l = test_input[t].width;
|
||||
if(!dst)
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(conversion failed) ");
|
||||
}
|
||||
else if(w == l)
|
||||
{
|
||||
if(strcmp(test_input[t].utf8full, dst))
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(mismatch) ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++lerr;
|
||||
fprintf(stderr, "(bad length %zu != %zu) ", w, l);
|
||||
}
|
||||
err += lerr;
|
||||
fprintf(stderr, "%s\n", lerr ? "FAIL" : "PASS");
|
||||
fprintf(stderr, "non-terminal non-filtering: ");
|
||||
lerr = 0;
|
||||
w = utf8outstr(&dst, test_input[t].in, 0);
|
||||
if(!dst || strcmp(test_input[t].in, dst))
|
||||
++lerr;
|
||||
err += lerr;
|
||||
fprintf(stderr, "%s\n", lerr ? "FAIL" : "PASS");
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
fprintf(stderr, "Skipped locale-based conversion\n");
|
||||
|
||||
free(dst);
|
||||
|
||||
printf("%s\n", err ? "FAIL" : "PASS");
|
||||
return err ? 1 : 0;
|
||||
}
|
||||
75
src/tests/volume.c
Normal file
75
src/tests/volume.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "syn123.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define AMPTEST(name, bits, wbits, enc) \
|
||||
int name(syn123_handle *sh) \
|
||||
{ \
|
||||
int err = 0; \
|
||||
float factor = 0.5; \
|
||||
fprintf(stderr, "amplification %d bits\n", bits); \
|
||||
int##bits##_t *audio = malloc(bits/8*1<<bits); \
|
||||
size_t clp = 0; \
|
||||
for(int##wbits##_t i=0; i<1<<bits; ++i) \
|
||||
audio[i] = (int##bits##_t)(i-(1<<(bits-1))); \
|
||||
if((err = syn123_amp(audio, enc, 1<<bits, factor, 0., &clp, sh))) \
|
||||
{ \
|
||||
fprintf(stderr, "cannot amp: %s\n", syn123_strerror(err)); \
|
||||
++err; \
|
||||
} \
|
||||
if(clp) \
|
||||
++err; \
|
||||
if(!err) \
|
||||
for(int##wbits##_t i=0; i<1<<bits; ++i) \
|
||||
if(labs((int##wbits##_t)audio[i] - ((i-(1<<(bits-1)))/2)) > 1) \
|
||||
{ \
|
||||
++err; \
|
||||
break; \
|
||||
} \
|
||||
free(audio); \
|
||||
return err ? 1 : 0; \
|
||||
}
|
||||
|
||||
AMPTEST(amptest_8, 8, 16, MPG123_ENC_SIGNED_8)
|
||||
AMPTEST(amptest_16, 16, 32, MPG123_ENC_SIGNED_16)
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
fprintf(stderr, "create handle\n");
|
||||
syn123_handle *sh = syn123_new(1,1,MPG123_ENC_FLOAT_32,0,NULL);
|
||||
if(!sh)
|
||||
{
|
||||
fprintf(stderr, "cannot create syn123 handle\n");
|
||||
++ret;
|
||||
}
|
||||
if(ret)
|
||||
goto end;
|
||||
|
||||
fprintf(stderr, "dB conversion\n");
|
||||
double lin = 0.37283;
|
||||
double db = syn123_lin2db(lin);
|
||||
double ldb = syn123_db2lin(db);
|
||||
if(fabs(ldb-lin) > 1e-15)
|
||||
{
|
||||
fprintf(stderr, "db2lin(lin2db) off by %g\n", ldb-lin);
|
||||
++ret;
|
||||
}
|
||||
db = syn123_lin2db(2);
|
||||
if(fabs(db-6.)>0.05)
|
||||
{
|
||||
fprintf(stderr, "lin2db of factor 2 off by %g", db-6.);
|
||||
++ret;
|
||||
}
|
||||
if(!ret)
|
||||
ret += amptest_8(sh);
|
||||
if(!ret)
|
||||
ret += amptest_16(sh);
|
||||
|
||||
end:
|
||||
syn123_del(sh);
|
||||
printf(ret ? "FAIL\n" : "PASS\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user