1 /*
2 ** Copyright (C) 1999-2014 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	<ctype.h>
37 
38 #include	<sndfile.h>
39 
40 #include	"common.h"
41 
42 #define		BUFFER_LEN	(1 << 16)
43 
44 
45 static void concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels) ;
46 static void concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels) ;
47 
48 static void
usage_exit(const char * progname)49 usage_exit (const char *progname)
50 {
51 	printf ("\nUsage : %s <infile1> <infile2>  ... <outfile>\n\n", progname) ;
52 	puts (
53 		"    Create a new output file <outfile> containing the concatenated\n"
54 		"    audio data from froms <infile1> <infile2> ....\n"
55 		"\n"
56 		"    The joined file will be encoded in the same format as the data\n"
57 		"    in infile1, with all the data in subsequent files automatically\n"
58 		"    converted to the correct encoding.\n"
59 		"\n"
60 		"    The only restriction is that the two files must have the same\n"
61 		"    number of channels.\n"
62 		) ;
63 
64 	exit (1) ;
65 } /* usage_exit */
66 
67 int
main(int argc,char * argv[])68 main (int argc, char *argv [])
69 {	const char	*progname, *outfilename ;
70 	SNDFILE		*outfile, **infiles ;
71 	SF_INFO		sfinfo_out, sfinfo_in ;
72 	void 		(*func) (SNDFILE*, SNDFILE*, int) ;
73 	int			k ;
74 
75 	progname = program_name (argv [0]) ;
76 
77 	if (argc < 4)
78 		usage_exit (progname) ;
79 
80 	argv ++ ;
81 	argc -- ;
82 
83 	argc -- ;
84 	outfilename = argv [argc] ;
85 
86 	if ((infiles = calloc (argc, sizeof (SNDFILE*))) == NULL)
87 	{	printf ("\nError : Malloc failed.\n\n") ;
88 		exit (1) ;
89 		} ;
90 
91 	memset (&sfinfo_in, 0, sizeof (sfinfo_in)) ;
92 
93 	if ((infiles [0] = sf_open (argv [0], SFM_READ, &sfinfo_in)) == NULL)
94 	{	printf ("\nError : failed to open file '%s'.\n\n", argv [0]) ;
95 		exit (1) ;
96 		} ;
97 
98 	sfinfo_out = sfinfo_in ;
99 
100 	for (k = 1 ; k < argc ; k++)
101 	{	if ((infiles [k] = sf_open (argv [k], SFM_READ, &sfinfo_in)) == NULL)
102 		{	printf ("\nError : failed to open file '%s'.\n\n", argv [k]) ;
103 			exit (1) ;
104 			} ;
105 
106 		if (sfinfo_in.channels != sfinfo_out.channels)
107 		{	printf ("\nError : File '%s' has %d channels (should have %d).\n\n", argv [k], sfinfo_in.channels, sfinfo_out.channels) ;
108 			exit (1) ;
109 			} ;
110 		} ;
111 
112 	if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo_out)) == NULL)
113 	{	printf ("\nError : Not able to open input file %s.\n", outfilename) ;
114 		puts (sf_strerror (NULL)) ;
115 		exit (1) ;
116 		} ;
117 
118 	if ((sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE ||
119 			(sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT)
120 		func = concat_data_fp ;
121 	else
122 		func = concat_data_int ;
123 
124 	for (k = 0 ; k < argc ; k++)
125 	{	func (outfile, infiles [k], sfinfo_out.channels) ;
126 		sf_close (infiles [k]) ;
127 		} ;
128 
129 	sf_close (outfile) ;
130 	free (infiles) ;
131 
132 	return 0 ;
133 } /* main */
134 
135 static void
concat_data_fp(SNDFILE * wfile,SNDFILE * rofile,int channels)136 concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels)
137 {	static double	data [BUFFER_LEN] ;
138 	int		frames, readcount ;
139 
140 	frames = BUFFER_LEN / channels ;
141 	readcount = frames ;
142 
143 	sf_seek (wfile, 0, SEEK_END) ;
144 
145 	while (readcount > 0)
146 	{	readcount = sf_readf_double (rofile, data, frames) ;
147 		sf_writef_double (wfile, data, readcount) ;
148 		} ;
149 
150 	return ;
151 } /* concat_data_fp */
152 
153 static void
concat_data_int(SNDFILE * wfile,SNDFILE * rofile,int channels)154 concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels)
155 {	static int	data [BUFFER_LEN] ;
156 	int		frames, readcount ;
157 
158 	frames = BUFFER_LEN / channels ;
159 	readcount = frames ;
160 
161 	sf_seek (wfile, 0, SEEK_END) ;
162 
163 	while (readcount > 0)
164 	{	readcount = sf_readf_int (rofile, data, frames) ;
165 		sf_writef_int (wfile, data, readcount) ;
166 		} ;
167 
168 	return ;
169 } /* concat_data_int */
170 
171