Edinburgh Speech Tools  2.1-release
os2audio.cc
Go to the documentation of this file.
1 /* Check all of ./speech_tools and ./festival for reference to win32audio, */
2 /* and add the equivalent for the os2audio module. You will need -los2me */
3 /* to compile this os2audio module. */
4 
5 
6 /* OS/2 16bit realtime DART Audio support for Festival */
7 /* Samuel Audet <guardia@cam.org> */
8 /* DeviceID is setup in here. Can be used as an external variable! */
9 
10 #ifdef SUPPORT_OS2AUDIO
11 
12 #include "EST_cutils.h"
13 
14 #include "EST_Wave.h"
15 
16 #include "EST_Option.h"
17 
18 #include "audioP.h"
19 
20 #include "EST_io_aux.h"
21 
22 #include "EST_unix.h"
23 
25 
26 #define INCL_OS2MM
27 
28 #define INCL_DOS
29 
30 #include <os2.h>
31 
32 #include <os2me.h>
33 
34 
35 USHORT DeviceID = 0; /* 0 = default sound device, 1 = 1st sound device, etc. */
36 
37 /* new stuff */
38 #define MIX_BUFFER_EOS 1
39 
40 
41 #define NUM_BUFFERS 8 /* Number of audio buffer usable */
42 static ULONG ulMCIBuffers; /* warning, minimum 2 */
43 
44 static MCI_AMP_OPEN_PARMS maop;
45 static MCI_MIXSETUP_PARMS mmp;
46 static MCI_BUFFER_PARMS mbp;
47 static MCI_GENERIC_PARMS mgp = {0};
48 static MCI_MIX_BUFFER MixBuffers[NUM_BUFFERS];
49 static unsigned char *wave, *startwave, *endwave;
50 static ULONG sizewave;
51 
52 static HEV dataplayed;
53 
54 
55 static void MciError(ULONG ulError)
56 {
57  unsigned char buffer[128];
58  unsigned char string[128];
59  ULONG rc;
60 
61  rc = mciGetErrorString(ulError, buffer, sizeof(buffer));
62 
63  if (rc == MCIERR_SUCCESS)
64  sprintf(string,"MCI Error %d: %s",ULONG_LOWD(ulError),buffer);
65  else
66  sprintf(string,"MCI Error %d: Cannot query error message.",ULONG_LOWD(rc));
67 
68  cerr << string << endl;
69 }
70 
71 
72 static LONG APIENTRY MyEvent(ULONG ulStatus, PMCI_MIX_BUFFER PlayedBuffer, ULONG ulFlags)
73 {
74  if(PlayedBuffer->ulFlags == MIX_BUFFER_EOS)
75  DosPostEventSem(dataplayed);
76  else
77  switch(ulFlags)
78  {
79  case MIX_STREAM_ERROR | MIX_WRITE_COMPLETE: /* error occur in device */
80 
81  if ( ulStatus == ERROR_DEVICE_UNDERRUN)
82  /* Write buffers to rekick off the amp mixer. */
83  mmp.pmixWrite( mmp.ulMixHandle,
84  MixBuffers,
85  ulMCIBuffers );
86  break;
87 
88  case MIX_WRITE_COMPLETE: /* for playback */
89 
90  if(wave < endwave)
91  {
92  /* copy new data in the played buffer */
93  if(wave + PlayedBuffer->ulBufferLength >= endwave)
94  {
95  PlayedBuffer->ulFlags = MIX_BUFFER_EOS; /* set end of stream */
96  PlayedBuffer->ulBufferLength = (ULONG) (endwave - wave);
97  }
98  memcpy(PlayedBuffer->pBuffer, wave, PlayedBuffer->ulBufferLength);
99  wave += PlayedBuffer->ulBufferLength;
100 
101  mmp.pmixWrite( mmp.ulMixHandle,
102  PlayedBuffer /* contains new data */,
103  1 );
104  }
105 
106  break;
107 
108  } /* end switch */
109 
110  return( TRUE );
111 
112 } /* end MyEvent */
113 
114 
115 int play_os2audio_wave(EST_Wave &inwave, EST_Option &al)
116 {
117  ULONG i,rc;
118 
119  startwave = (unsigned char *) inwave.values().memory();
120  sizewave = inwave.num_samples()*sizeof(short)*inwave.num_channels();
121  endwave = startwave + sizewave;
122  wave = startwave;
123 
124  /* open the mixer device */
125  memset (&maop, 0, sizeof(maop));
126  maop.usDeviceID = 0;
127  maop.pszDeviceType = (PSZ) MAKEULONG(MCI_DEVTYPE_AUDIO_AMPMIX, DeviceID);
128 
129  rc = mciSendCommand(0,
130  MCI_OPEN,
131  MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
132  &maop,
133  0);
134 
135  if (rc != MCIERR_SUCCESS)
136  {
137  MciError(rc);
138  return(-1);
139  }
140 
141  /* Set the MCI_MIXSETUP_PARMS data structure to match the audio stream. */
142 
143  memset(&mmp, 0, sizeof(mmp));
144 
145  mmp.ulBitsPerSample = 16;
146  mmp.ulFormatTag = MCI_WAVE_FORMAT_PCM;
147  mmp.ulSamplesPerSec = inwave.sample_rate();
148  mmp.ulChannels = inwave.num_channels();
149 
150  /* Setup the mixer for playback of wave data */
151  mmp.ulFormatMode = MCI_PLAY;
152  mmp.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
153  mmp.pmixEvent = MyEvent;
154 
155  rc = mciSendCommand( maop.usDeviceID,
156  MCI_MIXSETUP,
157  MCI_WAIT | MCI_MIXSETUP_INIT,
158  &mmp,
159  0 );
160 
161  if ( rc != MCIERR_SUCCESS )
162  {
163  MciError(rc);
164  return(-1);
165  }
166 
167  /* Set up the BufferParms data structure and allocate
168  * device buffers from the Amp-Mixer */
169 
170  ulMCIBuffers = NUM_BUFFERS;
171  mbp.ulNumBuffers = ulMCIBuffers;
172  mbp.ulBufferSize = mmp.ulBufferSize;
173  memset(MixBuffers, 0, sizeof(MixBuffers[0])*NUM_BUFFERS);
174  mbp.pBufList = MixBuffers;
175 
176  rc = mciSendCommand( maop.usDeviceID,
177  MCI_BUFFER,
178  MCI_WAIT | MCI_ALLOCATE_MEMORY,
179  (PVOID) &mbp,
180  0 );
181 
182  if ( ULONG_LOWD(rc) != MCIERR_SUCCESS )
183  {
184  MciError(rc);
185  return(-1);
186  }
187 
188  ulMCIBuffers = mbp.ulNumBuffers; /* never know! */
189 
190  /* Fill all device buffers with data from the wave stream. */
191 
192  for(i = 0; i < ulMCIBuffers; i++)
193  {
194  if(wave < endwave)
195  {
196  MixBuffers[i].ulFlags = 0;
197  MixBuffers[i].ulBufferLength = mbp.ulBufferSize;
198  if(wave + MixBuffers[i].ulBufferLength >= endwave)
199  {
200  MixBuffers[i].ulFlags = MIX_BUFFER_EOS; /* set end of stream */
201  MixBuffers[i].ulBufferLength = (ULONG) (endwave - wave);
202  }
203  memcpy(MixBuffers[i].pBuffer, wave, MixBuffers[i].ulBufferLength);
204  wave += MixBuffers[i].ulBufferLength;
205  }
206  }
207 
208  /* Create a semaphore to know when data has been played by the DART thread */
209  DosCreateEventSem(NULL,&dataplayed,0,FALSE);
210 
211  /* Write buffers to kick off the amp mixer. */
212  rc = mmp.pmixWrite( mmp.ulMixHandle,
213  MixBuffers,
214  ulMCIBuffers );
215 
216  if ( rc != MCIERR_SUCCESS )
217  {
218  MciError(rc);
219  return(-1);
220  }
221 
222  DosWaitEventSem(dataplayed, -1);
223  DosCloseEventSem(dataplayed);
224 
225  rc = mciSendCommand( maop.usDeviceID,
226  MCI_BUFFER,
227  MCI_WAIT | MCI_DEALLOCATE_MEMORY,
228  &mbp,
229  0 );
230 
231  if ( rc != MCIERR_SUCCESS )
232  {
233  MciError(rc);
234  return(-1);
235  }
236 
237  rc = mciSendCommand( maop.usDeviceID,
238  MCI_CLOSE,
239  MCI_WAIT ,
240  &mgp,
241  0 );
242 
243  if ( rc != MCIERR_SUCCESS )
244  {
245  MciError(rc);
246  return(-1);
247  }
248 
249  return TRUE;
250 }
251 
252 #else
253 
254 # include "EST_Wave.h"
255 # include "EST_Option.h"
256 # include <iostream>
257 
259 
261 {
262  (void)inwave;
263  (void)al;
264  std::cerr << "OS/2 16bit realtime DART playback not supported." << std::endl;
265  return -1;
266 }
267 
268 #endif
269 
270 
A class for storing digital waveforms. The waveform is stored as an array of 16 bit shorts...
Definition: EST_Wave.h:64
Utility IO Function header file.
ssize_t num_samples() const
return the number of samples in the waveform
Definition: EST_Wave.h:143
int os2audio_supported
Definition: os2audio.cc:258
const EST_SMatrix & values() const
Definition: EST_Wave.h:177
#define FALSE
Definition: EST_bool.h:119
int play_os2audio_wave(EST_Wave &inwave, EST_Option &al)
Definition: os2audio.cc:260
NULL
Definition: EST_WFST.cc:55
int sample_rate() const
return the sampling rate (frequency)
Definition: EST_Wave.h:147
const T * memory() const
Definition: EST_TVector.h:238
ssize_t num_channels() const
return the number of channels in the waveform
Definition: EST_Wave.h:145
#define TRUE
Definition: EST_bool.h:118
#define LONG
Definition: rateconv.cc:173