remove unnecessary sleep
[ardour.git] / tools / sftest.cc
1 /* g++ -o sftest sftest.cc `pkg-config --cflags --libs sndfile` `pkg-config --cflags --libs glibmm-2.4` */
2
3 #include <vector>
4 #include <iostream>
5 #include <iomanip>
6 #include <sstream>
7 #include <cstdlib>
8 #include <unistd.h>
9 #include <sndfile.h>
10 #include <stdint.h>
11 #include <string.h>
12 #include <getopt.h>
13
14 #include <glibmm/miscutils.h>
15
16 using namespace std;
17
18 SF_INFO format_info;
19 float* data = 0;
20 bool with_sync = false;
21
22 int
23 write_one (SNDFILE* sf, uint32_t nframes)
24 {
25         if (sf_write_float (sf, (float*) data, nframes) != nframes) {
26                 return -1;
27         }
28
29         if (with_sync) {
30                 sf_write_sync (sf);
31         }
32
33         return 0;
34 }
35
36 void
37 usage ()
38 {
39         cout << "sftest [ -f HEADER-FORMAT ] [ -F DATA-FORMAT ] [ -r SAMPLERATE ] [ -n NFILES ] [ -b BLOCKSIZE ] [ -s ]" << endl;
40         cout << "\tHEADER-FORMAT is one of:" << endl
41              << "\t\tWAV" << endl
42              << "\t\tCAF" << endl
43              << "\t\tW64" << endl;
44         cout << "\tDATA-FORMAT is one of:" << endl
45              << "\t\tFLOAT" << endl
46              << "\t\t32" << endl
47              << "\t\t24" << endl
48              << "\t\t16" << endl;
49 }
50
51 int
52 main (int argc, char* argv[])
53 {
54         vector<SNDFILE*> sndfiles;
55         uint32_t sample_size;
56         char optstring[] = "f:r:F:n:c:b:s";
57         int channels, samplerate;
58         char const *suffix = ".wav";
59         char const *header_format = "wav";
60         char const *data_format = "float";
61         uint32_t block_size = 64 * 1024;
62         uint32_t nfiles = 100;
63         const struct option longopts[] = {
64                 { "header-format", 1, 0, 'f' },
65                 { "data-format", 1, 0, 'F' },
66                 { "rate", 1, 0, 'r' },
67                 { "nfiles", 1, 0, 'n' },
68                 { "blocksize", 1, 0, 'b' },
69                 { "channels", 1, 0, 'c' },
70                 { "sync", 0, 0, 's' },
71                 { 0, 0, 0, 0 }
72         };
73
74         int option_index = 0;
75         int c = 0;
76         
77         while (1) {
78                 if ((c = getopt_long (argc, argv, optstring, longopts, &option_index)) == -1) {
79                         break;
80                 }
81
82                 switch (c) {
83                 case 'f':
84                         header_format = optarg;
85                         break;
86
87                 case 'F':
88                         data_format = optarg;
89                         break;
90
91                 case 'r':
92                         samplerate = atoi (optarg);
93                         break;
94
95                 case 'n':
96                         nfiles = atoi (optarg);
97                         break;
98
99                 case 'c':
100                         channels = atoi (optarg);
101
102                 case 'b':
103                         block_size = atoi (optarg);
104                         break;
105                 case 's':
106                         with_sync = true;
107                         break;
108
109                 default:
110                         usage ();
111                         return 0;
112                 }
113         }
114
115         /* setup file format */
116         memset (&format_info, 0, sizeof (format_info));
117
118         if (samplerate == 0 || nfiles == 0 || block_size == 0 || channels == 0) {
119                 usage ();
120                 return 1;
121         }
122
123         format_info.samplerate = samplerate;
124         format_info.channels = channels;
125         
126         if (strcasecmp (header_format, "wav") == 0) {
127                 format_info.format |= SF_FORMAT_WAV;
128                 suffix = ".wav";
129         } else if (strcasecmp (header_format, "caf") == 0) {
130                 format_info.format |= SF_FORMAT_CAF;
131                 suffix = ".caf";
132         } else if (strcasecmp (header_format, "w64") == 0) {
133                 format_info.format |= SF_FORMAT_W64;
134                 suffix = ".w64";
135         } else {
136                 usage ();
137                 return 0;
138         }
139
140         if (strcasecmp (data_format, "float") == 0) {
141                 format_info.format |= SF_FORMAT_FLOAT;
142                 sample_size = sizeof (float);
143         } else if (strcasecmp (data_format, "32") == 0) {
144                 format_info.format |= SF_FORMAT_PCM_32;
145                 sample_size = 4;
146         } else if (strcasecmp (data_format, "24") == 0) {
147                 format_info.format |= SF_FORMAT_PCM_24;
148                 sample_size = 3;
149         } else if (strcasecmp (data_format, "16") == 0) {
150                 format_info.format |= SF_FORMAT_PCM_16;
151                 sample_size = 2;
152         } else {
153                 usage ();
154                 return 0;
155         }
156         
157         char tmpdirname[] = "sftest-XXXXXX";
158         g_mkdtemp (tmpdirname);
159
160         for (uint32_t n = 0; n < nfiles; ++n) {
161                 SNDFILE* sf;
162                 string path;
163                 stringstream ss;
164
165                 ss << "sf-";
166                 ss << n;
167                 ss << suffix;
168                 
169                 path = Glib::build_filename (tmpdirname, ss.str());
170                 
171                 if ((sf = sf_open (path.c_str(), SFM_RDWR, &format_info)) == 0) {
172                         cerr << "Could not open file #" << n << " @ " << path << endl;
173                         return 1;
174                 }
175
176                 sndfiles.push_back (sf);
177         }
178
179         cout << nfiles << " files are in " << tmpdirname << endl;
180         cout << "Format is " << suffix << ' ' << channels << " channel" << (channels > 1 ? "s" : "") << " written in chunks of " << block_size << " frames, synced ? " << (with_sync ? "yes" : "no") << endl;
181                 
182         data = new float[block_size*channels];
183         uint64_t written = 0;
184         
185         while (true) {
186                 gint64 before;
187                 before = g_get_monotonic_time();
188                 for (vector<SNDFILE*>::iterator s = sndfiles.begin(); s != sndfiles.end(); ++s) {
189                         if (write_one (*s, block_size)) {
190                                 cerr << "Write failed for file #" << distance (sndfiles.begin(), s) << endl;
191                                 return 1;
192                         }
193                 }
194                 written += block_size;
195                 gint64 elapsed = g_get_monotonic_time() - before;
196                 double bandwidth = (sndfiles.size() * block_size * channels * sample_size) / (elapsed/1000000.0);
197                 double data_minutes = written / (double) (60.0 * 48000.0);
198                 const double data_rate = sndfiles.size() * channels * sample_size * samplerate;
199                 stringstream ds;
200                 ds << setprecision (1) << data_minutes;
201                 
202                 cout << "BW @ " << written << " frames (" << ds.str() << " minutes) = " << (bandwidth/1048576.0) <<  " MB/sec " << bandwidth / data_rate << " x faster than necessary " << endl;
203         }
204
205         return 0;
206 }
207
208