--- a/SoundStr.st Fri Jan 15 22:21:21 1999 +0100
+++ b/SoundStr.st Sat Jan 30 21:16:46 1999 +0100
@@ -12,7 +12,7 @@
FileStream subclass:#SoundStream
instanceVariableNames:'sampleRate numberOfChannels bitsPerSample audioFormat alPort
- pDirectSound pDSBuffer cbBufOffset cbBufSize'
+ handle1 handle2 bufferOffset bufferSize'
classVariableNames:'UnsupportedOperationSignal'
poolDictionaries:''
category:'Streams-External'
@@ -76,8 +76,41 @@
/* # include <stdarg.h> /* */
# include <stdio.h> /* */
# include <windows.h>
-# define CINTERFACE
-# include "dsound.h"
+
+# ifdef USE_DIRECTSOUND
+# define CINTERFACE
+# include "dsound.h"
+# define __DirectSoundVal(o) (LPDIRECTSOUND)(__externalAddressVal(o))
+# define __DSBufferVal(o) (LPDIRECTSOUNDBUFFER)(__externalAddressVal(o))
+
+# define RT_BUFFER_SIZE 4096
+# define NBUFS 4
+
+# define pDirectSound handle1
+# define pDSBuffer handle2
+
+# else /* USE WAVE... */
+
+# define __WaveHandleVal(o) (HWAVEOUT)(__externalAddressVal(o))
+# define MAXBUF 10 /* Maximum number of buffers */
+# define DATALEN 640 /* Size of wave data buffer */
+
+struct buf {
+ WAVEHDR hdr; /* Wave data header */
+ short data[DATALEN]; /* Actual wave data */
+ struct buf *next; /* Next buffer in free list */
+};
+
+HWAVEOUT waveHandle; /* Handle of wave output device */
+struct buf *free_list; /* List of available buffers */
+CRITICAL_SECTION free_list_lock;
+int free_buffers; /* Number of buffers in free list */
+int total_buffers; /* Total number of buffers allocated */
+HANDLE free_buffer_event; /* Automatic-reset event triggered whenever */
+
+# define waveHandle handle1
+
+# endif
# ifdef __DEF_Array
# define Array __DEF_Array
@@ -106,20 +139,37 @@
# ifdef __DEF_Context
# define Context __DEF_Context
# endif
-
# define INT int
-# define __DirectSoundVal(o) (LPDIRECTSOUND)(__externalAddressVal(o))
-# define __DSBufferVal(o) (LPDIRECTSOUNDBUFFER)(__externalAddressVal(o))
-
-# define RT_BUFFER_SIZE 4096
-# define NBUFS 4
-
-#endif
+#endif /* WIN32 */
%}
! !
+!SoundStream primitiveFunctions!
+
+%{
+#ifdef WIN32
+# ifndef USE_DIRECTSOUND
+
+static void CALLBACK
+waveCallBack(HWAVE waveHandle, UINT msg, DWORD inst, DWORD p1, DWORD p2)
+{
+ if (msg == MM_WOM_DONE) {
+ struct buf *bp = (struct buf *)p1;
+ EnterCriticalSection(&free_list_lock);
+ bp->next = free_list;
+ free_list = bp;
+ free_buffers++;
+ SetEvent(free_buffer_event);
+ LeaveCriticalSection(&free_list_lock);
+ }
+}
+
+# endif
+#endif
+
+%}
!SoundStream class methodsFor:'documentation'!
copyright
@@ -1223,6 +1273,8 @@
#endif
#ifdef WIN32
+# ifdef USE_DIRECTSOUND
+
OBJ oDirectSound, oDSBuffer;
LPDIRECTSOUND t_pDirectSound;
LPDIRECTSOUNDBUFFER t_pDSBuffer;
@@ -1242,6 +1294,38 @@
IDirectSound_Release(t_pDirectSound);
}
}
+# else
+ struct buf *bp, *next;
+ int r;
+ HWAVEOUT t_waveHandle;
+ OBJ oWaveHandle;
+
+ if ((oWaveHandle = __INST(waveHandle)) != nil) {
+ t_waveHandle = __WaveHandleVal(oWaveHandle);
+
+ /* Force cancellation of any pending buffers */
+ (void)waveOutReset(t_waveHandle);
+
+ /* Wait until all pending buffers have been freed */
+ while (free_buffers < total_buffers) {
+ WaitForSingleObject(free_buffer_event, INFINITE);
+ }
+
+ /* Close the device */
+ if ((r = waveOutClose(t_waveHandle)) != 0) {
+ printError("waveOutClose", r);
+ return;
+ }
+
+ /* Free allocated buffers */
+ for (bp = free_list; bp != NULL; bp = next) {
+ next = bp->next;
+ (void)free(bp);
+ }
+
+ __INST(waveHandle) = nil;
+ }
+# endif
RETURN (self);
#endif
@@ -1307,7 +1391,7 @@
isOpen
alPort notNil ifTrue:[^ true].
- pDirectSound notNil ifTrue:[^ true].
+ handle1 notNil ifTrue:[^ true].
^ filePointer notNil
!
@@ -1399,6 +1483,7 @@
#endif /* SGI_AUDIO */
#ifdef WIN32
+# ifdef USE_DIRECTSOUND
{
HRESULT hr;
DWORD status;
@@ -1426,8 +1511,8 @@
fprintf(stderr, "SoundStream not open!\n");
RETURN (0);
}
- t_cbBufOffset = __intVal(__INST(cbBufOffset));
- t_cbBufSize = __intVal(__INST(cbBufSize));
+ t_cbBufOffset = __intVal(__INST(bufferOffset));
+ t_cbBufSize = __intVal(__INST(bufferSize));
cnt = __intVal(count);
offs = __intVal(start) - 1;
@@ -1478,10 +1563,63 @@
t_cbBufOffset = (t_cbBufOffset + dwsize1 + dwsize2) % t_cbBufSize;
IDirectSoundBuffer_Unlock(t_pDSBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
}
- __INST(cbBufOffset) = __MKSMALLINT(t_cbBufOffset);
+ __INST(buffferOffset) = __MKSMALLINT(t_cbBufOffset);
RETURN (count);
}
+# else
+ {
+ struct buf *bp;
+ int len, i, r;
+
+ while (dataLen > 0) {
+ if (free_list == NULL && total_buffers < MAXBUF) {
+ /* Expand available buffer space */
+ bp = (struct buf *)malloc(sizeof(struct buf));
+ total_buffers++;
+ } else {
+ if (free_list == NULL) {
+ /* We must wait for a free buffer */
+ while (free_list == NULL) {
+ WaitForSingleObject(free_buffer_event, INFINITE);
+ }
+ }
+ EnterCriticalSection(&free_list_lock);
+ bp = free_list;
+ free_list = free_list->next;
+ --free_buffers;
+ LeaveCriticalSection(&free_list_lock);
+ r = waveOutUnprepareHeader(waveHandle, &bp->hdr, sizeof(WAVEHDR));
+ if (r != 0) {
+ printError("waveOutUnprepareHeader", r);
+ return;
+ }
+ }
+ len = min(dataLen, DATALEN);
+ bp->hdr.lpData = (char *)bp->data;
+ bp->hdr.dwBufferLength = len * sizeof(short);
+ bp->hdr.dwBytesRecorded = len * sizeof(short);
+ bp->hdr.dwUser = (DWORD)bp;
+ bp->hdr.dwFlags = 0;
+ bp->hdr.dwLoops = 0;
+ r = waveOutPrepareHeader(waveHandle, &bp->hdr, sizeof(WAVEHDR));
+ if (r != 0) {
+ printError("waveOutPrepareHeader", r);
+ return;
+ }
+ for (i = 0; i < len; i++) {
+ bp->data[i] = ulaw8tol16(data[i]);
+ }
+ r = waveOutWrite(waveHandle, &bp->hdr, sizeof(WAVEHDR));
+ if (r != 0) {
+ printError("waveOutWrite", r);
+ return;
+ }
+ data += len;
+ dataLen -= len;
+ }
+ }
+# endif
#endif /* WIN32 */
#if defined(DEV_AUDIO)
@@ -1647,6 +1785,7 @@
#endif /* SGI_AUDIO */
#ifdef WIN32
+# ifdef USE_DIRECTSOUND
{
HRESULT result;
LPDIRECTSOUND t_pDirectSound;
@@ -1671,7 +1810,7 @@
wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
wfFormat.cbSize = 0;
-#if 0
+# if 0
/* Setup the primary DS buffer description */
ZeroMemory(&primarydsbDesc, sizeof(DSBUFFERDESC));
primarydsbDesc.dwSize = sizeof(DSBUFFERDESC);
@@ -1696,11 +1835,11 @@
IDirectSound_Release(t_pDirectSound);
RETURN (nil);
}
-#endif
+# endif
/* Setup the secondary DS buffer description */
t_cbBufSize = RT_BUFFER_SIZE * sizeof(short) * NBUFS;
- __INST(cbBufSize) = __MKSMALLINT(t_cbBufSize);
+ __INST(bufferSize) = __MKSMALLINT(t_cbBufSize);
ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
@@ -1741,7 +1880,7 @@
RETURN (nil);
}
- __INST(cbBufOffset) = __MKSMALLINT(0); // reset last write position to start of buffer
+ __INST(bufferOffset) = __MKSMALLINT(0); // reset last write position to start of buffer
/* Start the buffer playback */
if ((result = IDirectSoundBuffer_Play(t_pDSBuffer, 0, 0, DSBPLAY_LOOPING) != DS_OK)) {
@@ -1761,6 +1900,59 @@
}
RETURN (self);
}
+# else /* WAVEOUT */
+ {
+ PCMWAVEFORMAT waveFormat;
+ int r;
+
+ if (waveHandle != NULL) {
+ return 1; /* output device already open */
+ }
+
+ waveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
+ waveFormat.wf.nChannels = 1;
+ waveFormat.wf.nSamplesPerSec = 8000;
+ waveFormat.wf.nAvgBytesPerSec = 16000;
+ waveFormat.wf.nBlockAlign = 2;
+ waveFormat.wBitsPerSample = 16;
+
+ r = waveOutOpen(&waveHandle,
+ WAVE_MAPPER,
+ (WAVEFORMAT *)&waveFormat,
+ (DWORD)waveCallBack,
+ 0,
+ CALLBACK_FUNCTION);
+ if (r != 0) {
+ printError("waveOutOpen", r);
+ return -1;
+ }
+
+ (void)waveOutReset(waveHandle);
+
+ free_list = NULL;
+ InitializeCriticalSection(&free_list_lock);
+ free_buffers = 0;
+ free_buffer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ total_buffers = 0;
+
+ /*
+ * HACK: If we immediately start writing valid audio data to the device
+ * then the sound is choppy in the beginning. Writing a null packet to
+ * to the device first seems to fix this problem although I have no idea
+ * why - DAC
+ */
+ {
+ char null[DATALEN];
+ int i;
+ for (i = 0; i < DATALEN; i++) {
+ null[i] = 127;
+ }
+ audioWrite(null, DATALEN);
+ }
+
+ return 1;
+ }
+# endif
#endif /* WIN32 */
%}.
@@ -1927,5 +2119,5 @@
!SoundStream class methodsFor:'documentation'!
version
-^ '$Header: /cvs/stx/stx/libbasic2/Attic/SoundStr.st,v 1.38 1999-01-15 21:21:16 cg Exp $'! !
+^ '$Header: /cvs/stx/stx/libbasic2/Attic/SoundStr.st,v 1.39 1999-01-30 20:16:46 cg Exp $'! !
SoundStream initialize!
--- a/SoundStream.st Fri Jan 15 22:21:21 1999 +0100
+++ b/SoundStream.st Sat Jan 30 21:16:46 1999 +0100
@@ -12,7 +12,7 @@
FileStream subclass:#SoundStream
instanceVariableNames:'sampleRate numberOfChannels bitsPerSample audioFormat alPort
- pDirectSound pDSBuffer cbBufOffset cbBufSize'
+ handle1 handle2 bufferOffset bufferSize'
classVariableNames:'UnsupportedOperationSignal'
poolDictionaries:''
category:'Streams-External'
@@ -76,8 +76,41 @@
/* # include <stdarg.h> /* */
# include <stdio.h> /* */
# include <windows.h>
-# define CINTERFACE
-# include "dsound.h"
+
+# ifdef USE_DIRECTSOUND
+# define CINTERFACE
+# include "dsound.h"
+# define __DirectSoundVal(o) (LPDIRECTSOUND)(__externalAddressVal(o))
+# define __DSBufferVal(o) (LPDIRECTSOUNDBUFFER)(__externalAddressVal(o))
+
+# define RT_BUFFER_SIZE 4096
+# define NBUFS 4
+
+# define pDirectSound handle1
+# define pDSBuffer handle2
+
+# else /* USE WAVE... */
+
+# define __WaveHandleVal(o) (HWAVEOUT)(__externalAddressVal(o))
+# define MAXBUF 10 /* Maximum number of buffers */
+# define DATALEN 640 /* Size of wave data buffer */
+
+struct buf {
+ WAVEHDR hdr; /* Wave data header */
+ short data[DATALEN]; /* Actual wave data */
+ struct buf *next; /* Next buffer in free list */
+};
+
+HWAVEOUT waveHandle; /* Handle of wave output device */
+struct buf *free_list; /* List of available buffers */
+CRITICAL_SECTION free_list_lock;
+int free_buffers; /* Number of buffers in free list */
+int total_buffers; /* Total number of buffers allocated */
+HANDLE free_buffer_event; /* Automatic-reset event triggered whenever */
+
+# define waveHandle handle1
+
+# endif
# ifdef __DEF_Array
# define Array __DEF_Array
@@ -106,20 +139,37 @@
# ifdef __DEF_Context
# define Context __DEF_Context
# endif
-
# define INT int
-# define __DirectSoundVal(o) (LPDIRECTSOUND)(__externalAddressVal(o))
-# define __DSBufferVal(o) (LPDIRECTSOUNDBUFFER)(__externalAddressVal(o))
-
-# define RT_BUFFER_SIZE 4096
-# define NBUFS 4
-
-#endif
+#endif /* WIN32 */
%}
! !
+!SoundStream primitiveFunctions!
+
+%{
+#ifdef WIN32
+# ifndef USE_DIRECTSOUND
+
+static void CALLBACK
+waveCallBack(HWAVE waveHandle, UINT msg, DWORD inst, DWORD p1, DWORD p2)
+{
+ if (msg == MM_WOM_DONE) {
+ struct buf *bp = (struct buf *)p1;
+ EnterCriticalSection(&free_list_lock);
+ bp->next = free_list;
+ free_list = bp;
+ free_buffers++;
+ SetEvent(free_buffer_event);
+ LeaveCriticalSection(&free_list_lock);
+ }
+}
+
+# endif
+#endif
+
+%}
!SoundStream class methodsFor:'documentation'!
copyright
@@ -1223,6 +1273,8 @@
#endif
#ifdef WIN32
+# ifdef USE_DIRECTSOUND
+
OBJ oDirectSound, oDSBuffer;
LPDIRECTSOUND t_pDirectSound;
LPDIRECTSOUNDBUFFER t_pDSBuffer;
@@ -1242,6 +1294,38 @@
IDirectSound_Release(t_pDirectSound);
}
}
+# else
+ struct buf *bp, *next;
+ int r;
+ HWAVEOUT t_waveHandle;
+ OBJ oWaveHandle;
+
+ if ((oWaveHandle = __INST(waveHandle)) != nil) {
+ t_waveHandle = __WaveHandleVal(oWaveHandle);
+
+ /* Force cancellation of any pending buffers */
+ (void)waveOutReset(t_waveHandle);
+
+ /* Wait until all pending buffers have been freed */
+ while (free_buffers < total_buffers) {
+ WaitForSingleObject(free_buffer_event, INFINITE);
+ }
+
+ /* Close the device */
+ if ((r = waveOutClose(t_waveHandle)) != 0) {
+ printError("waveOutClose", r);
+ return;
+ }
+
+ /* Free allocated buffers */
+ for (bp = free_list; bp != NULL; bp = next) {
+ next = bp->next;
+ (void)free(bp);
+ }
+
+ __INST(waveHandle) = nil;
+ }
+# endif
RETURN (self);
#endif
@@ -1307,7 +1391,7 @@
isOpen
alPort notNil ifTrue:[^ true].
- pDirectSound notNil ifTrue:[^ true].
+ handle1 notNil ifTrue:[^ true].
^ filePointer notNil
!
@@ -1399,6 +1483,7 @@
#endif /* SGI_AUDIO */
#ifdef WIN32
+# ifdef USE_DIRECTSOUND
{
HRESULT hr;
DWORD status;
@@ -1426,8 +1511,8 @@
fprintf(stderr, "SoundStream not open!\n");
RETURN (0);
}
- t_cbBufOffset = __intVal(__INST(cbBufOffset));
- t_cbBufSize = __intVal(__INST(cbBufSize));
+ t_cbBufOffset = __intVal(__INST(bufferOffset));
+ t_cbBufSize = __intVal(__INST(bufferSize));
cnt = __intVal(count);
offs = __intVal(start) - 1;
@@ -1478,10 +1563,63 @@
t_cbBufOffset = (t_cbBufOffset + dwsize1 + dwsize2) % t_cbBufSize;
IDirectSoundBuffer_Unlock(t_pDSBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
}
- __INST(cbBufOffset) = __MKSMALLINT(t_cbBufOffset);
+ __INST(buffferOffset) = __MKSMALLINT(t_cbBufOffset);
RETURN (count);
}
+# else
+ {
+ struct buf *bp;
+ int len, i, r;
+
+ while (dataLen > 0) {
+ if (free_list == NULL && total_buffers < MAXBUF) {
+ /* Expand available buffer space */
+ bp = (struct buf *)malloc(sizeof(struct buf));
+ total_buffers++;
+ } else {
+ if (free_list == NULL) {
+ /* We must wait for a free buffer */
+ while (free_list == NULL) {
+ WaitForSingleObject(free_buffer_event, INFINITE);
+ }
+ }
+ EnterCriticalSection(&free_list_lock);
+ bp = free_list;
+ free_list = free_list->next;
+ --free_buffers;
+ LeaveCriticalSection(&free_list_lock);
+ r = waveOutUnprepareHeader(waveHandle, &bp->hdr, sizeof(WAVEHDR));
+ if (r != 0) {
+ printError("waveOutUnprepareHeader", r);
+ return;
+ }
+ }
+ len = min(dataLen, DATALEN);
+ bp->hdr.lpData = (char *)bp->data;
+ bp->hdr.dwBufferLength = len * sizeof(short);
+ bp->hdr.dwBytesRecorded = len * sizeof(short);
+ bp->hdr.dwUser = (DWORD)bp;
+ bp->hdr.dwFlags = 0;
+ bp->hdr.dwLoops = 0;
+ r = waveOutPrepareHeader(waveHandle, &bp->hdr, sizeof(WAVEHDR));
+ if (r != 0) {
+ printError("waveOutPrepareHeader", r);
+ return;
+ }
+ for (i = 0; i < len; i++) {
+ bp->data[i] = ulaw8tol16(data[i]);
+ }
+ r = waveOutWrite(waveHandle, &bp->hdr, sizeof(WAVEHDR));
+ if (r != 0) {
+ printError("waveOutWrite", r);
+ return;
+ }
+ data += len;
+ dataLen -= len;
+ }
+ }
+# endif
#endif /* WIN32 */
#if defined(DEV_AUDIO)
@@ -1647,6 +1785,7 @@
#endif /* SGI_AUDIO */
#ifdef WIN32
+# ifdef USE_DIRECTSOUND
{
HRESULT result;
LPDIRECTSOUND t_pDirectSound;
@@ -1671,7 +1810,7 @@
wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
wfFormat.cbSize = 0;
-#if 0
+# if 0
/* Setup the primary DS buffer description */
ZeroMemory(&primarydsbDesc, sizeof(DSBUFFERDESC));
primarydsbDesc.dwSize = sizeof(DSBUFFERDESC);
@@ -1696,11 +1835,11 @@
IDirectSound_Release(t_pDirectSound);
RETURN (nil);
}
-#endif
+# endif
/* Setup the secondary DS buffer description */
t_cbBufSize = RT_BUFFER_SIZE * sizeof(short) * NBUFS;
- __INST(cbBufSize) = __MKSMALLINT(t_cbBufSize);
+ __INST(bufferSize) = __MKSMALLINT(t_cbBufSize);
ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
@@ -1741,7 +1880,7 @@
RETURN (nil);
}
- __INST(cbBufOffset) = __MKSMALLINT(0); // reset last write position to start of buffer
+ __INST(bufferOffset) = __MKSMALLINT(0); // reset last write position to start of buffer
/* Start the buffer playback */
if ((result = IDirectSoundBuffer_Play(t_pDSBuffer, 0, 0, DSBPLAY_LOOPING) != DS_OK)) {
@@ -1761,6 +1900,59 @@
}
RETURN (self);
}
+# else /* WAVEOUT */
+ {
+ PCMWAVEFORMAT waveFormat;
+ int r;
+
+ if (waveHandle != NULL) {
+ return 1; /* output device already open */
+ }
+
+ waveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
+ waveFormat.wf.nChannels = 1;
+ waveFormat.wf.nSamplesPerSec = 8000;
+ waveFormat.wf.nAvgBytesPerSec = 16000;
+ waveFormat.wf.nBlockAlign = 2;
+ waveFormat.wBitsPerSample = 16;
+
+ r = waveOutOpen(&waveHandle,
+ WAVE_MAPPER,
+ (WAVEFORMAT *)&waveFormat,
+ (DWORD)waveCallBack,
+ 0,
+ CALLBACK_FUNCTION);
+ if (r != 0) {
+ printError("waveOutOpen", r);
+ return -1;
+ }
+
+ (void)waveOutReset(waveHandle);
+
+ free_list = NULL;
+ InitializeCriticalSection(&free_list_lock);
+ free_buffers = 0;
+ free_buffer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ total_buffers = 0;
+
+ /*
+ * HACK: If we immediately start writing valid audio data to the device
+ * then the sound is choppy in the beginning. Writing a null packet to
+ * to the device first seems to fix this problem although I have no idea
+ * why - DAC
+ */
+ {
+ char null[DATALEN];
+ int i;
+ for (i = 0; i < DATALEN; i++) {
+ null[i] = 127;
+ }
+ audioWrite(null, DATALEN);
+ }
+
+ return 1;
+ }
+# endif
#endif /* WIN32 */
%}.
@@ -1927,5 +2119,5 @@
!SoundStream class methodsFor:'documentation'!
version
-^ '$Header: /cvs/stx/stx/libbasic2/SoundStream.st,v 1.38 1999-01-15 21:21:16 cg Exp $'! !
+^ '$Header: /cvs/stx/stx/libbasic2/SoundStream.st,v 1.39 1999-01-30 20:16:46 cg Exp $'! !
SoundStream initialize!