Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

796 lines
25KB

  1. /***************************************************/
  2. /*! \class FileWrite
  3. \brief STK audio file output class.
  4. This class provides output support for various
  5. audio file formats.
  6. FileWrite writes samples to an audio file. It supports
  7. multi-channel data.
  8. FileWrite currently supports uncompressed WAV, AIFF, AIFC, SND
  9. (AU), MAT-file (Matlab), and STK RAW file formats. Signed integer
  10. (8-, 16-, 24-, and 32-bit) and floating- point (32- and 64-bit)
  11. data types are supported. STK RAW files use 16-bit integers by
  12. definition. MAT-files will always be written as 64-bit floats.
  13. If a data type specification does not match the specified file
  14. type, the data type will automatically be modified. Compressed
  15. data types are not supported.
  16. by Perry R. Cook and Gary P. Scavone, 1995-2011.
  17. */
  18. /***************************************************/
  19. #include "FileWrite.h"
  20. #include <string>
  21. #include <cstdio>
  22. #include <cstring>
  23. #include <cmath>
  24. namespace stk {
  25. const FileWrite::FILE_TYPE FileWrite :: FILE_RAW = 1;
  26. const FileWrite::FILE_TYPE FileWrite :: FILE_WAV = 2;
  27. const FileWrite::FILE_TYPE FileWrite :: FILE_SND = 3;
  28. const FileWrite::FILE_TYPE FileWrite :: FILE_AIF = 4;
  29. const FileWrite::FILE_TYPE FileWrite :: FILE_MAT = 5;
  30. // WAV header structure. See ftp://ftp.isi.edu/in-notes/rfc2361.txt
  31. // for information regarding format codes.
  32. struct WaveHeader {
  33. char riff[4]; // "RIFF"
  34. SINT32 fileSize; // in bytes
  35. char wave[4]; // "WAVE"
  36. char fmt[4]; // "fmt "
  37. SINT32 chunkSize; // in bytes (16 for PCM)
  38. SINT16 formatCode; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law
  39. SINT16 nChannels; // 1=mono, 2=stereo
  40. SINT32 sampleRate;
  41. SINT32 bytesPerSecond;
  42. SINT16 bytesPerSample; // 2=16-bit mono, 4=16-bit stereo
  43. SINT16 bitsPerSample;
  44. SINT16 cbSize; // size of extension
  45. SINT16 validBits; // valid bits per sample
  46. SINT32 channelMask; // speaker position mask
  47. char subformat[16]; // format code and GUID
  48. char fact[4]; // "fact"
  49. SINT32 factSize; // fact chunk size
  50. SINT32 frames; // sample frames
  51. };
  52. // SND (AU) header structure (NeXT and Sun).
  53. struct SndHeader {
  54. char pref[4];
  55. SINT32 headerBytes;
  56. SINT32 dataBytes;
  57. SINT32 format;
  58. SINT32 sampleRate;
  59. SINT32 nChannels;
  60. char comment[16];
  61. };
  62. // AIFF/AIFC header structure ... only the part common to both
  63. // formats.
  64. struct AifHeader {
  65. char form[4]; // "FORM"
  66. SINT32 formSize; // in bytes
  67. char aiff[4]; // "AIFF" or "AIFC"
  68. char comm[4]; // "COMM"
  69. SINT32 commSize; // "COMM" chunk size (18 for AIFF, 24 for AIFC)
  70. SINT16 nChannels; // number of channels
  71. unsigned long sampleFrames; // sample frames of audio data
  72. SINT16 sampleSize; // in bits
  73. unsigned char srate[10]; // IEEE 754 floating point format
  74. };
  75. struct AifSsnd {
  76. char ssnd[4]; // "SSND"
  77. SINT32 ssndSize; // "SSND" chunk size
  78. unsigned long offset; // data offset in data block (should be 0)
  79. unsigned long blockSize; // not used by STK (should be 0)
  80. };
  81. // MAT-file 5 header structure.
  82. struct MatHeader {
  83. char heading[124]; // Header text field
  84. SINT16 hff[2]; // Header flag fields
  85. SINT32 fs[16]; // Sample rate data element
  86. SINT32 adf[11]; // Array data format fields
  87. // There's more, but it's of variable length
  88. };
  89. FileWrite :: FileWrite()
  90. : fd_( 0 )
  91. {
  92. }
  93. FileWrite::FileWrite( std::string fileName, unsigned int nChannels, FILE_TYPE type, Stk::StkFormat format )
  94. : fd_( 0 )
  95. {
  96. this->open( fileName, nChannels, type, format );
  97. }
  98. FileWrite :: ~FileWrite()
  99. {
  100. this->close();
  101. }
  102. void FileWrite :: close( void )
  103. {
  104. if ( fd_ == 0 ) return;
  105. if ( fileType_ == FILE_RAW )
  106. fclose( fd_ );
  107. else if ( fileType_ == FILE_WAV )
  108. this->closeWavFile();
  109. else if ( fileType_ == FILE_SND )
  110. this->closeSndFile();
  111. else if ( fileType_ == FILE_AIF )
  112. this->closeAifFile();
  113. else if ( fileType_ == FILE_MAT )
  114. this->closeMatFile();
  115. fd_ = 0;
  116. }
  117. bool FileWrite :: isOpen( void )
  118. {
  119. if ( fd_ ) return true;
  120. else return false;
  121. }
  122. void FileWrite :: open( std::string fileName, unsigned int nChannels, FileWrite::FILE_TYPE type, Stk::StkFormat format )
  123. {
  124. // Call close() in case another file is already open.
  125. this->close();
  126. if ( nChannels < 1 ) {
  127. oStream_ << "FileWrite::open: then channels argument must be greater than zero!";
  128. handleError( StkError::FUNCTION_ARGUMENT );
  129. }
  130. channels_ = nChannels;
  131. fileType_ = type;
  132. if ( format != STK_SINT8 && format != STK_SINT16 &&
  133. format != STK_SINT24 && format != STK_SINT32 &&
  134. format != STK_FLOAT32 && format != STK_FLOAT64 ) {
  135. oStream_ << "FileWrite::open: unknown data type (" << format << ") specified!";
  136. handleError( StkError::FUNCTION_ARGUMENT );
  137. }
  138. dataType_ = format;
  139. bool result = false;
  140. if ( fileType_ == FILE_RAW ) {
  141. if ( channels_ != 1 ) {
  142. oStream_ << "FileWrite::open: STK RAW files are, by definition, always monaural (channels = " << nChannels << " not supported)!";
  143. handleError( StkError::FUNCTION_ARGUMENT );
  144. }
  145. result = setRawFile( fileName );
  146. }
  147. else if ( fileType_ == FILE_WAV )
  148. result = setWavFile( fileName );
  149. else if ( fileType_ == FILE_SND )
  150. result = setSndFile( fileName );
  151. else if ( fileType_ == FILE_AIF )
  152. result = setAifFile( fileName );
  153. else if ( fileType_ == FILE_MAT )
  154. result = setMatFile( fileName );
  155. else {
  156. oStream_ << "FileWrite::open: unknown file type (" << fileType_ << ") specified!";
  157. handleError( StkError::FUNCTION_ARGUMENT );
  158. }
  159. if ( result == false )
  160. handleError( StkError::FILE_ERROR );
  161. frameCounter_ = 0;
  162. }
  163. bool FileWrite :: setRawFile( std::string fileName )
  164. {
  165. if ( fileName.find( ".raw" ) == std::string::npos ) fileName += ".raw";
  166. fd_ = fopen( fileName.c_str(), "wb" );
  167. if ( !fd_ ) {
  168. oStream_ << "FileWrite: could not create RAW file: " << fileName << '.';
  169. return false;
  170. }
  171. if ( dataType_ != STK_SINT16 ) {
  172. dataType_ = STK_SINT16;
  173. oStream_ << "FileWrite: using 16-bit signed integer data format for file " << fileName << '.';
  174. handleError( StkError::WARNING );
  175. }
  176. byteswap_ = false;
  177. #ifdef __LITTLE_ENDIAN__
  178. byteswap_ = true;
  179. #endif
  180. oStream_ << "FileWrite: creating RAW file: " << fileName;
  181. handleError( StkError::STATUS );
  182. return true;
  183. }
  184. bool FileWrite :: setWavFile( std::string fileName )
  185. {
  186. std::string name( fileName );
  187. if ( fileName.find( ".wav" ) == std::string::npos ) fileName += ".wav";
  188. fd_ = fopen( fileName.c_str(), "wb" );
  189. if ( !fd_ ) {
  190. oStream_ << "FileWrite: could not create WAV file: " << fileName;
  191. return false;
  192. }
  193. struct WaveHeader hdr = { {'R','I','F','F'}, 44, {'W','A','V','E'}, {'f','m','t',' '}, 16, 1, 1,
  194. (SINT32) Stk::sampleRate(), 0, 2, 16, 0, 0, 0,
  195. {'\x01','\x00','\x00','\x00','\x00','\x00','\x10','\x00','\x80','\x00','\x00','\xAA','\x00','\x38','\x9B','\x71'},
  196. {'f','a','c','t'}, 4, 0 };
  197. hdr.nChannels = (SINT16) channels_;
  198. if ( dataType_ == STK_SINT8 )
  199. hdr.bitsPerSample = 8;
  200. else if ( dataType_ == STK_SINT16 )
  201. hdr.bitsPerSample = 16;
  202. else if ( dataType_ == STK_SINT24 )
  203. hdr.bitsPerSample = 24;
  204. else if ( dataType_ == STK_SINT32 )
  205. hdr.bitsPerSample = 32;
  206. else if ( dataType_ == STK_FLOAT32 ) {
  207. hdr.formatCode = 3;
  208. hdr.bitsPerSample = 32;
  209. }
  210. else if ( dataType_ == STK_FLOAT64 ) {
  211. hdr.formatCode = 3;
  212. hdr.bitsPerSample = 64;
  213. }
  214. hdr.bytesPerSample = (SINT16) (channels_ * hdr.bitsPerSample / 8);
  215. hdr.bytesPerSecond = (SINT32) (hdr.sampleRate * hdr.bytesPerSample);
  216. unsigned int bytesToWrite = 36;
  217. bool useExtensible = false;
  218. if ( channels_ > 2 || hdr.bitsPerSample > 16 ) { // use extensible format
  219. useExtensible = true;
  220. bytesToWrite = 72;
  221. hdr.chunkSize += 24;
  222. hdr.formatCode = 0xFFFE;
  223. hdr.cbSize = 22;
  224. hdr.validBits = hdr.bitsPerSample;
  225. SINT16 *subFormat = (SINT16 *)&hdr.subformat[0];
  226. if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 )
  227. *subFormat = 3;
  228. else *subFormat = 1;
  229. }
  230. byteswap_ = false;
  231. #ifndef __LITTLE_ENDIAN__
  232. byteswap_ = true;
  233. swap32((unsigned char *)&hdr.chunkSize);
  234. swap16((unsigned char *)&hdr.formatCode);
  235. swap16((unsigned char *)&hdr.nChannels);
  236. swap32((unsigned char *)&hdr.sampleRate);
  237. swap32((unsigned char *)&hdr.bytesPerSecond);
  238. swap16((unsigned char *)&hdr.bytesPerSample);
  239. swap16((unsigned char *)&hdr.bitsPerSample);
  240. swap16((unsigned char *)&hdr.cbSize);
  241. swap16((unsigned char *)&hdr.validBits);
  242. swap16((unsigned char *)&hdr.subformat[0]);
  243. swap32((unsigned char *)&hdr.factSize);
  244. #endif
  245. char data[4] = {'d','a','t','a'};
  246. SINT32 dataSize = 0;
  247. if ( fwrite(&hdr, 1, bytesToWrite, fd_) != bytesToWrite ) goto error;
  248. if ( fwrite(&data, 4, 1, fd_) != 1 ) goto error;
  249. if ( fwrite(&dataSize, 4, 1, fd_) != 1 ) goto error;
  250. oStream_ << "FileWrite: creating WAV file: " << fileName;
  251. handleError( StkError::STATUS );
  252. return true;
  253. error:
  254. oStream_ << "FileWrite: could not write WAV header for file: " << fileName;
  255. return false;
  256. }
  257. void FileWrite :: closeWavFile( void )
  258. {
  259. int bytesPerSample = 1;
  260. if ( dataType_ == STK_SINT16 )
  261. bytesPerSample = 2;
  262. else if ( dataType_ == STK_SINT24 )
  263. bytesPerSample = 3;
  264. else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
  265. bytesPerSample = 4;
  266. else if ( dataType_ == STK_FLOAT64 )
  267. bytesPerSample = 8;
  268. bool useExtensible = false;
  269. int dataLocation = 40;
  270. if ( bytesPerSample > 2 || channels_ > 2 ) {
  271. useExtensible = true;
  272. dataLocation = 76;
  273. }
  274. SINT32 bytes = frameCounter_ * channels_ * bytesPerSample;
  275. if ( bytes % 2 ) { // pad extra byte if odd
  276. signed char sample = 0;
  277. fwrite( &sample, 1, 1, fd_ );
  278. }
  279. #ifndef __LITTLE_ENDIAN__
  280. swap32((unsigned char *)&bytes);
  281. #endif
  282. fseek( fd_, dataLocation, SEEK_SET ); // jump to data length
  283. fwrite( &bytes, 4, 1, fd_ );
  284. bytes = frameCounter_ * channels_ * bytesPerSample + 44;
  285. if ( useExtensible ) bytes += 36;
  286. #ifndef __LITTLE_ENDIAN__
  287. swap32((unsigned char *)&bytes);
  288. #endif
  289. fseek( fd_, 4, SEEK_SET ); // jump to file size
  290. fwrite( &bytes, 4, 1, fd_ );
  291. if ( useExtensible ) { // fill in the "fact" chunk frames value
  292. bytes = frameCounter_;
  293. #ifndef __LITTLE_ENDIAN__
  294. swap32((unsigned char *)&bytes);
  295. #endif
  296. fseek( fd_, 68, SEEK_SET );
  297. fwrite( &bytes, 4, 1, fd_ );
  298. }
  299. fclose( fd_ );
  300. }
  301. bool FileWrite :: setSndFile( std::string fileName )
  302. {
  303. std::string name( fileName );
  304. if ( fileName.find( ".snd" ) == std::string::npos ) fileName += ".snd";
  305. fd_ = fopen( fileName.c_str(), "wb" );
  306. if ( !fd_ ) {
  307. oStream_ << "FileWrite: could not create SND file: " << fileName;
  308. return false;
  309. }
  310. struct SndHeader hdr = {".sn", 40, 0, 3, (SINT32) Stk::sampleRate(), 1, "Created by STK"};
  311. hdr.pref[3] = 'd';
  312. hdr.nChannels = channels_;
  313. if ( dataType_ == STK_SINT8 )
  314. hdr.format = 2;
  315. else if ( dataType_ == STK_SINT16 )
  316. hdr.format = 3;
  317. else if ( dataType_ == STK_SINT24 )
  318. hdr.format = 4;
  319. else if ( dataType_ == STK_SINT32 )
  320. hdr.format = 5;
  321. else if ( dataType_ == STK_FLOAT32 )
  322. hdr.format = 6;
  323. else if ( dataType_ == STK_FLOAT64 )
  324. hdr.format = 7;
  325. byteswap_ = false;
  326. #ifdef __LITTLE_ENDIAN__
  327. byteswap_ = true;
  328. swap32 ((unsigned char *)&hdr.headerBytes);
  329. swap32 ((unsigned char *)&hdr.format);
  330. swap32 ((unsigned char *)&hdr.sampleRate);
  331. swap32 ((unsigned char *)&hdr.nChannels);
  332. #endif
  333. if ( fwrite(&hdr, 4, 10, fd_) != 10 ) {
  334. oStream_ << "FileWrite: Could not write SND header for file " << fileName << '.';
  335. return false;
  336. }
  337. oStream_ << "FileWrite: creating SND file: " << fileName;
  338. handleError( StkError::STATUS );
  339. return true;
  340. }
  341. void FileWrite :: closeSndFile( void )
  342. {
  343. int bytesPerSample = 1;
  344. if ( dataType_ == STK_SINT16 )
  345. bytesPerSample = 2;
  346. else if ( dataType_ == STK_SINT24 )
  347. bytesPerSample = 3;
  348. else if ( dataType_ == STK_SINT32 )
  349. bytesPerSample = 4;
  350. else if ( dataType_ == STK_FLOAT32 )
  351. bytesPerSample = 4;
  352. else if ( dataType_ == STK_FLOAT64 )
  353. bytesPerSample = 8;
  354. SINT32 bytes = frameCounter_ * bytesPerSample * channels_;
  355. #ifdef __LITTLE_ENDIAN__
  356. swap32 ((unsigned char *)&bytes);
  357. #endif
  358. fseek(fd_, 8, SEEK_SET); // jump to data size
  359. fwrite(&bytes, 4, 1, fd_);
  360. fclose(fd_);
  361. }
  362. bool FileWrite :: setAifFile( std::string fileName )
  363. {
  364. std::string name( fileName );
  365. if ( fileName.find( ".aif" ) == std::string::npos ) fileName += ".aif";
  366. fd_ = fopen( fileName.c_str(), "wb" );
  367. if ( !fd_ ) {
  368. oStream_ << "FileWrite: could not create AIF file: " << fileName;
  369. return false;
  370. }
  371. // Common parts of AIFF/AIFC header.
  372. struct AifHeader hdr = {{'F','O','R','M'}, 46, {'A','I','F','F'}, {'C','O','M','M'}, 18, 0, 0, 16, "0"};
  373. struct AifSsnd ssnd = {{'S','S','N','D'}, 8, 0, 0};
  374. hdr.nChannels = channels_;
  375. if ( dataType_ == STK_SINT8 )
  376. hdr.sampleSize = 8;
  377. else if ( dataType_ == STK_SINT16 )
  378. hdr.sampleSize = 16;
  379. else if ( dataType_ == STK_SINT24 )
  380. hdr.sampleSize = 24;
  381. else if ( dataType_ == STK_SINT32 )
  382. hdr.sampleSize = 32;
  383. else if ( dataType_ == STK_FLOAT32 ) {
  384. hdr.aiff[3] = 'C';
  385. hdr.sampleSize = 32;
  386. hdr.commSize = 24;
  387. }
  388. else if ( dataType_ == STK_FLOAT64 ) {
  389. hdr.aiff[3] = 'C';
  390. hdr.sampleSize = 64;
  391. hdr.commSize = 24;
  392. }
  393. // For AIFF files, the sample rate is stored in a 10-byte,
  394. // IEEE Standard 754 floating point number, so we need to
  395. // convert to that.
  396. SINT16 i;
  397. unsigned long exp;
  398. unsigned long rate = (unsigned long) Stk::sampleRate();
  399. memset( hdr.srate, 0, 10 );
  400. exp = rate;
  401. for ( i=0; i<32; i++ ) {
  402. exp >>= 1;
  403. if ( !exp ) break;
  404. }
  405. i += 16383;
  406. #ifdef __LITTLE_ENDIAN__
  407. swap16((unsigned char *)&i);
  408. #endif
  409. *(SINT16 *)(hdr.srate) = (SINT16) i;
  410. for ( i=32; i; i-- ) {
  411. if ( rate & 0x80000000 ) break;
  412. rate <<= 1;
  413. }
  414. #ifdef __LITTLE_ENDIAN__
  415. swap32((unsigned char *)&rate);
  416. #endif
  417. *(unsigned long *)(hdr.srate+2) = (unsigned long) rate;
  418. byteswap_ = false;
  419. #ifdef __LITTLE_ENDIAN__
  420. byteswap_ = true;
  421. swap32((unsigned char *)&hdr.formSize);
  422. swap32((unsigned char *)&hdr.commSize);
  423. swap16((unsigned char *)&hdr.nChannels);
  424. swap16((unsigned char *)&hdr.sampleSize);
  425. swap32((unsigned char *)&ssnd.ssndSize);
  426. swap32((unsigned char *)&ssnd.offset);
  427. swap32((unsigned char *)&ssnd.blockSize);
  428. #endif
  429. // The structure boundaries don't allow a single write of 54 bytes.
  430. if ( fwrite(&hdr, 4, 5, fd_) != 5 ) goto error;
  431. if ( fwrite(&hdr.nChannels, 2, 1, fd_) != 1 ) goto error;
  432. if ( fwrite(&hdr.sampleFrames, 4, 1, fd_) != 1 ) goto error;
  433. if ( fwrite(&hdr.sampleSize, 2, 1, fd_) != 1 ) goto error;
  434. if ( fwrite(&hdr.srate, 10, 1, fd_) != 1 ) goto error;
  435. if ( dataType_ == STK_FLOAT32 ) {
  436. char type[4] = {'f','l','3','2'};
  437. char zeroes[2] = { 0, 0 };
  438. if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
  439. if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
  440. }
  441. else if ( dataType_ == STK_FLOAT64 ) {
  442. char type[4] = {'f','l','6','4'};
  443. char zeroes[2] = { 0, 0 };
  444. if ( fwrite(&type, 4, 1, fd_) != 1 ) goto error;
  445. if ( fwrite(&zeroes, 2, 1, fd_) != 1 ) goto error;
  446. }
  447. if ( fwrite(&ssnd, 4, 4, fd_) != 4 ) goto error;
  448. oStream_ << "FileWrite: creating AIF file: " << fileName;
  449. handleError( StkError::STATUS );
  450. return true;
  451. error:
  452. oStream_ << "FileWrite: could not write AIF header for file: " << fileName;
  453. return false;
  454. }
  455. void FileWrite :: closeAifFile( void )
  456. {
  457. unsigned long frames = (unsigned long) frameCounter_;
  458. #ifdef __LITTLE_ENDIAN__
  459. swap32((unsigned char *)&frames);
  460. #endif
  461. fseek(fd_, 22, SEEK_SET); // jump to "COMM" sampleFrames
  462. fwrite(&frames, 4, 1, fd_);
  463. int bytesPerSample = 1;
  464. if ( dataType_ == STK_SINT16 )
  465. bytesPerSample = 2;
  466. if ( dataType_ == STK_SINT24 )
  467. bytesPerSample = 3;
  468. else if ( dataType_ == STK_SINT32 || dataType_ == STK_FLOAT32 )
  469. bytesPerSample = 4;
  470. else if ( dataType_ == STK_FLOAT64 )
  471. bytesPerSample = 8;
  472. unsigned long bytes = frameCounter_ * bytesPerSample * channels_ + 46;
  473. if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
  474. #ifdef __LITTLE_ENDIAN__
  475. swap32((unsigned char *)&bytes);
  476. #endif
  477. fseek(fd_, 4, SEEK_SET); // jump to file size
  478. fwrite(&bytes, 4, 1, fd_);
  479. bytes = frameCounter_ * bytesPerSample * channels_ + 8;
  480. if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 ) bytes += 6;
  481. #ifdef __LITTLE_ENDIAN__
  482. swap32((unsigned char *)&bytes);
  483. #endif
  484. if ( dataType_ == STK_FLOAT32 || dataType_ == STK_FLOAT64 )
  485. fseek(fd_, 48, SEEK_SET); // jump to "SSND" chunk size
  486. else
  487. fseek(fd_, 42, SEEK_SET); // jump to "SSND" chunk size
  488. fwrite(&bytes, 4, 1, fd_);
  489. fclose( fd_ );
  490. }
  491. bool FileWrite :: setMatFile( std::string fileName )
  492. {
  493. if ( fileName.find( ".mat" ) == std::string::npos ) fileName += ".mat";
  494. fd_ = fopen( fileName.c_str(), "w+b" );
  495. if ( !fd_ ) {
  496. oStream_ << "FileWrite: could not create MAT file: " << fileName;
  497. return false;
  498. }
  499. if ( dataType_ != STK_FLOAT64 ) {
  500. dataType_ = STK_FLOAT64;
  501. oStream_ << "FileWrite: using 64-bit floating-point data format for file " << fileName << '.';
  502. handleError( StkError::DEBUG_PRINT );
  503. }
  504. struct MatHeader hdr;
  505. strcpy( hdr.heading,"MATLAB 5.0 MAT-file, Generated using the Synthesis ToolKit in C++ (STK). By Perry R. Cook and Gary P. Scavone." );
  506. for ( int i=strlen(hdr.heading); i<124; i++ ) hdr.heading[i] = ' ';
  507. // Header Flag Fields
  508. hdr.hff[0] = (SINT16) 0x0100; // Version field
  509. hdr.hff[1] = (SINT16) 'M'; // Endian indicator field ("MI")
  510. hdr.hff[1] <<= 8;
  511. hdr.hff[1] += 'I';
  512. // Write sample rate in array data element
  513. hdr.fs[0] = (SINT32) 14; // Matlab array data type value
  514. hdr.fs[1] = (SINT32) 56; // Size of data element to follow (in bytes)
  515. // Numeric Array Subelements (4):
  516. // 1. Array Flags
  517. hdr.fs[2] = (SINT32) 6; // Matlab 32-bit unsigned integer data type value
  518. hdr.fs[3] = (SINT32) 8; // 8 bytes of data to follow
  519. hdr.fs[4] = (SINT32) 6; // Double-precision array, no array flags set
  520. hdr.fs[5] = (SINT32) 0; // 4 bytes undefined
  521. // 2. Array Dimensions
  522. hdr.fs[6] = (SINT32) 5; // Matlab 32-bit signed integer data type value
  523. hdr.fs[7] = (SINT32) 8; // 8 bytes of data to follow (2D array)
  524. hdr.fs[8] = (SINT32) 1; // 1 row
  525. hdr.fs[9] = (SINT32) 1; // 1 column
  526. // 3. Array Name (small data format element)
  527. hdr.fs[10] = 0x00020001;
  528. hdr.fs[11] = 's' << 8;
  529. hdr.fs[11] += 'f';
  530. // 4. Real Part
  531. hdr.fs[12] = 9; // Matlab IEEE 754 double data type
  532. hdr.fs[13] = 8; // 8 bytes of data to follow
  533. FLOAT64 *sampleRate = (FLOAT64 *)&hdr.fs[14];
  534. *sampleRate = (FLOAT64) Stk::sampleRate();
  535. // Write audio samples in array data element
  536. hdr.adf[0] = (SINT32) 14; // Matlab array data type value
  537. hdr.adf[1] = (SINT32) 0; // Size of file after this point to end (in bytes)
  538. // Numeric Array Subelements (4):
  539. // 1. Array Flags
  540. hdr.adf[2] = (SINT32) 6; // Matlab 32-bit unsigned integer data type value
  541. hdr.adf[3] = (SINT32) 8; // 8 bytes of data to follow
  542. hdr.adf[4] = (SINT32) 6; // Double-precision array, no array flags set
  543. hdr.adf[5] = (SINT32) 0; // 4 bytes undefined
  544. // 2. Array Dimensions
  545. hdr.adf[6] = (SINT32) 5; // Matlab 32-bit signed integer data type value
  546. hdr.adf[7] = (SINT32) 8; // 8 bytes of data to follow (2D array)
  547. hdr.adf[8] = (SINT32) channels_; // This is the number of rows
  548. hdr.adf[9] = (SINT32) 0; // This is the number of columns
  549. // 3. Array Name We'll use fileName for the matlab array name (as
  550. // well as the file name), though we might need to strip off a
  551. // leading directory path. If fileName is 4 characters or less, we
  552. // have to use a small data format element for the array name data
  553. // element. Otherwise, the array name must be formatted in 8-byte
  554. // increments (up to 31 characters + NULL).
  555. std::string name = fileName;
  556. size_t found;
  557. found = name.find_last_of("/\\");
  558. name = name.substr(found+1);
  559. SINT32 namelength = (SINT32) name.size() - 4; // strip off the ".mat" extension
  560. if ( namelength > 31 ) namelength = 31; // Truncate name to 31 characters.
  561. if ( namelength > 4 ) {
  562. hdr.adf[10] = (SINT32) 1; // Matlab 8-bit signed integer data type value
  563. }
  564. else { // Compressed data element format
  565. hdr.adf[10] = (namelength << 16) + 1;
  566. }
  567. SINT32 headsize = 40; // Number of bytes in audio data element so far.
  568. // Write the fixed portion of the header
  569. if ( fwrite(&hdr, 236, 1, fd_) != 1 ) goto error;
  570. // Write MATLAB array name
  571. SINT32 tmp;
  572. if ( namelength > 4 ) {
  573. if ( fwrite(&namelength, 4, 1, fd_) != 1) goto error;
  574. if ( fwrite(name.c_str(), namelength, 1, fd_) != 1 ) goto error;
  575. tmp = (SINT32) ceil((float)namelength / 8);
  576. if ( fseek(fd_, tmp*8-namelength, SEEK_CUR) == -1 ) goto error;
  577. headsize += tmp * 8;
  578. }
  579. else { // Compressed data element format
  580. if ( fwrite(name.c_str(), namelength, 1, fd_) != 1 ) goto error;
  581. tmp = 4 - namelength;
  582. if ( fseek(fd_, tmp, SEEK_CUR) == -1 ) goto error;
  583. }
  584. // Finish writing known header information
  585. //4. Real Part
  586. tmp = 9; // Matlab IEEE 754 double data type
  587. if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
  588. tmp = 0; // Size of real part subelement in bytes (8 per sample)
  589. if ( fwrite(&tmp, 4, 1, fd_) != 1 ) goto error;
  590. headsize += 8; // Total number of bytes in data element so far
  591. if ( fseek(fd_, 196, SEEK_SET) == -1 ) goto error;
  592. if ( fwrite(&headsize, 4, 1, fd_) != 1 ) goto error; // Write header size ... will update at end
  593. if ( fseek(fd_, 0, SEEK_END) == -1 ) goto error;
  594. byteswap_ = false;
  595. oStream_ << "FileWrite: creating MAT-file: " << fileName;
  596. handleError( StkError::STATUS );
  597. return true;
  598. error:
  599. oStream_ << "FileWrite: could not write MAT-file header for file " << fileName << '.';
  600. return false;
  601. }
  602. void FileWrite :: closeMatFile( void )
  603. {
  604. fseek(fd_, 228, SEEK_SET); // jump to number of columns
  605. fwrite(&frameCounter_, 4, 1, fd_);
  606. SINT32 headsize, temp;
  607. fseek(fd_, 196, SEEK_SET); // jump to header size
  608. fread(&headsize, 4, 1, fd_);
  609. temp = headsize;
  610. headsize += (SINT32) (frameCounter_ * 8 * channels_);
  611. fseek(fd_, 196, SEEK_SET);
  612. // Write file size (minus some header info)
  613. fwrite(&headsize, 4, 1, fd_);
  614. fseek(fd_, temp+196, SEEK_SET); // jumpt to data size (in bytes)
  615. temp = frameCounter_ * 8 * channels_;
  616. fwrite(&temp, 4, 1, fd_);
  617. fclose(fd_);
  618. }
  619. void FileWrite :: write( StkFrames& buffer )
  620. {
  621. if ( fd_ == 0 ) {
  622. oStream_ << "FileWrite::write(): a file has not yet been opened!";
  623. handleError( StkError::WARNING );
  624. return;
  625. }
  626. if ( buffer.channels() != channels_ ) {
  627. oStream_ << "FileWrite::write(): number of channels in the StkFrames argument does not match that specified to open() function!";
  628. handleError( StkError::FUNCTION_ARGUMENT );
  629. return;
  630. }
  631. unsigned long nSamples = buffer.size();
  632. if ( dataType_ == STK_SINT16 ) {
  633. SINT16 sample;
  634. for ( unsigned long k=0; k<nSamples; k++ ) {
  635. sample = (SINT16) (buffer[k] * 32767.0);
  636. //sample = ((SINT16) (( buffer[k] + 1.0 ) * 32767.5 + 0.5)) - 32768;
  637. if ( byteswap_ ) swap16( (unsigned char *)&sample );
  638. if ( fwrite(&sample, 2, 1, fd_) != 1 ) goto error;
  639. }
  640. }
  641. else if ( dataType_ == STK_SINT8 ) {
  642. if ( fileType_ == FILE_WAV ) { // 8-bit WAV data is unsigned!
  643. unsigned char sample;
  644. for ( unsigned long k=0; k<nSamples; k++ ) {
  645. sample = (unsigned char) (buffer[k] * 127.0 + 128.0);
  646. if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
  647. }
  648. }
  649. else {
  650. signed char sample;
  651. for ( unsigned long k=0; k<nSamples; k++ ) {
  652. sample = (signed char) (buffer[k] * 127.0);
  653. //sample = ((signed char) (( buffer[k] + 1.0 ) * 127.5 + 0.5)) - 128;
  654. if ( fwrite(&sample, 1, 1, fd_) != 1 ) goto error;
  655. }
  656. }
  657. }
  658. else if ( dataType_ == STK_SINT32 ) {
  659. SINT32 sample;
  660. for ( unsigned long k=0; k<nSamples; k++ ) {
  661. sample = (SINT32) (buffer[k] * 2147483647.0);
  662. //sample = ((SINT32) (( buffer[k] + 1.0 ) * 2147483647.5 + 0.5)) - 2147483648;
  663. if ( byteswap_ ) swap32( (unsigned char *)&sample );
  664. if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
  665. }
  666. }
  667. else if ( dataType_ == STK_FLOAT32 ) {
  668. FLOAT32 sample;
  669. for ( unsigned long k=0; k<nSamples; k++ ) {
  670. sample = (FLOAT32) (buffer[k]);
  671. if ( byteswap_ ) swap32( (unsigned char *)&sample );
  672. if ( fwrite(&sample, 4, 1, fd_) != 1 ) goto error;
  673. }
  674. }
  675. else if ( dataType_ == STK_FLOAT64 ) {
  676. FLOAT64 sample;
  677. for ( unsigned long k=0; k<nSamples; k++ ) {
  678. sample = (FLOAT64) (buffer[k]);
  679. if ( byteswap_ ) swap64( (unsigned char *)&sample );
  680. if ( fwrite(&sample, 8, 1, fd_) != 1 ) goto error;
  681. }
  682. }
  683. else if ( dataType_ == STK_SINT24 ) {
  684. SINT32 sample;
  685. for ( unsigned long k=0; k<nSamples; k++ ) {
  686. sample = (SINT32) (buffer[k] * 8388607.0);
  687. if ( byteswap_ ) {
  688. swap32( (unsigned char *)&sample );
  689. unsigned char *ptr = (unsigned char *) &sample;
  690. if ( fwrite(ptr+1, 3, 1, fd_) != 1 ) goto error;
  691. }
  692. else
  693. if ( fwrite(&sample, 3, 1, fd_) != 1 ) goto error;
  694. }
  695. }
  696. frameCounter_ += buffer.frames();
  697. return;
  698. error:
  699. oStream_ << "FileWrite::write(): error writing data to file!";
  700. handleError( StkError::FILE_ERROR );
  701. }
  702. } // stk namespace