sndfile-deinterleave.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. ** Copyright (C) 2009-2017 Erik de Castro Lopo <[email protected]>
  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. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sndfile.h>
  36. #include "common.h"
  37. #define BUFFER_LEN 4096
  38. #define MAX_CHANNELS 16
  39. typedef struct
  40. { SNDFILE * infile ;
  41. SNDFILE * outfile [MAX_CHANNELS] ;
  42. union
  43. { double d [MAX_CHANNELS * BUFFER_LEN] ;
  44. int i [MAX_CHANNELS * BUFFER_LEN] ;
  45. } din ;
  46. union
  47. { double d [BUFFER_LEN] ;
  48. int i [BUFFER_LEN] ;
  49. } dout ;
  50. int channels ;
  51. } STATE ;
  52. static void usage_exit (void) ;
  53. static void deinterleave_int (STATE * state) ;
  54. static void deinterleave_double (STATE * state) ;
  55. int
  56. main (int argc, char **argv)
  57. { STATE *state = NULL ;
  58. SF_INFO sfinfo ;
  59. char pathname [512], ext [32], *cptr ;
  60. int ch, double_split, ret = 1 ;
  61. if (argc != 2)
  62. { if (argc != 1)
  63. puts ("\nError : need a single input file.\n") ;
  64. usage_exit () ;
  65. goto cleanup ;
  66. } ;
  67. state = calloc (1, sizeof (*state)) ;
  68. if (!state)
  69. { printf ("\nError : Out of memory.\n") ;
  70. goto cleanup ;
  71. } ;
  72. memset (&sfinfo, 0, sizeof (sfinfo)) ;
  73. if ((state->infile = sf_open (argv [1], SFM_READ, &sfinfo)) == NULL)
  74. { printf ("\nError : Not able to open input file '%s'\n%s\n", argv [1], sf_strerror (NULL)) ;
  75. goto cleanup ;
  76. } ;
  77. if (sfinfo.channels < 2)
  78. { printf ("\nError : Input file '%s' only has one channel.\n", argv [1]) ;
  79. goto cleanup ;
  80. } ;
  81. if (sfinfo.channels > MAX_CHANNELS)
  82. { printf ("\nError : Input file '%s' has too many (%d) channels. Limit is %d.\n",
  83. argv [1], sfinfo.channels, MAX_CHANNELS) ;
  84. goto cleanup ;
  85. } ;
  86. state->channels = sfinfo.channels ;
  87. sfinfo.channels = 1 ;
  88. if (snprintf (pathname, sizeof (pathname), "%s", argv [1]) > (int) sizeof (pathname))
  89. { printf ("\nError : Length of provided filename '%s' exceeds MAX_PATH (%d).\n", argv [1], (int) sizeof (pathname)) ;
  90. goto cleanup ;
  91. } ;
  92. if ((cptr = strrchr (pathname, '.')) == NULL)
  93. ext [0] = 0 ;
  94. else
  95. { snprintf (ext, sizeof (ext), "%s", cptr) ;
  96. cptr [0] = 0 ;
  97. } ;
  98. printf ("Input file : %s\n", pathname) ;
  99. puts ("Output files :") ;
  100. for (ch = 0 ; ch < state->channels ; ch++)
  101. { char filename [520] ;
  102. size_t count ;
  103. count = snprintf (filename, sizeof (filename), "%s_%02d%s", pathname, ch, ext) ;
  104. if (count >= sizeof (filename))
  105. { printf ("File name truncated to %s\n", filename) ;
  106. } ;
  107. if ((state->outfile [ch] = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL)
  108. { printf ("Not able to open output file '%s'\n%s\n", filename, sf_strerror (NULL)) ;
  109. goto cleanup ;
  110. } ;
  111. printf (" %s\n", filename) ;
  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_split = 1 ;
  118. break ;
  119. default :
  120. double_split = 0 ;
  121. break ;
  122. } ;
  123. if (double_split)
  124. deinterleave_double (state) ;
  125. else
  126. deinterleave_int (state) ;
  127. ret = 0 ;
  128. cleanup :
  129. if (state != NULL)
  130. { sf_close (state->infile) ;
  131. for (ch = 0 ; ch < MAX_CHANNELS ; ch++)
  132. if (state->outfile [ch] != NULL)
  133. sf_close (state->outfile [ch]) ;
  134. } ;
  135. free (state) ;
  136. return ret ;
  137. } /* main */
  138. /*------------------------------------------------------------------------------
  139. */
  140. static void
  141. usage_exit (void)
  142. { puts ("\nUsage : sndfile-deinterleave <filename>\n") ;
  143. puts (
  144. "Split a mutli-channel file into a set of mono files.\n"
  145. "\n"
  146. "If the input file is named 'a.wav', the output files will be named\n"
  147. "a_00.wav, a_01.wav and so on.\n"
  148. ) ;
  149. printf ("Using %s.\n\n", sf_version_string ()) ;
  150. } /* usage_exit */
  151. static void
  152. deinterleave_int (STATE * state)
  153. { int read_len ;
  154. int ch, k ;
  155. do
  156. { read_len = (int) sf_readf_int (state->infile, state->din.i, BUFFER_LEN) ;
  157. for (ch = 0 ; ch < state->channels ; ch ++)
  158. { for (k = 0 ; k < read_len ; k++)
  159. state->dout.i [k] = state->din.i [k * state->channels + ch] ;
  160. sf_write_int (state->outfile [ch], state->dout.i, read_len) ;
  161. } ;
  162. }
  163. while (read_len > 0) ;
  164. } /* deinterleave_int */
  165. static void
  166. deinterleave_double (STATE * state)
  167. { int read_len ;
  168. int ch, k ;
  169. do
  170. { read_len = (int) sf_readf_double (state->infile, state->din.d, BUFFER_LEN) ;
  171. for (ch = 0 ; ch < state->channels ; ch ++)
  172. { for (k = 0 ; k < read_len ; k++)
  173. state->dout.d [k] = state->din.d [k * state->channels + ch] ;
  174. sf_write_double (state->outfile [ch], state->dout.d, read_len) ;
  175. } ;
  176. }
  177. while (read_len > 0) ;
  178. } /* deinterleave_double */