1/* 2** Copyright (C) 2009-2015 Erik de Castro Lopo <erikd@mega-nerd.com> 3** 4** All rights reserved. 5** 6** Redistribution and use in source and binary forms, with or without 7** modification, are permitted provided that the following conditions are 8** met: 9** 10** * Redistributions of source code must retain the above copyright 11** notice, this list of conditions and the following disclaimer. 12** * Redistributions in binary form must reproduce the above copyright 13** notice, this list of conditions and the following disclaimer in 14** the documentation and/or other materials provided with the 15** distribution. 16** * Neither the author nor the names of any contributors may be used 17** to endorse or promote products derived from this software without 18** specific prior written permission. 19** 20** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*/ 32 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <sndfile.h> 37 38#include "common.h" 39 40#define BUFFER_LEN 4096 41#define MAX_INPUTS 16 42 43 44typedef struct 45{ SNDFILE * infile [MAX_INPUTS] ; 46 SNDFILE * outfile ; 47 48 union 49 { double d [BUFFER_LEN] ; 50 int i [BUFFER_LEN] ; 51 } din ; 52 53 union 54 55 { double d [MAX_INPUTS * BUFFER_LEN] ; 56 int i [MAX_INPUTS * BUFFER_LEN] ; 57 } dout ; 58 59 int channels ; 60} STATE ; 61 62 63static void print_usage (void) ; 64static void interleave_int (STATE * state) ; 65static void interleave_double (STATE * state) ; 66 67 68int 69main (int argc, char **argv) 70{ STATE *state = NULL ; 71 SF_INFO sfinfo ; 72 int k, double_merge = 0 ; 73 int ret = 1 ; 74 75 if (argc < 5) 76 { if (argc > 1) 77 puts ("\nError : need at least 2 input files.") ; 78 print_usage () ; 79 goto cleanup ; 80 } ; 81 82 if (strcmp (argv [argc - 2], "-o") != 0) 83 { puts ("\nError : second last command line parameter should be '-o'.\n") ; 84 print_usage () ; 85 goto cleanup ; 86 } ; 87 88 if (argc - 3 > MAX_INPUTS) 89 { printf ("\nError : Cannot handle more than %d input channels.\n\n", MAX_INPUTS) ; 90 goto cleanup ; 91 } ; 92 93 state = calloc (1, sizeof (STATE)) ; 94 if (state == NULL) 95 { puts ("\nError : out of memory.\n") ; 96 goto cleanup ; 97 } ; 98 99 memset (&sfinfo, 0, sizeof (sfinfo)) ; 100 101 for (k = 1 ; k < argc - 2 ; k++) 102 { 103 if ((state->infile [k - 1] = sf_open (argv [k], SFM_READ, &sfinfo)) == NULL) 104 { printf ("\nError : Not able to open input file '%s'\n%s\n", argv [k], sf_strerror (NULL)) ; 105 goto cleanup ; 106 } ; 107 108 if (sfinfo.channels != 1) 109 { printf ("\bError : Input file '%s' should be mono (has %d channels).\n", argv [k], sfinfo.channels) ; 110 goto cleanup ; 111 } ; 112 113 switch (sfinfo.format & SF_FORMAT_SUBMASK) 114 { case SF_FORMAT_FLOAT : 115 case SF_FORMAT_DOUBLE : 116 case SF_FORMAT_VORBIS : 117 double_merge = 1 ; 118 break ; 119 120 default : 121 break ; 122 } ; 123 124 state->channels ++ ; 125 } ; 126 127 sfinfo.channels = state->channels ; 128 sfinfo.format = sfe_file_type_of_ext (argv [argc - 1], sfinfo.format) ; 129 130 if ((state->outfile = sf_open (argv [argc - 1], SFM_WRITE, &sfinfo)) == NULL) 131 { printf ("Not able to open output file '%s'\n%s\n", argv [argc - 1], sf_strerror (NULL)) ; 132 goto cleanup ; 133 } ; 134 135 if (double_merge) 136 interleave_double (state) ; 137 else 138 interleave_int (state) ; 139 140 ret = 0 ; 141 142cleanup : 143 144 if (state != NULL) 145 { for (k = 0 ; k < MAX_INPUTS ; k++) 146 if (state->infile [k] != NULL) 147 sf_close (state->infile [k]) ; 148 sf_close (state->outfile) ; 149 } 150 151 free (state) ; 152 153 return ret ; 154} /* main */ 155 156/*------------------------------------------------------------------------------ 157*/ 158 159 160static void 161print_usage (void) 162{ puts ("\nUsage : sndfile-interleave <input 1> <input 2> ... -o <output file>\n") ; 163 puts ("Merge two or more mono files into a single multi-channel file.\n") ; 164 printf ("Using %s.\n\n", sf_version_string ()) ; 165} /* print_usage */ 166 167 168static void 169interleave_int (STATE * state) 170{ int max_read_len, read_len ; 171 int ch, k ; 172 173 do 174 { max_read_len = 0 ; 175 176 for (ch = 0 ; ch < state->channels ; ch ++) 177 { read_len = (int) sf_read_int (state->infile [ch], state->din.i, BUFFER_LEN) ; 178 if (read_len < BUFFER_LEN) 179 memset (state->din.i + read_len, 0, sizeof (state->din.i [0]) * (BUFFER_LEN - read_len)) ; 180 181 for (k = 0 ; k < BUFFER_LEN ; k++) 182 state->dout.i [k * state->channels + ch] = state->din.i [k] ; 183 184 max_read_len = MAX (max_read_len, read_len) ; 185 } ; 186 187 sf_writef_int (state->outfile, state->dout.i, max_read_len) ; 188 } 189 while (max_read_len > 0) ; 190 191} /* interleave_int */ 192 193 194static void 195interleave_double (STATE * state) 196{ int max_read_len, read_len ; 197 int ch, k ; 198 199 do 200 { max_read_len = 0 ; 201 202 for (ch = 0 ; ch < state->channels ; ch ++) 203 { read_len = (int) sf_read_double (state->infile [ch], state->din.d, BUFFER_LEN) ; 204 if (read_len < BUFFER_LEN) 205 memset (state->din.d + read_len, 0, sizeof (state->din.d [0]) * (BUFFER_LEN - read_len)) ; 206 207 for (k = 0 ; k < BUFFER_LEN ; k++) 208 state->dout.d [k * state->channels + ch] = state->din.d [k] ; 209 210 max_read_len = MAX (max_read_len, read_len) ; 211 } ; 212 213 sf_writef_double (state->outfile, state->dout.d, max_read_len) ; 214 } 215 while (max_read_len > 0) ; 216 217} /* interleave_double */ 218