xref: /third_party/libsnd/src/interleave.c (revision b815c7f3)
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