xref: /third_party/libsnd/src/double64.c (revision b815c7f3)
1/*
2** Copyright (C) 1999-2015 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	"sfconfig.h"
20
21#include	<stdio.h>
22#include	<stdlib.h>
23#include	<string.h>
24#include	<limits.h>
25#include	<math.h>
26
27#include	"sndfile.h"
28#include	"sfendian.h"
29#include	"common.h"
30
31#if CPU_IS_LITTLE_ENDIAN
32	#define DOUBLE64_READ	double64_le_read
33	#define DOUBLE64_WRITE	double64_le_write
34#elif CPU_IS_BIG_ENDIAN
35	#define DOUBLE64_READ	double64_be_read
36	#define DOUBLE64_WRITE	double64_be_write
37#endif
38
39/* A 32 number which will not overflow when multiplied by sizeof (double). */
40#define SENSIBLE_LEN	(0x8000000)
41
42/*--------------------------------------------------------------------------------------------
43**	Processor floating point capabilities. double64_get_capability () returns one of the
44**	latter three values.
45*/
46
47enum
48{	DOUBLE_UNKNOWN		= 0x00,
49	DOUBLE_CAN_RW_LE	= 0x23,
50	DOUBLE_CAN_RW_BE	= 0x34,
51	DOUBLE_BROKEN_LE	= 0x45,
52	DOUBLE_BROKEN_BE	= 0x56
53} ;
54
55/*--------------------------------------------------------------------------------------------
56**	Prototypes for private functions.
57*/
58
59static sf_count_t		host_read_d2s	(SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
60static sf_count_t		host_read_d2i	(SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
61static sf_count_t		host_read_d2f	(SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
62static sf_count_t		host_read_d		(SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
63
64static sf_count_t		host_write_s2d	(SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
65static sf_count_t		host_write_i2d	(SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
66static sf_count_t		host_write_f2d	(SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
67static sf_count_t		host_write_d	(SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
68
69static void		double64_peak_update	(SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) ;
70
71static int		double64_get_capability	(SF_PRIVATE *psf) ;
72
73static sf_count_t	replace_read_d2s	(SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
74static sf_count_t	replace_read_d2i	(SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
75static sf_count_t	replace_read_d2f	(SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
76static sf_count_t	replace_read_d	(SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
77
78static sf_count_t	replace_write_s2d	(SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
79static sf_count_t	replace_write_i2d	(SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
80static sf_count_t	replace_write_f2d	(SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
81static sf_count_t	replace_write_d	(SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
82
83static	void	d2bd_read (double *buffer, int count) ;
84static	void	bd2d_write (double *buffer, int count) ;
85
86/*--------------------------------------------------------------------------------------------
87**	Exported functions.
88*/
89
90int
91double64_init	(SF_PRIVATE *psf)
92{	static int double64_caps ;
93
94	if (psf->sf.channels < 1 || psf->sf.channels > SF_MAX_CHANNELS)
95	{	psf_log_printf (psf, "double64_init : internal error : channels = %d\n", psf->sf.channels) ;
96		return SFE_INTERNAL ;
97		} ;
98
99	double64_caps = double64_get_capability (psf) ;
100
101	psf->blockwidth = sizeof (double) * psf->sf.channels ;
102
103	if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR)
104	{	switch (psf->endian + double64_caps)
105		{	case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
106					psf->data_endswap = SF_FALSE ;
107					psf->read_short		= host_read_d2s ;
108					psf->read_int		= host_read_d2i ;
109					psf->read_float		= host_read_d2f ;
110					psf->read_double	= host_read_d ;
111					break ;
112
113			case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
114					psf->data_endswap = SF_FALSE ;
115					psf->read_short		= host_read_d2s ;
116					psf->read_int		= host_read_d2i ;
117					psf->read_float		= host_read_d2f ;
118					psf->read_double	= host_read_d ;
119					break ;
120
121			case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) :
122					psf->data_endswap = SF_TRUE ;
123					psf->read_short		= host_read_d2s ;
124					psf->read_int		= host_read_d2i ;
125					psf->read_float		= host_read_d2f ;
126					psf->read_double	= host_read_d ;
127					break ;
128
129			case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) :
130					psf->data_endswap = SF_TRUE ;
131					psf->read_short		= host_read_d2s ;
132					psf->read_int		= host_read_d2i ;
133					psf->read_float		= host_read_d2f ;
134					psf->read_double	= host_read_d ;
135					break ;
136
137			/* When the CPU is not IEEE compatible. */
138			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) :
139					psf->data_endswap = SF_FALSE ;
140					psf->read_short		= replace_read_d2s ;
141					psf->read_int		= replace_read_d2i ;
142					psf->read_float		= replace_read_d2f ;
143					psf->read_double	= replace_read_d ;
144					break ;
145
146			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) :
147					psf->data_endswap = SF_FALSE ;
148					psf->read_short		= replace_read_d2s ;
149					psf->read_int		= replace_read_d2i ;
150					psf->read_float		= replace_read_d2f ;
151					psf->read_double	= replace_read_d ;
152					break ;
153
154			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) :
155					psf->data_endswap = SF_TRUE ;
156					psf->read_short		= replace_read_d2s ;
157					psf->read_int		= replace_read_d2i ;
158					psf->read_float		= replace_read_d2f ;
159					psf->read_double	= replace_read_d ;
160					break ;
161
162			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) :
163					psf->data_endswap = SF_TRUE ;
164					psf->read_short		= replace_read_d2s ;
165					psf->read_int		= replace_read_d2i ;
166					psf->read_float		= replace_read_d2f ;
167					psf->read_double	= replace_read_d ;
168					break ;
169
170			default : break ;
171			} ;
172		} ;
173
174	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
175	{	switch (psf->endian + double64_caps)
176		{	case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
177					psf->data_endswap = SF_FALSE ;
178					psf->write_short	= host_write_s2d ;
179					psf->write_int		= host_write_i2d ;
180					psf->write_float	= host_write_f2d ;
181					psf->write_double	= host_write_d ;
182					break ;
183
184			case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
185					psf->data_endswap = SF_FALSE ;
186					psf->write_short	= host_write_s2d ;
187					psf->write_int		= host_write_i2d ;
188					psf->write_float	= host_write_f2d ;
189					psf->write_double	= host_write_d ;
190					break ;
191
192			case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) :
193					psf->data_endswap = SF_TRUE ;
194					psf->write_short	= host_write_s2d ;
195					psf->write_int		= host_write_i2d ;
196					psf->write_float	= host_write_f2d ;
197					psf->write_double	= host_write_d ;
198					break ;
199
200			case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) :
201					psf->data_endswap = SF_TRUE ;
202					psf->write_short	= host_write_s2d ;
203					psf->write_int		= host_write_i2d ;
204					psf->write_float	= host_write_f2d ;
205					psf->write_double	= host_write_d ;
206					break ;
207
208			/* When the CPU is not IEEE compatible. */
209			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) :
210					psf->data_endswap = SF_FALSE ;
211					psf->write_short	= replace_write_s2d ;
212					psf->write_int		= replace_write_i2d ;
213					psf->write_float	= replace_write_f2d ;
214					psf->write_double	= replace_write_d ;
215					break ;
216
217			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) :
218					psf->data_endswap = SF_FALSE ;
219					psf->write_short	= replace_write_s2d ;
220					psf->write_int		= replace_write_i2d ;
221					psf->write_float	= replace_write_f2d ;
222					psf->write_double	= replace_write_d ;
223					break ;
224
225			case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) :
226					psf->data_endswap = SF_TRUE ;
227					psf->write_short	= replace_write_s2d ;
228					psf->write_int		= replace_write_i2d ;
229					psf->write_float	= replace_write_f2d ;
230					psf->write_double	= replace_write_d ;
231					break ;
232
233			case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) :
234					psf->data_endswap = SF_TRUE ;
235					psf->write_short	= replace_write_s2d ;
236					psf->write_int		= replace_write_i2d ;
237					psf->write_float	= replace_write_f2d ;
238					psf->write_double	= replace_write_d ;
239					break ;
240
241			default : break ;
242			} ;
243		} ;
244
245	if (psf->filelength > psf->dataoffset)
246	{	psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset :
247							psf->filelength - psf->dataoffset ;
248		}
249	else
250		psf->datalength = 0 ;
251
252	psf->sf.frames = psf->datalength / psf->blockwidth ;
253
254	return 0 ;
255} /* double64_init */
256
257/*----------------------------------------------------------------------------
258** From : http://www.hpcf.cam.ac.uk/fp_formats.html
259**
260** 64 bit double precision layout (big endian)
261** 	  Sign				bit 0
262** 	  Exponent			bits 1-11
263** 	  Mantissa			bits 12-63
264** 	  Exponent Offset	1023
265**
266**            double             single
267**
268** +INF     7FF0000000000000     7F800000
269** -INF     FFF0000000000000     FF800000
270**  NaN     7FF0000000000001     7F800001
271**                to               to
272**          7FFFFFFFFFFFFFFF     7FFFFFFF
273**                and              and
274**          FFF0000000000001     FF800001
275**                to               to
276**          FFFFFFFFFFFFFFFF     FFFFFFFF
277** +OVER    7FEFFFFFFFFFFFFF     7F7FFFFF
278** -OVER    FFEFFFFFFFFFFFFF     FF7FFFFF
279** +UNDER   0010000000000000     00800000
280** -UNDER   8010000000000000     80800000
281*/
282
283double
284double64_be_read (const unsigned char *cptr)
285{	int		exponent, negative, upper, lower ;
286	double	dvalue ;
287
288	negative = (cptr [0] & 0x80) ? 1 : 0 ;
289	exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ;
290
291	/* Might not have a 64 bit long, so load the mantissa into a double. */
292	upper = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8) | cptr [4]) ;
293	lower = (cptr [5] << 16) | (cptr [6] << 8) | cptr [7] ;
294
295	if (exponent == 0 && upper == 0 && lower == 0)
296		return 0.0 ;
297
298	dvalue = upper + lower / ((double) 0x1000000) ;
299	dvalue += 0x10000000 ;
300
301	exponent = exponent - 0x3FF ;
302
303	dvalue = dvalue / ((double) 0x10000000) ;
304
305	if (negative)
306		dvalue *= -1 ;
307
308	if (exponent > 0)
309		dvalue *= pow (2.0, exponent) ;
310	else if (exponent < 0)
311		dvalue /= pow (2.0, abs (exponent)) ;
312
313	return dvalue ;
314} /* double64_be_read */
315
316double
317double64_le_read (const unsigned char *cptr)
318{	int		exponent, negative, upper, lower ;
319	double	dvalue ;
320
321	negative = (cptr [7] & 0x80) ? 1 : 0 ;
322	exponent = ((cptr [7] & 0x7F) << 4) | ((cptr [6] >> 4) & 0xF) ;
323
324	/* Might not have a 64 bit long, so load the mantissa into a double. */
325	upper = ((cptr [6] & 0xF) << 24) | (cptr [5] << 16) | (cptr [4] << 8) | cptr [3] ;
326	lower = (cptr [2] << 16) | (cptr [1] << 8) | cptr [0] ;
327
328	if (exponent == 0 && upper == 0 && lower == 0)
329		return 0.0 ;
330
331	dvalue = upper + lower / ((double) 0x1000000) ;
332	dvalue += 0x10000000 ;
333
334	exponent = exponent - 0x3FF ;
335
336	dvalue = dvalue / ((double) 0x10000000) ;
337
338	if (negative)
339		dvalue *= -1 ;
340
341	if (exponent > 0)
342		dvalue *= pow (2.0, exponent) ;
343	else if (exponent < 0)
344		dvalue /= pow (2.0, abs (exponent)) ;
345
346	return dvalue ;
347} /* double64_le_read */
348
349void
350double64_be_write (double in, unsigned char *out)
351{	int		exponent, mantissa ;
352
353	memset (out, 0, sizeof (double)) ;
354
355	if (fabs (in) < 1e-30)
356		return ;
357
358	if (in < 0.0)
359	{	in *= -1.0 ;
360		out [0] |= 0x80 ;
361		} ;
362
363	in = frexp (in, &exponent) ;
364
365	exponent += 1022 ;
366
367	out [0] |= (exponent >> 4) & 0x7F ;
368	out [1] |= (exponent << 4) & 0xF0 ;
369
370	in *= 0x20000000 ;
371	mantissa = psf_lrint (floor (in)) ;
372
373	out [1] |= (mantissa >> 24) & 0xF ;
374	out [2] = (mantissa >> 16) & 0xFF ;
375	out [3] = (mantissa >> 8) & 0xFF ;
376	out [4] = mantissa & 0xFF ;
377
378	in = fmod (in, 1.0) ;
379	in *= 0x1000000 ;
380	mantissa = psf_lrint (floor (in)) ;
381
382	out [5] = (mantissa >> 16) & 0xFF ;
383	out [6] = (mantissa >> 8) & 0xFF ;
384	out [7] = mantissa & 0xFF ;
385
386	return ;
387} /* double64_be_write */
388
389void
390double64_le_write (double in, unsigned char *out)
391{	int		exponent, mantissa ;
392
393	memset (out, 0, sizeof (double)) ;
394
395	if (fabs (in) < 1e-30)
396		return ;
397
398	if (in < 0.0)
399	{	in *= -1.0 ;
400		out [7] |= 0x80 ;
401		} ;
402
403	in = frexp (in, &exponent) ;
404
405	exponent += 1022 ;
406
407	out [7] |= (exponent >> 4) & 0x7F ;
408	out [6] |= (exponent << 4) & 0xF0 ;
409
410	in *= 0x20000000 ;
411	mantissa = psf_lrint (floor (in)) ;
412
413	out [6] |= (mantissa >> 24) & 0xF ;
414	out [5] = (mantissa >> 16) & 0xFF ;
415	out [4] = (mantissa >> 8) & 0xFF ;
416	out [3] = mantissa & 0xFF ;
417
418	in = fmod (in, 1.0) ;
419	in *= 0x1000000 ;
420	mantissa = psf_lrint (floor (in)) ;
421
422	out [2] = (mantissa >> 16) & 0xFF ;
423	out [1] = (mantissa >> 8) & 0xFF ;
424	out [0] = mantissa & 0xFF ;
425
426	return ;
427} /* double64_le_write */
428
429/*==============================================================================================
430**	Private functions.
431*/
432
433static void
434double64_peak_update	(SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx)
435{	int 	chan ;
436	int		k, position ;
437	float	fmaxval ;
438
439	for (chan = 0 ; chan < psf->sf.channels ; chan++)
440	{	fmaxval = fabs (buffer [chan]) ;
441		position = 0 ;
442		for (k = chan ; k < count ; k += psf->sf.channels)
443			if (fmaxval < fabs (buffer [k]))
444			{	fmaxval = fabs (buffer [k]) ;
445				position = k ;
446				} ;
447
448		if (fmaxval > psf->peak_info->peaks [chan].value)
449		{	psf->peak_info->peaks [chan].value = fmaxval ;
450			psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ;
451			} ;
452		} ;
453
454	return ;
455} /* double64_peak_update */
456
457static int
458double64_get_capability	(SF_PRIVATE *psf)
459{	union
460	{	double			d ;
461		unsigned char	c [8] ;
462	} data ;
463
464	data.d = 1.234567890123456789 ; /* Some abitrary value. */
465
466	if (! psf->ieee_replace)
467	{	/* If this test is true ints and floats are compatible and little endian. */
468		if (data.c [0] == 0xfb && data.c [1] == 0x59 && data.c [2] == 0x8c && data.c [3] == 0x42 &&
469			data.c [4] == 0xca && data.c [5] == 0xc0 && data.c [6] == 0xf3 && data.c [7] == 0x3f)
470			return DOUBLE_CAN_RW_LE ;
471
472		/* If this test is true ints and floats are compatible and big endian. */
473		if (data.c [0] == 0x3f && data.c [1] == 0xf3 && data.c [2] == 0xc0 && data.c [3] == 0xca &&
474			data.c [4] == 0x42 && data.c [5] == 0x8c && data.c [6] == 0x59 && data.c [7] == 0xfb)
475			return DOUBLE_CAN_RW_BE ;
476		} ;
477
478	/* Doubles are broken. Don't expect reading or writing to be fast. */
479	psf_log_printf (psf, "Using IEEE replacement code for double.\n") ;
480
481	return (CPU_IS_LITTLE_ENDIAN) ? DOUBLE_BROKEN_LE : DOUBLE_BROKEN_BE ;
482} /* double64_get_capability */
483
484/*=======================================================================================
485*/
486
487static void
488d2s_array (const double *src, int count, short *dest, double scale)
489{	for (int i = 0 ; i < count ; i++)
490	{	dest [i] = psf_lrint (scale * src [i]) ;
491		} ;
492} /* d2s_array */
493
494static void
495d2s_clip_array (const double *src, int count, short *dest, double scale)
496{	for (int i = 0 ; i < count ; i++)
497	{	double tmp = scale * src [i] ;
498
499		if (tmp > 32767.0)
500			dest [i] = SHRT_MAX ;
501		else if (tmp < -32768.0)
502			dest [i] = SHRT_MIN ;
503		else
504			dest [i] = psf_lrint (tmp) ;
505		} ;
506} /* d2s_clip_array */
507
508static void
509d2i_array (const double *src, int count, int *dest, double scale)
510{	for (int i = 0 ; i < count ; i++)
511	{	dest [i] = psf_lrint (scale * src [i]) ;
512		} ;
513} /* d2i_array */
514
515static void
516d2i_clip_array (const double *src, int count, int *dest, double scale)
517{	for (int i = 0 ; i < count ; i++)
518	{	float tmp = scale * src [i] ;
519
520		if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX))
521			dest [i] = INT_MAX ;
522		else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX))
523			dest [i] = INT_MIN ;
524		else
525			dest [i] = psf_lrint (tmp) ;
526		} ;
527} /* d2i_clip_array */
528
529static inline void
530d2f_array (const double *src, int count, float *dest)
531{	for (int i = 0 ; i < count ; i++)
532	{	dest [i] = src [i] ;
533		} ;
534} /* d2f_array */
535
536static inline void
537s2d_array (const short *src, double *dest, int count, double scale)
538{	for (int i = 0 ; i < count ; i++)
539	{	dest [i] = scale * src [i] ;
540		} ;
541} /* s2d_array */
542
543static inline void
544i2d_array (const int *src, double *dest, int count, double scale)
545{	for (int i = 0 ; i < count ; i++)
546	{	dest [i] = scale * src [i] ;
547		} ;
548} /* i2d_array */
549
550static inline void
551f2d_array (const float *src, double *dest, int count)
552{	for (int i = 0 ; i < count ; i++)
553	{	dest [i] = src [i] ;
554		} ;
555} /* f2d_array */
556
557/*----------------------------------------------------------------------------------------------
558*/
559
560static sf_count_t
561host_read_d2s	(SF_PRIVATE *psf, short *ptr, sf_count_t len)
562{	BUF_UNION	ubuf ;
563	void		(*convert) (const double *, int, short *, double) ;
564	int			bufferlen, readcount ;
565	sf_count_t	total = 0 ;
566	double		scale ;
567
568	convert = (psf->add_clipping) ? d2s_clip_array : d2s_array ;
569	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
570	scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
571
572	while (len > 0)
573	{	if (len < bufferlen)
574			bufferlen = (int) len ;
575		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
576
577		if (psf->data_endswap == SF_TRUE)
578			endswap_double_array (ubuf.dbuf, readcount) ;
579
580		convert (ubuf.dbuf, readcount, ptr + total, scale) ;
581		total += readcount ;
582		len -= readcount ;
583		if (readcount < bufferlen)
584			break ;
585		} ;
586
587	return total ;
588} /* host_read_d2s */
589
590static sf_count_t
591host_read_d2i	(SF_PRIVATE *psf, int *ptr, sf_count_t len)
592{	BUF_UNION	ubuf ;
593	void		(*convert) (const double *, int, int *, double) ;
594	int			bufferlen, readcount ;
595	sf_count_t	total = 0 ;
596	double		scale ;
597
598	convert = (psf->add_clipping) ? d2i_clip_array : d2i_array ;
599	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
600	scale = (psf->float_int_mult == 0) ? 1.0 : 2147483648.0f / psf->float_max ;
601
602	while (len > 0)
603	{	if (len < bufferlen)
604			bufferlen = (int) len ;
605		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
606
607		if (psf->data_endswap == SF_TRUE)
608			endswap_double_array (ubuf.dbuf, bufferlen) ;
609
610		convert (ubuf.dbuf, readcount, ptr + total, scale) ;
611		total += readcount ;
612		len -= readcount ;
613		if (readcount < bufferlen)
614			break ;
615		} ;
616
617	return total ;
618} /* host_read_d2i */
619
620static sf_count_t
621host_read_d2f	(SF_PRIVATE *psf, float *ptr, sf_count_t len)
622{	BUF_UNION	ubuf ;
623	int			bufferlen, readcount ;
624	sf_count_t	total = 0 ;
625
626	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
627
628	while (len > 0)
629	{	if (len < bufferlen)
630			bufferlen = (int) len ;
631		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
632
633		if (psf->data_endswap == SF_TRUE)
634			endswap_double_array (ubuf.dbuf, readcount) ;
635
636		d2f_array (ubuf.dbuf, readcount, ptr + total) ;
637		total += readcount ;
638		len -= readcount ;
639		if (readcount < bufferlen)
640			break ;
641		} ;
642
643	return total ;
644} /* host_read_d2f */
645
646static sf_count_t
647host_read_d	(SF_PRIVATE *psf, double *ptr, sf_count_t len)
648{	int			bufferlen ;
649	sf_count_t	readcount, total = 0 ;
650
651	readcount = psf_fread (ptr, sizeof (double), len, psf) ;
652
653	if (psf->data_endswap != SF_TRUE)
654		return readcount ;
655
656	/* If the read length was sensible, endswap output in one go. */
657	if (readcount < SENSIBLE_LEN)
658	{	endswap_double_array (ptr, readcount) ;
659		return readcount ;
660		} ;
661
662	bufferlen = SENSIBLE_LEN ;
663	while (len > 0)
664	{	if (len < bufferlen)
665			bufferlen = (int) len ;
666
667		endswap_double_array (ptr + total, bufferlen) ;
668
669		total += bufferlen ;
670		len -= bufferlen ;
671		} ;
672
673	return total ;
674} /* host_read_d */
675
676static sf_count_t
677host_write_s2d	(SF_PRIVATE *psf, const short *ptr, sf_count_t len)
678{	BUF_UNION	ubuf ;
679	int			bufferlen, writecount ;
680	sf_count_t	total = 0 ;
681	double		scale ;
682
683	scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ;
684	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
685
686	while (len > 0)
687	{	if (len < bufferlen)
688			bufferlen = (int) len ;
689
690		s2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ;
691
692		if (psf->peak_info)
693			double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ;
694
695		if (psf->data_endswap == SF_TRUE)
696			endswap_double_array (ubuf.dbuf, bufferlen) ;
697
698		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
699		total += writecount ;
700		if (writecount < bufferlen)
701			break ;
702		len -= writecount ;
703		} ;
704
705	return total ;
706} /* host_write_s2d */
707
708static sf_count_t
709host_write_i2d	(SF_PRIVATE *psf, const int *ptr, sf_count_t len)
710{	BUF_UNION	ubuf ;
711	int			bufferlen, writecount ;
712	sf_count_t	total = 0 ;
713	double		scale ;
714
715	scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ;
716	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
717
718	while (len > 0)
719	{	if (len < bufferlen)
720			bufferlen = (int) len ;
721		i2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ;
722
723		if (psf->peak_info)
724			double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ;
725
726		if (psf->data_endswap == SF_TRUE)
727			endswap_double_array (ubuf.dbuf, bufferlen) ;
728
729		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
730		total += writecount ;
731		if (writecount < bufferlen)
732			break ;
733		len -= writecount ;
734		} ;
735
736	return total ;
737} /* host_write_i2d */
738
739static sf_count_t
740host_write_f2d	(SF_PRIVATE *psf, const float *ptr, sf_count_t len)
741{	BUF_UNION	ubuf ;
742	int			bufferlen, writecount ;
743	sf_count_t	total = 0 ;
744
745	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
746
747	while (len > 0)
748	{	if (len < bufferlen)
749			bufferlen = (int) len ;
750		f2d_array (ptr + total, ubuf.dbuf, bufferlen) ;
751
752		if (psf->peak_info)
753			double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ;
754
755		if (psf->data_endswap == SF_TRUE)
756			endswap_double_array (ubuf.dbuf, bufferlen) ;
757
758		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
759		total += writecount ;
760		if (writecount < bufferlen)
761			break ;
762		len -= writecount ;
763		} ;
764
765	return total ;
766} /* host_write_f2d */
767
768static sf_count_t
769host_write_d	(SF_PRIVATE *psf, const double *ptr, sf_count_t len)
770{	BUF_UNION	ubuf ;
771	int			bufferlen, writecount ;
772	sf_count_t	total = 0 ;
773
774	if (psf->peak_info)
775		double64_peak_update (psf, ptr, len, 0) ;
776
777	if (psf->data_endswap != SF_TRUE)
778		return psf_fwrite (ptr, sizeof (double), len, psf) ;
779
780	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
781
782	while (len > 0)
783	{	if (len < bufferlen)
784			bufferlen = (int) len ;
785
786		endswap_double_copy (ubuf.dbuf, ptr + total, bufferlen) ;
787
788		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
789		total += writecount ;
790		if (writecount < bufferlen)
791			break ;
792		len -= writecount ;
793		} ;
794
795	return total ;
796} /* host_write_d */
797
798/*=======================================================================================
799*/
800
801static sf_count_t
802replace_read_d2s	(SF_PRIVATE *psf, short *ptr, sf_count_t len)
803{	BUF_UNION	ubuf ;
804	int			bufferlen, readcount ;
805	sf_count_t	total = 0 ;
806	double		scale ;
807
808	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
809	scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
810
811	while (len > 0)
812	{	if (len < bufferlen)
813			bufferlen = (int) len ;
814		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
815
816		if (psf->data_endswap == SF_TRUE)
817			endswap_double_array (ubuf.dbuf, bufferlen) ;
818
819		d2bd_read (ubuf.dbuf, bufferlen) ;
820
821		d2s_array (ubuf.dbuf, readcount, ptr + total, scale) ;
822		total += readcount ;
823		if (readcount < bufferlen)
824			break ;
825		len -= readcount ;
826		} ;
827
828	return total ;
829} /* replace_read_d2s */
830
831static sf_count_t
832replace_read_d2i	(SF_PRIVATE *psf, int *ptr, sf_count_t len)
833{	BUF_UNION	ubuf ;
834	int			bufferlen, readcount ;
835	sf_count_t	total = 0 ;
836	double		scale ;
837
838	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
839	scale = (psf->float_int_mult == 0) ? 1.0 : 2147483648.0f / psf->float_max ;
840
841	while (len > 0)
842	{	if (len < bufferlen)
843			bufferlen = (int) len ;
844		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
845
846		if (psf->data_endswap == SF_TRUE)
847			endswap_double_array (ubuf.dbuf, bufferlen) ;
848
849		d2bd_read (ubuf.dbuf, bufferlen) ;
850
851		d2i_array (ubuf.dbuf, readcount, ptr + total, scale) ;
852		total += readcount ;
853		if (readcount < bufferlen)
854			break ;
855		len -= readcount ;
856		} ;
857
858	return total ;
859} /* replace_read_d2i */
860
861static sf_count_t
862replace_read_d2f	(SF_PRIVATE *psf, float *ptr, sf_count_t len)
863{	BUF_UNION	ubuf ;
864	int			bufferlen, readcount ;
865	sf_count_t	total = 0 ;
866
867	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
868
869	while (len > 0)
870	{	if (len < bufferlen)
871			bufferlen = (int) len ;
872		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
873
874		if (psf->data_endswap == SF_TRUE)
875			endswap_double_array (ubuf.dbuf, bufferlen) ;
876
877		d2bd_read (ubuf.dbuf, bufferlen) ;
878
879		memcpy (ptr + total, ubuf.dbuf, bufferlen * sizeof (double)) ;
880
881		total += readcount ;
882		if (readcount < bufferlen)
883			break ;
884		len -= readcount ;
885		} ;
886
887	return total ;
888} /* replace_read_d2f */
889
890static sf_count_t
891replace_read_d	(SF_PRIVATE *psf, double *ptr, sf_count_t len)
892{	BUF_UNION	ubuf ;
893	int			bufferlen, readcount ;
894	sf_count_t	total = 0 ;
895
896	/* FIXME : This is probably nowhere near optimal. */
897	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
898
899	while (len > 0)
900	{	if (len < bufferlen)
901			bufferlen = (int) len ;
902		readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
903
904		if (psf->data_endswap == SF_TRUE)
905			endswap_double_array (ubuf.dbuf, readcount) ;
906
907		d2bd_read (ubuf.dbuf, readcount) ;
908
909		memcpy (ptr + total, ubuf.dbuf, readcount * sizeof (double)) ;
910
911		total += readcount ;
912		if (readcount < bufferlen)
913			break ;
914		len -= readcount ;
915		} ;
916
917	return total ;
918} /* replace_read_d */
919
920static sf_count_t
921replace_write_s2d	(SF_PRIVATE *psf, const short *ptr, sf_count_t len)
922{	BUF_UNION	ubuf ;
923	int			bufferlen, writecount ;
924	sf_count_t	total = 0 ;
925	double		scale ;
926
927	scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ;
928	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
929
930	while (len > 0)
931	{	if (len < bufferlen)
932			bufferlen = (int) len ;
933		s2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ;
934
935		if (psf->peak_info)
936			double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ;
937
938		bd2d_write (ubuf.dbuf, bufferlen) ;
939
940		if (psf->data_endswap == SF_TRUE)
941			endswap_double_array (ubuf.dbuf, bufferlen) ;
942
943		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
944		total += writecount ;
945		if (writecount < bufferlen)
946			break ;
947		len -= writecount ;
948		} ;
949
950	return total ;
951} /* replace_write_s2d */
952
953static sf_count_t
954replace_write_i2d	(SF_PRIVATE *psf, const int *ptr, sf_count_t len)
955{	BUF_UNION	ubuf ;
956	int			bufferlen, writecount ;
957	sf_count_t	total = 0 ;
958	double		scale ;
959
960	scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ;
961	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
962
963	while (len > 0)
964	{	if (len < bufferlen)
965			bufferlen = (int) len ;
966		i2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ;
967
968		if (psf->peak_info)
969			double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ;
970
971		bd2d_write (ubuf.dbuf, bufferlen) ;
972
973		if (psf->data_endswap == SF_TRUE)
974			endswap_double_array (ubuf.dbuf, bufferlen) ;
975
976		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
977		total += writecount ;
978		if (writecount < bufferlen)
979			break ;
980		len -= writecount ;
981		} ;
982
983	return total ;
984} /* replace_write_i2d */
985
986static sf_count_t
987replace_write_f2d	(SF_PRIVATE *psf, const float *ptr, sf_count_t len)
988{	BUF_UNION	ubuf ;
989	int			bufferlen, writecount ;
990	sf_count_t	total = 0 ;
991
992	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
993
994	while (len > 0)
995	{	if (len < bufferlen)
996			bufferlen = (int) len ;
997		f2d_array (ptr + total, ubuf.dbuf, bufferlen) ;
998
999		bd2d_write (ubuf.dbuf, bufferlen) ;
1000
1001		if (psf->data_endswap == SF_TRUE)
1002			endswap_double_array (ubuf.dbuf, bufferlen) ;
1003
1004		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
1005		total += writecount ;
1006		if (writecount < bufferlen)
1007			break ;
1008		len -= writecount ;
1009		} ;
1010
1011	return total ;
1012} /* replace_write_f2d */
1013
1014static sf_count_t
1015replace_write_d	(SF_PRIVATE *psf, const double *ptr, sf_count_t len)
1016{	BUF_UNION	ubuf ;
1017	int			bufferlen, writecount ;
1018	sf_count_t	total = 0 ;
1019
1020	/* FIXME : This is probably nowhere near optimal. */
1021	if (psf->peak_info)
1022		double64_peak_update (psf, ptr, len, 0) ;
1023
1024	bufferlen = ARRAY_LEN (ubuf.dbuf) ;
1025
1026	while (len > 0)
1027	{	if (len < bufferlen)
1028			bufferlen = (int) len ;
1029
1030		memcpy (ubuf.dbuf, ptr + total, bufferlen * sizeof (double)) ;
1031
1032		bd2d_write (ubuf.dbuf, bufferlen) ;
1033
1034		if (psf->data_endswap == SF_TRUE)
1035			endswap_double_array (ubuf.dbuf, bufferlen) ;
1036
1037		writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ;
1038		total += writecount ;
1039		if (writecount < bufferlen)
1040			break ;
1041		len -= writecount ;
1042		} ;
1043
1044	return total ;
1045} /* replace_write_d */
1046
1047/*----------------------------------------------------------------------------------------------
1048*/
1049
1050static void
1051d2bd_read (double *buffer, int count)
1052{	for (int i = 0 ; i < count ; i++)
1053	{	buffer [i] = DOUBLE64_READ ((unsigned char *) &buffer [i]) ;
1054		} ;
1055} /* d2bd_read */
1056
1057static void
1058bd2d_write (double *buffer, int count)
1059{	for (int i = 0 ; i < count ; i++)
1060	{	DOUBLE64_WRITE (buffer [i], (unsigned char*) &buffer [i]) ;
1061		} ;
1062} /* bd2d_write */
1063
1064