annotate src/libsndfile-1.0.25/src/vox_adpcm.c @ 114:241db1b1eff2

added includes as well
author Matthias Mauch <matthiasmauch@gmail.com>
date Thu, 09 Jan 2014 13:23:08 +0000
parents 545efbb81310
children
rev   line source
cannam@85 1 /*
cannam@85 2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
cannam@85 3 **
cannam@85 4 ** This program is free software; you can redistribute it and/or modify
cannam@85 5 ** it under the terms of the GNU Lesser General Public License as published by
cannam@85 6 ** the Free Software Foundation; either version 2.1 of the License, or
cannam@85 7 ** (at your option) any later version.
cannam@85 8 **
cannam@85 9 ** This program is distributed in the hope that it will be useful,
cannam@85 10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
cannam@85 11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
cannam@85 12 ** GNU Lesser General Public License for more details.
cannam@85 13 **
cannam@85 14 ** You should have received a copy of the GNU Lesser General Public License
cannam@85 15 ** along with this program; if not, write to the Free Software
cannam@85 16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
cannam@85 17 */
cannam@85 18
cannam@85 19 /*
cannam@85 20 ** This is the OKI / Dialogic ADPCM encoder/decoder. It converts from
cannam@85 21 ** 12 bit linear sample data to a 4 bit ADPCM.
cannam@85 22 */
cannam@85 23
cannam@85 24 /*
cannam@85 25 * Note: some early Dialogic hardware does not always reset the ADPCM encoder
cannam@85 26 * at the start of each vox file. This can result in clipping and/or DC offset
cannam@85 27 * problems when it comes to decoding the audio. Whilst little can be done
cannam@85 28 * about the clipping, a DC offset can be removed by passing the decoded audio
cannam@85 29 * through a high-pass filter at e.g. 10Hz.
cannam@85 30 */
cannam@85 31
cannam@85 32 #include "sfconfig.h"
cannam@85 33
cannam@85 34 #include <stdio.h>
cannam@85 35 #include <stdlib.h>
cannam@85 36 #include <string.h>
cannam@85 37 #include <math.h>
cannam@85 38
cannam@85 39 #include "sndfile.h"
cannam@85 40 #include "sfendian.h"
cannam@85 41 #include "common.h"
cannam@85 42 #include "ima_oki_adpcm.h"
cannam@85 43
cannam@85 44
cannam@85 45 static sf_count_t vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
cannam@85 46 static sf_count_t vox_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
cannam@85 47 static sf_count_t vox_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
cannam@85 48 static sf_count_t vox_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
cannam@85 49
cannam@85 50 static sf_count_t vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
cannam@85 51 static sf_count_t vox_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
cannam@85 52 static sf_count_t vox_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
cannam@85 53 static sf_count_t vox_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
cannam@85 54
cannam@85 55 static int vox_read_block (SF_PRIVATE *psf, IMA_OKI_ADPCM *pvox, short *ptr, int len) ;
cannam@85 56
cannam@85 57 /*------------------------------------------------------------------------------
cannam@85 58 */
cannam@85 59
cannam@85 60 static int
cannam@85 61 codec_close (SF_PRIVATE * psf)
cannam@85 62 {
cannam@85 63 IMA_OKI_ADPCM * p = (IMA_OKI_ADPCM *) psf->codec_data ;
cannam@85 64
cannam@85 65 if (p->errors)
cannam@85 66 psf_log_printf (psf, "*** Warning : ADPCM state errors: %d\n", p->errors) ;
cannam@85 67 return p->errors ;
cannam@85 68 } /* code_close */
cannam@85 69
cannam@85 70 int
cannam@85 71 vox_adpcm_init (SF_PRIVATE *psf)
cannam@85 72 { IMA_OKI_ADPCM *pvox = NULL ;
cannam@85 73
cannam@85 74 if (psf->file.mode == SFM_RDWR)
cannam@85 75 return SFE_BAD_MODE_RW ;
cannam@85 76
cannam@85 77 if (psf->file.mode == SFM_WRITE && psf->sf.channels != 1)
cannam@85 78 return SFE_CHANNEL_COUNT ;
cannam@85 79
cannam@85 80 if ((pvox = malloc (sizeof (IMA_OKI_ADPCM))) == NULL)
cannam@85 81 return SFE_MALLOC_FAILED ;
cannam@85 82
cannam@85 83 psf->codec_data = (void*) pvox ;
cannam@85 84 memset (pvox, 0, sizeof (IMA_OKI_ADPCM)) ;
cannam@85 85
cannam@85 86 if (psf->file.mode == SFM_WRITE)
cannam@85 87 { psf->write_short = vox_write_s ;
cannam@85 88 psf->write_int = vox_write_i ;
cannam@85 89 psf->write_float = vox_write_f ;
cannam@85 90 psf->write_double = vox_write_d ;
cannam@85 91 }
cannam@85 92 else
cannam@85 93 { psf_log_printf (psf, "Header-less OKI Dialogic ADPCM encoded file.\n") ;
cannam@85 94 psf_log_printf (psf, "Setting up for 8kHz, mono, Vox ADPCM.\n") ;
cannam@85 95
cannam@85 96 psf->read_short = vox_read_s ;
cannam@85 97 psf->read_int = vox_read_i ;
cannam@85 98 psf->read_float = vox_read_f ;
cannam@85 99 psf->read_double = vox_read_d ;
cannam@85 100 } ;
cannam@85 101
cannam@85 102 /* Standard sample rate chennels etc. */
cannam@85 103 if (psf->sf.samplerate < 1)
cannam@85 104 psf->sf.samplerate = 8000 ;
cannam@85 105 psf->sf.channels = 1 ;
cannam@85 106
cannam@85 107 psf->sf.frames = psf->filelength * 2 ;
cannam@85 108
cannam@85 109 psf->sf.seekable = SF_FALSE ;
cannam@85 110 psf->codec_close = codec_close ;
cannam@85 111
cannam@85 112 /* Seek back to start of data. */
cannam@85 113 if (psf_fseek (psf, 0 , SEEK_SET) == -1)
cannam@85 114 return SFE_BAD_SEEK ;
cannam@85 115
cannam@85 116 ima_oki_adpcm_init (pvox, IMA_OKI_ADPCM_TYPE_OKI) ;
cannam@85 117
cannam@85 118 return 0 ;
cannam@85 119 } /* vox_adpcm_init */
cannam@85 120
cannam@85 121 /*==============================================================================
cannam@85 122 */
cannam@85 123
cannam@85 124 static int
cannam@85 125 vox_read_block (SF_PRIVATE *psf, IMA_OKI_ADPCM *pvox, short *ptr, int len)
cannam@85 126 { int indx = 0, k ;
cannam@85 127
cannam@85 128 while (indx < len)
cannam@85 129 { pvox->code_count = (len - indx > IMA_OKI_ADPCM_PCM_LEN) ? IMA_OKI_ADPCM_CODE_LEN : (len - indx + 1) / 2 ;
cannam@85 130
cannam@85 131 if ((k = psf_fread (pvox->codes, 1, pvox->code_count, psf)) != pvox->code_count)
cannam@85 132 { if (psf_ftell (psf) != psf->filelength)
cannam@85 133 psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pvox->code_count) ;
cannam@85 134 if (k == 0)
cannam@85 135 break ;
cannam@85 136 } ;
cannam@85 137
cannam@85 138 pvox->code_count = k ;
cannam@85 139
cannam@85 140 ima_oki_adpcm_decode_block (pvox) ;
cannam@85 141
cannam@85 142 memcpy (&(ptr [indx]), pvox->pcm, pvox->pcm_count * sizeof (short)) ;
cannam@85 143 indx += pvox->pcm_count ;
cannam@85 144 } ;
cannam@85 145
cannam@85 146 return indx ;
cannam@85 147 } /* vox_read_block */
cannam@85 148
cannam@85 149
cannam@85 150 static sf_count_t
cannam@85 151 vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
cannam@85 152 { IMA_OKI_ADPCM *pvox ;
cannam@85 153 int readcount, count ;
cannam@85 154 sf_count_t total = 0 ;
cannam@85 155
cannam@85 156 if (! psf->codec_data)
cannam@85 157 return 0 ;
cannam@85 158 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 159
cannam@85 160 while (len > 0)
cannam@85 161 { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ;
cannam@85 162
cannam@85 163 count = vox_read_block (psf, pvox, ptr, readcount) ;
cannam@85 164
cannam@85 165 total += count ;
cannam@85 166 len -= count ;
cannam@85 167 if (count != readcount)
cannam@85 168 break ;
cannam@85 169 } ;
cannam@85 170
cannam@85 171 return total ;
cannam@85 172 } /* vox_read_s */
cannam@85 173
cannam@85 174 static sf_count_t
cannam@85 175 vox_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
cannam@85 176 { IMA_OKI_ADPCM *pvox ;
cannam@85 177 short *sptr ;
cannam@85 178 int k, bufferlen, readcount, count ;
cannam@85 179 sf_count_t total = 0 ;
cannam@85 180
cannam@85 181 if (! psf->codec_data)
cannam@85 182 return 0 ;
cannam@85 183 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 184
cannam@85 185 sptr = psf->u.sbuf ;
cannam@85 186 bufferlen = ARRAY_LEN (psf->u.sbuf) ;
cannam@85 187 while (len > 0)
cannam@85 188 { readcount = (len >= bufferlen) ? bufferlen : (int) len ;
cannam@85 189 count = vox_read_block (psf, pvox, sptr, readcount) ;
cannam@85 190 for (k = 0 ; k < readcount ; k++)
cannam@85 191 ptr [total + k] = ((int) sptr [k]) << 16 ;
cannam@85 192 total += count ;
cannam@85 193 len -= readcount ;
cannam@85 194 if (count != readcount)
cannam@85 195 break ;
cannam@85 196 } ;
cannam@85 197
cannam@85 198 return total ;
cannam@85 199 } /* vox_read_i */
cannam@85 200
cannam@85 201 static sf_count_t
cannam@85 202 vox_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
cannam@85 203 { IMA_OKI_ADPCM *pvox ;
cannam@85 204 short *sptr ;
cannam@85 205 int k, bufferlen, readcount, count ;
cannam@85 206 sf_count_t total = 0 ;
cannam@85 207 float normfact ;
cannam@85 208
cannam@85 209 if (! psf->codec_data)
cannam@85 210 return 0 ;
cannam@85 211 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 212
cannam@85 213 normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
cannam@85 214
cannam@85 215 sptr = psf->u.sbuf ;
cannam@85 216 bufferlen = ARRAY_LEN (psf->u.sbuf) ;
cannam@85 217 while (len > 0)
cannam@85 218 { readcount = (len >= bufferlen) ? bufferlen : (int) len ;
cannam@85 219 count = vox_read_block (psf, pvox, sptr, readcount) ;
cannam@85 220 for (k = 0 ; k < readcount ; k++)
cannam@85 221 ptr [total + k] = normfact * (float) (sptr [k]) ;
cannam@85 222 total += count ;
cannam@85 223 len -= readcount ;
cannam@85 224 if (count != readcount)
cannam@85 225 break ;
cannam@85 226 } ;
cannam@85 227
cannam@85 228 return total ;
cannam@85 229 } /* vox_read_f */
cannam@85 230
cannam@85 231 static sf_count_t
cannam@85 232 vox_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
cannam@85 233 { IMA_OKI_ADPCM *pvox ;
cannam@85 234 short *sptr ;
cannam@85 235 int k, bufferlen, readcount, count ;
cannam@85 236 sf_count_t total = 0 ;
cannam@85 237 double normfact ;
cannam@85 238
cannam@85 239 if (! psf->codec_data)
cannam@85 240 return 0 ;
cannam@85 241 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 242
cannam@85 243 normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
cannam@85 244
cannam@85 245 sptr = psf->u.sbuf ;
cannam@85 246 bufferlen = ARRAY_LEN (psf->u.sbuf) ;
cannam@85 247 while (len > 0)
cannam@85 248 { readcount = (len >= bufferlen) ? bufferlen : (int) len ;
cannam@85 249 count = vox_read_block (psf, pvox, sptr, readcount) ;
cannam@85 250 for (k = 0 ; k < readcount ; k++)
cannam@85 251 ptr [total + k] = normfact * (double) (sptr [k]) ;
cannam@85 252 total += count ;
cannam@85 253 len -= readcount ;
cannam@85 254 if (count != readcount)
cannam@85 255 break ;
cannam@85 256 } ;
cannam@85 257
cannam@85 258 return total ;
cannam@85 259 } /* vox_read_d */
cannam@85 260
cannam@85 261 /*------------------------------------------------------------------------------
cannam@85 262 */
cannam@85 263
cannam@85 264 static int
cannam@85 265 vox_write_block (SF_PRIVATE *psf, IMA_OKI_ADPCM *pvox, const short *ptr, int len)
cannam@85 266 { int indx = 0, k ;
cannam@85 267
cannam@85 268 while (indx < len)
cannam@85 269 { pvox->pcm_count = (len - indx > IMA_OKI_ADPCM_PCM_LEN) ? IMA_OKI_ADPCM_PCM_LEN : len - indx ;
cannam@85 270
cannam@85 271 memcpy (pvox->pcm, &(ptr [indx]), pvox->pcm_count * sizeof (short)) ;
cannam@85 272
cannam@85 273 ima_oki_adpcm_encode_block (pvox) ;
cannam@85 274
cannam@85 275 if ((k = psf_fwrite (pvox->codes, 1, pvox->code_count, psf)) != pvox->code_count)
cannam@85 276 psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pvox->code_count) ;
cannam@85 277
cannam@85 278 indx += pvox->pcm_count ;
cannam@85 279 } ;
cannam@85 280
cannam@85 281 return indx ;
cannam@85 282 } /* vox_write_block */
cannam@85 283
cannam@85 284 static sf_count_t
cannam@85 285 vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
cannam@85 286 { IMA_OKI_ADPCM *pvox ;
cannam@85 287 int writecount, count ;
cannam@85 288 sf_count_t total = 0 ;
cannam@85 289
cannam@85 290 if (! psf->codec_data)
cannam@85 291 return 0 ;
cannam@85 292 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 293
cannam@85 294 while (len)
cannam@85 295 { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ;
cannam@85 296
cannam@85 297 count = vox_write_block (psf, pvox, ptr, writecount) ;
cannam@85 298
cannam@85 299 total += count ;
cannam@85 300 len -= count ;
cannam@85 301 if (count != writecount)
cannam@85 302 break ;
cannam@85 303 } ;
cannam@85 304
cannam@85 305 return total ;
cannam@85 306 } /* vox_write_s */
cannam@85 307
cannam@85 308 static sf_count_t
cannam@85 309 vox_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
cannam@85 310 { IMA_OKI_ADPCM *pvox ;
cannam@85 311 short *sptr ;
cannam@85 312 int k, bufferlen, writecount, count ;
cannam@85 313 sf_count_t total = 0 ;
cannam@85 314
cannam@85 315 if (! psf->codec_data)
cannam@85 316 return 0 ;
cannam@85 317 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 318
cannam@85 319 sptr = psf->u.sbuf ;
cannam@85 320 bufferlen = ARRAY_LEN (psf->u.sbuf) ;
cannam@85 321 while (len > 0)
cannam@85 322 { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
cannam@85 323 for (k = 0 ; k < writecount ; k++)
cannam@85 324 sptr [k] = ptr [total + k] >> 16 ;
cannam@85 325 count = vox_write_block (psf, pvox, sptr, writecount) ;
cannam@85 326 total += count ;
cannam@85 327 len -= writecount ;
cannam@85 328 if (count != writecount)
cannam@85 329 break ;
cannam@85 330 } ;
cannam@85 331
cannam@85 332 return total ;
cannam@85 333 } /* vox_write_i */
cannam@85 334
cannam@85 335 static sf_count_t
cannam@85 336 vox_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
cannam@85 337 { IMA_OKI_ADPCM *pvox ;
cannam@85 338 short *sptr ;
cannam@85 339 int k, bufferlen, writecount, count ;
cannam@85 340 sf_count_t total = 0 ;
cannam@85 341 float normfact ;
cannam@85 342
cannam@85 343 if (! psf->codec_data)
cannam@85 344 return 0 ;
cannam@85 345 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 346
cannam@85 347 normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
cannam@85 348
cannam@85 349 sptr = psf->u.sbuf ;
cannam@85 350 bufferlen = ARRAY_LEN (psf->u.sbuf) ;
cannam@85 351 while (len > 0)
cannam@85 352 { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
cannam@85 353 for (k = 0 ; k < writecount ; k++)
cannam@85 354 sptr [k] = lrintf (normfact * ptr [total + k]) ;
cannam@85 355 count = vox_write_block (psf, pvox, sptr, writecount) ;
cannam@85 356 total += count ;
cannam@85 357 len -= writecount ;
cannam@85 358 if (count != writecount)
cannam@85 359 break ;
cannam@85 360 } ;
cannam@85 361
cannam@85 362 return total ;
cannam@85 363 } /* vox_write_f */
cannam@85 364
cannam@85 365 static sf_count_t
cannam@85 366 vox_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
cannam@85 367 { IMA_OKI_ADPCM *pvox ;
cannam@85 368 short *sptr ;
cannam@85 369 int k, bufferlen, writecount, count ;
cannam@85 370 sf_count_t total = 0 ;
cannam@85 371 double normfact ;
cannam@85 372
cannam@85 373 if (! psf->codec_data)
cannam@85 374 return 0 ;
cannam@85 375 pvox = (IMA_OKI_ADPCM*) psf->codec_data ;
cannam@85 376
cannam@85 377 normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
cannam@85 378
cannam@85 379 sptr = psf->u.sbuf ;
cannam@85 380 bufferlen = ARRAY_LEN (psf->u.sbuf) ;
cannam@85 381 while (len > 0)
cannam@85 382 { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
cannam@85 383 for (k = 0 ; k < writecount ; k++)
cannam@85 384 sptr [k] = lrint (normfact * ptr [total + k]) ;
cannam@85 385 count = vox_write_block (psf, pvox, sptr, writecount) ;
cannam@85 386 total += count ;
cannam@85 387 len -= writecount ;
cannam@85 388 if (count != writecount)
cannam@85 389 break ;
cannam@85 390 } ;
cannam@85 391
cannam@85 392 return total ;
cannam@85 393 } /* vox_write_d */
cannam@85 394