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