1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker *
4*bebae9c0SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker *
8*bebae9c0SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker *
10*bebae9c0SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker */
16*bebae9c0SAndroid Build Coastguard Worker
17*bebae9c0SAndroid Build Coastguard Worker /** Permute is a host tool to randomly permute an audio file.
18*bebae9c0SAndroid Build Coastguard Worker * It takes as input an ordinary .wav file and produces as output a
19*bebae9c0SAndroid Build Coastguard Worker * permuted .wav file and .map which can be given the seek torture test
20*bebae9c0SAndroid Build Coastguard Worker * located in seekTorture.c. A build prerequisite is libsndfile;
21*bebae9c0SAndroid Build Coastguard Worker * see installation instructions at http://www.mega-nerd.com/libsndfile/
22*bebae9c0SAndroid Build Coastguard Worker * The format of the .map file is a sequence of lines, each of which is:
23*bebae9c0SAndroid Build Coastguard Worker * seek_position_in_ms duration_in_ms
24*bebae9c0SAndroid Build Coastguard Worker */
25*bebae9c0SAndroid Build Coastguard Worker
26*bebae9c0SAndroid Build Coastguard Worker
27*bebae9c0SAndroid Build Coastguard Worker #include <assert.h>
28*bebae9c0SAndroid Build Coastguard Worker #include <stdio.h>
29*bebae9c0SAndroid Build Coastguard Worker #include <stdlib.h>
30*bebae9c0SAndroid Build Coastguard Worker #include <string.h>
31*bebae9c0SAndroid Build Coastguard Worker #include <sndfile.h>
32*bebae9c0SAndroid Build Coastguard Worker
33*bebae9c0SAndroid Build Coastguard Worker
34*bebae9c0SAndroid Build Coastguard Worker /** Global variables */
35*bebae9c0SAndroid Build Coastguard Worker
36*bebae9c0SAndroid Build Coastguard Worker // command line options
37*bebae9c0SAndroid Build Coastguard Worker
38*bebae9c0SAndroid Build Coastguard Worker // mean length of each segment of the permutation, in seconds
39*bebae9c0SAndroid Build Coastguard Worker static double meanSegmentLengthSeconds = 5.0;
40*bebae9c0SAndroid Build Coastguard Worker // minimum length of each segment of the permutation, in seconds
41*bebae9c0SAndroid Build Coastguard Worker static double minSegmentLengthSeconds = 1.0;
42*bebae9c0SAndroid Build Coastguard Worker
43*bebae9c0SAndroid Build Coastguard Worker
44*bebae9c0SAndroid Build Coastguard Worker /** Describes each contiguous segment generated */
45*bebae9c0SAndroid Build Coastguard Worker
46*bebae9c0SAndroid Build Coastguard Worker typedef struct {
47*bebae9c0SAndroid Build Coastguard Worker unsigned mFrameStart;
48*bebae9c0SAndroid Build Coastguard Worker unsigned mFrameLength;
49*bebae9c0SAndroid Build Coastguard Worker unsigned mPermutedStart;
50*bebae9c0SAndroid Build Coastguard Worker } Segment;
51*bebae9c0SAndroid Build Coastguard Worker
52*bebae9c0SAndroid Build Coastguard Worker
53*bebae9c0SAndroid Build Coastguard Worker /** Global state during the split phase */
54*bebae9c0SAndroid Build Coastguard Worker
55*bebae9c0SAndroid Build Coastguard Worker typedef struct {
56*bebae9c0SAndroid Build Coastguard Worker // derived from command line options combined with file properties
57*bebae9c0SAndroid Build Coastguard Worker unsigned mMinSegmentLengthFrames;
58*bebae9c0SAndroid Build Coastguard Worker //unsigned mMeanSegmentLengthFrames;
59*bebae9c0SAndroid Build Coastguard Worker unsigned mSegmentMax; // maximum number of segments allowed
60*bebae9c0SAndroid Build Coastguard Worker unsigned mSegmentCount; // number of segments generated so far
61*bebae9c0SAndroid Build Coastguard Worker Segment *mSegmentArray; // storage for the segments [max]
62*bebae9c0SAndroid Build Coastguard Worker } State;
63*bebae9c0SAndroid Build Coastguard Worker
64*bebae9c0SAndroid Build Coastguard Worker
65*bebae9c0SAndroid Build Coastguard Worker /** Called by qsort as the comparison handler */
66*bebae9c0SAndroid Build Coastguard Worker
qsortCompare(const void * x,const void * y)67*bebae9c0SAndroid Build Coastguard Worker static int qsortCompare(const void *x, const void *y)
68*bebae9c0SAndroid Build Coastguard Worker {
69*bebae9c0SAndroid Build Coastguard Worker const Segment *x_ = (Segment *) x;
70*bebae9c0SAndroid Build Coastguard Worker const Segment *y_ = (Segment *) y;
71*bebae9c0SAndroid Build Coastguard Worker return x_->mFrameStart - y_->mFrameStart;
72*bebae9c0SAndroid Build Coastguard Worker }
73*bebae9c0SAndroid Build Coastguard Worker
74*bebae9c0SAndroid Build Coastguard Worker
75*bebae9c0SAndroid Build Coastguard Worker /** Split the specified range of frames, using the allowed budget of segments.
76*bebae9c0SAndroid Build Coastguard Worker * Returns the actual number of segments consumed.
77*bebae9c0SAndroid Build Coastguard Worker */
78*bebae9c0SAndroid Build Coastguard Worker
split(State * s,unsigned frameStart,unsigned frameLength,unsigned segmentBudget)79*bebae9c0SAndroid Build Coastguard Worker static unsigned split(State *s, unsigned frameStart, unsigned frameLength, unsigned segmentBudget)
80*bebae9c0SAndroid Build Coastguard Worker {
81*bebae9c0SAndroid Build Coastguard Worker if (frameLength <= 0)
82*bebae9c0SAndroid Build Coastguard Worker return 0;
83*bebae9c0SAndroid Build Coastguard Worker assert(segmentBudget > 0);
84*bebae9c0SAndroid Build Coastguard Worker if ((frameLength <= s->mMinSegmentLengthFrames*2) || (segmentBudget <= 1)) {
85*bebae9c0SAndroid Build Coastguard Worker assert(s->mSegmentCount < s->mSegmentMax);
86*bebae9c0SAndroid Build Coastguard Worker Segment *seg = &s->mSegmentArray[s->mSegmentCount++];
87*bebae9c0SAndroid Build Coastguard Worker seg->mFrameStart = frameStart;
88*bebae9c0SAndroid Build Coastguard Worker seg->mFrameLength = frameLength;
89*bebae9c0SAndroid Build Coastguard Worker seg->mPermutedStart = ~0;
90*bebae9c0SAndroid Build Coastguard Worker return 1;
91*bebae9c0SAndroid Build Coastguard Worker }
92*bebae9c0SAndroid Build Coastguard Worker // slop is how much wiggle room we have to play with
93*bebae9c0SAndroid Build Coastguard Worker unsigned slop = frameLength - s->mMinSegmentLengthFrames*2;
94*bebae9c0SAndroid Build Coastguard Worker assert(slop > 0);
95*bebae9c0SAndroid Build Coastguard Worker // choose a random cut point within the slop region
96*bebae9c0SAndroid Build Coastguard Worker unsigned r = rand() & 0x7FFFFFFF;
97*bebae9c0SAndroid Build Coastguard Worker unsigned cut = r % slop;
98*bebae9c0SAndroid Build Coastguard Worker unsigned leftStart = frameStart;
99*bebae9c0SAndroid Build Coastguard Worker unsigned leftLength = s->mMinSegmentLengthFrames + cut;
100*bebae9c0SAndroid Build Coastguard Worker unsigned rightStart = frameStart + leftLength;
101*bebae9c0SAndroid Build Coastguard Worker unsigned rightLength = s->mMinSegmentLengthFrames + (slop - cut);
102*bebae9c0SAndroid Build Coastguard Worker assert(leftLength + rightLength == frameLength);
103*bebae9c0SAndroid Build Coastguard Worker // process the two sides in random order
104*bebae9c0SAndroid Build Coastguard Worker assert(segmentBudget >= 2);
105*bebae9c0SAndroid Build Coastguard Worker unsigned used;
106*bebae9c0SAndroid Build Coastguard Worker if (leftLength <= rightLength) {
107*bebae9c0SAndroid Build Coastguard Worker used = split(s, leftStart, leftLength, segmentBudget / 2);
108*bebae9c0SAndroid Build Coastguard Worker used += split(s, rightStart, rightLength, segmentBudget - used);
109*bebae9c0SAndroid Build Coastguard Worker } else {
110*bebae9c0SAndroid Build Coastguard Worker used = split(s, rightStart, rightLength, segmentBudget / 2);
111*bebae9c0SAndroid Build Coastguard Worker used += split(s, leftStart, leftLength, segmentBudget - used);
112*bebae9c0SAndroid Build Coastguard Worker }
113*bebae9c0SAndroid Build Coastguard Worker assert(used >= 2);
114*bebae9c0SAndroid Build Coastguard Worker assert(used <= segmentBudget);
115*bebae9c0SAndroid Build Coastguard Worker return used;
116*bebae9c0SAndroid Build Coastguard Worker }
117*bebae9c0SAndroid Build Coastguard Worker
118*bebae9c0SAndroid Build Coastguard Worker
119*bebae9c0SAndroid Build Coastguard Worker /** Permute the specified input file */
120*bebae9c0SAndroid Build Coastguard Worker
permute(char * path_in)121*bebae9c0SAndroid Build Coastguard Worker void permute(char *path_in)
122*bebae9c0SAndroid Build Coastguard Worker {
123*bebae9c0SAndroid Build Coastguard Worker
124*bebae9c0SAndroid Build Coastguard Worker // Open the file using libsndfile
125*bebae9c0SAndroid Build Coastguard Worker SNDFILE *sf_in;
126*bebae9c0SAndroid Build Coastguard Worker SF_INFO sfinfo_in;
127*bebae9c0SAndroid Build Coastguard Worker sfinfo_in.format = 0;
128*bebae9c0SAndroid Build Coastguard Worker sf_in = sf_open(path_in, SFM_READ, &sfinfo_in);
129*bebae9c0SAndroid Build Coastguard Worker if (NULL == sf_in) {
130*bebae9c0SAndroid Build Coastguard Worker perror(path_in);
131*bebae9c0SAndroid Build Coastguard Worker return;
132*bebae9c0SAndroid Build Coastguard Worker }
133*bebae9c0SAndroid Build Coastguard Worker
134*bebae9c0SAndroid Build Coastguard Worker // Check if it is a supported file format: must be WAV
135*bebae9c0SAndroid Build Coastguard Worker unsigned type = sfinfo_in.format & SF_FORMAT_TYPEMASK;
136*bebae9c0SAndroid Build Coastguard Worker switch (type) {
137*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_WAV:
138*bebae9c0SAndroid Build Coastguard Worker break;
139*bebae9c0SAndroid Build Coastguard Worker default:
140*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: unsupported type 0x%X\n", path_in, type);
141*bebae9c0SAndroid Build Coastguard Worker goto out;
142*bebae9c0SAndroid Build Coastguard Worker }
143*bebae9c0SAndroid Build Coastguard Worker
144*bebae9c0SAndroid Build Coastguard Worker #if 0
145*bebae9c0SAndroid Build Coastguard Worker // Must be 16-bit signed or 8-bit unsigned PCM
146*bebae9c0SAndroid Build Coastguard Worker unsigned subtype = sfinfo_in.format & SF_FORMAT_SUBMASK;
147*bebae9c0SAndroid Build Coastguard Worker unsigned sampleSizeIn = 0;
148*bebae9c0SAndroid Build Coastguard Worker switch (subtype) {
149*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_PCM_16:
150*bebae9c0SAndroid Build Coastguard Worker sampleSizeIn = 2;
151*bebae9c0SAndroid Build Coastguard Worker break;
152*bebae9c0SAndroid Build Coastguard Worker case SF_FORMAT_PCM_U8:
153*bebae9c0SAndroid Build Coastguard Worker sampleSizeIn = 1;
154*bebae9c0SAndroid Build Coastguard Worker break;
155*bebae9c0SAndroid Build Coastguard Worker default:
156*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: unsupported subtype 0x%X\n", path_in, subtype);
157*bebae9c0SAndroid Build Coastguard Worker goto out;
158*bebae9c0SAndroid Build Coastguard Worker }
159*bebae9c0SAndroid Build Coastguard Worker #endif
160*bebae9c0SAndroid Build Coastguard Worker // always read shorts
161*bebae9c0SAndroid Build Coastguard Worker unsigned sampleSizeRead = 2;
162*bebae9c0SAndroid Build Coastguard Worker
163*bebae9c0SAndroid Build Coastguard Worker // Must be little-endian
164*bebae9c0SAndroid Build Coastguard Worker unsigned endianness = sfinfo_in.format & SF_FORMAT_ENDMASK;
165*bebae9c0SAndroid Build Coastguard Worker switch (endianness) {
166*bebae9c0SAndroid Build Coastguard Worker case SF_ENDIAN_FILE:
167*bebae9c0SAndroid Build Coastguard Worker case SF_ENDIAN_LITTLE:
168*bebae9c0SAndroid Build Coastguard Worker break;
169*bebae9c0SAndroid Build Coastguard Worker default:
170*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: unsupported endianness 0x%X\n", path_in, endianness);
171*bebae9c0SAndroid Build Coastguard Worker goto out;
172*bebae9c0SAndroid Build Coastguard Worker }
173*bebae9c0SAndroid Build Coastguard Worker
174*bebae9c0SAndroid Build Coastguard Worker // Must be a known sample rate
175*bebae9c0SAndroid Build Coastguard Worker switch (sfinfo_in.samplerate) {
176*bebae9c0SAndroid Build Coastguard Worker case 8000:
177*bebae9c0SAndroid Build Coastguard Worker case 11025:
178*bebae9c0SAndroid Build Coastguard Worker case 16000:
179*bebae9c0SAndroid Build Coastguard Worker case 22050:
180*bebae9c0SAndroid Build Coastguard Worker case 32000:
181*bebae9c0SAndroid Build Coastguard Worker case 44100:
182*bebae9c0SAndroid Build Coastguard Worker case 48000:
183*bebae9c0SAndroid Build Coastguard Worker break;
184*bebae9c0SAndroid Build Coastguard Worker default:
185*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: unsupported sample rate %d\n", path_in, sfinfo_in.samplerate);
186*bebae9c0SAndroid Build Coastguard Worker goto out;
187*bebae9c0SAndroid Build Coastguard Worker }
188*bebae9c0SAndroid Build Coastguard Worker
189*bebae9c0SAndroid Build Coastguard Worker // Must be either stereo or mono
190*bebae9c0SAndroid Build Coastguard Worker unsigned frameSizeRead = 0;
191*bebae9c0SAndroid Build Coastguard Worker switch (sfinfo_in.channels) {
192*bebae9c0SAndroid Build Coastguard Worker case 1:
193*bebae9c0SAndroid Build Coastguard Worker case 2:
194*bebae9c0SAndroid Build Coastguard Worker frameSizeRead = sampleSizeRead * sfinfo_in.channels;
195*bebae9c0SAndroid Build Coastguard Worker break;
196*bebae9c0SAndroid Build Coastguard Worker default:
197*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: unsupported channels %d\n", path_in, sfinfo_in.channels);
198*bebae9c0SAndroid Build Coastguard Worker goto out;
199*bebae9c0SAndroid Build Coastguard Worker }
200*bebae9c0SAndroid Build Coastguard Worker
201*bebae9c0SAndroid Build Coastguard Worker // Duration must be known
202*bebae9c0SAndroid Build Coastguard Worker switch (sfinfo_in.frames) {
203*bebae9c0SAndroid Build Coastguard Worker case (sf_count_t) 0:
204*bebae9c0SAndroid Build Coastguard Worker case (sf_count_t) ~0:
205*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: unsupported frames %d\n", path_in, (int) sfinfo_in.frames);
206*bebae9c0SAndroid Build Coastguard Worker goto out;
207*bebae9c0SAndroid Build Coastguard Worker default:
208*bebae9c0SAndroid Build Coastguard Worker break;
209*bebae9c0SAndroid Build Coastguard Worker }
210*bebae9c0SAndroid Build Coastguard Worker
211*bebae9c0SAndroid Build Coastguard Worker // Allocate space to hold the audio data, based on duration
212*bebae9c0SAndroid Build Coastguard Worker double durationSeconds = (double) sfinfo_in.frames / (double) sfinfo_in.samplerate;
213*bebae9c0SAndroid Build Coastguard Worker State s;
214*bebae9c0SAndroid Build Coastguard Worker s.mMinSegmentLengthFrames = minSegmentLengthSeconds * sfinfo_in.samplerate;
215*bebae9c0SAndroid Build Coastguard Worker if (s.mMinSegmentLengthFrames <= 0)
216*bebae9c0SAndroid Build Coastguard Worker s.mMinSegmentLengthFrames = 1;
217*bebae9c0SAndroid Build Coastguard Worker s.mSegmentMax = durationSeconds / meanSegmentLengthSeconds;
218*bebae9c0SAndroid Build Coastguard Worker if (s.mSegmentMax <= 0)
219*bebae9c0SAndroid Build Coastguard Worker s.mSegmentMax = 1;
220*bebae9c0SAndroid Build Coastguard Worker s.mSegmentCount = 0;
221*bebae9c0SAndroid Build Coastguard Worker s.mSegmentArray = (Segment *) malloc(sizeof(Segment) * s.mSegmentMax);
222*bebae9c0SAndroid Build Coastguard Worker assert(s.mSegmentArray != NULL);
223*bebae9c0SAndroid Build Coastguard Worker unsigned used;
224*bebae9c0SAndroid Build Coastguard Worker used = split(&s, 0, sfinfo_in.frames, s.mSegmentMax);
225*bebae9c0SAndroid Build Coastguard Worker assert(used <= s.mSegmentMax);
226*bebae9c0SAndroid Build Coastguard Worker assert(used == s.mSegmentCount);
227*bebae9c0SAndroid Build Coastguard Worker
228*bebae9c0SAndroid Build Coastguard Worker // now permute the segments randomly using a bad algorithm
229*bebae9c0SAndroid Build Coastguard Worker unsigned i;
230*bebae9c0SAndroid Build Coastguard Worker for (i = 0; i < used; ++i) {
231*bebae9c0SAndroid Build Coastguard Worker unsigned r = rand() & 0x7FFFFFFF;
232*bebae9c0SAndroid Build Coastguard Worker unsigned j = r % used;
233*bebae9c0SAndroid Build Coastguard Worker if (j != i) {
234*bebae9c0SAndroid Build Coastguard Worker Segment temp = s.mSegmentArray[i];
235*bebae9c0SAndroid Build Coastguard Worker s.mSegmentArray[i] = s.mSegmentArray[j];
236*bebae9c0SAndroid Build Coastguard Worker s.mSegmentArray[j] = temp;
237*bebae9c0SAndroid Build Coastguard Worker }
238*bebae9c0SAndroid Build Coastguard Worker }
239*bebae9c0SAndroid Build Coastguard Worker
240*bebae9c0SAndroid Build Coastguard Worker // read the entire file into memory
241*bebae9c0SAndroid Build Coastguard Worker void *ptr = malloc(sfinfo_in.frames * frameSizeRead);
242*bebae9c0SAndroid Build Coastguard Worker assert(NULL != ptr);
243*bebae9c0SAndroid Build Coastguard Worker sf_count_t count;
244*bebae9c0SAndroid Build Coastguard Worker count = sf_readf_short(sf_in, ptr, sfinfo_in.frames);
245*bebae9c0SAndroid Build Coastguard Worker if (count != sfinfo_in.frames) {
246*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: expected to read %d frames but actually read %d frames\n", path_in,
247*bebae9c0SAndroid Build Coastguard Worker (int) sfinfo_in.frames, (int) count);
248*bebae9c0SAndroid Build Coastguard Worker goto out;
249*bebae9c0SAndroid Build Coastguard Worker }
250*bebae9c0SAndroid Build Coastguard Worker
251*bebae9c0SAndroid Build Coastguard Worker // Create a permuted output file
252*bebae9c0SAndroid Build Coastguard Worker char *path_out = malloc(strlen(path_in) + 8);
253*bebae9c0SAndroid Build Coastguard Worker assert(path_out != NULL);
254*bebae9c0SAndroid Build Coastguard Worker strcpy(path_out, path_in);
255*bebae9c0SAndroid Build Coastguard Worker strcat(path_out, ".wav");
256*bebae9c0SAndroid Build Coastguard Worker SNDFILE *sf_out;
257*bebae9c0SAndroid Build Coastguard Worker SF_INFO sfinfo_out;
258*bebae9c0SAndroid Build Coastguard Worker memset(&sfinfo_out, 0, sizeof(SF_INFO));
259*bebae9c0SAndroid Build Coastguard Worker sfinfo_out.samplerate = sfinfo_in.samplerate;
260*bebae9c0SAndroid Build Coastguard Worker sfinfo_out.channels = sfinfo_in.channels;
261*bebae9c0SAndroid Build Coastguard Worker sfinfo_out.format = sfinfo_in.format;
262*bebae9c0SAndroid Build Coastguard Worker sf_out = sf_open(path_out, SFM_WRITE, &sfinfo_out);
263*bebae9c0SAndroid Build Coastguard Worker if (sf_out == NULL) {
264*bebae9c0SAndroid Build Coastguard Worker perror(path_out);
265*bebae9c0SAndroid Build Coastguard Worker goto out;
266*bebae9c0SAndroid Build Coastguard Worker }
267*bebae9c0SAndroid Build Coastguard Worker unsigned permutedStart = 0;
268*bebae9c0SAndroid Build Coastguard Worker for (i = 0; i < used; ++i) {
269*bebae9c0SAndroid Build Coastguard Worker s.mSegmentArray[i].mPermutedStart = permutedStart;
270*bebae9c0SAndroid Build Coastguard Worker count = sf_writef_short(sf_out, &((short *) ptr)[sfinfo_in.channels * s.mSegmentArray[i]
271*bebae9c0SAndroid Build Coastguard Worker .mFrameStart], s.mSegmentArray[i].mFrameLength);
272*bebae9c0SAndroid Build Coastguard Worker if (count != s.mSegmentArray[i].mFrameLength) {
273*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: expected to write %d frames but actually wrote %d frames\n",
274*bebae9c0SAndroid Build Coastguard Worker path_out, (int) s.mSegmentArray[i].mFrameLength, (int) count);
275*bebae9c0SAndroid Build Coastguard Worker break;
276*bebae9c0SAndroid Build Coastguard Worker }
277*bebae9c0SAndroid Build Coastguard Worker permutedStart += s.mSegmentArray[i].mFrameLength;
278*bebae9c0SAndroid Build Coastguard Worker }
279*bebae9c0SAndroid Build Coastguard Worker assert(permutedStart == sfinfo_in.frames);
280*bebae9c0SAndroid Build Coastguard Worker sf_close(sf_out);
281*bebae9c0SAndroid Build Coastguard Worker
282*bebae9c0SAndroid Build Coastguard Worker // now create a seek map to let us play this back in a reasonable order
283*bebae9c0SAndroid Build Coastguard Worker qsort((void *) s.mSegmentArray, used, sizeof(Segment), qsortCompare);
284*bebae9c0SAndroid Build Coastguard Worker char *path_map = malloc(strlen(path_in) + 8);
285*bebae9c0SAndroid Build Coastguard Worker assert(path_map != NULL);
286*bebae9c0SAndroid Build Coastguard Worker strcpy(path_map, path_in);
287*bebae9c0SAndroid Build Coastguard Worker strcat(path_map, ".map");
288*bebae9c0SAndroid Build Coastguard Worker FILE *fp_map = fopen(path_map, "w");
289*bebae9c0SAndroid Build Coastguard Worker if (fp_map == NULL) {
290*bebae9c0SAndroid Build Coastguard Worker perror(path_map);
291*bebae9c0SAndroid Build Coastguard Worker } else {
292*bebae9c0SAndroid Build Coastguard Worker for (i = 0; i < used; ++i)
293*bebae9c0SAndroid Build Coastguard Worker fprintf(fp_map, "%u %u\n", (unsigned) ((s.mSegmentArray[i].mPermutedStart * 1000.0) /
294*bebae9c0SAndroid Build Coastguard Worker sfinfo_in.samplerate), (unsigned) ((s.mSegmentArray[i].mFrameLength * 1000.0) /
295*bebae9c0SAndroid Build Coastguard Worker sfinfo_in.samplerate));
296*bebae9c0SAndroid Build Coastguard Worker fclose(fp_map);
297*bebae9c0SAndroid Build Coastguard Worker }
298*bebae9c0SAndroid Build Coastguard Worker
299*bebae9c0SAndroid Build Coastguard Worker out:
300*bebae9c0SAndroid Build Coastguard Worker // Close the input file
301*bebae9c0SAndroid Build Coastguard Worker sf_close(sf_in);
302*bebae9c0SAndroid Build Coastguard Worker }
303*bebae9c0SAndroid Build Coastguard Worker
304*bebae9c0SAndroid Build Coastguard Worker
305*bebae9c0SAndroid Build Coastguard Worker // main program
306*bebae9c0SAndroid Build Coastguard Worker
main(int argc,char ** argv)307*bebae9c0SAndroid Build Coastguard Worker int main(int argc, char **argv)
308*bebae9c0SAndroid Build Coastguard Worker {
309*bebae9c0SAndroid Build Coastguard Worker int i;
310*bebae9c0SAndroid Build Coastguard Worker for (i = 1; i < argc; ++i) {
311*bebae9c0SAndroid Build Coastguard Worker char *arg = argv[i];
312*bebae9c0SAndroid Build Coastguard Worker
313*bebae9c0SAndroid Build Coastguard Worker // process command line options
314*bebae9c0SAndroid Build Coastguard Worker if (!strncmp(arg, "-m", 2)) {
315*bebae9c0SAndroid Build Coastguard Worker double mval = atof(&arg[2]);
316*bebae9c0SAndroid Build Coastguard Worker if (mval >= 0.1 && mval <= 1000.0)
317*bebae9c0SAndroid Build Coastguard Worker minSegmentLengthSeconds = mval;
318*bebae9c0SAndroid Build Coastguard Worker else
319*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: invalid value %s\n", argv[0], arg);
320*bebae9c0SAndroid Build Coastguard Worker continue;
321*bebae9c0SAndroid Build Coastguard Worker }
322*bebae9c0SAndroid Build Coastguard Worker if (!strncmp(arg, "-s", 2)) {
323*bebae9c0SAndroid Build Coastguard Worker double sval = atof(&arg[2]);
324*bebae9c0SAndroid Build Coastguard Worker if (sval >= 0.1 && sval <= 1000.0)
325*bebae9c0SAndroid Build Coastguard Worker meanSegmentLengthSeconds = sval;
326*bebae9c0SAndroid Build Coastguard Worker else
327*bebae9c0SAndroid Build Coastguard Worker fprintf(stderr, "%s: invalid value %s\n", argv[0], arg);
328*bebae9c0SAndroid Build Coastguard Worker continue;
329*bebae9c0SAndroid Build Coastguard Worker }
330*bebae9c0SAndroid Build Coastguard Worker if (!strncmp(arg, "-r", 2)) {
331*bebae9c0SAndroid Build Coastguard Worker srand(atoi(&arg[2]));
332*bebae9c0SAndroid Build Coastguard Worker continue;
333*bebae9c0SAndroid Build Coastguard Worker }
334*bebae9c0SAndroid Build Coastguard Worker if (meanSegmentLengthSeconds < minSegmentLengthSeconds)
335*bebae9c0SAndroid Build Coastguard Worker meanSegmentLengthSeconds = minSegmentLengthSeconds * 2.0;
336*bebae9c0SAndroid Build Coastguard Worker
337*bebae9c0SAndroid Build Coastguard Worker // Permute the file
338*bebae9c0SAndroid Build Coastguard Worker permute(arg);
339*bebae9c0SAndroid Build Coastguard Worker
340*bebae9c0SAndroid Build Coastguard Worker }
341*bebae9c0SAndroid Build Coastguard Worker return EXIT_SUCCESS;
342*bebae9c0SAndroid Build Coastguard Worker }
343