mat5.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /*
  2. ** Copyright (C) 2002-2017 Erik de Castro Lopo <[email protected]>
  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. #include "sfconfig.h"
  19. #include <stdio.h>
  20. #include <fcntl.h>
  21. #include <string.h>
  22. #include <ctype.h>
  23. #include <math.h>
  24. #include "sndfile.h"
  25. #include "sfendian.h"
  26. #include "common.h"
  27. /*------------------------------------------------------------------------------
  28. ** Information on how to decode and encode this file was obtained in a PDF
  29. ** file which I found on http://www.wotsit.org/.
  30. ** Also did a lot of testing with GNU Octave but do not have access to
  31. ** Matlab (tm) and so could not test it there.
  32. */
  33. /*------------------------------------------------------------------------------
  34. ** Macros to handle big/little endian issues.
  35. */
  36. #define MATL_MARKER (MAKE_MARKER ('M', 'A', 'T', 'L'))
  37. #define IM_MARKER (('I' << 8) + 'M')
  38. #define MI_MARKER (('M' << 8) + 'I')
  39. /*------------------------------------------------------------------------------
  40. ** Enums and typedefs.
  41. */
  42. enum
  43. { MAT5_TYPE_SCHAR = 0x1,
  44. MAT5_TYPE_UCHAR = 0x2,
  45. MAT5_TYPE_INT16 = 0x3,
  46. MAT5_TYPE_UINT16 = 0x4,
  47. MAT5_TYPE_INT32 = 0x5,
  48. MAT5_TYPE_UINT32 = 0x6,
  49. MAT5_TYPE_FLOAT = 0x7,
  50. MAT5_TYPE_DOUBLE = 0x9,
  51. MAT5_TYPE_ARRAY = 0xE,
  52. MAT5_TYPE_COMP_USHORT = 0x00020004,
  53. MAT5_TYPE_COMP_UINT = 0x00040006
  54. } ;
  55. typedef struct
  56. { sf_count_t size ;
  57. int rows, cols ;
  58. char name [32] ;
  59. } MAT5_MATRIX ;
  60. /*------------------------------------------------------------------------------
  61. ** Private static functions.
  62. */
  63. static int mat5_close (SF_PRIVATE *psf) ;
  64. static int mat5_write_header (SF_PRIVATE *psf, int calc_length) ;
  65. static int mat5_read_header (SF_PRIVATE *psf) ;
  66. /*------------------------------------------------------------------------------
  67. ** Public function.
  68. */
  69. int
  70. mat5_open (SF_PRIVATE *psf)
  71. { int subformat, error = 0 ;
  72. if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
  73. { if ((error = mat5_read_header (psf)))
  74. return error ;
  75. } ;
  76. if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MAT5)
  77. return SFE_BAD_OPEN_FORMAT ;
  78. subformat = SF_CODEC (psf->sf.format) ;
  79. if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
  80. { if (psf->is_pipe)
  81. return SFE_NO_PIPE_WRITE ;
  82. psf->endian = SF_ENDIAN (psf->sf.format) ;
  83. if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0))
  84. psf->endian = SF_ENDIAN_LITTLE ;
  85. else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0))
  86. psf->endian = SF_ENDIAN_BIG ;
  87. if ((error = mat5_write_header (psf, SF_FALSE)))
  88. return error ;
  89. psf->write_header = mat5_write_header ;
  90. } ;
  91. psf->container_close = mat5_close ;
  92. psf->blockwidth = psf->bytewidth * psf->sf.channels ;
  93. switch (subformat)
  94. { case SF_FORMAT_PCM_U8 :
  95. case SF_FORMAT_PCM_16 :
  96. case SF_FORMAT_PCM_32 :
  97. error = pcm_init (psf) ;
  98. break ;
  99. case SF_FORMAT_FLOAT :
  100. error = float32_init (psf) ;
  101. break ;
  102. case SF_FORMAT_DOUBLE :
  103. error = double64_init (psf) ;
  104. break ;
  105. default : break ;
  106. } ;
  107. return error ;
  108. } /* mat5_open */
  109. /*------------------------------------------------------------------------------
  110. */
  111. static int
  112. mat5_close (SF_PRIVATE *psf)
  113. {
  114. if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
  115. mat5_write_header (psf, SF_TRUE) ;
  116. return 0 ;
  117. } /* mat5_close */
  118. /*------------------------------------------------------------------------------
  119. */
  120. static int
  121. mat5_write_header (SF_PRIVATE *psf, int calc_length)
  122. { static const char *filename = "MATLAB 5.0 MAT-file, written by " PACKAGE_NAME "-" PACKAGE_VERSION ", " ;
  123. static const char *sr_name = "samplerate\0\0\0\0\0\0\0\0\0\0\0" ;
  124. static const char *wd_name = "wavedata\0" ;
  125. char buffer [256] ;
  126. sf_count_t current, datasize ;
  127. int encoding ;
  128. current = psf_ftell (psf) ;
  129. if (calc_length)
  130. { psf_fseek (psf, 0, SEEK_END) ;
  131. psf->filelength = psf_ftell (psf) ;
  132. psf_fseek (psf, 0, SEEK_SET) ;
  133. psf->datalength = psf->filelength - psf->dataoffset ;
  134. if (psf->dataend)
  135. psf->datalength -= psf->filelength - psf->dataend ;
  136. psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
  137. } ;
  138. switch (SF_CODEC (psf->sf.format))
  139. { case SF_FORMAT_PCM_U8 :
  140. encoding = MAT5_TYPE_UCHAR ;
  141. break ;
  142. case SF_FORMAT_PCM_16 :
  143. encoding = MAT5_TYPE_INT16 ;
  144. break ;
  145. case SF_FORMAT_PCM_32 :
  146. encoding = MAT5_TYPE_INT32 ;
  147. break ;
  148. case SF_FORMAT_FLOAT :
  149. encoding = MAT5_TYPE_FLOAT ;
  150. break ;
  151. case SF_FORMAT_DOUBLE :
  152. encoding = MAT5_TYPE_DOUBLE ;
  153. break ;
  154. default :
  155. return SFE_BAD_OPEN_FORMAT ;
  156. } ;
  157. /* Reset the current header length to zero. */
  158. psf->header.ptr [0] = 0 ;
  159. psf->header.indx = 0 ;
  160. psf_fseek (psf, 0, SEEK_SET) ;
  161. psf_get_date_str (buffer, sizeof (buffer)) ;
  162. psf_binheader_writef (psf, "bb", BHWv (filename), BHWz (strlen (filename)), BHWv (buffer), BHWz (strlen (buffer) + 1)) ;
  163. memset (buffer, ' ', 124 - psf->header.indx) ;
  164. psf_binheader_writef (psf, "b", BHWv (buffer), BHWz (124 - psf->header.indx)) ;
  165. psf->rwf_endian = psf->endian ;
  166. if (psf->rwf_endian == SF_ENDIAN_BIG)
  167. psf_binheader_writef (psf, "2b", BHW2 (0x0100), BHWv ("MI"), BHWz (2)) ;
  168. else
  169. psf_binheader_writef (psf, "2b", BHW2 (0x0100), BHWv ("IM"), BHWz (2)) ;
  170. psf_binheader_writef (psf, "444444", BHW4 (MAT5_TYPE_ARRAY), BHW4 (64), BHW4 (MAT5_TYPE_UINT32), BHW4 (8), BHW4 (6), BHW4 (0)) ;
  171. psf_binheader_writef (psf, "4444", BHW4 (MAT5_TYPE_INT32), BHW4 (8), BHW4 (1), BHW4 (1)) ;
  172. psf_binheader_writef (psf, "44b", BHW4 (MAT5_TYPE_SCHAR), BHW4 (strlen (sr_name)), BHWv (sr_name), BHWz (16)) ;
  173. if (psf->sf.samplerate > 0xFFFF)
  174. psf_binheader_writef (psf, "44", BHW4 (MAT5_TYPE_COMP_UINT), BHW4 (psf->sf.samplerate)) ;
  175. else
  176. { unsigned short samplerate = psf->sf.samplerate ;
  177. psf_binheader_writef (psf, "422", BHW4 (MAT5_TYPE_COMP_USHORT), BHW2 (samplerate), BHW2 (0)) ;
  178. } ;
  179. datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ;
  180. psf_binheader_writef (psf, "t484444", BHW4 (MAT5_TYPE_ARRAY), BHW8 (datasize + 64), BHW4 (MAT5_TYPE_UINT32), BHW4 (8), BHW4 (6), BHW4 (0)) ;
  181. psf_binheader_writef (psf, "t4448", BHW4 (MAT5_TYPE_INT32), BHW4 (8), BHW4 (psf->sf.channels), BHW8 (psf->sf.frames)) ;
  182. psf_binheader_writef (psf, "44b", BHW4 (MAT5_TYPE_SCHAR), BHW4 (strlen (wd_name)), BHWv (wd_name), BHWz (strlen (wd_name))) ;
  183. datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ;
  184. if (datasize > 0x7FFFFFFF)
  185. datasize = 0x7FFFFFFF ;
  186. psf_binheader_writef (psf, "t48", BHW4 (encoding), BHW8 (datasize)) ;
  187. /* Header construction complete so write it out. */
  188. psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
  189. if (psf->error)
  190. return psf->error ;
  191. psf->dataoffset = psf->header.indx ;
  192. if (current > 0)
  193. psf_fseek (psf, current, SEEK_SET) ;
  194. return psf->error ;
  195. } /* mat5_write_header */
  196. static int
  197. mat5_read_header (SF_PRIVATE *psf)
  198. { char buffer [256], name [32] ;
  199. short version, endian ;
  200. int type, flags1, flags2, rows, cols ;
  201. unsigned size ;
  202. int have_samplerate = 1 ;
  203. psf_binheader_readf (psf, "pb", 0, buffer, 124) ;
  204. buffer [125] = 0 ;
  205. if (strlen (buffer) >= 124)
  206. return SFE_UNIMPLEMENTED ;
  207. if (strstr (buffer, "MATLAB 5.0 MAT-file") == buffer)
  208. psf_log_printf (psf, "%s\n", buffer) ;
  209. psf_binheader_readf (psf, "E22", &version, &endian) ;
  210. if (endian == MI_MARKER)
  211. { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ;
  212. if (CPU_IS_LITTLE_ENDIAN) version = ENDSWAP_16 (version) ;
  213. }
  214. else if (endian == IM_MARKER)
  215. { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ;
  216. if (CPU_IS_BIG_ENDIAN) version = ENDSWAP_16 (version) ;
  217. }
  218. else
  219. return SFE_MAT5_BAD_ENDIAN ;
  220. if ((CPU_IS_LITTLE_ENDIAN && endian == IM_MARKER) ||
  221. (CPU_IS_BIG_ENDIAN && endian == MI_MARKER))
  222. version = ENDSWAP_16 (version) ;
  223. psf_log_printf (psf, "Version : 0x%04X\n", version) ;
  224. psf_log_printf (psf, "Endian : 0x%04X => %s\n", endian,
  225. (psf->endian == SF_ENDIAN_LITTLE) ? "Little" : "Big") ;
  226. /*========================================================*/
  227. psf_binheader_readf (psf, "44", &type, &size) ;
  228. psf_log_printf (psf, "Block\n Type : %X Size : %d\n", type, size) ;
  229. if (type != MAT5_TYPE_ARRAY)
  230. return SFE_MAT5_NO_BLOCK ;
  231. psf_binheader_readf (psf, "44", &type, &size) ;
  232. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  233. if (type != MAT5_TYPE_UINT32)
  234. return SFE_MAT5_NO_BLOCK ;
  235. psf_binheader_readf (psf, "44", &flags1, &flags2) ;
  236. psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ;
  237. psf_binheader_readf (psf, "44", &type, &size) ;
  238. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  239. if (type != MAT5_TYPE_INT32)
  240. return SFE_MAT5_NO_BLOCK ;
  241. psf_binheader_readf (psf, "44", &rows, &cols) ;
  242. psf_log_printf (psf, " Rows : %d Cols : %d\n", rows, cols) ;
  243. if (rows != 1 || cols != 1)
  244. { if (psf->sf.samplerate == 0)
  245. psf->sf.samplerate = 44100 ;
  246. have_samplerate = 0 ;
  247. }
  248. psf_binheader_readf (psf, "4", &type) ;
  249. if (type == MAT5_TYPE_SCHAR)
  250. { psf_binheader_readf (psf, "4", &size) ;
  251. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  252. if (size > SIGNED_SIZEOF (name) - 1)
  253. { psf_log_printf (psf, "Error : Bad name length.\n") ;
  254. return SFE_MAT5_NO_BLOCK ;
  255. } ;
  256. psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ;
  257. name [size] = 0 ;
  258. }
  259. else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR)
  260. { size = type >> 16 ;
  261. if (size > 4)
  262. { psf_log_printf (psf, "Error : Bad name length.\n") ;
  263. return SFE_MAT5_NO_BLOCK ;
  264. } ;
  265. psf_log_printf (psf, " Type : %X\n", type) ;
  266. psf_binheader_readf (psf, "4", &name) ;
  267. name [size] = 0 ;
  268. }
  269. else
  270. return SFE_MAT5_NO_BLOCK ;
  271. psf_log_printf (psf, " Name : %s\n", name) ;
  272. /*-----------------------------------------*/
  273. psf_binheader_readf (psf, "44", &type, &size) ;
  274. if (!have_samplerate)
  275. goto skip_samplerate ;
  276. switch (type)
  277. { case MAT5_TYPE_DOUBLE :
  278. { double samplerate ;
  279. psf_binheader_readf (psf, "d", &samplerate) ;
  280. snprintf (name, sizeof (name), "%f\n", samplerate) ;
  281. psf_log_printf (psf, " Val : %s\n", name) ;
  282. psf->sf.samplerate = psf_lrint (samplerate) ;
  283. } ;
  284. break ;
  285. case MAT5_TYPE_COMP_USHORT :
  286. { unsigned short samplerate ;
  287. psf_binheader_readf (psf, "j2j", -4, &samplerate, 2) ;
  288. psf_log_printf (psf, " Val : %u\n", samplerate) ;
  289. psf->sf.samplerate = samplerate ;
  290. }
  291. break ;
  292. case MAT5_TYPE_COMP_UINT :
  293. psf_log_printf (psf, " Val : %u\n", size) ;
  294. psf->sf.samplerate = size ;
  295. break ;
  296. default :
  297. psf_log_printf (psf, " Type : %X Size : %d ***\n", type, size) ;
  298. return SFE_MAT5_SAMPLE_RATE ;
  299. } ;
  300. /*-----------------------------------------*/
  301. psf_binheader_readf (psf, "44", &type, &size) ;
  302. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  303. if (type != MAT5_TYPE_ARRAY)
  304. return SFE_MAT5_NO_BLOCK ;
  305. psf_binheader_readf (psf, "44", &type, &size) ;
  306. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  307. if (type != MAT5_TYPE_UINT32)
  308. return SFE_MAT5_NO_BLOCK ;
  309. psf_binheader_readf (psf, "44", &flags1, &flags2) ;
  310. psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ;
  311. psf_binheader_readf (psf, "44", &type, &size) ;
  312. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  313. if (type != MAT5_TYPE_INT32)
  314. return SFE_MAT5_NO_BLOCK ;
  315. psf_binheader_readf (psf, "44", &rows, &cols) ;
  316. psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ;
  317. psf_binheader_readf (psf, "4", &type) ;
  318. if (type == MAT5_TYPE_SCHAR)
  319. { psf_binheader_readf (psf, "4", &size) ;
  320. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  321. if (size > SIGNED_SIZEOF (name) - 1)
  322. { psf_log_printf (psf, "Error : Bad name length.\n") ;
  323. return SFE_MAT5_NO_BLOCK ;
  324. } ;
  325. psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ;
  326. name [size] = 0 ;
  327. }
  328. else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR)
  329. { size = type >> 16 ;
  330. if (size > 4)
  331. { psf_log_printf (psf, "Error : Bad name length.\n") ;
  332. return SFE_MAT5_NO_BLOCK ;
  333. } ;
  334. psf_log_printf (psf, " Type : %X\n", type) ;
  335. psf_binheader_readf (psf, "4", &name) ;
  336. name [size] = 0 ;
  337. }
  338. else
  339. return SFE_MAT5_NO_BLOCK ;
  340. psf_log_printf (psf, " Name : %s\n", name) ;
  341. psf_binheader_readf (psf, "44", &type, &size) ;
  342. psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ;
  343. skip_samplerate :
  344. /*++++++++++++++++++++++++++++++++++++++++++++++++++*/
  345. if (rows == 0 && cols == 0)
  346. { psf_log_printf (psf, "*** Error : zero channel count.\n") ;
  347. return SFE_CHANNEL_COUNT_ZERO ;
  348. } ;
  349. psf->sf.channels = rows ;
  350. psf->sf.frames = cols ;
  351. psf->sf.format = psf->endian | SF_FORMAT_MAT5 ;
  352. switch (type)
  353. { case MAT5_TYPE_DOUBLE :
  354. psf_log_printf (psf, "Data type : double\n") ;
  355. psf->sf.format |= SF_FORMAT_DOUBLE ;
  356. psf->bytewidth = 8 ;
  357. break ;
  358. case MAT5_TYPE_FLOAT :
  359. psf_log_printf (psf, "Data type : float\n") ;
  360. psf->sf.format |= SF_FORMAT_FLOAT ;
  361. psf->bytewidth = 4 ;
  362. break ;
  363. case MAT5_TYPE_INT32 :
  364. psf_log_printf (psf, "Data type : 32 bit PCM\n") ;
  365. psf->sf.format |= SF_FORMAT_PCM_32 ;
  366. psf->bytewidth = 4 ;
  367. break ;
  368. case MAT5_TYPE_INT16 :
  369. psf_log_printf (psf, "Data type : 16 bit PCM\n") ;
  370. psf->sf.format |= SF_FORMAT_PCM_16 ;
  371. psf->bytewidth = 2 ;
  372. break ;
  373. case MAT5_TYPE_UCHAR :
  374. psf_log_printf (psf, "Data type : unsigned 8 bit PCM\n") ;
  375. psf->sf.format |= SF_FORMAT_PCM_U8 ;
  376. psf->bytewidth = 1 ;
  377. break ;
  378. default :
  379. psf_log_printf (psf, "*** Error : Bad marker %08X\n", type) ;
  380. return SFE_UNIMPLEMENTED ;
  381. } ;
  382. psf->dataoffset = psf_ftell (psf) ;
  383. psf->datalength = psf->filelength - psf->dataoffset ;
  384. return 0 ;
  385. } /* mat5_read_header */