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.

478 lines
11KB

  1. /* SpiralSound
  2. * Copyleft (C) 2001 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. // for lrintf()
  19. #define _ISOC9X_SOURCE 1
  20. #define _ISOC99_SOURCE 1
  21. #include <math.h>
  22. #include <sys/types.h>
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <unistd.h>
  26. #include <limits.h>
  27. #if defined (__FreeBSD__)
  28. #include <machine/soundcard.h>
  29. #else
  30. #if defined (__NetBSD__) || defined (__OpenBSD__)
  31. #include <soundcard.h> /* OSS emulation */
  32. #undef ioctl
  33. #else /* BSDI, Linux, Solaris */
  34. #include <sys/soundcard.h>
  35. #endif /* __NetBSD__ or __OpenBSD__ */
  36. #endif /* __FreeBSD__ */
  37. #include <sys/ioctl.h>
  38. #include <limits.h>
  39. #include "OutputPlugin.h"
  40. #include "OutputPluginGUI.h"
  41. #include <FL/fl_file_chooser.H>
  42. #include "SpiralIcon.xpm"
  43. static const int IN_FREQ = 0;
  44. static const int IN_PW = 1;
  45. static const int IN_SHLEN = 2;
  46. static const int OUT_MAIN = 0;
  47. static const HostInfo* host;
  48. OSSOutput* OSSOutput::m_Singleton = NULL;
  49. int OutputPlugin::m_RefCount=0;
  50. int OutputPlugin::m_NoExecuted=0;
  51. #define CHECK_AND_REPORT_ERROR if (result<0) \
  52. { \
  53. perror("Sound device did not accept settings"); \
  54. m_OutputOk=false; \
  55. return; \
  56. }
  57. extern "C"
  58. {
  59. SpiralPlugin* CreateInstance()
  60. {
  61. return new OutputPlugin;
  62. }
  63. char** GetIcon()
  64. {
  65. return SpiralIcon_xpm;
  66. }
  67. int GetID()
  68. {
  69. return 0x0000;
  70. }
  71. }
  72. ///////////////////////////////////////////////////////
  73. OutputPlugin::OutputPlugin()
  74. {
  75. m_RefCount++;
  76. m_PluginInfo.Name="OSS";
  77. m_PluginInfo.Width=100;
  78. m_PluginInfo.Height=130;
  79. m_PluginInfo.NumInputs=3;
  80. m_PluginInfo.NumOutputs=2;
  81. m_PluginInfo.PortTips.push_back("Left Out");
  82. m_PluginInfo.PortTips.push_back("Right Out");
  83. m_PluginInfo.PortTips.push_back("Record Controller");
  84. m_PluginInfo.PortTips.push_back("Left In");
  85. m_PluginInfo.PortTips.push_back("Right In");
  86. m_AudioCH->Register("Mode",(char*)&m_Mode,ChannelHandler::INPUT);
  87. m_Mode=OUTPUT;
  88. }
  89. OutputPlugin::~OutputPlugin()
  90. {
  91. m_RefCount--;
  92. if (m_RefCount==0)
  93. {
  94. OSSOutput::PackUpAndGoHome();
  95. }
  96. }
  97. PluginInfo &OutputPlugin::Initialise(const HostInfo *Host)
  98. {
  99. PluginInfo& Info= SpiralPlugin::Initialise(Host);
  100. host=Host;
  101. OSSOutput::Get()->AllocateBuffer();
  102. return Info;
  103. }
  104. SpiralGUIType *OutputPlugin::CreateGUI()
  105. {
  106. return new OutputPluginGUI(m_PluginInfo.Width,
  107. m_PluginInfo.Height,
  108. this,
  109. m_AudioCH,
  110. m_HostInfo);
  111. }
  112. void OutputPlugin::Execute()
  113. {
  114. // Only Play() once per set of plugins
  115. m_NoExecuted++;
  116. if (m_NoExecuted==m_RefCount)
  117. {
  118. if (m_Mode==INPUT || m_Mode==DUPLEX) OSSOutput::Get()->Read();
  119. if (m_Mode==OUTPUT || m_Mode==DUPLEX) OSSOutput::Get()->Play();
  120. m_NoExecuted=0;
  121. }
  122. if (m_Mode==OUTPUT || m_Mode==DUPLEX)
  123. {
  124. OSSOutput::Get()->SendStereo(GetInput(0),GetInput(1));
  125. for (int n=0; n<m_HostInfo->BUFSIZE;n++)
  126. {
  127. if (GetInput(2,n)!=0)
  128. {
  129. if (! m_CheckedAlready)
  130. {
  131. m_CheckedAlready=true;
  132. // an experimental line, should *theoretically* cut down on CPU time.
  133. n=m_HostInfo->BUFSIZE;
  134. if (! m_Recmode)
  135. {
  136. char *fn=fl_file_chooser("Pick a Wav file to save to", "*.wav", NULL);
  137. if (fn && fn!="")
  138. {
  139. OSSOutput::Get()->WavOpen(fn);
  140. }
  141. m_Recmode=true;
  142. }
  143. else
  144. {
  145. OSSOutput::Get()->WavClose();
  146. m_Recmode=false;
  147. }
  148. }
  149. }
  150. else
  151. m_CheckedAlready=false;
  152. }
  153. }
  154. if (m_Mode==INPUT || m_Mode==DUPLEX) OSSOutput::Get()->GetStereo(GetOutputBuf(0),GetOutputBuf(1));
  155. }
  156. //////////////////////////////////////////////////////////////////////
  157. //////////////////////////////////////////////////////////////////////
  158. OSSOutput::OSSOutput() :
  159. m_Amp(0.5),
  160. m_Channels(2),
  161. m_ReadBufferNum(0),
  162. m_WriteBufferNum(0),
  163. m_OutputOk(true)
  164. {
  165. m_Buffer[0]=NULL;
  166. m_Buffer[1]=NULL;
  167. m_InBuffer[0]=NULL;
  168. m_InBuffer[1]=NULL;
  169. OpenWrite();
  170. }
  171. //////////////////////////////////////////////////////////////////////
  172. OSSOutput::~OSSOutput()
  173. {
  174. Close();
  175. }
  176. //////////////////////////////////////////////////////////////////////
  177. void OSSOutput::AllocateBuffer()
  178. {
  179. if (m_Buffer[0]==NULL)
  180. {
  181. m_BufSizeBytes=host->BUFSIZE*m_Channels*2;
  182. // initialise for stereo
  183. m_Buffer[0] = (short*) calloc(m_BufSizeBytes/2,m_BufSizeBytes);
  184. m_Buffer[1] = (short*) calloc(m_BufSizeBytes/2,m_BufSizeBytes);
  185. m_InBuffer[0] = (short*) calloc(m_BufSizeBytes/2,m_BufSizeBytes);
  186. m_InBuffer[1] = (short*) calloc(m_BufSizeBytes/2,m_BufSizeBytes);
  187. }
  188. m_Wav.SetSamplerate(host->SAMPLERATE);
  189. }
  190. //////////////////////////////////////////////////////////////////////
  191. void OSSOutput::SendStereo(const Sample *ldata,const Sample *rdata)
  192. {
  193. if (m_Channels!=2) return;
  194. int on=0;
  195. float t;
  196. for (int n=0; n<host->BUFSIZE; n++)
  197. {
  198. // stereo channels - interleave
  199. if (ldata)
  200. {
  201. t=(*ldata)[n]*m_Amp;
  202. if (t>1) t=1;
  203. if (t<-1) t=-1;
  204. m_Buffer[m_WriteBufferNum][on]+=lrintf(t*SHRT_MAX);
  205. }
  206. on++;
  207. if (rdata)
  208. {
  209. t=(*rdata)[n]*m_Amp;
  210. if (t>1) t=1;
  211. if (t<-1) t=-1;
  212. m_Buffer[m_WriteBufferNum][on]+=lrintf(t*SHRT_MAX);
  213. }
  214. on++;
  215. }
  216. }
  217. //////////////////////////////////////////////////////////////////////
  218. void OSSOutput::Play()
  219. {
  220. int BufferToSend=!m_WriteBufferNum;
  221. #if __BYTE_ORDER == BIG_ENDIAN
  222. for (int n=0; n<host->BUFSIZE*m_Channels; n++)
  223. {
  224. m_Buffer[BufferToSend][n]=(short)((m_Buffer[BufferToSend][n]<<8)&0xff00)|
  225. ((m_Buffer[BufferToSend][n]>>8)&0xff);
  226. }
  227. #endif
  228. if (m_OutputOk)
  229. write(m_Dspfd,m_Buffer[BufferToSend],m_BufSizeBytes);
  230. if(m_Wav.Recording())
  231. {
  232. m_Wav.Save(m_Buffer[BufferToSend],m_BufSizeBytes);
  233. }
  234. memset(m_Buffer[BufferToSend],0,m_BufSizeBytes);
  235. m_WriteBufferNum=BufferToSend;
  236. }
  237. //////////////////////////////////////////////////////////////////////
  238. void OSSOutput::GetStereo(Sample *ldata,Sample *rdata)
  239. {
  240. if (m_Channels!=2) return;
  241. int on=0;
  242. for (int n=0; n<host->BUFSIZE; n++)
  243. {
  244. // stereo channels - interleave
  245. if (ldata) ldata->Set(n,(m_InBuffer[m_ReadBufferNum][on]*m_Amp)/(float)SHRT_MAX);
  246. on++;
  247. if (rdata) rdata->Set(n,(m_InBuffer[m_ReadBufferNum][on]*m_Amp)/(float)SHRT_MAX);
  248. on++;
  249. }
  250. }
  251. //////////////////////////////////////////////////////////////////////
  252. void OSSOutput::Read()
  253. {
  254. int BufferToRead=!m_ReadBufferNum;
  255. if (m_OutputOk)
  256. read(m_Dspfd,m_InBuffer[BufferToRead],m_BufSizeBytes);
  257. #if __BYTE_ORDER == BIG_ENDIAN
  258. for (int n=0; n<host->BUFSIZE*m_Channels; n++)
  259. {
  260. m_InBuffer[BufferToRead][n]=(short)((m_InBuffer[BufferToRead][n]<<8)&0xff00)|
  261. ((m_InBuffer[BufferToRead][n]>>8)&0xff);
  262. }
  263. #endif
  264. m_ReadBufferNum=BufferToRead;
  265. }
  266. //////////////////////////////////////////////////////////////////////
  267. void OSSOutput::Close()
  268. {
  269. cerr<<"Closing dsp output"<<endl;
  270. close(m_Dspfd);
  271. }
  272. //////////////////////////////////////////////////////////////////////
  273. void OSSOutput::OpenWrite()
  274. {
  275. int result,val;
  276. cerr<<"Opening dsp output"<<endl;
  277. m_Dspfd = open(host->OUTPUTFILE.c_str(),O_WRONLY);
  278. if(m_Dspfd<0)
  279. {
  280. fprintf(stderr,"Can't open audio driver for writing.\n");
  281. m_OutputOk=false;
  282. return;
  283. }
  284. result = ioctl(m_Dspfd,SNDCTL_DSP_RESET,NULL);
  285. CHECK_AND_REPORT_ERROR;
  286. short fgmtsize=0;
  287. int numfgmts=host->FRAGCOUNT;
  288. if (host->FRAGCOUNT==-1) numfgmts=0x7fff;
  289. for (int i=0; i<32; i++)
  290. {
  291. if ((host->FRAGSIZE)==(1<<i))
  292. {
  293. fgmtsize=i;
  294. break;
  295. }
  296. }
  297. if (fgmtsize==0)
  298. {
  299. cerr<<"Fragment size ["<<host->FRAGSIZE<<"] must be power of two!"<<endl;
  300. fgmtsize=256;
  301. }
  302. numfgmts=numfgmts<<16;
  303. val=numfgmts|(int)fgmtsize;
  304. result=ioctl(m_Dspfd, SNDCTL_DSP_SETFRAGMENT, &val);
  305. CHECK_AND_REPORT_ERROR;
  306. val = 1;
  307. result = ioctl(m_Dspfd, SOUND_PCM_WRITE_CHANNELS, &val);
  308. CHECK_AND_REPORT_ERROR;
  309. val = AFMT_S16_LE;
  310. result = ioctl(m_Dspfd,SNDCTL_DSP_SETFMT,&val);
  311. CHECK_AND_REPORT_ERROR;
  312. if (m_Channels==2) val=1;
  313. else val=0;
  314. result = ioctl(m_Dspfd,SNDCTL_DSP_STEREO,&val);
  315. CHECK_AND_REPORT_ERROR;
  316. val = host->SAMPLERATE;
  317. result = ioctl(m_Dspfd,SNDCTL_DSP_SPEED,&val);
  318. CHECK_AND_REPORT_ERROR;
  319. }
  320. //////////////////////////////////////////////////////////////////////
  321. void OSSOutput::OpenRead()
  322. {
  323. int result,val;
  324. cerr<<"Opening dsp input"<<endl;
  325. m_Dspfd = open(host->OUTPUTFILE.c_str(),O_RDONLY);
  326. if(m_Dspfd<0)
  327. {
  328. fprintf(stderr,"Can't open audio driver for reading.\n");
  329. m_OutputOk=false;
  330. return;
  331. }
  332. result = ioctl(m_Dspfd,SNDCTL_DSP_RESET,NULL);
  333. CHECK_AND_REPORT_ERROR;
  334. val = 1;
  335. result = ioctl(m_Dspfd, SOUND_PCM_READ_CHANNELS, &val);
  336. CHECK_AND_REPORT_ERROR;
  337. val = AFMT_S16_LE;
  338. result = ioctl(m_Dspfd,SNDCTL_DSP_SETFMT,&val);
  339. CHECK_AND_REPORT_ERROR;
  340. val = host->SAMPLERATE;
  341. result = ioctl(m_Dspfd,SNDCTL_DSP_SPEED,&val);
  342. CHECK_AND_REPORT_ERROR;
  343. }
  344. //////////////////////////////////////////////////////////////////////
  345. void OSSOutput::OpenReadWrite()
  346. {
  347. int result,val;
  348. cerr<<"Opening dsp output (duplex)"<<endl;
  349. m_Dspfd = open(host->OUTPUTFILE.c_str(),O_RDWR);
  350. if(m_Dspfd<0)
  351. {
  352. fprintf(stderr,"Can't open audio driver for writing.\n");
  353. m_OutputOk=false;
  354. return;
  355. }
  356. result = ioctl(m_Dspfd,SNDCTL_DSP_RESET,NULL);
  357. CHECK_AND_REPORT_ERROR;
  358. short fgmtsize=0;
  359. int numfgmts=host->FRAGCOUNT;
  360. if (host->FRAGCOUNT==-1) numfgmts=0x7fff;
  361. for (int i=0; i<32; i++)
  362. {
  363. if ((host->FRAGSIZE)==(1<<i))
  364. {
  365. fgmtsize=i;
  366. break;
  367. }
  368. }
  369. if (fgmtsize==0)
  370. {
  371. cerr<<"Fragment size ["<<host->FRAGSIZE<<"] must be power of two!"<<endl;
  372. fgmtsize=256;
  373. }
  374. numfgmts=numfgmts<<16;
  375. val=numfgmts|(int)fgmtsize;
  376. result=ioctl(m_Dspfd, SNDCTL_DSP_SETFRAGMENT, &val);
  377. CHECK_AND_REPORT_ERROR;
  378. val = 1;
  379. result = ioctl(m_Dspfd, SOUND_PCM_WRITE_CHANNELS, &val);
  380. CHECK_AND_REPORT_ERROR;
  381. val = AFMT_S16_LE;
  382. result = ioctl(m_Dspfd,SNDCTL_DSP_SETFMT,&val);
  383. CHECK_AND_REPORT_ERROR;
  384. if (m_Channels==2) val=1;
  385. else val=0;
  386. result = ioctl(m_Dspfd,SNDCTL_DSP_STEREO,&val);
  387. CHECK_AND_REPORT_ERROR;
  388. val = host->SAMPLERATE;
  389. result = ioctl(m_Dspfd,SNDCTL_DSP_SPEED,&val);
  390. CHECK_AND_REPORT_ERROR;
  391. }