1/* 2** Copyright (C) 2002-2013 Erik de Castro Lopo <erikd@mega-nerd.com> 3** 4** This program is free software; you can redistribute it and/or modify 5** it under the terms of the GNU Lesser General Public License as published by 6** the Free Software Foundation; either version 2.1 of the License, or 7** (at your option) any later version. 8** 9** This program is distributed in the hope that it will be useful, 10** but WITHOUT ANY WARRANTY; without even the implied warranty of 11** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12** GNU Lesser General Public License for more details. 13** 14** You should have received a copy of the GNU Lesser General Public License 15** along with this program; if not, write to the Free Software 16** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17*/ 18 19#include "sfendian.h" 20 21#include <stdlib.h> 22 23#include "sndfile.h" 24#include "common.h" 25 26#define INTERLEAVE_CHANNELS 6 27 28typedef struct 29{ double buffer [SF_BUFFER_LEN / sizeof (double)] ; 30 31 sf_count_t channel_len ; 32 33 sf_count_t (*read_short) (SF_PRIVATE*, short *ptr, sf_count_t len) ; 34 sf_count_t (*read_int) (SF_PRIVATE*, int *ptr, sf_count_t len) ; 35 sf_count_t (*read_float) (SF_PRIVATE*, float *ptr, sf_count_t len) ; 36 sf_count_t (*read_double) (SF_PRIVATE*, double *ptr, sf_count_t len) ; 37 38} INTERLEAVE_DATA ; 39 40 41 42static sf_count_t interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; 43static sf_count_t interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; 44static sf_count_t interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; 45static sf_count_t interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; 46 47static sf_count_t interleave_seek (SF_PRIVATE*, int mode, sf_count_t samples_from_start) ; 48 49 50 51 52int 53interleave_init (SF_PRIVATE *psf) 54{ INTERLEAVE_DATA *pdata ; 55 56 if (psf->file.mode != SFM_READ) 57 return SFE_INTERLEAVE_MODE ; 58 59 if (psf->interleave) 60 { psf_log_printf (psf, "*** Weird, already have interleave.\n") ; 61 return 666 ; 62 } ; 63 64 /* Free this in sf_close() function. */ 65 if (! (pdata = malloc (sizeof (INTERLEAVE_DATA)))) 66 return SFE_MALLOC_FAILED ; 67 68puts ("interleave_init") ; 69 70 psf->interleave = pdata ; 71 72 /* Save the existing methods. */ 73 pdata->read_short = psf->read_short ; 74 pdata->read_int = psf->read_int ; 75 pdata->read_float = psf->read_float ; 76 pdata->read_double = psf->read_double ; 77 78 pdata->channel_len = psf->sf.frames * psf->bytewidth ; 79 80 /* Insert our new methods. */ 81 psf->read_short = interleave_read_short ; 82 psf->read_int = interleave_read_int ; 83 psf->read_float = interleave_read_float ; 84 psf->read_double = interleave_read_double ; 85 86 psf->seek = interleave_seek ; 87 88 return 0 ; 89} /* pcm_interleave_init */ 90 91/*------------------------------------------------------------------------------ 92*/ 93 94static sf_count_t 95interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) 96{ INTERLEAVE_DATA *pdata ; 97 sf_count_t offset, templen ; 98 int chan, count, k ; 99 short *inptr, *outptr ; 100 101 if (! (pdata = psf->interleave)) 102 return 0 ; 103 104 inptr = (short*) pdata->buffer ; 105 106 for (chan = 0 ; chan < psf->sf.channels ; chan++) 107 { outptr = ptr + chan ; 108 109 offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; 110 111 if (psf_fseek (psf, offset, SEEK_SET) != offset) 112 { psf->error = SFE_INTERLEAVE_SEEK ; 113 return 0 ; 114 } ; 115 116 templen = len / psf->sf.channels ; 117 118 while (templen > 0) 119 { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short)) 120 count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short) ; 121 else 122 count = (int) templen ; 123 124 if (pdata->read_short (psf, inptr, count) != count) 125 { psf->error = SFE_INTERLEAVE_READ ; 126 return 0 ; 127 } ; 128 129 for (k = 0 ; k < count ; k++) 130 { *outptr = inptr [k] ; 131 outptr += psf->sf.channels ; 132 } ; 133 134 templen -= count ; 135 } ; 136 } ; 137 138 return len ; 139} /* interleave_read_short */ 140 141static sf_count_t 142interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) 143{ INTERLEAVE_DATA *pdata ; 144 sf_count_t offset, templen ; 145 int chan, count, k ; 146 int *inptr, *outptr ; 147 148 if (! (pdata = psf->interleave)) 149 return 0 ; 150 151 inptr = (int*) pdata->buffer ; 152 153 for (chan = 0 ; chan < psf->sf.channels ; chan++) 154 { outptr = ptr + chan ; 155 156 offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; 157 158 if (psf_fseek (psf, offset, SEEK_SET) != offset) 159 { psf->error = SFE_INTERLEAVE_SEEK ; 160 return 0 ; 161 } ; 162 163 templen = len / psf->sf.channels ; 164 165 while (templen > 0) 166 { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int)) 167 count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int) ; 168 else 169 count = (int) templen ; 170 171 if (pdata->read_int (psf, inptr, count) != count) 172 { psf->error = SFE_INTERLEAVE_READ ; 173 return 0 ; 174 } ; 175 176 for (k = 0 ; k < count ; k++) 177 { *outptr = inptr [k] ; 178 outptr += psf->sf.channels ; 179 } ; 180 181 templen -= count ; 182 } ; 183 } ; 184 185 return len ; 186} /* interleave_read_int */ 187 188static sf_count_t 189interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) 190{ INTERLEAVE_DATA *pdata ; 191 sf_count_t offset, templen ; 192 int chan, count, k ; 193 float *inptr, *outptr ; 194 195 if (! (pdata = psf->interleave)) 196 return 0 ; 197 198 inptr = (float*) pdata->buffer ; 199 200 for (chan = 0 ; chan < psf->sf.channels ; chan++) 201 { outptr = ptr + chan ; 202 203 offset = psf->dataoffset + pdata->channel_len * chan + psf->read_current * psf->bytewidth ; 204 205/*-printf ("chan : %d read_current : %6lld offset : %6lld\n", chan, psf->read_current, offset) ;-*/ 206 207 if (psf_fseek (psf, offset, SEEK_SET) != offset) 208 { psf->error = SFE_INTERLEAVE_SEEK ; 209/*-puts ("interleave_seek error") ; exit (1) ;-*/ 210 return 0 ; 211 } ; 212 213 templen = len / psf->sf.channels ; 214 215 while (templen > 0) 216 { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float)) 217 count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float) ; 218 else 219 count = (int) templen ; 220 221 if (pdata->read_float (psf, inptr, count) != count) 222 { psf->error = SFE_INTERLEAVE_READ ; 223/*-puts ("interleave_read error") ; exit (1) ;-*/ 224 return 0 ; 225 } ; 226 227 for (k = 0 ; k < count ; k++) 228 { *outptr = inptr [k] ; 229 outptr += psf->sf.channels ; 230 } ; 231 232 templen -= count ; 233 } ; 234 } ; 235 236 return len ; 237} /* interleave_read_float */ 238 239static sf_count_t 240interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) 241{ INTERLEAVE_DATA *pdata ; 242 sf_count_t offset, templen ; 243 int chan, count, k ; 244 double *inptr, *outptr ; 245 246 if (! (pdata = psf->interleave)) 247 return 0 ; 248 249 inptr = (double*) pdata->buffer ; 250 251 for (chan = 0 ; chan < psf->sf.channels ; chan++) 252 { outptr = ptr + chan ; 253 254 offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; 255 256 if (psf_fseek (psf, offset, SEEK_SET) != offset) 257 { psf->error = SFE_INTERLEAVE_SEEK ; 258 return 0 ; 259 } ; 260 261 templen = len / psf->sf.channels ; 262 263 while (templen > 0) 264 { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double)) 265 count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double) ; 266 else 267 count = (int) templen ; 268 269 if (pdata->read_double (psf, inptr, count) != count) 270 { psf->error = SFE_INTERLEAVE_READ ; 271 return 0 ; 272 } ; 273 274 for (k = 0 ; k < count ; k++) 275 { *outptr = inptr [k] ; 276 outptr += psf->sf.channels ; 277 } ; 278 279 templen -= count ; 280 } ; 281 } ; 282 283 return len ; 284} /* interleave_read_double */ 285 286/*------------------------------------------------------------------------------ 287*/ 288 289static sf_count_t 290interleave_seek (SF_PRIVATE * UNUSED (psf), int UNUSED (mode), sf_count_t samples_from_start) 291{ 292 /* 293 ** Do nothing here. This is a place holder to prevent the default 294 ** seek function from being called. 295 */ 296 297 return samples_from_start ; 298} /* interleave_seek */ 299 300