Initial commit of mpg123-1.29.3

This commit is contained in:
Sam Lantinga
2022-05-07 15:47:18 -07:00
commit 01b6013145
352 changed files with 159933 additions and 0 deletions

111
src/tests/Makemodule.am Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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 chars.

View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,2 @@
#!/bin/sh
exec src/tests/seek_whence "$srcdir/src/tests/sweep.mp3"

BIN
src/tests/sweep.mp3 Normal file

Binary file not shown.

149
src/tests/sweeper.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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;
}