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