1/* 2** Copyright (C) 2002-2017 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 <fcntl.h> 23#include <string.h> 24#include <ctype.h> 25#include <math.h> 26 27#include "sndfile.h" 28#include "sfendian.h" 29#include "common.h" 30 31/*------------------------------------------------------------------------------ 32** Information on how to decode and encode this file was obtained in a PDF 33** file which I found on http://www.wotsit.org/. 34** Also did a lot of testing with GNU Octave but do not have access to 35** Matlab (tm) and so could not test it there. 36*/ 37 38/*------------------------------------------------------------------------------ 39** Macros to handle big/little endian issues. 40*/ 41 42#define MAT4_BE_DOUBLE (MAKE_MARKER (0, 0, 0x03, 0xE8)) 43#define MAT4_LE_DOUBLE (MAKE_MARKER (0, 0, 0, 0)) 44 45#define MAT4_BE_FLOAT (MAKE_MARKER (0, 0, 0x03, 0xF2)) 46#define MAT4_LE_FLOAT (MAKE_MARKER (0x0A, 0, 0, 0)) 47 48#define MAT4_BE_PCM_32 (MAKE_MARKER (0, 0, 0x03, 0xFC)) 49#define MAT4_LE_PCM_32 (MAKE_MARKER (0x14, 0, 0, 0)) 50 51#define MAT4_BE_PCM_16 (MAKE_MARKER (0, 0, 0x04, 0x06)) 52#define MAT4_LE_PCM_16 (MAKE_MARKER (0x1E, 0, 0, 0)) 53 54/* Can't see any reason to ever implement this. */ 55#define MAT4_BE_PCM_U8 (MAKE_MARKER (0, 0, 0x04, 0x1A)) 56#define MAT4_LE_PCM_U8 (MAKE_MARKER (0x32, 0, 0, 0)) 57 58/*------------------------------------------------------------------------------ 59** Private static functions. 60*/ 61 62static int mat4_close (SF_PRIVATE *psf) ; 63 64static int mat4_format_to_encoding (int format, int endian) ; 65 66static int mat4_write_header (SF_PRIVATE *psf, int calc_length) ; 67static int mat4_read_header (SF_PRIVATE *psf) ; 68 69static const char * mat4_marker_to_str (int marker) ; 70 71/*------------------------------------------------------------------------------ 72** Public function. 73*/ 74 75int 76mat4_open (SF_PRIVATE *psf) 77{ int subformat, error = 0 ; 78 79 if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) 80 { if ((error = mat4_read_header (psf))) 81 return error ; 82 } ; 83 84 if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MAT4) 85 return SFE_BAD_OPEN_FORMAT ; 86 87 subformat = SF_CODEC (psf->sf.format) ; 88 89 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) 90 { if (psf->is_pipe) 91 return SFE_NO_PIPE_WRITE ; 92 93 psf->endian = SF_ENDIAN (psf->sf.format) ; 94 if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) 95 psf->endian = SF_ENDIAN_LITTLE ; 96 else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) 97 psf->endian = SF_ENDIAN_BIG ; 98 99 if ((error = mat4_write_header (psf, SF_FALSE))) 100 return error ; 101 102 psf->write_header = mat4_write_header ; 103 } ; 104 105 psf->container_close = mat4_close ; 106 107 psf->blockwidth = psf->bytewidth * psf->sf.channels ; 108 109 switch (subformat) 110 { case SF_FORMAT_PCM_16 : 111 case SF_FORMAT_PCM_32 : 112 error = pcm_init (psf) ; 113 break ; 114 115 case SF_FORMAT_FLOAT : 116 error = float32_init (psf) ; 117 break ; 118 119 case SF_FORMAT_DOUBLE : 120 error = double64_init (psf) ; 121 break ; 122 123 default : break ; 124 } ; 125 126 return error ; 127} /* mat4_open */ 128 129/*------------------------------------------------------------------------------ 130*/ 131 132static int 133mat4_close (SF_PRIVATE *psf) 134{ 135 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) 136 mat4_write_header (psf, SF_TRUE) ; 137 138 return 0 ; 139} /* mat4_close */ 140 141/*------------------------------------------------------------------------------ 142*/ 143 144static int 145mat4_write_header (SF_PRIVATE *psf, int calc_length) 146{ sf_count_t current ; 147 int encoding ; 148 double samplerate ; 149 150 current = psf_ftell (psf) ; 151 152 if (calc_length) 153 { psf->filelength = psf_get_filelen (psf) ; 154 155 psf->datalength = psf->filelength - psf->dataoffset ; 156 if (psf->dataend) 157 psf->datalength -= psf->filelength - psf->dataend ; 158 159 psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; 160 } ; 161 162 encoding = mat4_format_to_encoding (SF_CODEC (psf->sf.format), psf->endian) ; 163 164 if (encoding == -1) 165 return SFE_BAD_OPEN_FORMAT ; 166 167 /* Reset the current header length to zero. */ 168 psf->header.ptr [0] = 0 ; 169 psf->header.indx = 0 ; 170 psf_fseek (psf, 0, SEEK_SET) ; 171 172 /* Need sample rate as a double for writing to the header. */ 173 samplerate = psf->sf.samplerate ; 174 175 if (psf->endian == SF_ENDIAN_BIG) 176 { psf_binheader_writef (psf, "Em444", BHWm (MAT4_BE_DOUBLE), BHW4 (1), BHW4 (1), BHW4 (0)) ; 177 psf_binheader_writef (psf, "E4bd", BHW4 (11), BHWv ("samplerate"), BHWz (11), BHWd (samplerate)) ; 178 psf_binheader_writef (psf, "tEm484", BHWm (encoding), BHW4 (psf->sf.channels), BHW8 (psf->sf.frames), BHW4 (0)) ; 179 psf_binheader_writef (psf, "E4b", BHW4 (9), BHWv ("wavedata"), BHWz (9)) ; 180 } 181 else if (psf->endian == SF_ENDIAN_LITTLE) 182 { psf_binheader_writef (psf, "em444", BHWm (MAT4_LE_DOUBLE), BHW4 (1), BHW4 (1), BHW4 (0)) ; 183 psf_binheader_writef (psf, "e4bd", BHW4 (11), BHWv ("samplerate"), BHWz (11), BHWd (samplerate)) ; 184 psf_binheader_writef (psf, "tem484", BHWm (encoding), BHW4 (psf->sf.channels), BHW8 (psf->sf.frames), BHW4 (0)) ; 185 psf_binheader_writef (psf, "e4b", BHW4 (9), BHWv ("wavedata"), BHWz (9)) ; 186 } 187 else 188 return SFE_BAD_OPEN_FORMAT ; 189 190 /* Header construction complete so write it out. */ 191 psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; 192 193 if (psf->error) 194 return psf->error ; 195 196 psf->dataoffset = psf->header.indx ; 197 198 if (current > 0) 199 psf_fseek (psf, current, SEEK_SET) ; 200 201 return psf->error ; 202} /* mat4_write_header */ 203 204static int 205mat4_read_header (SF_PRIVATE *psf) 206{ char buffer [256] ; 207 uint32_t marker, namesize ; 208 int rows, cols, imag ; 209 double value ; 210 const char *marker_str ; 211 char name [64] ; 212 213 psf_binheader_readf (psf, "pm", 0, &marker) ; 214 215 /* MAT4 file must start with a double for the samplerate. */ 216 if (marker == MAT4_BE_DOUBLE) 217 { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; 218 marker_str = "big endian double" ; 219 } 220 else if (marker == MAT4_LE_DOUBLE) 221 { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; 222 marker_str = "little endian double" ; 223 } 224 else 225 return SFE_UNIMPLEMENTED ; 226 227 psf_log_printf (psf, "GNU Octave 2.0 / MATLAB v4.2 format\nMarker : %s\n", marker_str) ; 228 229 psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; 230 231 psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; 232 233 psf_binheader_readf (psf, "4", &namesize) ; 234 235 if (namesize >= SIGNED_SIZEOF (name)) 236 return SFE_MAT4_BAD_NAME ; 237 238 psf_binheader_readf (psf, "b", name, namesize) ; 239 name [namesize] = 0 ; 240 241 psf_log_printf (psf, " Name : %s\n", name) ; 242 243 psf_binheader_readf (psf, "d", &value) ; 244 245 snprintf (buffer, sizeof (buffer), " Value : %f\n", value) ; 246 psf_log_printf (psf, buffer) ; 247 248 if ((rows != 1) || (cols != 1)) 249 return SFE_MAT4_NO_SAMPLERATE ; 250 251 psf->sf.samplerate = psf_lrint (value) ; 252 253 /* Now write out the audio data. */ 254 255 psf_binheader_readf (psf, "m", &marker) ; 256 257 psf_log_printf (psf, "Marker : %s\n", mat4_marker_to_str (marker)) ; 258 259 psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; 260 261 psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; 262 263 psf_binheader_readf (psf, "4", &namesize) ; 264 265 if (namesize >= SIGNED_SIZEOF (name)) 266 return SFE_MAT4_BAD_NAME ; 267 268 psf_binheader_readf (psf, "b", name, namesize) ; 269 name [namesize] = 0 ; 270 271 psf_log_printf (psf, " Name : %s\n", name) ; 272 273 psf->dataoffset = psf_ftell (psf) ; 274 275 if (rows == 0) 276 { psf_log_printf (psf, "*** Error : zero channel count.\n") ; 277 return SFE_CHANNEL_COUNT_ZERO ; 278 } 279 else if (rows > SF_MAX_CHANNELS) 280 { psf_log_printf (psf, "*** Error : channel count %d > SF_MAX_CHANNELS.\n", rows) ; 281 return SFE_CHANNEL_COUNT ; 282 } ; 283 284 psf->sf.channels = rows ; 285 psf->sf.frames = cols ; 286 287 psf->sf.format = psf->endian | SF_FORMAT_MAT4 ; 288 switch (marker) 289 { case MAT4_BE_DOUBLE : 290 case MAT4_LE_DOUBLE : 291 psf->sf.format |= SF_FORMAT_DOUBLE ; 292 psf->bytewidth = 8 ; 293 break ; 294 295 case MAT4_BE_FLOAT : 296 case MAT4_LE_FLOAT : 297 psf->sf.format |= SF_FORMAT_FLOAT ; 298 psf->bytewidth = 4 ; 299 break ; 300 301 case MAT4_BE_PCM_32 : 302 case MAT4_LE_PCM_32 : 303 psf->sf.format |= SF_FORMAT_PCM_32 ; 304 psf->bytewidth = 4 ; 305 break ; 306 307 case MAT4_BE_PCM_16 : 308 case MAT4_LE_PCM_16 : 309 psf->sf.format |= SF_FORMAT_PCM_16 ; 310 psf->bytewidth = 2 ; 311 break ; 312 313 default : 314 psf_log_printf (psf, "*** Error : Bad marker %08X\n", marker) ; 315 return SFE_UNIMPLEMENTED ; 316 } ; 317 318 if ((psf->filelength - psf->dataoffset) < psf->sf.channels * psf->sf.frames * psf->bytewidth) 319 { psf_log_printf (psf, "*** File seems to be truncated. %D <--> %D\n", 320 psf->filelength - psf->dataoffset, psf->sf.channels * psf->sf.frames * psf->bytewidth) ; 321 } 322 else if ((psf->filelength - psf->dataoffset) > psf->sf.channels * psf->sf.frames * psf->bytewidth) 323 psf->dataend = psf->dataoffset + rows * cols * psf->bytewidth ; 324 325 psf->datalength = psf->filelength - psf->dataoffset - psf->dataend ; 326 327 psf->sf.sections = 1 ; 328 329 return 0 ; 330} /* mat4_read_header */ 331 332static int 333mat4_format_to_encoding (int format, int endian) 334{ 335 switch (format | endian) 336 { case (SF_FORMAT_PCM_16 | SF_ENDIAN_BIG) : 337 return MAT4_BE_PCM_16 ; 338 339 case (SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE) : 340 return MAT4_LE_PCM_16 ; 341 342 case (SF_FORMAT_PCM_32 | SF_ENDIAN_BIG) : 343 return MAT4_BE_PCM_32 ; 344 345 case (SF_FORMAT_PCM_32 | SF_ENDIAN_LITTLE) : 346 return MAT4_LE_PCM_32 ; 347 348 case (SF_FORMAT_FLOAT | SF_ENDIAN_BIG) : 349 return MAT4_BE_FLOAT ; 350 351 case (SF_FORMAT_FLOAT | SF_ENDIAN_LITTLE) : 352 return MAT4_LE_FLOAT ; 353 354 case (SF_FORMAT_DOUBLE | SF_ENDIAN_BIG) : 355 return MAT4_BE_DOUBLE ; 356 357 case (SF_FORMAT_DOUBLE | SF_ENDIAN_LITTLE) : 358 return MAT4_LE_DOUBLE ; 359 360 default : break ; 361 } ; 362 363 return -1 ; 364} /* mat4_format_to_encoding */ 365 366static const char * 367mat4_marker_to_str (int marker) 368{ static char str [32] ; 369 370 switch (marker) 371 { 372 case MAT4_BE_PCM_16 : return "big endian 16 bit PCM" ; 373 case MAT4_LE_PCM_16 : return "little endian 16 bit PCM" ; 374 375 case MAT4_BE_PCM_32 : return "big endian 32 bit PCM" ; 376 case MAT4_LE_PCM_32 : return "little endian 32 bit PCM" ; 377 378 379 case MAT4_BE_FLOAT : return "big endian float" ; 380 case MAT4_LE_FLOAT : return "big endian float" ; 381 382 case MAT4_BE_DOUBLE : return "big endian double" ; 383 case MAT4_LE_DOUBLE : return "little endian double" ; 384 } ; 385 386 /* This is a little unsafe but is really only for debugging. */ 387 str [sizeof (str) - 1] = 0 ; 388 snprintf (str, sizeof (str) - 1, "%08X", marker) ; 389 return str ; 390} /* mat4_marker_to_str */ 391 392