1 /*
2    playAudio.c
3    PortAudio v19 code for all actually outputting the audio
4    Depends on:
5    playAudio.h
6    BinauralBeat.h
7 
8    Copyright (C) 2008  Bret Logan
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 //IMPORTANT: PortAudio was used for multi-platform compatibility. PortAudio v18
26 //still uses OSS, which is a problem because most linux systems now are ALSA,
27 //and therefore only emulate OSS. And the drawback: ALSA doesn't mix OSS apps
28 //well or at all. This means that a cheap soundcard with no onboard mixers
29 //(most, actually), can only run one OSS a time (unlike real OSS, which did
30 //software mixing).
31 //PortAudio v19 has ALSA in it; this file represents the last stable v18
32 //before Gnaural switches to v19, which is sometimes called "PortAudio2"
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "BinauralBeat.h"
39 #include "playAudio.h"
40 
41 //START Globals for Port Audio handling:
42 PaStream *playAudio_SoundStream = NULL; //this will equal NULL if the sound system wasn't detected, so use to check
43 PaDeviceIndex playAudio_SoundDevice = GNAURAL_USEDEFAULTSOUNDDEVICE;
44 PaStreamParameters outputStreamParams;
45 
46 //################################################
47 //START PortAudio v19 code:
48 
49 // ======================================
50 // PortAudio will call this local function:
playAudio_MyCallback(const void * inputBuffer,void * outputBuffer,unsigned long framesPerBuffer,const PaStreamCallbackTimeInfo * timeInfo,PaStreamCallbackFlags statusFlags,void * userData)51 static int playAudio_MyCallback (const void *inputBuffer,
52                                  void *outputBuffer,
53                                  unsigned long framesPerBuffer,
54                                  const PaStreamCallbackTimeInfo * timeInfo,
55                                  PaStreamCallbackFlags statusFlags,
56                                  void *userData)
57 {
58  if (playAudio_SoundStream != NULL)
59  {
60   BB_MainLoop (outputBuffer, (framesPerBuffer << 2));
61  }
62  // BB_UserSoundProc(outputBuffer, (framesPerBuffer<<2));//IMPORTANT: no matter what units the sndbuffer uses, CBinauralBeat wants sndbufsize in bytes
63  return 0;      //return 1 to stop sound server
64 }
65 
66 //======================================
playAudio_SoundStart()67 void playAudio_SoundStart ()
68 {
69  Pa_StartStream (playAudio_SoundStream);
70 }
71 
72 // ======================================
playAudio_GetAPI(int i)73 void playAudio_GetAPI (int i)
74 {
75  char tmpstr[64];
76  const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo (i);
77 
78  if (NULL == deviceInfo)
79  {
80   BB_ERROUT ("Pa_GetDeviceInfo returned NULL"); //20100628: fixed a segfault when "Cannot connect to server socket err = No such file or directory"
81   return;
82  }
83 
84  const PaHostApiInfo *apiInfo = Pa_GetHostApiInfo (deviceInfo->hostApi);
85 
86  if (NULL == apiInfo)
87  {
88   BB_ERROUT ("CPa_GetHostApiInfo returned NULL");
89   return;
90  }
91 
92  strcpy (tmpstr, "Sound API: ");
93  switch (apiInfo->type)
94  {
95  case paALSA:
96   strcat (tmpstr, "ALSA");
97   break;
98 
99  case paOSS:
100   strcat (tmpstr, "OSS");
101   break;
102 
103  case paJACK:
104   strcat (tmpstr, "JACK");
105   break;
106 
107  case paASIO:
108   strcat (tmpstr, "ASIO");
109   break;
110 
111  case paMME:
112   strcat (tmpstr, "MME");
113   break;
114 
115  case paDirectSound:
116   strcat (tmpstr, "DirectSound");
117   break;
118 
119  case paBeOS:
120   strcat (tmpstr, "BeOS");
121   break;
122 
123  case paAL:
124   strcat (tmpstr, "AL");
125   break;
126 
127  case paCoreAudio:
128   strcat (tmpstr, "CoreAudio");
129   break;
130 
131  case paSoundManager:
132   strcat (tmpstr, "SoundManager");
133   break;
134 
135  case paAudioScienceHPI:
136   strcat (tmpstr, "AudioScienceHPI");
137   break;
138 
139  case paWASAPI:
140   strcat (tmpstr, "WASAPI");
141   break;
142 
143  case paWDMKS:
144   strcat (tmpstr, "WDMKS");
145   break;
146 
147  case paInDevelopment:
148   strcat (tmpstr, "In Development");
149   break;
150 
151  default:
152   strcat (tmpstr, "Unknown");
153   break;
154  }
155 
156  BB_DBGOUT (tmpstr);
157 }
158 
159 //======================================
playAudio_SoundInit(char * local_tmpstr)160 int playAudio_SoundInit (char *local_tmpstr)
161 {
162  PaError err;
163  int data;                      //Not using this currently
164 
165  BB_DBGOUT_STR ("Starting sound:", Pa_GetVersionText ());
166 
167  err = Pa_Initialize ();
168  if (err != paNoError)
169  {
170   //let user know status of audio system:
171   sprintf (local_tmpstr, "Audio System Init: %s", Pa_GetErrorText (err));
172   return EXIT_FAILURE;
173  }
174 
175  if (playAudio_SoundDevice == GNAURAL_USEDEFAULTSOUNDDEVICE)
176  {
177   playAudio_SoundDevice = Pa_GetDefaultOutputDevice ();
178  }
179 
180  if (TRUE == BB_DebugFlag)
181   playAudio_GetAPI (playAudio_SoundDevice);
182 
183  outputStreamParams.device = playAudio_SoundDevice;
184  outputStreamParams.channelCount = 2;
185  outputStreamParams.sampleFormat = paInt16;     // short -- use for inteleaved 32-bit stereo
186 
187  err = Pa_OpenStream (&playAudio_SoundStream, NULL, &outputStreamParams, GNAURAL_SAMPLE_RATE, GNAURAL_FRAMES_PER_BUFFER, paClipOff,     // we won't output out of range samples so don't bother clipping them
188                       playAudio_MyCallback, &data);
189 
190  //let user know status of audio system:
191  sprintf (local_tmpstr, "Init Audio System: %s [device %d]",
192           Pa_GetErrorText (err), playAudio_SoundDevice);
193 
194  if (err != paNoError)
195  {
196   BB_ERROUT (local_tmpstr);
197   return EXIT_FAILURE;
198  }
199 
200  return EXIT_SUCCESS;
201 }       //end playAudio_SoundInit
202 
203 // ======================================
playAudio_SoundCleanup()204 void playAudio_SoundCleanup ()
205 {
206  BB_DBGOUT ("Stopping PortAudio sound");
207  if (playAudio_SoundStream != NULL)
208  {
209   Pa_StopStream (playAudio_SoundStream);
210   Pa_CloseStream (playAudio_SoundStream);
211  }
212  Pa_Terminate ();
213  playAudio_SoundStream = NULL;
214  playAudio_SoundDevice = GNAURAL_USEDEFAULTSOUNDDEVICE;
215  //all done with PortAudio
216 }
217 
218 //END PortAudio v19 code
219 //################################################
220