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.

408 lines
10KB

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