xref: /aosp_15_r20/frameworks/wilhelm/tools/permute/permute.c (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
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