preps for WaveOut (WIN32)
authorClaus Gittinger <cg@exept.de>
Sat, 30 Jan 1999 21:16:46 +0100
changeset 721 99f4c93ca492
parent 720 967fad20a8f1
child 722 0c3c1f866eb4
preps for WaveOut (WIN32)
SoundStr.st
SoundStream.st
--- 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!