1 /* SoX Resampler Library      Copyright (c) 2007-16 robs@users.sourceforge.net
2  * Licence for this file: LGPL v2.1                  See LICENCE for details. */
3 
4 #include <soxr.h>
5 #include "rint.h"
6 #include "../examples/examples-common.h"
7 
8 #define k 1000
9 
10 #if defined _WIN32
11   #define WIN32_LEAN_AND_MEAN
12   #include <windows.h>
13   #define timerStart(msecs) LARGE_INTEGER start, stop, tmp; \
14       QueryPerformanceCounter(&start), QueryPerformanceFrequency(&tmp), \
15       stop.QuadPart = (msecs * tmp.QuadPart + k/2) / k
16   #define timerRunning() (QueryPerformanceCounter(&tmp), \
17       (tmp.QuadPart-start.QuadPart < stop.QuadPart))
18 #else
19   #include <sys/time.h>
20   #if defined timeradd
21     #define K k
22     #define tv_frac tv_usec
23     #define timespec timeval
24     #define get_time(x) gettimeofday(x, NULL)
25   #else
26     #include <time.h>
27     #include <unistd.h>
28     #if defined _POSIX_TIMERS && _POSIX_TIMERS > 0
29       #define K (k*k)
30       #define tv_frac tv_nsec
31       #if defined _POSIX_MONOTONIC_CLOCK
32         #define get_time(x) clock_gettime(CLOCK_MONOTONIC, x)
33       #else
34         #define get_time(x) clock_gettime(CLOCK_REALTIME, x)
35       #endif
36     #else
37       #include <sys/timeb.h>
38       #define K 1
39       #define tv_frac millitm
40       #define tv_sec time
41       #define timespec timeb
42       #define get_time(x) ftime(x)
43     #endif
44   #endif
45 
46   #define timerStart(msecs) struct timespec stop, tmp; get_time(&stop), \
47       stop.tv_frac += (msecs%k)*K, \
48       stop.tv_sec  += msecs/k + stop.tv_frac/(K*k), \
49       stop.tv_frac %= K*k
50   #define timerRunning() (get_time(&tmp), \
51       (tmp.tv_sec < stop.tv_sec || tmp.tv_frac < stop.tv_frac))
52 #endif
53 
main(int n,char const * arg[])54 int main(int n, char const * arg[])
55 {
56   char const *     const arg0 = n? --n, *arg++ : "", * engine = "";
57   double          const irate = n? --n, atof(*arg++) : 96000.;
58   double          const orate = n? --n, atof(*arg++) : 44100.;
59   unsigned        const chans = n? --n, (unsigned)atoi(*arg++) : 1;
60   soxr_datatype_t const itype = n? --n, (soxr_datatype_t)atoi(*arg++) : 0;
61   unsigned        const ospec = n? --n, (soxr_datatype_t)atoi(*arg++) : 0;
62   unsigned long const q_recipe= n? --n, strtoul(*arg++, 0, 16) : SOXR_HQ;
63   unsigned long const q_flags = n? --n, strtoul(*arg++, 0, 16) : 0;
64   double   const passband_end = n? --n, atof(*arg++) : 0;
65   double const stopband_begin = n? --n, atof(*arg++) : 0;
66   double const phase_response = n? --n, atof(*arg++) : -1;
67   int       const use_threads = n? --n, atoi(*arg++) : 1;
68   soxr_datatype_t const otype = ospec & 3;
69 
70   soxr_quality_spec_t       q_spec = soxr_quality_spec(q_recipe, q_flags);
71   soxr_io_spec_t            io_spec = soxr_io_spec(itype, otype);
72   soxr_runtime_spec_t const runtime_spec = soxr_runtime_spec(!use_threads);
73 
74   /* Allocate resampling input and output buffers in proportion to the input
75    * and output rates: */
76   #define buf_total_len 15000  /* In samples per channel. */
77   size_t const osize = soxr_datatype_size(otype) * chans;
78   size_t const isize = soxr_datatype_size(itype) * chans;
79   size_t const olen0= (size_t)(orate * buf_total_len / (irate + orate) + .5);
80   size_t const olen = min(max(olen0, 1), buf_total_len - 1);
81   size_t const ilen = buf_total_len - olen;
82   void * const obuf = malloc(osize * olen);
83   void * const ibuf = malloc(isize * ilen);
84 
85   size_t odone = 0, clips = 0, omax = 0, i;
86   soxr_error_t error;
87   soxr_t soxr;
88   int32_t seed = 0;
89   char const * e = getenv("SOXR_THROUGHPUT_GAIN");
90   double gain = e? atof(e) : .5;
91 
92   /* Overrides (if given): */
93   if (passband_end   > 0) q_spec.passband_end   = passband_end / 100;
94   if (stopband_begin > 0) q_spec.stopband_begin = stopband_begin / 100;
95   if (phase_response >=0) q_spec.phase_response = phase_response;
96   io_spec.flags = ospec & ~7u;
97 
98   /* Create a stream resampler: */
99   soxr = soxr_create(
100       irate, orate, chans,         /* Input rate, output rate, # of channels. */
101       &error,                         /* To report any error during creation. */
102       &io_spec, &q_spec, &runtime_spec);
103 
104 #define ranqd1(x) ((x) = 1664525 * (x) + 1013904223) /* int32_t x */
105 #define dranqd1(x) (ranqd1(x) * (1. / (65536. * 32768.))) /* [-1,1) */
106 #define RAND (dranqd1(seed) * gain)
107 #define DURATION_MSECS 125
108 #define NUM_ATTEMPTS 8
109 
110   if (!error) {                         /* If all is well, run the resampler: */
111     engine = soxr_engine(soxr);
112     switch (itype & 3) {
113       case 0: for (i=0;i<ilen*chans; ((float   *)ibuf)[i]=(float  )RAND, ++i); break;
114       case 1: for (i=0;i<ilen*chans; ((double  *)ibuf)[i]=(double )RAND, ++i); break;
115       case 2: for (i=0;i<ilen*chans; ((int32_t *)ibuf)[i]=rint32(65536.*32768*RAND), ++i); break;
116       case 3: for (i=0;i<ilen*chans; ((int16_t *)ibuf)[i]=rint16(    1.*32768*RAND), ++i); break;
117     }
118                                                        /* Resample in blocks: */
119     for (i=0; i<NUM_ATTEMPTS; ++i) {
120       size_t itotal = 0, ototal = 0;
121       timerStart(DURATION_MSECS);
122       do {
123         size_t const ilen1 = odone < olen? ilen : 0;
124         error = soxr_process(soxr, ibuf, ilen1, NULL, obuf, olen, &odone);
125         itotal += ilen1;
126         ototal += odone;
127       } while (!error && timerRunning());
128       omax = max(omax, ototal);
129     }
130   }
131                                                                   /* Tidy up: */
132   clips = *soxr_num_clips(soxr);     /* Can occur only with integer output. */
133   soxr_delete(soxr);
134   free(obuf), free(ibuf);
135                                                               /* Diagnostics: */
136   fprintf(stderr, "%-26s %s; %lu clips; I/O: %s (%-5s) %.2f Ms/s\n",
137       arg0, soxr_strerror(error), (long unsigned)clips,
138       ferror(stdin) || ferror(stdout)? strerror(errno) : "no error", engine,
139       1e-6 * k / DURATION_MSECS * chans * (double)omax);
140   return !!error;
141 }
142