1095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/*
2095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * Copyright (C) 2010 The Android Open Source Project
3095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *
4095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * you may not use this file except in compliance with the License.
6095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * You may obtain a copy of the License at
7095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *
8095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *
10095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * Unless required by applicable law or agreed to in writing, software
11095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * See the License for the specific language governing permissions and
14095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten * limitations under the License.
15095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten */
16095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
17095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Permute is a host tool to randomly permute an audio file.
18095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *  It takes as input an ordinary .wav file and produces as output a
19095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *  permuted .wav file and .map which can be given the seek torture test
20095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *  located in seekTorture.c.  A build prerequisite is libsndfile;
21095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *  see installation instructions at http://www.mega-nerd.com/libsndfile/
22095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *  The format of the .map file is a sequence of lines, each of which is:
23095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *     seek_position_in_ms  duration_in_ms
24095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten */
25095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
26095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
27095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten#include <assert.h>
28095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten#include <stdio.h>
29095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten#include <stdlib.h>
30095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten#include <string.h>
31095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten#include <sndfile.h>
32095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
33095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
34095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Global variables */
35095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
36095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten// command line options
37095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
38095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten// mean length of each segment of the permutation, in seconds
39095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenstatic double meanSegmentLengthSeconds = 5.0;
40095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten// minimum length of each segment of the permutation, in seconds
41095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenstatic double minSegmentLengthSeconds = 1.0;
42095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
43095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
44095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Describes each contiguous segment generated */
45095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
46095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastentypedef struct {
47095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned mFrameStart;
48095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned mFrameLength;
49095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned mPermutedStart;
50095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten} Segment;
51095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
52095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
53095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Global state during the split phase */
54095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
55095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastentypedef struct {
56095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // derived from command line options combined with file properties
57095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned mMinSegmentLengthFrames;
58095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    //unsigned mMeanSegmentLengthFrames;
59095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned mSegmentMax;   // maximum number of segments allowed
60095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned mSegmentCount; // number of segments generated so far
61095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    Segment *mSegmentArray; // storage for the segments [max]
62095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten} State;
63095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
64095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
65095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Called by qsort as the comparison handler */
66095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
67095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenstatic int qsortCompare(const void *x, const void *y)
68095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten{
69095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    const Segment *x_ = (Segment *) x;
70095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    const Segment *y_ = (Segment *) y;
71095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    return x_->mFrameStart - y_->mFrameStart;
72095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten}
73095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
74095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
75095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Split the specified range of frames, using the allowed budget of segments.
76095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten *  Returns the actual number of segments consumed.
77095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten */
78095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
79095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenstatic unsigned split(State *s, unsigned frameStart, unsigned frameLength, unsigned segmentBudget)
80095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten{
81095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (frameLength <= 0)
82095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        return 0;
83095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(segmentBudget > 0);
84095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if ((frameLength <= s->mMinSegmentLengthFrames*2) || (segmentBudget <= 1)) {
85095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        assert(s->mSegmentCount < s->mSegmentMax);
86095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        Segment *seg = &s->mSegmentArray[s->mSegmentCount++];
87095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        seg->mFrameStart = frameStart;
88095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        seg->mFrameLength = frameLength;
89095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        seg->mPermutedStart = ~0;
90095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        return 1;
91095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
92095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // slop is how much wiggle room we have to play with
93095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned slop = frameLength - s->mMinSegmentLengthFrames*2;
94095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(slop > 0);
95095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // choose a random cut point within the slop region
96095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned r = rand() & 0x7FFFFFFF;
97095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned cut = r % slop;
98095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned leftStart = frameStart;
99095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned leftLength = s->mMinSegmentLengthFrames + cut;
100095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned rightStart = frameStart + leftLength;
101095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned rightLength = s->mMinSegmentLengthFrames + (slop - cut);
102095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(leftLength + rightLength == frameLength);
103095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // process the two sides in random order
104095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(segmentBudget >= 2);
105095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned used;
106095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (leftLength <= rightLength) {
107095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        used = split(s, leftStart, leftLength, segmentBudget / 2);
108095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        used += split(s, rightStart, rightLength, segmentBudget - used);
109095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    } else {
110095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        used = split(s, rightStart, rightLength, segmentBudget / 2);
111095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        used += split(s, leftStart, leftLength, segmentBudget - used);
112095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
113095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(used >= 2);
114095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(used <= segmentBudget);
115095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    return used;
116095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten}
117095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
118095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
119095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten/** Permute the specified input file */
120095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
121095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenvoid permute(char *path_in)
122095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten{
123095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
124095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Open the file using libsndfile
125095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    SNDFILE *sf_in;
126095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    SF_INFO sfinfo_in;
127095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sfinfo_in.format = 0;
128095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sf_in = sf_open(path_in, SFM_READ, &sfinfo_in);
129095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (NULL == sf_in) {
130095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        perror(path_in);
131095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        return;
132095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
133095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
134095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Check if it is a supported file format: must be WAV
135095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned type = sfinfo_in.format & SF_FORMAT_TYPEMASK;
136095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    switch (type) {
137095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case SF_FORMAT_WAV:
138095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
139095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    default:
140095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: unsupported type 0x%X\n", path_in, type);
141095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
142095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
143095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
144095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Must be 16-bit signed or 8-bit unsigned PCM
145095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned subtype = sfinfo_in.format & SF_FORMAT_SUBMASK;
146095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned sampleSizeIn = 0;
147095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    switch (subtype) {
148095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case SF_FORMAT_PCM_16:
149095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        sampleSizeIn = 2;
150095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
151095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case SF_FORMAT_PCM_U8:
152095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        sampleSizeIn = 1;
153095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
154095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    default:
155095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: unsupported subtype 0x%X\n", path_in, subtype);
156095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
157095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
158095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // always read shorts
159095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned sampleSizeRead = 2;
160095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
161095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Must be little-endian
162095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned endianness = sfinfo_in.format & SF_FORMAT_ENDMASK;
163095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    switch (endianness) {
164095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case SF_ENDIAN_FILE:
165095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case SF_ENDIAN_LITTLE:
166095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
167095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    default:
168095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: unsupported endianness 0x%X\n", path_in, endianness);
169095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
170095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
171095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
172095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Must be a known sample rate
173095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    switch (sfinfo_in.samplerate) {
174095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 8000:
175095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 11025:
176095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 16000:
177095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 22050:
178095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 32000:
179095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 44100:
180095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 48000:
181095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
182095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    default:
183095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: unsupported sample rate %d\n", path_in, sfinfo_in.samplerate);
184095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
185095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
186095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
187095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Must be either stereo or mono
188095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned frameSizeIn = 0;
189095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned frameSizeRead = 0;
190095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    switch (sfinfo_in.channels) {
191095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 1:
192095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case 2:
193095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        frameSizeIn = sampleSizeIn * sfinfo_in.channels;
194095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        frameSizeRead = sampleSizeRead * sfinfo_in.channels;
195095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
196095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    default:
197095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: unsupported channels %d\n", path_in, sfinfo_in.channels);
198095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
199095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
200095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
201095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Duration must be known
202095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    switch (sfinfo_in.frames) {
203095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case (sf_count_t) 0:
204095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    case (sf_count_t) ~0:
205095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: unsupported frames %d\n", path_in, (int) sfinfo_in.frames);
206095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
207095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    default:
208095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        break;
209095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
210095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
211095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Allocate space to hold the audio data, based on duration
212095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    double durationSeconds = (double) sfinfo_in.frames / (double) sfinfo_in.samplerate;
213095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    State s;
214095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    s.mMinSegmentLengthFrames = minSegmentLengthSeconds * sfinfo_in.samplerate;
215095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (s.mMinSegmentLengthFrames <= 0)
216095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        s.mMinSegmentLengthFrames = 1;
217095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    s.mSegmentMax = durationSeconds / meanSegmentLengthSeconds;
218095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (s.mSegmentMax <= 0)
219095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        s.mSegmentMax = 1;
220095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    s.mSegmentCount = 0;
221095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    s.mSegmentArray = (Segment *) malloc(sizeof(Segment) * s.mSegmentMax);
222095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(s.mSegmentArray != NULL);
223095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned used;
224095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    used = split(&s, 0, sfinfo_in.frames, s.mSegmentMax);
225095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(used <= s.mSegmentMax);
226095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(used == s.mSegmentCount);
227095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
228095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // now permute the segments randomly using a bad algorithm
229095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned i;
230095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    for (i = 0; i < used; ++i) {
231095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        unsigned r = rand() & 0x7FFFFFFF;
232095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        unsigned j = r % used;
233095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        if (j != i) {
234095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            Segment temp = s.mSegmentArray[i];
235095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            s.mSegmentArray[i] = s.mSegmentArray[j];
236095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            s.mSegmentArray[j] = temp;
237095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        }
238095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
239095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
240095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // read the entire file into memory
241095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    void *ptr = malloc(sfinfo_in.frames * frameSizeRead);
242095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(NULL != ptr);
243095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sf_count_t count;
244095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    count = sf_readf_short(sf_in, ptr, sfinfo_in.frames);
245095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (count != sfinfo_in.frames) {
246095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fprintf(stderr, "%s: expected to read %d frames but actually read %d frames\n", path_in,
247095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            (int) sfinfo_in.frames, (int) count);
248095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
249095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
250095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
251095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Create a permuted output file
252095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    char *path_out = malloc(strlen(path_in) + 8);
253095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(path_out != NULL);
254095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    strcpy(path_out, path_in);
255095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    strcat(path_out, ".wav");
256095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    SNDFILE *sf_out;
257095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    SF_INFO sfinfo_out;
258095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    memset(&sfinfo_out, 0, sizeof(SF_INFO));
259095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sfinfo_out.samplerate = sfinfo_in.samplerate;
260095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sfinfo_out.channels = sfinfo_in.channels;
261095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sfinfo_out.format = sfinfo_in.format;
262095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sf_out = sf_open(path_out, SFM_WRITE, &sfinfo_out);
263095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (sf_out == NULL) {
264095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        perror(path_out);
265095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        goto out;
266095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
267095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    unsigned permutedStart = 0;
268095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    for (i = 0; i < used; ++i) {
269095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        s.mSegmentArray[i].mPermutedStart = permutedStart;
270095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        count = sf_writef_short(sf_out, &((short *) ptr)[sfinfo_in.channels * s.mSegmentArray[i]
271095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            .mFrameStart], s.mSegmentArray[i].mFrameLength);
272095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        if (count != s.mSegmentArray[i].mFrameLength) {
273095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            fprintf(stderr, "%s: expected to write %d frames but actually wrote %d frames\n",
274095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                path_out, (int) s.mSegmentArray[i].mFrameLength, (int) count);
275095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            break;
276095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        }
277095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        permutedStart += s.mSegmentArray[i].mFrameLength;
278095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
279095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(permutedStart == sfinfo_in.frames);
280095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sf_close(sf_out);
281095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
282095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // now create a seek map to let us play this back in a reasonable order
283095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    qsort((void *) s.mSegmentArray, used, sizeof(Segment), qsortCompare);
284095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    char *path_map = malloc(strlen(path_in) + 8);
285095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    assert(path_map != NULL);
286095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    strcpy(path_map, path_in);
287095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    strcat(path_map, ".map");
288095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    FILE *fp_map = fopen(path_map, "w");
289095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    if (fp_map == NULL) {
290095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        perror(path_map);
291095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    } else {
292095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        for (i = 0; i < used; ++i)
293095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            fprintf(fp_map, "%u %u\n", (unsigned) ((s.mSegmentArray[i].mPermutedStart * 1000.0) /
294095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                sfinfo_in.samplerate), (unsigned) ((s.mSegmentArray[i].mFrameLength * 1000.0) /
295095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                sfinfo_in.samplerate));
296095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        fclose(fp_map);
297095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
298095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
299095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenout:
300095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    // Close the input file
301095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    sf_close(sf_in);
302095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten}
303095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
304095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
305095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten// main program
306095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
307095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kastenint main(int argc, char **argv)
308095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten{
309095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    int i;
310095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    for (i = 1; i < argc; ++i) {
311095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        char *arg = argv[i];
312095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
313095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        // process command line options
314095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        if (!strncmp(arg, "-m", 2)) {
315095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            double mval = atof(&arg[2]);
316095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            if (mval >= 0.1 && mval <= 1000.0)
317095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                minSegmentLengthSeconds = mval;
318095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            else
319095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                fprintf(stderr, "%s: invalid value %s\n", argv[0], arg);
320095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            continue;
321095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        }
322095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        if (!strncmp(arg, "-s", 2)) {
323095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            double sval = atof(&arg[2]);
324095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            if (sval >= 0.1 && sval <= 1000.0)
325095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                meanSegmentLengthSeconds = sval;
326095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            else
327095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten                fprintf(stderr, "%s: invalid value %s\n", argv[0], arg);
328095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            continue;
329095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        }
330095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        if (!strncmp(arg, "-r", 2)) {
331095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            srand(atoi(&arg[2]));
332095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            continue;
333095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        }
334095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        if (meanSegmentLengthSeconds < minSegmentLengthSeconds)
335095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten            meanSegmentLengthSeconds = minSegmentLengthSeconds * 2.0;
336095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
337095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        // Permute the file
338095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten        permute(arg);
339095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten
340095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    }
341095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten    return EXIT_SUCCESS;
342095ce2204cc75a50d9f1df60d1c8f357209a7c3dGlenn Kasten}
343