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