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.

435 lines
11KB

  1. /* SpiralSynth
  2. * Copyleft (C) 2000 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 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 General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU 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 <iostream>
  19. #include <fstream>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <limits.h>
  23. #include "RiffWav.h"
  24. #include "SpiralInfo.h"
  25. #include <sys/types.h>
  26. #include <sys/stat.h>
  27. #include <fcntl.h>
  28. //#define TRACE_OUT
  29. const int HEADERLEN = (4+24+8);
  30. #if __BYTE_ORDER == BIG_ENDIAN
  31. #define SWAPSHORT(a) (a)=(((a)<<8)|(((a)>>8)&0xff))
  32. #define SWAPINT(a) (a)=(((a)&0x000000ff)<<24)|(((a)&0x0000ff00)<<8)|(((a)&0x00ff0000)>>8)|(((a)&0xff000000)>>24)
  33. #else
  34. #define SWAPSHORT(a)
  35. #define SWAPINT(a)
  36. #endif
  37. int WavFile::Open(string FileName, Mode mode, Channels channels)
  38. {
  39. if (m_Stream!=NULL)
  40. {
  41. cerr<<"WavFile: File already open ["<<FileName<<"]"<<endl;
  42. return 0;
  43. }
  44. if (mode==WRITE) m_Stream = fopen (FileName.c_str(), "wb");
  45. else m_Stream = fopen (FileName.c_str(), "rb");
  46. if (m_Stream == (FILE*)0)
  47. {
  48. cerr<<"WavFile: File ["<<FileName<<"] does not exist"<<endl;
  49. return 0;
  50. }
  51. //Write the header
  52. if (mode==WRITE)
  53. {
  54. m_Header.RiffName[0]='R';
  55. m_Header.RiffName[1]='I';
  56. m_Header.RiffName[2]='F';
  57. m_Header.RiffName[3]='F';
  58. m_Header.RiffFileLength=HEADERLEN; // bzzt - wrong
  59. m_Header.RiffTypeName[0]='W';
  60. m_Header.RiffTypeName[1]='A';
  61. m_Header.RiffTypeName[2]='V';
  62. m_Header.RiffTypeName[3]='E';
  63. m_Header.FmtName[0]='f';
  64. m_Header.FmtName[1]='m';
  65. m_Header.FmtName[2]='t';
  66. m_Header.FmtName[3]=' ';
  67. m_Header.FmtLength=0x00000010; // length of fmt data (16 bytes)
  68. m_Header.FmtTag=0x0001; // Format tag: 1 = PCM
  69. if (channels==STEREO) m_Header.FmtChannels=2;
  70. else m_Header.FmtChannels=1;
  71. m_Header.FmtSamplerate=WavFile::m_Samplerate;
  72. m_Header.FmtBitsPerSample=16;
  73. m_Header.FmtBytesPerSec=m_Header.FmtSamplerate*m_Header.FmtBlockAlign;
  74. m_Header.FmtBlockAlign=m_Header.FmtChannels*m_Header.FmtBitsPerSample/8;
  75. m_DataHeader.DataName[0]='d';
  76. m_DataHeader.DataName[1]='a';
  77. m_DataHeader.DataName[2]='t';
  78. m_DataHeader.DataName[3]='a';
  79. m_DataHeader.DataLengthBytes=0;
  80. SWAPINT(m_Header.RiffFileLength);
  81. SWAPINT(m_Header.FmtLength);
  82. SWAPSHORT(m_Header.FmtTag);
  83. SWAPSHORT(m_Header.FmtChannels);
  84. SWAPINT(m_Header.FmtSamplerate);
  85. SWAPINT(m_Header.FmtBytesPerSec);
  86. SWAPSHORT(m_Header.FmtBlockAlign);
  87. SWAPSHORT(m_Header.FmtBitsPerSample);
  88. SWAPINT(m_DataHeader.DataLengthBytes);
  89. fwrite(&m_Header,1,sizeof(CanonicalWavHeader),m_Stream);
  90. fwrite(&m_DataHeader,1,sizeof(DataHeader),m_Stream);
  91. return 1;
  92. }
  93. else
  94. if (mode==READ)
  95. {
  96. fread(&m_Header,sizeof(CanonicalWavHeader),1,m_Stream);
  97. SWAPINT(m_Header.RiffFileLength);
  98. SWAPINT(m_Header.FmtLength);
  99. SWAPSHORT(m_Header.FmtTag);
  100. SWAPSHORT(m_Header.FmtChannels);
  101. SWAPINT(m_Header.FmtSamplerate);
  102. SWAPINT(m_Header.FmtBytesPerSec);
  103. SWAPSHORT(m_Header.FmtBlockAlign);
  104. SWAPSHORT(m_Header.FmtBitsPerSample);
  105. #ifdef TRACE_OUT
  106. cerr<<FileName<<endl;
  107. cerr<<"RiffFileLength "<<m_Header.RiffFileLength<<endl;
  108. cerr<<"FmtLength "<<m_Header.FmtLength<<endl;
  109. cerr<<"FmtTag "<<m_Header.FmtTag<<endl;
  110. cerr<<"FmtChannels "<<m_Header.FmtChannels<<endl;
  111. cerr<<"FmtSamplerate "<<m_Header.FmtSamplerate<<endl;
  112. cerr<<"FmtBytesPerSec "<<m_Header.FmtBytesPerSec<<endl;
  113. cerr<<"FmtBlockAlign "<<m_Header.FmtBlockAlign<<endl;
  114. cerr<<"FmtBitsPerSample "<<m_Header.FmtBitsPerSample<<endl;
  115. #endif
  116. // skip the rest of the fmt header if necissary
  117. if (m_Header.FmtLength>16)
  118. {
  119. fseek(m_Stream,m_Header.FmtLength-16,SEEK_CUR);
  120. }
  121. fread(&m_DataHeader,sizeof(DataHeader),1,m_Stream);
  122. SWAPINT(m_DataHeader.DataLengthBytes);
  123. while (m_DataHeader.DataName[0]!='d' ||
  124. m_DataHeader.DataName[1]!='a' ||
  125. m_DataHeader.DataName[2]!='t' ||
  126. m_DataHeader.DataName[3]!='a')
  127. {
  128. // crawl through the rest of the propriatory headers
  129. // if we need to to try and get to the data header
  130. if (feof(m_Stream) || fseek(m_Stream,-(sizeof(DataHeader)-1),SEEK_CUR)==-1)
  131. {
  132. cerr<<"WavFile: File open error, wrong format ["<<FileName<<"]"<<endl;
  133. return 0;
  134. }
  135. fread(&m_DataHeader,sizeof(DataHeader),1,m_Stream);
  136. }
  137. fgetpos(m_Stream,(fpos_t*)&m_DataStart);
  138. m_CurSeekPos=m_DataStart;
  139. #ifdef TRACE_OUT
  140. cerr<<m_DataHeader.DataName[0]<<m_DataHeader.DataName[1]<<
  141. m_DataHeader.DataName[2]<<m_DataHeader.DataName[3]<<endl;
  142. cerr<<"DataLengthBytes "<<m_DataHeader.DataLengthBytes<<endl;
  143. #endif
  144. // check we have a wav file here
  145. if (m_Header.RiffName[0]=='R' &&
  146. m_Header.RiffName[1]=='I' &&
  147. m_Header.RiffName[2]=='F' &&
  148. m_Header.RiffName[3]=='F')
  149. {
  150. return 1;
  151. }
  152. fclose(m_Stream);
  153. cerr<<"WavFile: File open error, wrong format ["<<FileName<<"]"<<endl;
  154. return 0;
  155. }
  156. return 0;
  157. }
  158. int WavFile::Close()
  159. {
  160. if (m_Stream==NULL)
  161. {
  162. return 0;
  163. }
  164. // write the total length in
  165. fseek(m_Stream, 40, SEEK_SET);
  166. fwrite(&m_DataHeader.DataLengthBytes,4,1,m_Stream);
  167. fclose(m_Stream);
  168. m_Stream=NULL;
  169. return 1;
  170. }
  171. int WavFile::Save(Sample &data)
  172. {
  173. if (m_Stream==NULL || data.GetLength()==0)
  174. {
  175. return 0;
  176. }
  177. // convert to integer for saving
  178. short *temp=new short[data.GetLength()];
  179. for (int n=0; n<data.GetLength(); n++)
  180. {
  181. //clip
  182. float v=data[n];
  183. if (v<-1) v=-1; if (v>1) v=1;
  184. temp[n]=(short)(v*SHRT_MAX);
  185. SWAPSHORT(temp[n]);
  186. }
  187. m_DataHeader.DataLengthBytes+=data.GetLength()*2;
  188. fwrite(temp,sizeof(&temp),data.GetLength()/2,m_Stream);
  189. // leak!
  190. delete[] temp;
  191. return 1;
  192. }
  193. int WavFile::Save(short *data, int Bytes)
  194. {
  195. if (m_Stream==NULL || data==NULL)
  196. {
  197. return 0;
  198. }
  199. m_DataHeader.DataLengthBytes+=Bytes;
  200. fwrite(data,sizeof(data),Bytes/4,m_Stream);
  201. return 1;
  202. }
  203. int WavFile::GetSize()
  204. {
  205. if (m_Header.FmtBitsPerSample!=8 && m_Header.FmtBitsPerSample!=16)
  206. {
  207. cerr<<"WavFile Warning: FmtBitsPerSample="<<m_Header.FmtBitsPerSample<<" (can't cope, treating as 16)"<<endl;
  208. m_Header.FmtBitsPerSample=16;
  209. }
  210. int ret=0;
  211. if (m_Header.FmtBitsPerSample==8)
  212. {
  213. if (IsStereo()) ret=m_DataHeader.DataLengthBytes/2;
  214. else ret=m_DataHeader.DataLengthBytes;
  215. }
  216. else
  217. {
  218. if (IsStereo()) ret=m_DataHeader.DataLengthBytes/4;
  219. else ret=m_DataHeader.DataLengthBytes/2;
  220. }
  221. return ret;
  222. }
  223. int WavFile::Load(Sample &data)
  224. {
  225. if (m_Header.FmtChannels>1) // mix the channels into a mono buffer
  226. {
  227. #ifdef TRACE_OUT
  228. cerr<<"WavFile::Load - Channels = "<<m_Header.FmtChannels<<
  229. " Mixing down to mono..."<<endl;
  230. #endif
  231. short *TempBuf = new short[m_DataHeader.DataLengthBytes];
  232. if (m_DataHeader.DataLengthBytes!=(int)fread(TempBuf,1,m_DataHeader.DataLengthBytes,m_Stream))
  233. {
  234. cerr<<"WavFile: Read error"<<endl;
  235. return 0;
  236. }
  237. for (int n=0; n<GetSize(); n++)
  238. {
  239. long value=0;
  240. for (int i=0; i<m_Header.FmtChannels; i++)
  241. {
  242. short s = TempBuf[(n*m_Header.FmtChannels)+i];
  243. SWAPSHORT(s);
  244. value+=s;
  245. }
  246. value/=m_Header.FmtChannels;
  247. data.Set(n,value/(float)SHRT_MAX);
  248. }
  249. m_DataHeader.DataLengthBytes /= m_Header.FmtChannels;
  250. m_Header.FmtChannels=1;
  251. delete[] TempBuf;
  252. }
  253. else // it's mono.
  254. {
  255. short *TempBuf = new short[GetSize()];
  256. int t=(int)fread(TempBuf,1,m_DataHeader.DataLengthBytes,m_Stream);
  257. if (m_DataHeader.DataLengthBytes!=t)
  258. {
  259. cerr<<"WavFile: Read error read "<<t<<" expected "<<m_DataHeader.DataLengthBytes<<endl;
  260. //return 0;
  261. }
  262. for (int n=0; n<GetSize(); n++)
  263. {
  264. short s = TempBuf[n];
  265. SWAPSHORT(s);
  266. data.Set(n,s/(float)SHRT_MAX);
  267. }
  268. delete[] TempBuf;
  269. }
  270. return 1;
  271. }
  272. int WavFile::Load(short *data)
  273. {
  274. if (m_Header.FmtChannels>1) // mix the channels into a mono buffer
  275. {
  276. #ifdef TRACE_OUT
  277. cerr<<"WavFile::Load - Channels = "<<m_Header.FmtChannels<<
  278. " Mixing down to mono..."<<endl;
  279. #endif
  280. short *TempBuf = new short[m_DataHeader.DataLengthBytes];
  281. if (m_DataHeader.DataLengthBytes!=(int)fread(TempBuf,1,m_DataHeader.DataLengthBytes,m_Stream))
  282. {
  283. cerr<<"WavFile: Read error"<<endl;
  284. return 0;
  285. }
  286. for (int n=0; n<GetSize(); n++)
  287. {
  288. long value=0;
  289. for (int i=0; i<m_Header.FmtChannels; i++)
  290. {
  291. short s = TempBuf[(n*m_Header.FmtChannels)+i];
  292. SWAPSHORT(s);
  293. value+=s;
  294. }
  295. value/=m_Header.FmtChannels;
  296. data[n]=value;
  297. }
  298. m_DataHeader.DataLengthBytes /= m_Header.FmtChannels;
  299. m_Header.FmtChannels=1;
  300. delete[] TempBuf;
  301. }
  302. else // we can read the data directly in, it's mono.
  303. {
  304. if (m_DataHeader.DataLengthBytes==
  305. (int)fread(data,1,m_DataHeader.DataLengthBytes,m_Stream))
  306. {
  307. #if __BYTE_ORDER == BIG_ENDIAN
  308. short *TempBuf = (short*)data;
  309. for (int n=0; n < m_DataHeader.DataLengthBytes / 2; n++)
  310. SWAPSHORT(TempBuf[n]);
  311. #endif
  312. return 1;
  313. }
  314. cerr<<"WavFile: Read error"<<endl;
  315. return 0;
  316. }
  317. return 0;
  318. }
  319. int WavFile::SeekToChunk(int Pos)
  320. {
  321. Pos*=4;
  322. if (m_CurSeekPos==m_DataStart+Pos) return 1;
  323. m_CurSeekPos=m_DataStart+Pos;
  324. #ifdef TRACE_OUT
  325. cerr<<"Seeking to "<<m_DataStart+Pos<<" "<<m_CurSeekPos<<endl;
  326. #endif
  327. if (fseek(m_Stream, m_DataStart+Pos, SEEK_SET)!=0)
  328. {
  329. cerr<<"WavFile::SeekToChunk: Seek error"<<endl;
  330. }
  331. return 1;
  332. }
  333. int WavFile::LoadChunk(int NumSamples, Sample &ldata, Sample &rdata)
  334. {
  335. if (m_Header.FmtChannels>1) // untangle the interleaved data
  336. {
  337. int SizeBytes=NumSamples*4; // stereo,16bit
  338. short *TempBuf = new short[NumSamples*2];
  339. if (SizeBytes!=(int)fread(TempBuf,1,SizeBytes,m_Stream))
  340. {
  341. cerr<<"WavFile: Read chunk error"<<endl;
  342. return 0;
  343. }
  344. m_CurSeekPos+=SizeBytes;
  345. for (int n=0; n<NumSamples; n++)
  346. {
  347. ldata.Set(n,TempBuf[n*2]/(float)SHRT_MAX);
  348. rdata.Set(n,TempBuf[(n*2)+1]/(float)SHRT_MAX);
  349. }
  350. delete[] TempBuf;
  351. }
  352. else // we can read the data directly in, it's mono.
  353. {
  354. if (m_DataHeader.DataLengthBytes==
  355. (int)fread(ldata.GetNonConstBuffer(),1,NumSamples*2,m_Stream))
  356. {
  357. return 1;
  358. }
  359. cerr<<"WavFile: Read error"<<endl;
  360. return 0;
  361. }
  362. return 0;
  363. }