SoundStream.st
changeset 5402 a6ef442609cf
parent 5401 3f2bb4b5331f
child 5403 7b72eccc4366
--- a/SoundStream.st	Thu Jan 02 00:50:20 2020 +0100
+++ b/SoundStream.st	Fri Jan 03 14:51:21 2020 +0100
@@ -18,11 +18,46 @@
 FileStream subclass:#SoundStream
 	instanceVariableNames:'sampleRate numberOfChannels bitsPerSample audioFormat handle1
 		handle2 bufferOffset bufferSize lastErrorString fragmentSize'
-	classVariableNames:'IsInitialized UnsupportedOperationSignal'
+	classVariableNames:'IsInitialized UnsupportedOperationSignal ConcreteClass'
 	poolDictionaries:''
 	category:'Streams-External'
 !
 
+SoundStream subclass:#DevAudio
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:SoundStream
+!
+
+SoundStream subclass:#IRISAudio
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:SoundStream
+!
+
+SoundStream subclass:#PortAudio
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:SoundStream
+!
+
+SoundStream subclass:#Win32DirectSound
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:SoundStream
+!
+
+SoundStream subclass:#Win32WaveSound
+	instanceVariableNames:''
+	classVariableNames:''
+	poolDictionaries:''
+	privateIn:SoundStream
+!
+
 !SoundStream primitiveDefinitions!
 %{
 
@@ -450,37 +485,43 @@
 	UnsupportedOperationSignal nameClass:self message:#unsupportedOperationSignal.
 	UnsupportedOperationSignal notifierString:'unsupported operation'.
     ]
-!
-
-primitiveInitializeDevice
-    |errorMessageOrNil|
-
-%{
-#ifdef USE_PORTAUDIO
-    {
-	PaError paErr = 0;
-
-	if (DEBUGGING) {
-	    fprintf(stderr, "calling Pa_Initialize...\n");
-	}
-	if ((paErr = Pa_Initialize()) != paNoError ) {
-	    errorMessageOrNil = __MKSTRING(Pa_GetErrorText( paErr ) );
-	    fprintf(stderr, "SoundStream [error]: Pa_Initialize failed\n");
-	};
-    }
-#endif
-%}.
-    errorMessageOrNil notNil ifTrue:[
-	self error:'failed to initialize audio device: ',errorMessageOrNil
-    ].
 ! !
 
 !SoundStream class methodsFor:'instance creation'!
 
+determineConcreteClass
+    self allSubclassesDo:[:each |
+        each isAbstract ifFalse:[
+            each isSupported ifTrue:[
+                ^ each
+            ]
+        ]
+    ].
+    ^ nil
+!
+
+new
+    self == SoundStream ifTrue:[
+        ConcreteClass isNil ifTrue:[
+            ConcreteClass := self determineConcreteClass.
+            ConcreteClass isNil ifTrue:[
+                self openErrorSignal raiseErrorString:'missing sound support'.
+            ].
+        ].
+        ^ ConcreteClass new.
+    ].
+    ^ self basicNew initialize
+
+    "
+     SoundStream new
+    "
+!
+
 readWrite
     "create and return a new soundStream for readWrite (i.e. filtering)"
 
     |newStream|
+
     newStream := (self basicNew) initialize.
     newStream openForReadWrite isNil ifTrue:[^nil].
     ^ newStream
@@ -1005,15 +1046,6 @@
 defaultSampleRate
     "minimum, supported by all audio systems"
 
-%{
-#ifdef USE_DEV_AUDIO
-    RETURN (__MKSMALLINT(DEV_AUDIO_DEFAULT_FREQ));
-#endif
-#ifdef USE_PORTAUDIO
-    RETURN (__MKSMALLINT(PORTAUDIO_DEFAULT_FREQ));
-#endif
-%}.
-
     ^ 8000
 ! !
 
@@ -1022,8 +1054,13 @@
 playSoundFile:aFilename
     "play a soundFile"
 
-    |inStream soundStream count totalCount buffer startTime playTime delayedTime waitTime|
-
+    |mime inStream soundStream count totalCount buffer startTime playTime delayedTime waitTime|
+
+    mime := aFilename asFilename mimeTypeFromName.
+    mime isAudioType ifFalse:[
+        self error:'not an audio file: ',aFilename asFilename baseName
+    ].
+    self halt.
     inStream := aFilename asFilename readStream.
     inStream isNil ifTrue:[self error:'cannot open'].
 
@@ -1035,8 +1072,8 @@
 
     buffer := ByteArray new:4096.
     [(count := inStream nextBytesInto:buffer) > 0] whileTrue:[
-	totalCount := totalCount + count.
-	soundStream nextPutBytes:count from:buffer.
+        totalCount := totalCount + count.
+        soundStream nextPutBytes:count from:buffer.
     ].
 
     inStream close.
@@ -1056,6 +1093,7 @@
     "
      SoundStream playSoundFile:'/usr/local/lib/sounds/laugh.snd'
      SoundStream playSoundFile:'/usr/local/lib/sounds/spacemusic.snd'
+     SoundStream playSoundFile:'../../goodies/not_ported/sound/sampleFiles/pluck-pcm16.aiff'
     "
 
     "Created: / 17-11-1995 / 17:25:30 / cg"
@@ -1064,6 +1102,10 @@
 
 !SoundStream class methodsFor:'queries'!
 
+isSupported
+    ^ false.
+!
+
 usedAudio
     "returns a symbol describing which audio system is used;
      one of PORTAUDIO, DEV_AUDIO, WIN32_WAVESOUND, IRIS_AUDIO"
@@ -1189,196 +1231,24 @@
 dumpSettings
     "debugging interface - dump the current settings"
 
-    |fd blockSize speed channels stereo format|
-
-    fd := self fileDescriptorOrNil.
-    fd isNil ifTrue:[
-	self errorNotOpen.
-	^ nil
-    ].
     audioFormat == #S16 ifTrue:[
-	UninterpretedBytes isBigEndian ifTrue:[
-	    audioFormat := #S16_BE
-	] ifFalse:[
-	    audioFormat := #S16_LE
-	]
+        UninterpretedBytes isBigEndian ifTrue:[
+            audioFormat := #S16_BE
+        ] ifFalse:[
+            audioFormat := #S16_LE
+        ]
     ].
     audioFormat == #U16 ifTrue:[
-	UninterpretedBytes isBigEndian ifTrue:[
-	    audioFormat := #U16_BE
-	] ifFalse:[
-	    audioFormat := #U16_LE
-	]
+        UninterpretedBytes isBigEndian ifTrue:[
+            audioFormat := #U16_BE
+        ] ifFalse:[
+            audioFormat := #U16_LE
+        ]
     ].
-
-%{
-    int f = __intVal(fd);
-    int __blockSize = -1;
-    int __speed = -1;
-    int __channels = __intVal(__INST(numberOfChannels));
-    int __stereo = __channels > 1;
-    int __format = -1;
-
-    if (0) {
-    }
-    else if (__INST(audioFormat) == @symbol(MU_LAW)) {
-#  ifdef AFMT_MU_LAW
-	__format = AFMT_MU_LAW;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(A_LAW)) {
-#  ifdef AFMT_A_LAW
-	__format = AFMT_A_LAW;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(IMA_ADPCM)) {
-#  ifdef AFMT_IMA_ADPCM
-	__format = AFMT_IMA_ADPCM;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(U8)) {
-#  ifdef AFMT_U8
-	__format = AFMT_U8;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(S16_LE)) {
-#  ifdef AFMT_S16_LE
-	__format = AFMT_S16_LE;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(S16_BE)) {
-#  ifdef AFMT_S16_BE
-	__format = AFMT_S16_BE;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(S8)) {
-#  ifdef AFMT_S8
-	__format = AFMT_S8;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(U16_LE)) {
-#  ifdef AFMT_U16_LE
-	__format = AFMT_U16_LE;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(U16_BE)) {
-#  ifdef AFMT_U16_BE
-	__format = AFMT_U16_BE;
-#  endif
-    }
-    else if (__INST(audioFormat) == @symbol(MPEG)) {
-#  ifdef AFMT_MPEG
-	__format = AFMT_MPEG;
-#  endif
-    }
-
-#ifdef USE_DEV_AUDIO
-    channels = nil;
-    blockSize = nil;
-    stereo = nil;
-    speed = nil;
-
-# if defined(SNDCTL_DSP_GETBLKSIZE)
-    if (ioctl(f, SNDCTL_DSP_GETBLKSIZE, &__blockSize) >= 0) {
-	blockSize = __MKSMALLINT(__blockSize);
-    }
-# endif
-# if defined(SNDCTL_DSP_CHANNELS)
-    if (ioctl(f, SNDCTL_DSP_CHANNELS, &__channels) >= 0) {
-	channels = __MKSMALLINT(__channels);
-	stereo = __MKSMALLINT(__channels > 1);
-    }
-# else
-#  if defined(SNDCTL_DSP_STEREO)
-    if (ioctl(f, SNDCTL_DSP_STEREO, &__stereo) >= 0) {
-	stereo = __MKSMALLINT(__stereo);
-    }
-#  endif
-# endif
-# if defined(SNDCTL_DSP_SPEED)
-    if (ioctl(f, SNDCTL_DSP_SPEED, &__speed) >= 0) {
-	speed = __MKSMALLINT(__speed);
-    }
-# endif
-# if defined(SNDCTL_DSP_GETFMT)
-    if (ioctl(f, SNDCTL_DSP_GETFMT, &__format) >= 0) {
-	format = __MKSMALLINT(__format);
-    }
-# else
-#  if defined(SNDCTL_DSP_SETFMT) && defined(AFMT_QUERY)
-    __format = AFMT_QUERY;
-    if (ioctl(f, SNDCTL_DSP_SETFMT, &__format) >= 0) {
-	switch (__format) {
-#   ifdef AFMT_MU_LAW
-	    case AFMT_MU_LAW:
-		format = @symbol(MU_LAW);
-		break;
-#   endif
-#   ifdef AFMT_A_LAW
-	    case AFMT_A_LAW:
-		format = @symbol(A_LAW);
-		break;
-#   endif
-#   ifdef AFMT_U8
-	    case AFMT_U8:
-		format = @symbol(U8);
-		break;
-#   endif
-#   ifdef AFMT_S8
-	    case AFMT_S8:
-		format = @symbol(S8);
-		break;
-#   endif
-#   ifdef AFMT_S16_LE
-	    case AFMT_S16_LE:
-		format = @symbol(S16_LE);
-		break;
-#   endif
-#   ifdef AFMT_S16_BE
-	    case AFMT_S16_BE:
-		format = @symbol(S16_BE);
-		break;
-#   endif
-#   ifdef AFMT_U16_LE
-	    case AFMT_U16_LE:
-		format = @symbol(U16_LE);
-		break;
-#   endif
-#   ifdef AFMT_U16_BE
-	    case AFMT_U16_BE:
-		format = @symbol(U16_BE);
-		break;
-#   endif
-#   ifdef AFMT_MPEG
-	    case AFMT_MPEG:
-		format = @symbol(MPEG);
-		break;
-#   endif
-	    default:
-		format = nil;
-	}
-    }
-#  endif
-# endif
-#endif /* USE_DEV_AUDIO */
-
-%}.
-    format notNil ifTrue:[
-	Transcript show:'format: '; showCR:format
-    ].
-    blockSize notNil ifTrue:[
-	Transcript show:'blockSize: '; showCR:blockSize
-    ].
-    speed notNil ifTrue:[
-	Transcript show:'speed: '; showCR:speed
-    ].
-    channels notNil ifTrue:[
-	Transcript show:'channels: '; showCR:channels
-    ].
-    stereo notNil ifTrue:[
-	Transcript show:'stereo: '; showCR:stereo
-    ].
-
+    Transcript show:'sampleRate: '; showCR:sampleRate.
+    Transcript show:'format: '; showCR:audioFormat.
+    Transcript show:'fragmentSize: '; showCR:fragmentSize.
+    Transcript show:'channels: '; showCR:numberOfChannels.
     Transcript show:'supported audioFormats: '; showCR:(self supportedAudioFormats).
 
     "
@@ -1406,49 +1276,11 @@
     numberOfChannels := self class defaultNumberOfChannels.
     sampleRate := self class defaultSampleRate.
     pathName := nil.
-
-    OperatingSystem isUNIXlike ifTrue:[
-	'/dev/audio' asFilename exists ifTrue:[
-	    "/
-	    "/ sunos or linux
-	    "/
-	    pathName := '/dev/audio'.
-	].
-    ].
-
-    (IsInitialized ? false) ifFalse:[
-	self class primitiveInitializeDevice
-    ].
-
-    "Created: 17.11.1995 / 17:28:14 / cg"
 !
 
 resetSoundCard
     "debugging interface - reset the soundCard"
 
-    |fd|
-
-    handle notNil ifTrue:[
-	fd := self fileDescriptor.
-	fd isNil ifTrue:[
-	self errorNotOpen.
-	    ^ nil
-	]
-    ].
-%{
-    int f = __intVal(fd);
-    int __dummy;
-
-#ifdef USE_DEV_AUDIO
-    if (__isSmallInteger(fd)) {
-# if defined(SNDCTL_DSP_RESET)
-	if (ioctl(f, SNDCTL_DSP_RESET, &__dummy) >= 0) {
-	    RETURN (self);
-	}
-# endif
-    }
-#endif /* USE_DEV_AUDIO */
-%}.
     ^ UnsupportedOperationSignal raise
 
     "
@@ -1460,166 +1292,26 @@
     "set the format of the audio data as specified by aSymbol.
      Returns true if sucessful - may fail with some formats on many sound devices."
 
-    |fd ok|
-
-    handle notNil ifTrue:[
-	fd := self fileDescriptor.
-	fd isNil ifTrue:[
-	    self errorNotOpen.
-	    ^ nil
-	]
-    ].
-%{
-    OBJ sym = aSymbol;
-
-    if (__INST(audioFormat) == sym) {
-	RETURN (self);
-    }
-
-#ifdef USE_DEV_AUDIO
-    if (__isSmallInteger(fd)) {
-	int f = __intVal(fd);
-	int __fmt = 0, __fmtWant;
-	union {
-	    unsigned short us;
-	    unsigned char ub[2];
-	} u;
-
-	if (__isSymbol(sym)) {
-	    if (sym == @symbol(U16)) {
-		u.us = 0x1234;
-		if (u.ub[0] == 0x34) {
-		    /* printf("U16_LE\n"); */
-		    sym = @symbol(U16_LE);
-		} else {
-		    /* printf("U16_BE\n"); */
-		    sym = @symbol(U16_BE);
-		}
-	    } else if (sym == @symbol(S16)) {
-		u.us = 0x1234;
-		if (u.ub[0] == 0x34) {
-		    /* printf("S16_LE\n"); */
-		   sym = @symbol(S16_LE);
-		} else {
-		    /* printf("S16_BE\n"); */
-		   sym = @symbol(S16_BE);
-		}
-	    }
-
-	    if (0) {
-# ifdef AFMT_MU_LAW
-	    } else if (sym == @symbol(MU_LAW)) {
-		__fmt = AFMT_MU_LAW;
-# endif
-# ifdef AFMT_A_LAW
-	    } else if (sym == @symbol(A_LAW)) {
-		__fmt = AFMT_A_LAW;
-# endif
-# ifdef AFMT_IMA_ADPCM
-	    } else if (sym == @symbol(IMA_ADPCM)) {
-		__fmt = AFMT_IMA_ADPCM;
-# endif
-# ifdef AFMT_U8
-	    } else if (sym == @symbol(U8)) {
-		__fmt = AFMT_U8;
-# endif
-# ifdef AFMT_S8
-	    } else if (sym == @symbol(S8)) {
-		__fmt = AFMT_S8;
-# endif
-# ifdef AFMT_U16_LE
-	    } else if (sym == @symbol(U16_LE)) {
-		__fmt = AFMT_U16_LE;
-# endif
-# ifdef AFMT_U16_BE
-	    } else if (sym == @symbol(U16_BE)) {
-		__fmt = AFMT_U16_BE;
-# endif
-# ifdef AFMT_S16_LE
-	    } else if (sym == @symbol(S16_LE)) {
-		__fmt = AFMT_S16_LE;
-# endif
-# ifdef AFMT_S16_BE
-	    } else if (sym == @symbol(S16_BE)) {
-		__fmt = AFMT_S16_BE;
-# endif
-# ifdef AFMT_MPEG
-	    } else if (sym == @symbol(MPEG)) {
-		__fmt = AFMT_MPEG;
-# endif
-
-# ifdef AUDIO_FORMAT_LINEAR16BIT
-	    } else if (sym == @symbol(S16)) {
-		__fmt = AUDIO_FORMAT_LINEAR16BIT;
-# endif
-# ifdef AUDIO_FORMAT_ULAW
-	    } else if (sym == @symbol(MU_LAW)) {
-		__fmt = AUDIO_FORMAT_ULAW;
-# endif
-# ifdef AUDIO_FORMAT_ALAW
-	    } else if (sym == @symbol(A_LAW)) {
-		__fmt = AUDIO_FORMAT_ALAW;
-# endif
-	    } else {
-		console_fprintf(stderr, "bad format: %s\n", __stringVal(sym));
-		ok = false;
-		goto bad;
-	    }
-	}
-
-# ifdef SNDCTL_DSP_SETFMT
-	__fmtWant = __fmt;
-
-	if (ioctl(f, SNDCTL_DSP_SETFMT, &__fmt) >= 0) {
-	    if (__fmt == __fmtWant) {
-		__INST(audioFormat) = sym;
-	    } else {
-		/* console_fprintf(stderr, "want: %x; got: %x\n", __fmtWant, __fmt); */
-	    }
-	} else {
-	    /* console_fprintf(stderr, "got err-ret from setFmp %x\n", __fmt); */
-	    ok = false;
-	}
-# else
-#  ifdef AUDIO_SET_DATA_FORMAT /* hpux */
-	if (ioctl (f, AUDIO_SET_DATA_FORMAT, __fmt)) {
-	    /* console_fprintf(stderr, "got err-ret from AUDIO_SET_DATA_FORMAT\n"); */
-	}
-#  endif
-# endif /* SNDCTL_DSP_SETFMT */
-
-bad: ;
-    }
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_PORTAUDIO
-    __INST(audioFormat) = aSymbol;
-    __STORE(self, aSymbol);
-#endif
-
-%}.
-    (ok ? true) ifFalse:[
-	^ UnsupportedOperationSignal raise
-    ].
+    audioFormat := aSymbol.
     ((audioFormat == #U8) or:[audioFormat == #S8]) ifTrue:[
-	bitsPerSample := 8.
-	^ self
+        bitsPerSample := 8.
+        ^ self
     ].
     (#(U16 U16_LE U16_BE S16 S16_LE S16_BE) includes:audioFormat) ifTrue:[
-	bitsPerSample := 16.
-	^ self
+        bitsPerSample := 16.
+        ^ self
     ].
     (#(U24 U24_LE U24_BE S24 S24_LE S24_BE) includes:audioFormat) ifTrue:[
-	bitsPerSample := 24.
-	^ self
+        bitsPerSample := 24.
+        ^ self
     ].
     (#(U32 U32_LE U32_BE S32 S32_LE S32_BE) includes:audioFormat) ifTrue:[
-	bitsPerSample := 32.
-	^ self
+        bitsPerSample := 32.
+        ^ self
     ].
     (audioFormat == #F32) ifTrue:[
-	bitsPerSample := 32.
-	^ self
+        bitsPerSample := 32.
+        ^ self
     ].
     bitsPerSample := 8.
 
@@ -1635,61 +1327,7 @@
     "set the number of channels (1 -> mono; 2 -> stereo).
      Returns true if sucessful - may fail with many sound devices."
 
-    |fd|
-
-    handle notNil ifTrue:[
-	fd := self fileDescriptor.
-	fd isNil ifTrue:[
-	    self errorNotOpen.
-	    ^ nil
-	]
-    ].
-%{
-
-#ifdef USE_DEV_AUDIO
-    if (__isSmallInteger(fd) && __isSmallInteger(nChannels)) {
-	int f = __intVal(fd);
-	int __nCh = __intVal(nChannels);
-
-# ifdef SNDCTL_DSP_STEREO
-	if ((__nCh == 1) || (__nCh == 2)) {
-	    int __stereo = (__nCh == 2) ? 1 : 0;
-
-	    if (ioctl(f, SNDCTL_DSP_STEREO, &__stereo) >= 0) {
-		if (__stereo == 0) {
-		    __INST(numberOfChannels) = __MKSMALLINT(1);
-		} else {
-		    __INST(numberOfChannels) = __MKSMALLINT(2);
-		}
-		RETURN (self);
-	    }
-	}
-# else
-#  ifdef SOUND_PCM_WRITE_CHANNELS
-	if (ioctl(f, SOUND_PCM_WRITE_CHANNELS, &__nCh) >= 0) {
-	    __INST(numberOfChannels) = nChannels;
-	    RETURN (self);
-	}
-#  else
-#   ifdef AUDIO_SET_CHANNELS /* hpux */
-	if (ioctl (f, AUDIO_SET_CHANNELS, __nCh)) {
-	    /* console_fprintf(stderr, "got err-ret from AUDIO_SET_CHANNELS\n"); */
-	    __INST(numberOfChannels) = nChannels;
-	    RETURN (self);
-	}
-#   endif
-#  endif
-# endif
-    }
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_PORTAUDIO
-    __INST(numberOfChannels) = nChannels;
-    RETURN (self);
-#endif
-
-%}.
-    ^ UnsupportedOperationSignal raise
+    numberOfChannels := nChannels. 
 
     "
      self writing setChannels:2; dumpSettings; close
@@ -1699,107 +1337,15 @@
 !
 
 setFragmentSize:blockSize
-    "set the soundDriver's fragmentSize.
-     Returns true if sucessful - may fail with many sound devices."
-
-    |fd|
-
-    handle notNil ifTrue:[
-	fd := self fileDescriptor.
-	fd isNil ifTrue:[
-	    self errorNotOpen.
-	    ^ nil
-	]
-    ].
-%{
-    int f = __intVal(fd);
-    int __blockSize = 0;
-
-#ifdef USE_DEV_AUDIO
-    if (__isSmallInteger(fd) && __isSmallInteger(blockSize)) {
-	__blockSize = __intVal(blockSize);
-# if defined(SNDCTL_DSP_SETFRAGMENT)
-	if (ioctl(f, SNDCTL_DSP_SETFRAGMENT, &__blockSize) >= 0) {
-	    /* __INST(blockSize) = blockSize; */
-	    RETURN (self);
-	}
-# endif
-# ifdef AUDIO_SET_CHANNELS /* hpux */
-	if (ioctl (f, AUDIO_SET_TXBUFSIZE, __blockSize)) {
-	    /* console_fprintf(stderr, "got err-ret from AUDIO_SET_TXBUFSIZE\n"); */
-	    /* __INST(blockSize) = blockSize; */
-	    RETURN (self);
-	}
-# endif
-    }
-#endif // USE_DEV_AUDIO
-
-#ifdef USE_PORTAUDIO
-    __INST(fragmentSize) = blockSize;
-    RETURN (self);
-#endif
-%}.
-    ^ UnsupportedOperationSignal raise
+    "set the soundDriver's fragmentSize"
+
+    fragmentSize := blockSize.
 !
 
 setSampleRate:hz
-    "set the sample rate.
-     Returns true if sucessful - may fail with many sound devices."
-
-    |fd|
-
-    handle notNil ifTrue:[
-	fd := self fileDescriptor.
-	fd isNil ifTrue:[
-	    self errorNotOpen.
-	    ^ nil
-	]
-    ].
-%{
-#ifdef USE_DEV_AUDIO
-    if (__isSmallInteger(fd) && __isSmallInteger(hz)) {
-	int f = __intVal(fd);
-	int __rate = __intVal(hz);
-	int __rateWant = __rate;
-
-# if defined(SNDCTL_DSP_SPEED)
-	if (ioctl(f, SNDCTL_DSP_SPEED, &__rate) >= 0) {
-	    if (__rate != __rateWant) {
-		console_fprintf(stderr, "SoundStream [warning]: actual rate is %d\n", __rate);
-		hz = __MKSMALLINT(__rate);
-	    }
-	    __INST(sampleRate) = hz;
-	    RETURN (self);
-	}
-# else
-#  if defined(SOUND_PCM_WRITE_RATE)
-	if (ioctl(f, SOUND_PCM_WRITE_RATE, &__rate) >= 0) {
-	    if (__rate != __rateWant) {
-		console_fprintf(stderr, "SoundStream [warning]: actual rate is %d\n", __rate);
-		hz = __MKSMALLINT(__rate);
-	    }
-	    __INST(sampleRate) = hz;
-	    RETURN (self);
-	}
-#  else
-#   ifdef AUDIO_SET_SAMPLE_RATE /* hpux */
-	if (ioctl (f, AUDIO_SET_SAMPLE_RATE, __rate)) {
-	    /* console_fprintf(stderr, "got err-ret from AUDIO_SET_SAMPLE_RATE\n"); */
-	    __INST(sampleRate) = hz;
-	    RETURN (self);
-	}
-#   endif
-#  endif
-# endif
-    }
-#endif // USE_DEV_AUDIO
-
-#ifdef USE_PORTAUDIO
-    __INST(sampleRate) = hz;
-    RETURN (self);
-#endif
-%}.
-    ^ UnsupportedOperationSignal raise
+    "set the sample rate"
+
+    sampleRate := hz.
 
     "
      self writing setSampleRate:10000; dumpSettings; close
@@ -1811,185 +1357,29 @@
 supportedAudioFormats
     "return a collection of supported audio formats.
      possibly returned symbols are:
-	U8        unsigned 8bit samples
-	S8        signed 8bit samples
-	U16       unsigned 16bit samples in native format
-	U16_LE    unsigned 16bit big endian samples
-	U16_BE    unsigned 16bit big endian samples
-	S16       signed 16bit little endian samples in native format
-	S16_LE    signed 16bit little endian samples
-	S16_BE    signed 16bit big endian samples
-	S24       signed 24bit little endian samples in native format
-	S24_LE    signed 24bit little endian samples
-	S24_BE    signed 24bit big endian samples
-	S32       signed 32bit little endian samples in native format
-	S32_LE    signed 32bit little endian samples
-	S32_BE    signed 32bit big endian samples
-	F32       float samples
-	MPEG      audio mpeg encoded
-	MU_LAW    u-law encoded 8bit samples
-	A_LAW     a-law encoded 8bit samples
-	IMA_ADPCM adpcm encoded
+        U8        unsigned 8bit samples
+        S8        signed 8bit samples
+        U16       unsigned 16bit samples in native format
+        U16_LE    unsigned 16bit big endian samples
+        U16_BE    unsigned 16bit big endian samples
+        S16       signed 16bit little endian samples in native format
+        S16_LE    signed 16bit little endian samples
+        S16_BE    signed 16bit big endian samples
+        S24       signed 24bit little endian samples in native format
+        S24_LE    signed 24bit little endian samples
+        S24_BE    signed 24bit big endian samples
+        S32       signed 32bit little endian samples in native format
+        S32_LE    signed 32bit little endian samples
+        S32_BE    signed 32bit big endian samples
+        F32       float samples
+        MPEG      audio mpeg encoded
+        MU_LAW    u-law encoded 8bit samples
+        A_LAW     a-law encoded 8bit samples
+        IMA_ADPCM adpcm encoded
      the set of returned symbols depends on the underlying sound hardware.
     "
 
-    |fd audioFormatMask
-     supportedFormats
-     supports_MU_LAW supports_A_LAW supports_MPEG
-     supports_IMA_ADPCM
-     supports_S8 supports_U8
-     supports_S16_LE supports_S16_BE
-     supports_U16_LE supports_U16_BE
-     supports_U32_LE supports_U32_BE
-     supports_S24_LE supports_S24_BE
-     supports_S32_LE supports_S32_BE
-     supports_F32
-    |
-
-    fd := self fileDescriptorOrNil.
-
-%{
-#ifdef USE_DEV_AUDIO
-    supports_MU_LAW = true;
-
-    if (fd != nil) {
-	int f = __intVal(fd);
-	int __audioFormatMask = 0;
-
-# if defined(SNDCTL_DSP_GETFMTS)
-	if (ioctl(f, SNDCTL_DSP_GETFMTS, &__audioFormatMask) >= 0) {
-	    audioFormatMask = __MKSMALLINT(__audioFormatMask);
-
-#  ifdef AFMT_MU_LAW
-	    supports_MU_LAW = (__audioFormatMask & AFMT_MU_LAW) ? true : false;
-#  endif
-#  ifdef AFMT_A_LAW
-	    supports_A_LAW = (__audioFormatMask & AFMT_A_LAW) ? true : false;
-#  endif
-#  ifdef AFMT_IMA_ADPCM
-	    supports_IMA_ADPCM = (__audioFormatMask & AFMT_IMA_ADPCM) ? true : false;
-#  endif
-#  ifdef AFMT_U8
-	    supports_U8 = (__audioFormatMask & AFMT_U8) ? true : false;
-#  endif
-#  ifdef AFMT_S16_LE
-	    supports_S16_LE = (__audioFormatMask & AFMT_S16_LE) ? true : false;
-#  endif
-#  ifdef AFMT_S16_BE
-	    supports_S16_BE = (__audioFormatMask & AFMT_S16_BE) ? true : false;
-#  endif
-#  ifdef AFMT_S8
-	    supports_S8 = (__audioFormatMask & AFMT_S8) ? true : false;
-#  endif
-#  ifdef AFMT_U16_LE
-	    supports_U16_LE = (__audioFormatMask & AFMT_U16_LE) ? true : false;
-#  endif
-#  ifdef AFMT_U16_BE
-	    supports_U16_BE = (__audioFormatMask & AFMT_U16_BE) ? true : false;
-#  endif
-#  ifdef AFMT_MPEG
-	    supports_MPEG = (__audioFormatMask & AFMT_MPEG) ? true : false;
-#  endif
-	}
-    }
-# endif // SNDCTL_DSP_GETFMTS
-
-# ifdef hpux
-    supports_A_LAW = true;
-    supports_S16_BE = true;
-# endif
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_IRIS_AUDIO
-    supports_U8 = true;
-    supports_U16_BE = true;
-#endif
-
-#ifdef USE_PORTAUDIO
-    supports_U8 = true;
-    supports_S8 = true;
-    supports_S16_LE = true;
-    supports_S24_LE = true;
-    supports_S32_LE = true;
-    supports_F32 = true;
-#endif
-
-#ifdef __win32__
-    supports_S16_LE = true;
-#endif
-
-%}.
-    supportedFormats := IdentitySet new.
-    (supports_MU_LAW ? false) ifTrue:[
-	supportedFormats add:#'MU_LAW'
-    ].
-    (supports_A_LAW ? false)  ifTrue:[
-	supportedFormats add:#'A_LAW'
-    ].
-    (supports_IMA_ADPCM ? false)  ifTrue:[
-	supportedFormats add:#'IMA_ADPCM'
-    ].
-    (supports_MPEG ? false)  ifTrue:[
-	supportedFormats add:#'MPEG'
-    ].
-    (supports_S8 ? false)  ifTrue:[
-	supportedFormats add:#'S8'
-    ].
-    (supports_U8 ? false)  ifTrue:[
-	supportedFormats add:#'U8'
-    ].
-    (supports_S16_LE ? false)  ifTrue:[
-	supportedFormats add:#'S16_LE'.
-	UninterpretedBytes isBigEndian ifFalse:[
-	    supportedFormats add:#'S16'.
-	]
-    ].
-    (supports_S16_BE ? false)  ifTrue:[
-	supportedFormats add:#'S16_BE'.
-	UninterpretedBytes isBigEndian ifTrue:[
-	    supportedFormats add:#'S16'.
-	]
-    ].
-    (supports_S24_LE ? false)  ifTrue:[
-	supportedFormats add:#'S24_LE'.
-	UninterpretedBytes isBigEndian ifFalse:[
-	    supportedFormats add:#'S24'.
-	]
-    ].
-    (supports_S24_BE ? false)  ifTrue:[
-	supportedFormats add:#'S24_BE'.
-	UninterpretedBytes isBigEndian ifTrue:[
-	    supportedFormats add:#'S24'.
-	]
-    ].
-    (supports_S32_LE ? false)  ifTrue:[
-	supportedFormats add:#'S32_LE'.
-	UninterpretedBytes isBigEndian ifFalse:[
-	    supportedFormats add:#'S32'.
-	]
-    ].
-    (supports_S32_BE ? false)  ifTrue:[
-	supportedFormats add:#'S32_BE'.
-	UninterpretedBytes isBigEndian ifTrue:[
-	    supportedFormats add:#'S32'.
-	]
-    ].
-    (supports_U16_LE ? false)  ifTrue:[
-	supportedFormats add:#'U16_LE'.
-	UninterpretedBytes isBigEndian ifFalse:[
-	    supportedFormats add:#'U16'.
-	]
-    ].
-    (supports_U16_BE ? false)  ifTrue:[
-	supportedFormats add:#'U16_BE'.
-	UninterpretedBytes isBigEndian ifTrue:[
-	    supportedFormats add:#'U16'.
-	]
-    ].
-    (supports_F32 ? false)  ifTrue:[
-	supportedFormats add:#'F32'
-    ].
-    ^ supportedFormats.
+    ^ #( U8)
 
     "
      |s formats|
@@ -2013,155 +1403,7 @@
 closeFile
     "a stream has been collected - close the file"
 
-%{
-#ifdef USE_IRIS_AUDIO
-    OBJ port;
-
-    if ((port = __INST(alPort)) != nil) {
-	__INST(alPort) = nil;
-	ALcloseport(__ALportVal(port));
-    }
-    RETURN (self);
-#endif /* USE_IRIS_AUDIO */
-
-#ifdef USE_WIN32_DIRECTSOUND
-    OBJ oDirectSound, oDSBuffer;
-    LPDIRECTSOUND       t_pDirectSound;
-    LPDIRECTSOUNDBUFFER t_pDSBuffer;
-
-    if ((oDSBuffer = __INST(pDSBuffer)) != nil) {
-	__INST(pDSBuffer) = nil;
-	t_pDSBuffer = __DSBufferVal(oDSBuffer);
-	if (t_pDSBuffer) {
-	    IDirectSoundBuffer_Stop(t_pDSBuffer);
-	    IDirectSoundBuffer_Release(t_pDSBuffer);
-	}
-    }
-    if ((oDirectSound = __INST(pDirectSound)) != nil) {
-	__INST(pDirectSound) = nil;
-	t_pDirectSound = __DirectSoundVal(oDirectSound);
-	if (t_pDirectSound) {
-	    IDirectSound_Release(t_pDirectSound);
-	}
-    }
-    RETURN (self);
-#endif /* USE_WIN32_DIRECTSOUND */
-
-#ifdef USE_WIN32_WAVESOUND
-    struct buf *bp, *next;
-    int r;
-    HWAVEOUT t_waveHandle;
-    OBJ oWaveHandle;
-
-    if ((oWaveHandle = __INST(waveHandle)) != nil) {
-	t_waveHandle = __WaveHandleVal(oWaveHandle);
-
-# ifdef NO_WAIT_IN_CLOSE
-	/* Force cancellation of any pending buffers */
-	(void)waveOutReset(t_waveHandle);
-# endif
-
-	/* Wait until all pending buffers have been freed */
-	while (free_buffers < total_buffers) {
-	    WaitForSingleObject(free_buffer_event, INFINITE);
-	}
-
-# ifndef NO_WAIT_IN_CLOSE
-	/* Force cancellation of any pending buffers */
-	(void)waveOutReset(t_waveHandle);
-# endif
-
-	/* Close the device */
-	if ((r = waveOutClose(t_waveHandle)) != 0) {
-	    console_printf("waveOutClose\n");
-	    RETURN(self);
-	}
-
-	EnterCriticalSection(&free_list_lock);
-
-	/* Free allocated buffers */
-	for (bp = free_list; bp != NULL; bp = next) {
-	    next = bp->next;
-	    (void)free(bp);
-	}
-	free_list = NULL;
-
-	LeaveCriticalSection(&free_list_lock);
-
-	__INST(waveHandle) = nil;
-    }
-    RETURN (self);
-#endif /* USE_WIN32_WAVESOUND */
-
-#ifdef USE_DEV_AUDIO
-    OBJ fp;
-    int fd;
-    FILE *f;
-
-    if ((fp = __INST(handle)) != nil) {
-	f = __FILEVal(fp);
-	__INST(handle) = nil;
-# ifdef LINUX
-	sigsetmask(~0);
-# endif
-	if (__INST(buffered) == true) {
-	    fflush(f);
-	    fclose(f);
-	} else {
-	    fd = fileno(f);
-	    close(fd);
-	    fclose(f);
-	}
-# ifdef LINUX
-	sigsetmask(0);
-# endif
-    }
-    RETURN (self);
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_PORTAUDIO
-    OBJ str;
-    if ((str = __INST(handle1)) != nil) {
-	struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
-	struct paBuffer* buffer;
-
-	if (DEBUGGING) {
-	    fprintf(stderr, "pa close\n");
-	}
-	__externalAddressVal(str) = NULL;
-	__INST(handle1) = nil;
-	// Pa_StopStream( paStreamData->stream );
-	Pa_CloseStream( paStreamData->stream );
-
-	LOCK(paStreamData->lock);
-
-	buffer = paStreamData->currentBuffer;
-	paStreamData->currentBuffer = NULL;
-	paStreamData->lastBuffer = NULL;
-	while (buffer != NULL) {
-	    struct paBuffer* nextBuffer = buffer->nextBuffer;
-	    free(buffer->sampleData);
-	    free(buffer);
-	    buffer = nextBuffer;
-	}
-	buffer = paStreamData->freeList;
-	paStreamData->freeList = NULL;
-	while (buffer != NULL) {
-	    struct paBuffer* nextBuffer = buffer->nextBuffer;
-	    free(buffer->sampleData);
-	    free(buffer);
-	    buffer = nextBuffer;
-	}
-
-	UNLOCK(paStreamData->lock);
-	RELEASELOCK(paStreamData->lock);
-	free(paStreamData);
-    }
-    RETURN (self);
-#endif // USE_PORTAUDIO
-
-%}.
-    ^ super closeFile
+    self subclassResponsibility
 ! !
 
 !SoundStream methodsFor:'redefined'!
@@ -2169,49 +1411,8 @@
 flush
     "wait until all sound has been played"
 
-    |fd|
-
-    fd := self fileDescriptorOrNil.
-%{
-#ifdef USE_IRIS_AUDIO
-    OPJ port;
-    ALport p;
-
-    if ((port = __INST(alPort)) != nil) {
-	p = __ALportVal(port);
-	while (ALgetfilled(p) > 0) {
-	    sginap(1);
-	}
-    }
-    RETURN(self);
-#endif /* USE_IRIS_AUDIO */
-
-#ifdef USE_DEV_AUDIO
-    if (__isSmallInteger(fd)) {
-	int f = __intVal(fd);
-	/* ... */
-    }
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_PORTAUDIO
-    OBJ str;
-    if ((str = __INST(handle1)) != nil) {
-	struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
-
-	while (paStreamData->currentBuffer != NULL) {
-	    struct timespec a;
-	    a.tv_sec  = 0;
-	    a.tv_nsec = 1 * 1000000; // 1 milliseconds asNanoseconds -> 1000000
-	    nanosleep( &a, NULL );
-	}
-    }
-#endif /* USE_PORTAUDIO */
-
-#ifdef USE_IRIS_AUDIO
-    // don't know how to wait on non-iris systems
-#endif /* USE_IRIS_AUDIO */
-%}.
-    ^ self
+    self subclassResponsibility
+
 !
 
 isOpen
@@ -2230,107 +1431,7 @@
      bytes read or nil on error.
      Use with ByteArrays only."
 
-%{
-#ifdef USE_IRIS_AUDIO
-  {
-    OBJ port;
-    ALport p;
-    int cnt, offs, nSamp;
-    int objSize;
-    char *cp;
-
-    if ((port = __INST(alPort)) != nil) {
-	if (__INST(mode) != _writeonly) {
-	    if (__bothSmallInteger(count, start)) {
-		cnt = __intVal(count);
-		offs = __intVal(start) - 1;
-		p = __ALportVal(port);
-		objSize = _Size(anObject) - OHDR_SIZE;
-		if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
-		    cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
-		    if (__INST(bitsPerSample) == __MKSMALLINT(16))
-			nSamp = cnt / 2;
-		    else
-			nSamp = cnt;
-		    ALreadsamps(p, cp, nSamp);
-		    RETURN ( __MKSMALLINT(cnt) );
-		}
-	    }
-	}
-    }
-  }
-#endif /* USE_IRIS_AUDIO */
-
-#ifdef USE_DEV_AUDIO
-   /*
-    * redefine to work around a bug in the linux sound driver;
-    * if a write is interrupted (EINTR), it is not defined, how many
-    * bytes have been read from the device.
-    *
-    * As a workaround, disable signals here to prevent the write from
-    * being interrupted.
-    */
-    int cnt, offs, objSize, n;
-    char *cp;
-    OBJ fp;
-    FILE *f;
-    int fd;
-
-    if ((fp = __INST(handle)) != nil) {
-	f = __FILEVal(fp);
-	if (__INST(mode) != @symbol(writeonly)) {
-	    if (__bothSmallInteger(count, start)) {
-		cnt = __intVal(count);
-		offs = __intVal(start) - 1;
-
-		objSize = _Size(anObject) - OHDR_SIZE;
-		if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
-		    do {
-			cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
-
-			n = cnt;
-/*                        if (n > 4096) n = 4096; */
-# ifdef LINUX
-			sigsetmask(~0);
-# endif
-			if (__INST(buffered) == true) {
-			    n = fread(cp, 1, n, f);
-			} else {
-			    fd = fileno(f);
-			    n = read(fd, cp, n);
-			}
-# ifdef LINUX
-			sigsetmask(0);
-# endif
-			__BEGIN_INTERRUPTABLE__
-			__END_INTERRUPTABLE__
-/* console_printf("SoundStream: read %d bytes\n", n); */
-			if (n > 0) {
-			    offs += n;
-			    cnt -= n;
-			} else {
-			    if (n < 0) {
-				console_fprintf(stderr, "read error: %d\n", __threadErrno);
-				RETURN (count);
-			    }
-			}
-		    } while (cnt);
-		}
-		RETURN (count);
-	    }
-	}
-    }
-#endif /* USE_DEV_AUDIO */
-
-%}.
-    OperatingSystem getOSType = 'irix' ifFalse:[
-	OperatingSystem getOSType = 'win32' ifFalse:[
-	    ^ super nextPutBytes:count from:anObject startingAt:start
-	].
-    ].
-    handle isNil ifTrue:[^ self errorNotOpen].
-    (mode == #writeonly) ifTrue:[^ self errorWriteOnly].
-    self primitiveFailed
+    self subclassResponsibility
 !
 
 nextPutBytes:count from:anObject startingAt:start
@@ -2339,784 +1440,11 @@
      Redefined, since IRIS audio library cannot be used with stdio.
      (at least I don't know). Use with ByteArrays only."
 
-%{
-#ifdef USE_IRIS_AUDIO
-  {
-    OBJ port;
-    ALport p;
-    int cnt, offs, nSamp;
-    int objSize;
-    char *cp;
-
-    if ((port = __INST(alPort)) != nil) {
-	if (__INST(mode) != @symbol(readonly)) {
-	    if (__bothSmallInteger(count, start)) {
-		cnt = __intVal(count);
-		offs = __intVal(start) - 1;
-		p = __ALportVal(port);
-
-		/*
-		 * compute number of samples
-		 */
-		objSize = _Size(anObject) - OHDR_SIZE;
-		if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
-		    cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
-		    if (__INST(bitsPerSample) == __MKSMALLINT(16))
-			nSamp = cnt / 2;
-		    else
-			nSamp = cnt;
-		    ALwritesamps(p, cp, cnt);
-		    RETURN ( count );
-		}
-	    }
-	}
-    }
-  }
-#endif /* USE_IRIS_AUDIO */
-
-#ifdef USE_WIN32_DIRECTSOUND
-  {
-    HRESULT hr;
-    DWORD status;
-    LPVOID lpbuf1 = NULL;
-    LPVOID lpbuf2 = NULL;
-    DWORD dwsize1 = 0;
-    DWORD dwsize2 = 0;
-    DWORD playPos, safePos, endWrite;
-    DWORD millis;
-    OBJ oDirectSound, oDSBuffer;
-    LPDIRECTSOUND       t_pDirectSound = (LPDIRECTSOUND)0;
-    LPDIRECTSOUNDBUFFER t_pDSBuffer = (LPDIRECTSOUNDBUFFER)0;
-    int t_cbBufOffset, t_cbBufSize;
-    short *buf;
-    int cnt, offs;
-
-    if ((oDSBuffer = __INST(pDSBuffer)) != nil) {
-	t_pDSBuffer = __DSBufferVal(oDSBuffer);
-    }
-    if ((oDirectSound = __INST(pDirectSound)) != nil) {
-	t_pDirectSound = __DirectSoundVal(oDirectSound);
-    }
-
-    if (!t_pDSBuffer || !t_pDirectSound) {
-	console_fprintf(stderr, "SoundStream not open!\n");
-	RETURN (0);
-    }
-    t_cbBufOffset = __intVal(__INST(bufferOffset));
-    t_cbBufSize = __intVal(__INST(bufferSize));
-
-    cnt = __intVal(count);
-    offs = __intVal(start) - 1;
-    buf = (short *)__InstPtr(anObject) + OHDR_SIZE + offs;
-
-    // Should be playing, right?
-    hr = IDirectSoundBuffer_GetStatus(t_pDSBuffer, &status );
-    if (!(status && DSBSTATUS_PLAYING)) {
-	console_fprintf(stderr, "Buffer not playing!\n");
-	RETURN (0);
-    }
-
-    // Sleep until we have enough room in buffer.
-    hr = IDirectSoundBuffer_GetCurrentPosition(t_pDSBuffer, &playPos, &safePos );
-    if( hr != DS_OK ) {
-	console_fprintf(stderr, "Cannot get position!\n");
-	RETURN (0);
-    }
-    if( playPos < t_cbBufOffset ) playPos += t_cbBufSize;
-
-    endWrite = t_cbBufOffset + (cnt * sizeof(short));
-    while ( playPos < endWrite ) {
-	// Calculate number of milliseconds until we will have room, as
-	// time = distance * (milliseconds/second) / ((bytes/sample) * (samples/second)),
-	// rounded up.
-	millis = (DWORD) (1.0 + ((endWrite - playPos) * 1000.0) / ( sizeof(short) * __intVal(__INST(sampleRate))));
-
-	// Sleep for that long
-	Sleep( millis );
-
-	// Wake up, find out where we are now
-	hr = IDirectSoundBuffer_GetCurrentPosition(t_pDSBuffer, &playPos, &safePos );
-	if( hr != DS_OK ) {
-	    console_fprintf(stderr, "Cannot get position!\n");
-	    RETURN (0);
-	}
-	if( playPos < t_cbBufOffset ) playPos += t_cbBufSize; // unwrap offset
-    }
-
-    // Lock free space in the DS
-    hr = IDirectSoundBuffer_Lock(t_pDSBuffer, t_cbBufOffset, cnt * sizeof(short), &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0);
-    if (hr == DS_OK) {
-	// Copy the buffer into the DS
-	CopyMemory(lpbuf1, buf, dwsize1);
-	if(NULL != lpbuf2) CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
-
-	// Update our buffer offset and unlock sound buffer
-	t_cbBufOffset = (t_cbBufOffset + dwsize1 + dwsize2) % t_cbBufSize;
-	IDirectSoundBuffer_Unlock(t_pDSBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
-    }
-    __INST(buffferOffset) = __MKSMALLINT(t_cbBufOffset);
-
-    RETURN (count);
-  }
-#endif /* USE_WIN32_DIRECTSOUND */
-
-#ifdef USE_WIN32_WAVESOUND
-  {
-    struct buf *bp;
-    int len, i, r;
-    int dataLen, offs;
-    short *buf;
-
-    HWAVEOUT t_waveHandle;
-    OBJ oWaveHandle;
-
-    if ((oWaveHandle = __INST(waveHandle)) == nil) {
-	RETURN(0);
-    }
-    t_waveHandle = __WaveHandleVal(oWaveHandle);
-
-    dataLen = __intVal(count);
-    offs = __intVal(start) - 1;
-    buf = (short *)__InstPtr(anObject) + OHDR_SIZE + offs;
-
-    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(t_waveHandle, &bp->hdr, sizeof(WAVEHDR));
-	    if (r != 0) {
-		console_printf("waveOutUnprepareHeader\n");
-		RETURN(self);
-	    }
-	}
-	len = min(dataLen, DATALEN);
-	bp->hdr.lpData = (char *)bp->data;
-	bp->hdr.dwBufferLength = len;
-	bp->hdr.dwBytesRecorded = len;
-	bp->hdr.dwUser = (INT)(bp);
-	bp->hdr.dwFlags = 0;
-	bp->hdr.dwLoops = 0;
-	r = waveOutPrepareHeader(t_waveHandle, &bp->hdr, sizeof(WAVEHDR));
-	if (r != 0) {
-	    console_printf("waveOutPrepareHeader\n");
-	    RETURN(self);
-	}
-	for (i = 0; i < len; i++) {
-	    bp->data[i] = buf[i];
-	}
-	r = waveOutWrite(t_waveHandle, &bp->hdr, sizeof(WAVEHDR));
-	if (r != 0) {
-	    console_printf("waveOutWrite\n");
-	    RETURN(self);
-	}
-	buf += len;
-	dataLen -= len;
-    }
-    RETURN (count);
-  }
-#endif /* USE_WIN32_WAVESOUND */
-
-#ifdef USE_DEV_AUDIO
-   /*
-    * redefine to work around a bug in the linux sound driver;
-    * if a write is interrupted (EINTR), it is not defined, how many
-    * bytes have been written to the device.
-    * I.e. a retry of the write may lead to ever-playing without ever
-    * finishing.
-    *
-    * As a workaround, disable signals here to prevent the write from
-    * being interrupted.
-    */
-    int cnt, offs, objSize, n;
-    char *cp;
-    OBJ fp;
-    FILE *f;
-    int fd;
-
-    if ((fp = __INST(handle)) != nil) {
-	f = __FILEVal(fp);
-	if (__INST(mode) != @symbol(readonly)) {
-	    if (__bothSmallInteger(count, start)) {
-		cnt = __intVal(count);
-		offs = __intVal(start) - 1;
-
-		objSize = _Size(anObject) - OHDR_SIZE;
-		if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
-		    do {
-			cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
-
-			n = cnt;
-# ifdef LINUX
-			sigsetmask(~0);
-# endif
-			if (__INST(buffered) == true) {
-			    n = fwrite(cp, 1, n, f);
-			} else {
-			    fd = fileno(f);
-			    n = write(fd, cp, n);
-			}
-# ifdef LINUX
-			sigsetmask(0);
-# endif
-			__BEGIN_INTERRUPTABLE__
-			__END_INTERRUPTABLE__
-			if (n > 0) {
-			    offs += n;
-			    cnt -= n;
-			} else {
-			    if (n < 0) {
-				console_fprintf(stderr, "write error: %d\n", __threadErrno);
-				RETURN (count);
-			    }
-			}
-		    } while (cnt);
-		}
-		RETURN (count);
-	    }
-	}
-    }
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_PORTAUDIO
-    OBJ str;
-
-    if ((str = __INST(handle1)) != nil) {
-	if (__INST(mode) != @symbol(readonly)) {
-	    if (__bothSmallInteger(count, start)) {
-		// allocate a buffer
-		struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
-		int cnt = __intVal(count);
-		int offs = __intVal(start) - 1;
-		int objSize;
-
-		objSize = _Size(anObject) - OHDR_SIZE;
-		if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
-		    struct paBuffer* newBuffer;
-		    struct paBuffer* toFree;
-		    int mustStart = 0;
-		    unsigned char* newSampleData;
-
-		    // try freeList
-		    LOCK(paStreamData->lock);
-		    if ((paStreamData->freeList != NULL)
-		     && (paStreamData->freeList->bufferSize == cnt)) {
-			// reuse
-			newBuffer = paStreamData->freeList;
-			paStreamData->freeList = newBuffer->nextBuffer;
-			newSampleData = newBuffer->sampleData;
-			toFree = NULL;
-			if (DEBUGGING) {
-			    fprintf(stderr, "from free: %p (->%p)\n", newBuffer, newBuffer->sampleData);
-			}
-		    } else {
-			// free them all
-			toFree = paStreamData->freeList;
-			paStreamData->freeList = NULL;
-			newBuffer = malloc(sizeof(struct paBuffer));
-			newSampleData = malloc(cnt);
-			newBuffer->sampleData = newSampleData;
-			newBuffer->bufferSize = cnt;
-			if (DEBUGGING) {
-			    fprintf(stderr, "alloc: %p (->%p)\n", newBuffer, newBuffer->sampleData);
-			}
-		    }
-
-		    memcpy(newSampleData, (__ByteArrayInstPtr(anObject)->ba_element)+offs, cnt);
-		    newBuffer->nextBuffer = NULL;
-
-		    if (paStreamData->lastBuffer == NULL) {
-			// start stream's buffer list
-			paStreamData->currentBuffer = newBuffer;
-			mustStart = 1;
-		    } else {
-			// append to stream's buffer list
-			paStreamData->lastBuffer->nextBuffer = newBuffer;
-		    }
-		    paStreamData->lastBuffer = newBuffer;
-		    paStreamData->hasFinished = 0;
-		    UNLOCK(paStreamData->lock);
-
-		    if (mustStart) {
-			PaError paErr = Pa_StartStream( paStreamData->stream );
-			if ( paErr != paNoError ) {
-			    if (DEBUGGING) {
-				fprintf(stderr, "start error\n");
-			    }
-			    RETURN (0);
-			};
-		    }
-		    RETURN (count);
-		}
-	    }
-	}
-    }
-#endif /* USE_PORTAUDIO */
-
-%}.
-    ^ super nextPutBytes:count from:anObject startingAt:start
+    self subclassResponsibility
 !
 
 openWithMode:aMode attributes:attributeSpec
-    |ok error errorStringOrNil|
-
-%{
-#ifdef USE_IRIS_AUDIO
-  {
-    ALconfig config;
-    ALport p;
-    long params[] = {
-	AL_INPUT_SOURCE, AL_INPUT_MIC,
-	AL_INPUT_RATE, 8000,
-	AL_OUTPUT_RATE, 8000,
-    };
-
-    config = ALnewconfig();
-    if (__INST(numberOfChannels) == __MKSMALLINT(2))
-	ALsetchannels(config, AL_STEREO);
-    else
-	ALsetchannels(config, AL_MONO);
-    if (__INST(bitsPerSample) == __MKSMALLINT(16))
-	ALsetwidth(config, AL_SAMPLE_16);
-    else
-	ALsetwidth(config, AL_SAMPLE_8);
-
-    if (__isSmallInteger(__INST(sampleRate)))
-	params[3] = params[5] = __intVal(__INST(sampleRate));
-
-    ALsetparams(AL_DEFAULT_DEVICE, params, 6);
-    p = ALopenport("smallchat", (char *)_stringVal(aMode), config);
-    if (p) {
-	OBJ t;
-
-	t = __MKEXTERNALADDRESS(p); __INST(alPort) = t; __STORE(self, t);
-    } else {
-	__INST(alPort) = nil;
-	goto out;
-    }
-    __INST(binary) = true;
-
-    ALfreeconfig(config);
-    /*
-     * get the parameters actually installed
-     */
-    config = ALgetconfig(p);
-    switch (ALgetchannels(config)) {
-	default:
-	    /* cannot happen */
-	case AL_MONO:
-	    __INST(numberOfChannels) = __MKSMALLINT(1);
-	    break;
-	case AL_STEREO:
-	    __INST(numberOfChannels) = __MKSMALLINT(2);
-	    break;
-    }
-    switch (ALgetwidth(config)) {
-	default:
-	    /* cannot happen */
-	case AL_SAMPLE_8:
-	    __INST(bitsPerSample) = __MKSMALLINT(8);
-	    break;
-	case AL_SAMPLE_16:
-	    __INST(bitsPerSample) = __MKSMALLINT(16);
-	    break;
-	case AL_SAMPLE_24:
-	    __INST(bitsPerSample) = __MKSMALLINT(24);
-	    break;
-    }
-    ALgetparams(AL_DEFAULT_DEVICE, params, 6);
-    __INST(sampleRate) = __MKSMALLINT(params[3]);
-
-    ALfreeconfig(config);
-    ok = true;
-    goto out;
-  }
-#endif /* USE_IRIS_AUDIO */
-
-#ifdef USE_WIN32_DIRECTSOUND
-  {
-    HRESULT result;
-    LPDIRECTSOUND       t_pDirectSound;
-    LPDIRECTSOUNDBUFFER t_pDSBuffer, t_pDSPrimeBuffer;
-    WAVEFORMATEX        wfFormat;
-    DSBUFFERDESC        dsbdDesc, primarydsbDesc;
-    BYTE                *pDSBuffData;
-    int                 t_cbBufSize;
-    int                 dwDataLen;
-
-    /* Create the DS object */
-    if ((result = DirectSoundCreate(NULL, &t_pDirectSound, NULL)) != DS_OK) {
-	console_fprintf(stderr,"SoundStream: Cannot open default sound device!!\n");
-	goto out;
-    }
-
-    /* Define the wave format structure */
-    wfFormat.wFormatTag = WAVE_FORMAT_PCM;
-    wfFormat.nChannels = __intVal(__INST(numberOfChannels));
-    wfFormat.nSamplesPerSec = __intVal(__INST(sampleRate));
-    wfFormat.wBitsPerSample = __intVal(__INST(bitsPerSample));
-    wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
-    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
-    wfFormat.cbSize = 0;
-#  if 0
-    /* Setup the primary DS buffer description */
-    ZeroMemory(&primarydsbDesc, sizeof(DSBUFFERDESC));
-    primarydsbDesc.dwSize = sizeof(DSBUFFERDESC);
-    primarydsbDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
-    primarydsbDesc.dwBufferBytes = 0;
-    primarydsbDesc.lpwfxFormat = NULL;
-
-    /* Create the primary DS buffer */
-    if ((result = IDirectSound_CreateSoundBuffer(t_pDirectSound, &primarydsbDesc,
-						 &t_pDSPrimeBuffer, NULL)) != DS_OK) {
-	console_fprintf(stderr,"SoundStream: Cannot get the primary DS buffer address!\n");
-	IDirectSound_Release(t_pDirectSound);
-	goto out;
-    }
-
-    /* Set the primary DS buffer sound format.  We have to do this because
-       the default primary buffer is 8-bit, 22kHz! */
-    if ((result = IDirectSoundBuffer_SetFormat(t_pDSPrimeBuffer, &wfFormat)) != DS_OK) {
-	console_fprintf(stderr,"SoundStream: Cannot set the primary DS buffer to proper sound format (%x) (%d)!\n", result, result);
-	IDirectSoundBuffer_Stop(t_pDSPrimeBuffer);
-	IDirectSoundBuffer_Release(t_pDSPrimeBuffer);
-	IDirectSound_Release(t_pDirectSound);
-	goto out;
-    }
-#  endif /* 0 */
-
-    /* Setup the secondary DS buffer description */
-    t_cbBufSize = RT_BUFFER_SIZE * sizeof(short) * NBUFS;
-    __INST(bufferSize) = __MKSMALLINT(t_cbBufSize);
-
-    ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
-    dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
-    dsbdDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
-    dsbdDesc.dwBufferBytes = t_cbBufSize;
-    dsbdDesc.lpwfxFormat = &wfFormat;
-
-    /* Create the secondary DS buffer */
-    if ((result = IDirectSound_CreateSoundBuffer(t_pDirectSound, &dsbdDesc, &t_pDSBuffer, NULL)) != DS_OK) {
-	console_fprintf(stderr,"SoundStream: couldn't create sound buffer!\n");
-	IDirectSoundBuffer_Stop(t_pDSPrimeBuffer);
-	IDirectSoundBuffer_Release(t_pDSPrimeBuffer);
-	IDirectSound_Release(t_pDirectSound);
-	goto out;
-    }
-
-    /* Lock the DS buffer */
-    if ((result = IDirectSoundBuffer_Lock(t_pDSBuffer, 0, t_cbBufSize, (LPLPVOID)&pDSBuffData,
-					  &dwDataLen, NULL, NULL, 0)) != DS_OK) {
-	console_fprintf(stderr,"SoundStream: couldn't lock sound buffer!\n");
-	goto errorAndOut;
-    }
-
-    /* Zero the DS buffer */
-    ZeroMemory(pDSBuffData, dwDataLen);
-
-    /* Unlock the DS buffer */
-    if ((result = IDirectSoundBuffer_Unlock(t_pDSBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) {
-	console_fprintf(stderr,"SoundStream: couldn't unlock sound buffer!\n");
-	goto errorAndOut;
-    }
-
-    __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)) {
-	console_fprintf(stderr,"SoundStream: couldn't play sound buffer!\n");
-errorAndOut:
-	IDirectSoundBuffer_Stop(t_pDSBuffer);
-	IDirectSoundBuffer_Stop(t_pDSPrimeBuffer);
-	IDirectSoundBuffer_Release(t_pDSPrimeBuffer);
-	IDirectSound_Release(t_pDirectSound);
-	ok = false;
-	goto out;
-    }
-
-    {
-	OBJ t;
-
-	t = __MKEXTERNALADDRESS(t_pDSBuffer); __INST(pDSBuffer) = t; __STORE(self, t);
-	t = __MKEXTERNALADDRESS(t_pDirectSound); __INST(pDirectSound) = t; __STORE(self, t);
-    }
-    ok = true;
-    goto out;
-  }
-#endif /* USE_WIN32_DIRECTSOUND */
-
-#ifdef USE_WIN32_WAVESOUND
-  {
-    PCMWAVEFORMAT waveFormat;
-    int r;
-    HWAVEOUT t_waveHandle;
-    OBJ oWaveHandle;
-
-    if ((oWaveHandle = __INST(waveHandle)) != nil) {
-	ok = false;
-	goto out;
-    }
-
-    waveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
-    waveFormat.wf.nChannels = __intVal(__INST(numberOfChannels));
-    waveFormat.wf.nSamplesPerSec = __intVal(__INST(sampleRate));
-    waveFormat.wBitsPerSample = __intVal(__INST(bitsPerSample));
-    waveFormat.wf.nBlockAlign = waveFormat.wf.nChannels * waveFormat.wBitsPerSample / 8;
-    waveFormat.wf.nAvgBytesPerSec = waveFormat.wf.nSamplesPerSec * waveFormat.wf.nBlockAlign;
-
-    r = waveOutOpen(&t_waveHandle,
-		    WAVE_MAPPER,
-		    (WAVEFORMAT *)&waveFormat,
-		    (DWORD_PTR)waveCallBack,
-		    (DWORD_PTR)0,
-		    CALLBACK_FUNCTION);
-    if (r != 0) {
-	console_printf("waveOutOpen\n");
-	ok = false;
-	goto out;
-    }
-
-    (void)waveOutReset(t_waveHandle);
-
-    free_list = NULL;
-    InitializeCriticalSection(&free_list_lock);
-    free_buffers = 0;
-    free_buffer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
-    total_buffers = 0;
-
-    {
-	OBJ t;
-
-	t = __MKEXTERNALADDRESS(t_waveHandle); __INST(waveHandle) = t; __STORE(self, t);
-    }
-
-# if 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);
-    }
-# endif /* 0 */
-    ok = true;
-    goto out;
-  }
-#endif /* !USE_WIN32_DIRECTSOUND */
-
-#ifdef USE_DEV_AUDIO
-  {
-      int __fd;
-      int __mode;
-      FILE *f;
-
-      if (strcmp(__stringVal(aMode), "w") == 0) {
-	  __mode = O_WRONLY;
-      } else if (strcmp(__stringVal(aMode), "r") == 0) {
-	  __mode = O_RDONLY;
-      } else {
-	  __mode = O_RDWR;
-      }
-      do {
-	  __BEGIN_INTERRUPTABLE__
-	  __fd = open((char *) __stringVal(__INST(pathName)), __mode /* |O_NDELAY */);
-	  __END_INTERRUPTABLE__
-      } while ((__fd < 0) && (errno == EINTR));
-
-      if (__fd >= 0) {
-	  /*
-	   * make it a FILE *
-	   */
-	  f = fdopen(__fd, __stringVal(aMode));
-	  if (! f) {
-	      error = __mkSmallInteger(errno);
-	      __BEGIN_INTERRUPTABLE__
-	      close(__fd);
-	      __END_INTERRUPTABLE__
-	      ok = false;
-	      goto out;
-	  }
-	  setbuf(f, NULL);
-	  __INST(buffered) = false;
-	  __INST(handle) = __MKEXTERNALADDRESS(f);
-	  __STORESELF(handle);
-
-#if defined(PCM_ENABLE_OUTPUT) && defined(PCM_ENABLE_INPUT)
-# if defined(SNDCTL_DSP_SETTRIGGER)
-	  if (__mode == O_RDWR) {
-	      int enable_bits = ~(PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT);
-
-	      if (ioctl(__fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1)
-	      {
-		  console_fprintf(stderr, "can't request synchronous start of fullduplex operation");
-	      }
-	  }
-# endif
-#endif
-	  ok = true;
-	  goto out;
-      } else {
-	  error = __mkSmallInteger(errno);
-      }
-  }
-#endif /* USE_DEV_AUDIO */
-
-#ifdef USE_PORTAUDIO
-  {
-    static PaStreamParameters outputParameters;
-    PaStream *stream;
-    PaError paErr;
-    struct paStreamData* paStreamData;
-    int nChannels, sampleRate, bytesPerSample;
-#   define FRAMES_PER_BUFFER 128
-
-    /* default output device */
-    outputParameters.device = Pa_GetDefaultOutputDevice();
-    if (outputParameters.device == paNoDevice) {
-	fprintf(stderr, "SoundStream [warning]: No default output device.\n");
-	ok = false;
-	errorStringOrNil = __MKSTRING("No default output device");
-	goto out;
-    }
-
-    if (__isSmallInteger(__INST(numberOfChannels))) {
-	nChannels = __intVal(__INST(numberOfChannels));
-    } else {
-	nChannels = 1;
-    }
-    outputParameters.channelCount = nChannels;
-    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
-    outputParameters.hostApiSpecificStreamInfo = NULL;
-
-    // The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8
-    // and aUInt8 are usually implemented by all implementations.
-    // The floating point representation (paFloat32) uses +1.0 and -1.0 as the
-    // maximum and minimum respectively.
-    // paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
-
-    if (__INST(audioFormat) == @symbol(S16)) {
-	outputParameters.sampleFormat = paInt16;
-	bytesPerSample = 2;
-    } else if (__INST(audioFormat) == @symbol(S32)) {
-	outputParameters.sampleFormat = paInt32;
-	bytesPerSample = 4;
-    } else if (__INST(audioFormat) == @symbol(S24)) {
-	outputParameters.sampleFormat = paInt24;
-	bytesPerSample = 3;
-    } else if (__INST(audioFormat) == @symbol(S8)) {
-	outputParameters.sampleFormat = paInt8;
-	bytesPerSample = 1;
-    } else if (__INST(audioFormat) == @symbol(F32)) {
-	outputParameters.sampleFormat = paFloat32;
-	bytesPerSample = 4;
-    } else if (__INST(audioFormat) == @symbol(U8)) {
-	outputParameters.sampleFormat = paUInt8;
-	bytesPerSample = 1;
-    } else {
-	fprintf(stderr, "SoundStream [warning]: unknown format - using U8\n");
-	outputParameters.sampleFormat = paUInt8;
-	bytesPerSample = 1;
-    }
-
-    if (__isSmallInteger(__INST(sampleRate))) {
-	sampleRate = __intVal(__INST(sampleRate));
-    } else {
-	fprintf(stderr, "SoundStream [warning]: using default sampleRate 8000\n");
-	sampleRate = 8000;
-    }
-
-    paStreamData = (struct paStreamData*)malloc(sizeof(struct paStreamData));
-    if (paStreamData == NULL) {
-	fprintf(stderr, "SoundStream [warning]: failed to allocate paStream\n");
-	ok = false;
-	errorStringOrNil = __MKSTRING("failed to allocate paStream");
-	goto out;
-    }
-
-    paErr = Pa_OpenStream(
-	      &stream,
-	      NULL, /* no input */
-	      &outputParameters,
-	      sampleRate,
-	      FRAMES_PER_BUFFER,
-	      paClipOff,      /* we won't output out of range samples so don't bother clipping them */
-	      paCallback,
-	      paStreamData );
-
-    if (paErr != paNoError) {
-	fprintf(stderr, "SoundStream [warning]: openStream: %s\n", Pa_GetErrorText( paErr ));
-	free(paStreamData);
-	ok = false;
-	errorStringOrNil = __MKSTRING(Pa_GetErrorText( paErr ));
-	goto out;
-    }
-    paStreamData->stream = stream;
-    INITLOCK(paStreamData->lock);
-    paStreamData->readOffset = 0;
-    paStreamData->bytesPerSample = bytesPerSample;
-    paStreamData->nChannels = nChannels;
-
-    paStreamData->currentBuffer = NULL;
-    paStreamData->lastBuffer = NULL;
-    paStreamData->freeList = NULL;
-    paStreamData->hasFinished = 0;
-
-    {
-	OBJ t;
-	t = __MKEXTERNALADDRESS(paStreamData); __INST(handle1) = t; __STORE(self, t);
-    }
-    __INST(binary) = true;
-
-    paErr = Pa_SetStreamFinishedCallback( stream, &paStreamFinished );
-    if( paErr != paNoError ) {
-	fprintf(stderr, "SoundStream [warning]: setFinishedCallback: %s\n", Pa_GetErrorText( paErr ));
-	free(paStreamData);
-	ok = false;
-	errorStringOrNil = __MKSTRING(Pa_GetErrorText( paErr ));
-	goto out;
-    };
-
-    ok = true;
-    goto out;
-  }
-#endif /* USE_PORTAUDIO */
-
-out:;
-%}.
-    ok == false ifTrue:[
-	lastErrorString := errorStringOrNil.
-	lastErrorNumber := error ? -1.
-	self openError:error.
-	"normally not reached"
-	^ nil.
-    ].
-
-    ok isNil ifTrue:[
-	"its a regular file open (i.e. /dev/audio) "
-	^ super openWithMode:aMode attributes:attributeSpec.
-    ].
-
-    self registerForFinalization.
-    ^ self.
+    self subclassResponsibility
 ! !
 
 !SoundStream methodsFor:'sine wave generation'!
@@ -3377,14 +1705,52 @@
 !
 
 tuneTone:freq
+    self tuneTone:freq seconds:3
+
+    "
+     SoundStream writing tuneTone:880; close
+     SoundStream writing setSampleRate:4000; tuneTone:440; close
+     SoundStream writing setSampleRate:4000; tuneTone:880; close
+     SoundStream writing setSampleRate:8000; tuneTone:440; close
+     SoundStream writing setSampleRate:8000; tuneTone:880; close
+     SoundStream writing setSampleRate:10000; tuneTone:440; close
+     SoundStream writing setSampleRate:10000; tuneTone:880; close
+
+     SoundStream writing setSampleRate:20000; tuneTone:440; close
+     SoundStream writing setSampleRate:20000; tuneTone:880; close
+
+     SoundStream writing setSampleRate:40000; tuneTone:440; close
+     SoundStream writing setSampleRate:40000; tuneTone:880; close
+     SoundStream writing setSampleRate:40000; tuneTone:1760; close
+     SoundStream writing setSampleRate:40000; tuneTone:3520; close
+     SoundStream writing setSampleRate:40000; tuneTone:7020; close
+     SoundStream writing setSampleRate:40000; tuneTone:14040; close
+
+     SoundStream writing setSampleRate:44100; tuneTone:440; close
+     SoundStream writing setSampleRate:44100; tuneTone:880; close
+     SoundStream writing setSampleRate:44100; tuneTone:1760; close
+     SoundStream writing setSampleRate:44100; tuneTone:3520; close
+     SoundStream writing setSampleRate:44100; tuneTone:7020; close
+     SoundStream writing setSampleRate:44100; tuneTone:14040; close
+
+     SoundStream writing setSampleRate:20000; dumpSettings; close
+    "
+
+    "Modified: / 31.1.1999 / 12:07:14 / cg"
+!
+
+tuneTone:freq seconds:nSeconds 
     ((audioFormat startsWith:#S16)
     or:[audioFormat startsWith:#U16]) ifTrue:[
-	^ self tuneTone16:freq
+        ^ self tuneTone16:freq seconds:nSeconds
+    ].
+    audioFormat == #F32 ifTrue:[
+        ^ self tuneToneF32:freq seconds:nSeconds
     ].
     audioFormat == #MU_LAW ifTrue:[
-	^ self tuneToneMU:freq
+        ^ self tuneToneMU:freq seconds:nSeconds 
     ].
-    self tuneTone8:freq
+    self tuneTone8:freq seconds:nSeconds
 
     "
      SoundStream writing tuneTone:880; close
@@ -3475,10 +1841,10 @@
     "Created: / 31.1.1999 / 12:05:17 / cg"
 !
 
-tuneToneMU:freq
-    "output some tone for 3 seconds in MU_LAW audioFormat - a test method"
-
-    |buffer numSamples val scale oldFormat|
+tuneToneMU:freq seconds:nSeconds
+    "output some tone for nSeconds in MU_LAW audioFormat - a test method"
+
+    |buffer numSamples val scale restSamples|
 
     "allocate memory for 1sec playing time"
     numSamples := self sampleRate.
@@ -3488,17 +1854,18 @@
 
     scale := freq * 2 * (Float pi).
     1 to:numSamples do:[:i |
-	val := (scale * i / numSamples) sin.
-	val := (val * 16r7FFF) rounded.
-	buffer at:i put:(self class linear16ToUlaw:val)
+        val := (scale * i / numSamples) sin.
+        val := (val * 16r7FFF) rounded.
+        buffer at:i put:(self class linear16ToUlaw:val)
     ].
 
-    oldFormat := audioFormat.
-    self setAudioFormat:#MU_LAW.
-    1 to:3 do:[:s |
-	self nextPutBytes:numSamples from:buffer startingAt:1
+    1 to:nSeconds truncated do:[:s |
+        self nextPutBytes:numSamples from:buffer startingAt:1
     ].
-    self setAudioFormat:oldFormat.
+    restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
+    restSamples > 0 ifTrue:[
+        self nextPutBytes:restSamples from:buffer startingAt:1
+    ].
 
     "of course, the frequency should be below half the
      sampleRate - hear below ...
@@ -3512,6 +1879,2508 @@
     "Modified: / 15.12.1997 / 13:46:19 / cg"
 ! !
 
+!SoundStream::DevAudio class methodsFor:'default values'!
+
+defaultSampleRate
+    "minimum, supported by all audio systems"
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    RETURN (__MKSMALLINT(DEV_AUDIO_DEFAULT_FREQ));
+#endif
+%}.
+
+    ^ 8000
+! !
+
+!SoundStream::DevAudio class methodsFor:'documentation'!
+
+documentation
+"
+    documentation to be added.
+
+    class:
+        <a short class summary here, describing what instances represent>
+
+    responsibilities:    
+        <describing what my main role is>
+
+    collaborators:    
+        <describing with whom and how I talk to>
+
+    API:
+        <public api and main messages>
+        
+    example:
+        <a one-line examples on how to use - can also be in a separate example method>
+
+    implementation:
+        <implementation points>
+
+    [author:]
+        exept MBP
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!SoundStream::DevAudio class methodsFor:'queries'!
+
+isSupported
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    RETURN(true);
+#endif
+%}.
+    ^ false.
+! !
+
+!SoundStream::DevAudio methodsFor:'misc'!
+
+dumpSettings
+    "debugging interface - dump the current settings"
+
+    |fd blockSize speed channels stereo format|
+
+    fd := self fileDescriptorOrNil.
+
+    audioFormat == #S16 ifTrue:[
+        UninterpretedBytes isBigEndian ifTrue:[
+            audioFormat := #S16_BE
+        ] ifFalse:[
+            audioFormat := #S16_LE
+        ]
+    ].
+    audioFormat == #U16 ifTrue:[
+        UninterpretedBytes isBigEndian ifTrue:[
+            audioFormat := #U16_BE
+        ] ifFalse:[
+            audioFormat := #U16_LE
+        ]
+    ].
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    if (fd != nil) {
+        int f = __intVal(fd);
+        int __blockSize = -1;
+        int __speed = -1;
+        int __channels = __intVal(__INST(numberOfChannels));
+        int __stereo = __channels > 1;
+        int __format = -1;
+
+        channels = nil;
+        blockSize = nil;
+        stereo = nil;
+        speed = nil;
+
+# if defined(SNDCTL_DSP_GETBLKSIZE)
+        if (ioctl(f, SNDCTL_DSP_GETBLKSIZE, &__blockSize) >= 0) {
+            blockSize = __MKSMALLINT(__blockSize);
+        }
+# endif
+
+# if defined(SNDCTL_DSP_CHANNELS)
+        if (ioctl(f, SNDCTL_DSP_CHANNELS, &__channels) >= 0) {
+            channels = __MKSMALLINT(__channels);
+            stereo = __MKSMALLINT(__channels > 1);
+        }
+# else
+#  if defined(SNDCTL_DSP_STEREO)
+        if (ioctl(f, SNDCTL_DSP_STEREO, &__stereo) >= 0) {
+            stereo = __MKSMALLINT(__stereo);
+        }
+#  endif
+# endif
+
+# if defined(SNDCTL_DSP_SPEED)
+        if (ioctl(f, SNDCTL_DSP_SPEED, &__speed) >= 0) {
+            speed = __MKSMALLINT(__speed);
+        }
+# endif
+
+# if defined(SNDCTL_DSP_GETFMT)
+        if (ioctl(f, SNDCTL_DSP_GETFMT, &__format) >= 0) {
+            format = __MKSMALLINT(__format);
+        }
+# else
+#  if defined(SNDCTL_DSP_SETFMT) && defined(AFMT_QUERY)
+        __format = AFMT_QUERY;
+        if (ioctl(f, SNDCTL_DSP_SETFMT, &__format) >= 0) {
+            switch (__format) {
+#   ifdef AFMT_MU_LAW
+                case AFMT_MU_LAW:
+                    format = @symbol(MU_LAW);
+                    break;
+#   endif
+#   ifdef AFMT_A_LAW
+                case AFMT_A_LAW:
+                    format = @symbol(A_LAW);
+                    break;
+#   endif
+#   ifdef AFMT_U8
+                case AFMT_U8:
+                    format = @symbol(U8);
+                    break;
+#   endif
+#   ifdef AFMT_S8
+                case AFMT_S8:
+                    format = @symbol(S8);
+                    break;
+#   endif
+#   ifdef AFMT_S16_LE
+                case AFMT_S16_LE:
+                    format = @symbol(S16_LE);
+                    break;
+#   endif
+#   ifdef AFMT_S16_BE
+                case AFMT_S16_BE:
+                    format = @symbol(S16_BE);
+                    break;
+#   endif
+#   ifdef AFMT_U16_LE
+                case AFMT_U16_LE:
+                    format = @symbol(U16_LE);
+                    break;
+#   endif
+#   ifdef AFMT_U16_BE
+                case AFMT_U16_BE:
+                    format = @symbol(U16_BE);
+                    break;
+#   endif
+#   ifdef AFMT_MPEG
+                case AFMT_MPEG:
+                    format = @symbol(MPEG);
+                    break;
+#   endif
+                default:
+                    format = nil;
+            }
+        }
+    }
+#  endif
+# endif
+#endif /* SUPPORT_DEV_AUDIO */
+
+%}.
+    format notNil ifTrue:[
+        Transcript show:'format: '; showCR:format
+    ].
+    blockSize notNil ifTrue:[
+        Transcript show:'blockSize: '; showCR:blockSize
+    ].
+    speed notNil ifTrue:[
+        Transcript show:'speed: '; showCR:speed
+    ].
+    channels notNil ifTrue:[
+        Transcript show:'channels: '; showCR:channels
+    ].
+    stereo notNil ifTrue:[
+        Transcript show:'stereo: '; showCR:stereo
+    ].
+
+    Transcript show:'supported audioFormats: '; showCR:(self supportedAudioFormats).
+
+    "
+     self writing dumpSettings; close
+    "
+!
+
+flush
+    "wait until all sound has been played"
+
+    self fileDescriptorOrNil isNil ifTrue:[^ self].
+    super flush.
+! !
+
+!SoundStream::DevAudio methodsFor:'open & close'!
+
+closeFile
+    "a stream has been collected - close the file"
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    OBJ fp;
+    int fd;
+    FILE *f;
+
+    if ((fp = __INST(handle)) != nil) {
+        f = __FILEVal(fp);
+        __INST(handle) = nil;
+# ifdef LINUX
+        sigsetmask(~0);
+# endif
+        if (__INST(buffered) == true) {
+            fflush(f);
+            fclose(f);
+        } else {
+            fd = fileno(f);
+            close(fd);
+            fclose(f);
+        }
+# ifdef LINUX
+        sigsetmask(0);
+# endif
+    }
+    RETURN (self);
+#endif /* SUPPORT_DEV_AUDIO */
+%}.
+!
+
+openWithMode:aMode attributes:attributeSpec
+    |ok error errorStringOrNil|
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+      int __fd;
+      int __mode;
+      FILE *f;
+
+      ok = false;
+      if (strcmp(__stringVal(aMode), "w") == 0) {
+          __mode = O_WRONLY;
+      } else if (strcmp(__stringVal(aMode), "r") == 0) {
+          __mode = O_RDONLY;
+      } else {
+          __mode = O_RDWR;
+      }
+      do {
+          __BEGIN_INTERRUPTABLE__
+          __fd = open((char *) __stringVal(__INST(pathName)), __mode /* |O_NDELAY */);
+          __END_INTERRUPTABLE__
+      } while ((__fd < 0) && (errno == EINTR));
+
+      if (__fd >= 0) {
+          /*
+           * make it a FILE *
+           */
+          f = fdopen(__fd, __stringVal(aMode));
+          if (! f) {
+              error = __mkSmallInteger(errno);
+              __BEGIN_INTERRUPTABLE__
+              close(__fd);
+              __END_INTERRUPTABLE__
+              goto out;
+          }
+          setbuf(f, NULL);
+          __INST(buffered) = false;
+          __INST(handle) = __MKEXTERNALADDRESS(f);
+          __STORESELF(handle);
+
+#if defined(PCM_ENABLE_OUTPUT) && defined(PCM_ENABLE_INPUT)
+# if defined(SNDCTL_DSP_SETTRIGGER)
+          if (__mode == O_RDWR) {
+              int enable_bits = ~(PCM_ENABLE_OUTPUT|PCM_ENABLE_INPUT);
+
+              if (ioctl(__fd, SNDCTL_DSP_SETTRIGGER, &enable_bits) == -1)
+              {
+                  console_fprintf(stderr, "can't request synchronous start of fullduplex operation");
+              }
+          }
+# endif
+#endif
+          ok = true;
+      } else {
+          error = __mkSmallInteger(errno);
+      }
+out:;
+#endif /* SUPPORT_DEV_AUDIO */
+%}.
+    ok == false ifTrue:[
+        lastErrorString := errorStringOrNil.
+        lastErrorNumber := error ? -1.
+        self openError:error.
+        "normally not reached"
+        ^ nil.
+    ].
+    self registerForFinalization.
+! !
+
+!SoundStream::DevAudio methodsFor:'private'!
+
+initialize
+    "initialize for least common mode"
+
+    super initialize.
+
+    OperatingSystem isUNIXlike ifTrue:[
+        '/dev/audio' asFilename exists ifTrue:[
+            "/
+            "/ sunos or linux
+            "/
+            pathName := '/dev/audio'.
+        ].
+    ].
+!
+
+resetSoundCard
+    "debugging interface - reset the soundCard"
+
+    |fd|
+
+    fd := self fileDescriptorOrNil.
+    fd isNil ifTrue:[
+        self errorNotOpen.
+        ^ nil
+    ].
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    int f = __intVal(fd);
+
+    if (__isSmallInteger(fd)) {
+        int __dummy;
+# if defined(SNDCTL_DSP_RESET)
+        if (ioctl(f, SNDCTL_DSP_RESET, &__dummy) >= 0) {
+            RETURN (self);
+        }
+# endif
+    }
+#endif /* SUPPORT_DEV_AUDIO */
+%}.
+    ^ UnsupportedOperationSignal raise
+
+    "
+     self writing resetSoundCard; dumpSettings; close
+    "
+!
+
+setAudioFormat:aSymbol
+    "set the format of the audio data as specified by aSymbol.
+     Returns true if sucessful - may fail with some formats on many sound devices."
+
+    |fd ok|
+
+    audioFormat == aSymbol ifTrue:[^ self].
+    super setAudioFormat:aSymbol.
+
+    fd := self fileDescriptor.
+    fd isNil ifTrue:[
+        ^ self
+    ].
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    OBJ sym = aSymbol;
+
+    if (__isSmallInteger(fd)) {
+        int f = __intVal(fd);
+        int __fmt = 0, __fmtWant;
+        union {
+            unsigned short us;
+            unsigned char ub[2];
+        } u;
+
+        if (__isSymbol(sym)) {
+            if (sym == @symbol(U16)) {
+                u.us = 0x1234;
+                if (u.ub[0] == 0x34) {
+                    /* printf("U16_LE\n"); */
+                    sym = @symbol(U16_LE);
+                } else {
+                    /* printf("U16_BE\n"); */
+                    sym = @symbol(U16_BE);
+                }
+            } else if (sym == @symbol(S16)) {
+                u.us = 0x1234;
+                if (u.ub[0] == 0x34) {
+                    /* printf("S16_LE\n"); */
+                   sym = @symbol(S16_LE);
+                } else {
+                    /* printf("S16_BE\n"); */
+                   sym = @symbol(S16_BE);
+                }
+            }
+
+            if (0) {
+# ifdef AFMT_MU_LAW
+            } else if (sym == @symbol(MU_LAW)) {
+                __fmt = AFMT_MU_LAW;
+# endif
+# ifdef AFMT_A_LAW
+            } else if (sym == @symbol(A_LAW)) {
+                __fmt = AFMT_A_LAW;
+# endif
+# ifdef AFMT_IMA_ADPCM
+            } else if (sym == @symbol(IMA_ADPCM)) {
+                __fmt = AFMT_IMA_ADPCM;
+# endif
+# ifdef AFMT_U8
+            } else if (sym == @symbol(U8)) {
+                __fmt = AFMT_U8;
+# endif
+# ifdef AFMT_S8
+            } else if (sym == @symbol(S8)) {
+                __fmt = AFMT_S8;
+# endif
+# ifdef AFMT_U16_LE
+            } else if (sym == @symbol(U16_LE)) {
+                __fmt = AFMT_U16_LE;
+# endif
+# ifdef AFMT_U16_BE
+            } else if (sym == @symbol(U16_BE)) {
+                __fmt = AFMT_U16_BE;
+# endif
+# ifdef AFMT_S16_LE
+            } else if (sym == @symbol(S16_LE)) {
+                __fmt = AFMT_S16_LE;
+# endif
+# ifdef AFMT_S16_BE
+            } else if (sym == @symbol(S16_BE)) {
+                __fmt = AFMT_S16_BE;
+# endif
+# ifdef AFMT_MPEG
+            } else if (sym == @symbol(MPEG)) {
+                __fmt = AFMT_MPEG;
+# endif
+
+# ifdef AUDIO_FORMAT_LINEAR16BIT
+            } else if (sym == @symbol(S16)) {
+                __fmt = AUDIO_FORMAT_LINEAR16BIT;
+# endif
+# ifdef AUDIO_FORMAT_ULAW
+            } else if (sym == @symbol(MU_LAW)) {
+                __fmt = AUDIO_FORMAT_ULAW;
+# endif
+# ifdef AUDIO_FORMAT_ALAW
+            } else if (sym == @symbol(A_LAW)) {
+                __fmt = AUDIO_FORMAT_ALAW;
+# endif
+            } else {
+                console_fprintf(stderr, "bad format: %s\n", __stringVal(sym));
+                ok = false;
+                goto bad;
+            }
+        }
+
+# ifdef SNDCTL_DSP_SETFMT
+        __fmtWant = __fmt;
+
+        if (ioctl(f, SNDCTL_DSP_SETFMT, &__fmt) >= 0) {
+            if (__fmt == __fmtWant) {
+                __INST(audioFormat) = sym;
+            } else {
+                /* console_fprintf(stderr, "want: %x; got: %x\n", __fmtWant, __fmt); */
+            }
+        } else {
+            /* console_fprintf(stderr, "got err-ret from setFmp %x\n", __fmt); */
+            ok = false;
+        }
+# else
+#  ifdef AUDIO_SET_DATA_FORMAT /* hpux */
+        if (ioctl (f, AUDIO_SET_DATA_FORMAT, __fmt)) {
+            /* console_fprintf(stderr, "got err-ret from AUDIO_SET_DATA_FORMAT\n"); */
+        }
+#  endif
+# endif /* SNDCTL_DSP_SETFMT */
+
+bad: ;
+    }
+#endif /* SUPPORT_DEV_AUDIO */
+%}.
+
+    "
+     self writing dumpSettings; close
+     self writing setAudioFormat:#'MU_LAW'; close
+     self writing setAudioFormat:#'U8'; dumpSettings; close
+     self writing setAudioFormat:#'MPEG'; dumpSettings; close
+    "
+!
+
+setChannels:nChannels
+    "set the number of channels (1 -> mono; 2 -> stereo).
+     Returns true if sucessful - may fail with many sound devices."
+
+    |fd|
+
+    numberOfChannels := nChannels.
+
+    fd := self fileDescriptorOrNil.
+    fd isNil ifTrue:[
+        ^ self
+    ].
+%{
+
+#ifdef SUPPORT_DEV_AUDIO
+    if (__isSmallInteger(fd) && __isSmallInteger(nChannels)) {
+        int f = __intVal(fd);
+        int __nCh = __intVal(nChannels);
+
+# ifdef SNDCTL_DSP_STEREO
+        if ((__nCh == 1) || (__nCh == 2)) {
+            int __stereo = (__nCh == 2) ? 1 : 0;
+
+            if (ioctl(f, SNDCTL_DSP_STEREO, &__stereo) >= 0) {
+                if (__stereo == 0) {
+                    __INST(numberOfChannels) = __MKSMALLINT(1);
+                } else {
+                    __INST(numberOfChannels) = __MKSMALLINT(2);
+                }
+                RETURN (self);
+            }
+        }
+# else
+#  ifdef SOUND_PCM_WRITE_CHANNELS
+        if (ioctl(f, SOUND_PCM_WRITE_CHANNELS, &__nCh) >= 0) {
+            RETURN (self);
+        }
+#  else
+#   ifdef AUDIO_SET_CHANNELS /* hpux */
+        if (ioctl (f, AUDIO_SET_CHANNELS, __nCh)) {
+            /* console_fprintf(stderr, "got err-ret from AUDIO_SET_CHANNELS\n"); */
+            RETURN (self);
+        }
+#   endif
+#  endif
+# endif
+    }
+#endif /* SUPPORT_DEV_AUDIO */
+%}.
+
+    "
+     self writing setChannels:2; dumpSettings; close
+     self writing setChannels:2; setSampleRate:10000; dumpSettings; close
+     self writing setChannels:2; setSampleRate:40000; dumpSettings; close
+    "
+!
+
+setFragmentSize:blockSize
+    "set the soundDriver's fragmentSize"
+
+    |fd|
+
+    fragmentSize := blockSize.
+
+    fd := self fileDescriptorOrNil.
+    fd isNil ifTrue:[
+        ^ self
+    ].
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    int f = __intVal(fd);
+    int __blockSize = __intVal(blockSize);
+
+    if (__isSmallInteger(fd) && __isSmallInteger(blockSize)) {
+        __blockSize = __intVal(blockSize);
+# if defined(SNDCTL_DSP_SETFRAGMENT)
+        if (ioctl(f, SNDCTL_DSP_SETFRAGMENT, &__blockSize) >= 0) {
+            RETURN (self);
+        }
+# endif
+# ifdef AUDIO_SET_CHANNELS /* hpux */
+        if (ioctl (f, AUDIO_SET_TXBUFSIZE, __blockSize)) {
+            /* console_fprintf(stderr, "got err-ret from AUDIO_SET_TXBUFSIZE\n"); */
+            RETURN (self);
+        }
+# endif
+    }
+#endif // SUPPORT_DEV_AUDIO
+%}.
+!
+
+setSampleRate:hz
+    "set the sample rate"
+
+    |fd|
+
+    sampleRate := hz.
+
+    fd := self fileDescriptorOrNil.
+    fd isNil ifTrue:[
+        ^ self
+    ].
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    int f = __intVal(fd);
+    int __rate = __intVal(hz);
+
+    if (__isSmallInteger(fd) && __isSmallInteger(hz)) {
+        int __rateWant = __rate;
+
+# if defined(SNDCTL_DSP_SPEED)
+        if (ioctl(f, SNDCTL_DSP_SPEED, &__rate) >= 0) {
+            if (__rate != __rateWant) {
+                console_fprintf(stderr, "SoundStream [warning]: actual rate is %d\n", __rate);
+                hz = __MKSMALLINT(__rate);
+            }
+            __INST(sampleRate) = hz;
+            RETURN (self);
+        }
+# else
+#  if defined(SOUND_PCM_WRITE_RATE)
+        if (ioctl(f, SOUND_PCM_WRITE_RATE, &__rate) >= 0) {
+            if (__rate != __rateWant) {
+                console_fprintf(stderr, "SoundStream [warning]: actual rate is %d\n", __rate);
+                hz = __MKSMALLINT(__rate);
+            }
+            __INST(sampleRate) = hz;
+            RETURN (self);
+        }
+#  else
+#   ifdef AUDIO_SET_SAMPLE_RATE /* hpux */
+        if (ioctl (f, AUDIO_SET_SAMPLE_RATE, __rate)) {
+            /* console_fprintf(stderr, "got err-ret from AUDIO_SET_SAMPLE_RATE\n"); */
+            __INST(sampleRate) = hz;
+            RETURN (self);
+        }
+#   endif
+#  endif
+# endif
+    }
+#endif // SUPPORT_DEV_AUDIO
+%}.
+
+    "
+     self writing setSampleRate:10000; dumpSettings; close
+     self writing setSampleRate:1000; dumpSettings; close
+     self writing setSampleRate:8000; dumpSettings; close
+    "
+! !
+
+!SoundStream::DevAudio methodsFor:'queries'!
+
+supportedAudioFormats
+    "return a collection of supported audio formats.
+     possibly returned symbols are:
+        U8        unsigned 8bit samples
+        S8        signed 8bit samples
+        U16       unsigned 16bit samples in native format
+        U16_LE    unsigned 16bit big endian samples
+        U16_BE    unsigned 16bit big endian samples
+        S16       signed 16bit little endian samples in native format
+        S16_LE    signed 16bit little endian samples
+        S16_BE    signed 16bit big endian samples
+        S24       signed 24bit little endian samples in native format
+        S24_LE    signed 24bit little endian samples
+        S24_BE    signed 24bit big endian samples
+        S32       signed 32bit little endian samples in native format
+        S32_LE    signed 32bit little endian samples
+        S32_BE    signed 32bit big endian samples
+        F32       float samples
+        MPEG      audio mpeg encoded
+        MU_LAW    u-law encoded 8bit samples
+        A_LAW     a-law encoded 8bit samples
+        IMA_ADPCM adpcm encoded
+     the set of returned symbols depends on the underlying sound hardware.
+    "
+
+    |fd audioFormatMask
+     supportedFormats
+     supports_MU_LAW supports_A_LAW supports_MPEG
+     supports_IMA_ADPCM
+     supports_S8 supports_U8
+     supports_S16_LE supports_S16_BE
+     supports_U16_LE supports_U16_BE
+     supports_U32_LE supports_U32_BE
+     supports_S24_LE supports_S24_BE
+     supports_S32_LE supports_S32_BE
+     supports_F32
+    |
+
+    fd := self fileDescriptorOrNil.
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+    supports_MU_LAW = true;
+
+    if (fd != nil) {
+        int f = __intVal(fd);
+        int __audioFormatMask = 0;
+
+# if defined(SNDCTL_DSP_GETFMTS)
+        if (ioctl(f, SNDCTL_DSP_GETFMTS, &__audioFormatMask) >= 0) {
+            audioFormatMask = __MKSMALLINT(__audioFormatMask);
+
+#  ifdef AFMT_MU_LAW
+            supports_MU_LAW = (__audioFormatMask & AFMT_MU_LAW) ? true : false;
+#  endif
+#  ifdef AFMT_A_LAW
+            supports_A_LAW = (__audioFormatMask & AFMT_A_LAW) ? true : false;
+#  endif
+#  ifdef AFMT_IMA_ADPCM
+            supports_IMA_ADPCM = (__audioFormatMask & AFMT_IMA_ADPCM) ? true : false;
+#  endif
+#  ifdef AFMT_U8
+            supports_U8 = (__audioFormatMask & AFMT_U8) ? true : false;
+#  endif
+#  ifdef AFMT_S16_LE
+            supports_S16_LE = (__audioFormatMask & AFMT_S16_LE) ? true : false;
+#  endif
+#  ifdef AFMT_S16_BE
+            supports_S16_BE = (__audioFormatMask & AFMT_S16_BE) ? true : false;
+#  endif
+#  ifdef AFMT_S8
+            supports_S8 = (__audioFormatMask & AFMT_S8) ? true : false;
+#  endif
+#  ifdef AFMT_U16_LE
+            supports_U16_LE = (__audioFormatMask & AFMT_U16_LE) ? true : false;
+#  endif
+#  ifdef AFMT_U16_BE
+            supports_U16_BE = (__audioFormatMask & AFMT_U16_BE) ? true : false;
+#  endif
+#  ifdef AFMT_MPEG
+            supports_MPEG = (__audioFormatMask & AFMT_MPEG) ? true : false;
+#  endif
+        }
+    }
+# endif // SNDCTL_DSP_GETFMTS
+
+# ifdef hpux
+    supports_A_LAW = true;
+    supports_S16_BE = true;
+# endif
+#endif /* SUPPORT_DEV_AUDIO */
+%}.
+    supportedFormats := IdentitySet new.
+    (supports_MU_LAW ? false) ifTrue:[
+        supportedFormats add:#'MU_LAW'
+    ].
+    (supports_A_LAW ? false)  ifTrue:[
+        supportedFormats add:#'A_LAW'
+    ].
+    (supports_IMA_ADPCM ? false)  ifTrue:[
+        supportedFormats add:#'IMA_ADPCM'
+    ].
+    (supports_MPEG ? false)  ifTrue:[
+        supportedFormats add:#'MPEG'
+    ].
+    (supports_S8 ? false)  ifTrue:[
+        supportedFormats add:#'S8'
+    ].
+    (supports_U8 ? false)  ifTrue:[
+        supportedFormats add:#'U8'
+    ].
+    (supports_S16_LE ? false)  ifTrue:[
+        supportedFormats add:#'S16_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'S16'.
+        ]
+    ].
+    (supports_S16_BE ? false)  ifTrue:[
+        supportedFormats add:#'S16_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'S16'.
+        ]
+    ].
+    (supports_S24_LE ? false)  ifTrue:[
+        supportedFormats add:#'S24_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'S24'.
+        ]
+    ].
+    (supports_S24_BE ? false)  ifTrue:[
+        supportedFormats add:#'S24_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'S24'.
+        ]
+    ].
+    (supports_S32_LE ? false)  ifTrue:[
+        supportedFormats add:#'S32_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'S32'.
+        ]
+    ].
+    (supports_S32_BE ? false)  ifTrue:[
+        supportedFormats add:#'S32_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'S32'.
+        ]
+    ].
+    (supports_U16_LE ? false)  ifTrue:[
+        supportedFormats add:#'U16_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'U16'.
+        ]
+    ].
+    (supports_U16_BE ? false)  ifTrue:[
+        supportedFormats add:#'U16_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'U16'.
+        ]
+    ].
+    (supports_F32 ? false)  ifTrue:[
+        supportedFormats add:#'F32'
+    ].
+    ^ supportedFormats.
+
+    "
+     |s formats|
+
+     s := self writing.
+     formats := s supportedAudioFormats.
+     s close.
+     formats
+    "
+! !
+
+!SoundStream::DevAudio methodsFor:'reading'!
+
+nextBytes:count into:anObject startingAt:start
+    "read the next count bytes into an object and return the number of
+     bytes read or nil on error.
+     Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+   /*
+    * redefined to work around a bug in the linux sound driver;
+    * if a read is interrupted (EINTR), it is not defined, how many
+    * bytes have been read from the device.
+    *
+    * As a workaround, disable signals here to prevent being interrupted.
+    */
+    int cnt, offs, objSize, n;
+    char *cp;
+    OBJ fp;
+    FILE *f;
+    int fd;
+
+    if ((fp = __INST(handle)) != nil) {
+        f = __FILEVal(fp);
+        if (__INST(mode) != @symbol(writeonly)) {
+            if (__bothSmallInteger(count, start)) {
+                cnt = __intVal(count);
+                offs = __intVal(start) - 1;
+
+                objSize = _Size(anObject) - OHDR_SIZE;
+                if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
+                    do {
+                        cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
+
+                        n = cnt;
+# ifdef LINUX
+                        sigsetmask(~0);
+# endif
+                        if (__INST(buffered) == true) {
+                            n = fread(cp, 1, n, f);
+                        } else {
+                            fd = fileno(f);
+                            n = read(fd, cp, n);
+                        }
+# ifdef LINUX
+                        sigsetmask(0);
+# endif
+                        __BEGIN_INTERRUPTABLE__
+                        __END_INTERRUPTABLE__
+                        // console_fprintf(stderr, "SoundStream: read %d bytes\n", n);
+                        if (n > 0) {
+                            offs += n;
+                            cnt -= n;
+                        } else {
+                            if (n < 0) {
+                                console_fprintf(stderr, "read error: %d\n", __threadErrno);
+                                RETURN (count);
+                            }
+                        }
+                    } while (cnt);
+                }
+                RETURN (count);
+            }
+        }
+    }
+#endif /* SUPPORT_DEV_AUDIO */
+
+%}.
+    self errorUnsupportedOperation
+! !
+
+!SoundStream::DevAudio methodsFor:'writing'!
+
+nextPutBytes:count from:anObject startingAt:start
+    "write count bytes from an object starting at index start.
+     return the number of bytes written or nil on error.
+     Redefined, since IRIS audio library cannot be used with stdio.
+     (at least I don't know). Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_DEV_AUDIO
+   /*
+    * redefine to work around a bug in the linux sound driver;
+    * if a write is interrupted (EINTR), it is not defined, how many
+    * bytes have been written to the device.
+    * I.e. a retry of the write may lead to ever-playing without ever
+    * finishing.
+    *
+    * As a workaround, disable signals here to prevent the write from
+    * being interrupted.
+    */
+    int cnt, offs, objSize, n;
+    char *cp;
+    OBJ fp;
+    FILE *f;
+    int fd;
+
+    if ((fp = __INST(handle)) != nil) {
+        f = __FILEVal(fp);
+        if (__INST(mode) != @symbol(readonly)) {
+            if (__bothSmallInteger(count, start)) {
+                cnt = __intVal(count);
+                offs = __intVal(start) - 1;
+
+                objSize = _Size(anObject) - OHDR_SIZE;
+                if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
+                    do {
+                        cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
+
+                        n = cnt;
+# ifdef LINUX
+                        sigsetmask(~0);
+# endif
+                        if (__INST(buffered) == true) {
+                            n = fwrite(cp, 1, n, f);
+                        } else {
+                            fd = fileno(f);
+                            n = write(fd, cp, n);
+                        }
+# ifdef LINUX
+                        sigsetmask(0);
+# endif
+                        __BEGIN_INTERRUPTABLE__
+                        __END_INTERRUPTABLE__
+                        if (n > 0) {
+                            offs += n;
+                            cnt -= n;
+                        } else {
+                            if (n < 0) {
+                                console_fprintf(stderr, "write error: %d\n", __threadErrno);
+                                RETURN (count);
+                            }
+                        }
+                    } while (cnt);
+                }
+                RETURN (count);
+            }
+        }
+    }
+#endif /* SUPPORT_DEV_AUDIO */
+
+%}.
+    ^ self errorUnsupportedOperation
+! !
+
+!SoundStream::IRISAudio class methodsFor:'documentation'!
+
+documentation
+"
+    documentation to be added.
+
+    class:
+        <a short class summary here, describing what instances represent>
+
+    responsibilities:    
+        <describing what my main role is>
+
+    collaborators:    
+        <describing with whom and how I talk to>
+
+    API:
+        <public api and main messages>
+        
+    example:
+        <a one-line examples on how to use - can also be in a separate example method>
+
+    implementation:
+        <implementation points>
+
+    [author:]
+        exept MBP
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!SoundStream::IRISAudio class methodsFor:'queries'!
+
+isSupported
+%{
+#ifdef SUPPORT_IRIS_AUDIO
+    RETURN(true);
+#endif
+%}.
+    ^ false.
+! !
+
+!SoundStream::IRISAudio methodsFor:'misc'!
+
+flush
+    "wait until all sound has been played"
+
+%{
+#ifdef SUPPORT_IRIS_AUDIO
+    OPJ port;
+    ALport p;
+
+    if ((port = __INST(alPort)) != nil) {
+        p = __ALportVal(port);
+        while (ALgetfilled(p) > 0) {
+            sginap(1);
+        }
+    }
+    RETURN(self);
+#endif /* SUPPORT_IRIS_AUDIO */
+%}.
+
+! !
+
+!SoundStream::IRISAudio methodsFor:'open & close'!
+
+closeFile
+    "a stream has been collected - close the file"
+
+%{
+#ifdef SUPPORT_IRIS_AUDIO
+    OBJ port;
+
+    if ((port = __INST(alPort)) != nil) {
+        __INST(alPort) = nil;
+        ALcloseport(__ALportVal(port));
+    }
+    RETURN (self);
+#endif /* SUPPORT_IRIS_AUDIO */
+%}.
+
+!
+
+openWithMode:aMode attributes:attributeSpec
+    |ok error errorStringOrNil|
+
+%{
+#ifdef SUPPORT_IRIS_AUDIO
+    ALconfig config;
+    ALport p;
+    long params[] = {
+        AL_INPUT_SOURCE, AL_INPUT_MIC,
+        AL_INPUT_RATE, 8000,
+        AL_OUTPUT_RATE, 8000,
+    };
+
+    ok = false.
+    config = ALnewconfig();
+    if (__INST(numberOfChannels) == __MKSMALLINT(2))
+        ALsetchannels(config, AL_STEREO);
+    else
+        ALsetchannels(config, AL_MONO);
+    if (__INST(bitsPerSample) == __MKSMALLINT(16))
+        ALsetwidth(config, AL_SAMPLE_16);
+    else
+        ALsetwidth(config, AL_SAMPLE_8);
+
+    if (__isSmallInteger(__INST(sampleRate)))
+        params[3] = params[5] = __intVal(__INST(sampleRate));
+
+    ALsetparams(AL_DEFAULT_DEVICE, params, 6);
+    p = ALopenport("smallchat", (char *)_stringVal(aMode), config);
+    if (p) {
+        OBJ t;
+
+        t = __MKEXTERNALADDRESS(p); __INST(alPort) = t; __STORE(self, t);
+    } else {
+        __INST(alPort) = nil;
+        goto out;
+    }
+    __INST(binary) = true;
+
+    ALfreeconfig(config);
+    /*
+     * get the parameters actually installed
+     */
+    config = ALgetconfig(p);
+    switch (ALgetchannels(config)) {
+        default:
+            /* cannot happen */
+        case AL_MONO:
+            __INST(numberOfChannels) = __MKSMALLINT(1);
+            break;
+        case AL_STEREO:
+            __INST(numberOfChannels) = __MKSMALLINT(2);
+            break;
+    }
+    switch (ALgetwidth(config)) {
+        default:
+            /* cannot happen */
+        case AL_SAMPLE_8:
+            __INST(bitsPerSample) = __MKSMALLINT(8);
+            break;
+        case AL_SAMPLE_16:
+            __INST(bitsPerSample) = __MKSMALLINT(16);
+            break;
+        case AL_SAMPLE_24:
+            __INST(bitsPerSample) = __MKSMALLINT(24);
+            break;
+    }
+    ALgetparams(AL_DEFAULT_DEVICE, params, 6);
+    __INST(sampleRate) = __MKSMALLINT(params[3]);
+
+    ALfreeconfig(config);
+    ok = true;
+out:;
+#endif /* SUPPORT_IRIS_AUDIO */
+
+%}.
+    ok == false ifTrue:[
+        lastErrorString := errorStringOrNil.
+        lastErrorNumber := error ? -1.
+        self openError:error.
+        "normally not reached"
+        ^ nil.
+    ].
+    self registerForFinalization.
+! !
+
+!SoundStream::IRISAudio methodsFor:'queries'!
+
+supportedAudioFormats
+    "return a collection of supported audio formats.
+     possibly returned symbols are:
+        U8        unsigned 8bit samples
+        S8        signed 8bit samples
+        U16       unsigned 16bit samples in native format
+        U16_LE    unsigned 16bit big endian samples
+        U16_BE    unsigned 16bit big endian samples
+        S16       signed 16bit little endian samples in native format
+        S16_LE    signed 16bit little endian samples
+        S16_BE    signed 16bit big endian samples
+        S24       signed 24bit little endian samples in native format
+        S24_LE    signed 24bit little endian samples
+        S24_BE    signed 24bit big endian samples
+        S32       signed 32bit little endian samples in native format
+        S32_LE    signed 32bit little endian samples
+        S32_BE    signed 32bit big endian samples
+        F32       float samples
+        MPEG      audio mpeg encoded
+        MU_LAW    u-law encoded 8bit samples
+        A_LAW     a-law encoded 8bit samples
+        IMA_ADPCM adpcm encoded
+     the set of returned symbols depends on the underlying sound hardware.
+    "
+
+    ^ #( U8 U16_BE U16 )
+
+    "
+     |s formats|
+
+     s := self writing.
+     formats := s supportedAudioFormats.
+     s close.
+     formats
+    "
+! !
+
+!SoundStream::IRISAudio methodsFor:'reading'!
+
+nextBytes:count into:anObject startingAt:start
+    "read the next count bytes into an object and return the number of
+     bytes read or nil on error.
+     Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_IRIS_AUDIO
+  {
+    OBJ port;
+    ALport p;
+    int cnt, offs, nSamp;
+    int objSize;
+    char *cp;
+
+    if ((port = __INST(alPort)) != nil) {
+        if (__INST(mode) != _writeonly) {
+            if (__bothSmallInteger(count, start)) {
+                cnt = __intVal(count);
+                offs = __intVal(start) - 1;
+                p = __ALportVal(port);
+                objSize = _Size(anObject) - OHDR_SIZE;
+                if ((offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs))) {
+                    cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
+                    if (__INST(bitsPerSample) == __MKSMALLINT(16))
+                        nSamp = cnt / 2;
+                    else
+                        nSamp = cnt;
+                    ALreadsamps(p, cp, nSamp);
+                    RETURN ( __MKSMALLINT(cnt) );
+                }
+            }
+        }
+    }
+  }
+#endif /* SUPPORT_IRIS_AUDIO */
+
+%}.
+    self errorUnsupportedOperation
+! !
+
+!SoundStream::IRISAudio methodsFor:'writing'!
+
+nextPutBytes:count from:anObject startingAt:start
+    "write count bytes from an object starting at index start.
+     return the number of bytes written or nil on error.
+     Redefined, since IRIS audio library cannot be used with stdio.
+     (at least I don't know). Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_IRIS_AUDIO
+  {
+    OBJ port;
+    ALport p;
+    int cnt, offs, nSamp;
+    int objSize;
+    char *cp;
+
+    if ((port = __INST(alPort)) != nil) {
+        if (__INST(mode) != @symbol(readonly)) {
+            if (__bothSmallInteger(count, start)) {
+                cnt = __intVal(count);
+                offs = __intVal(start) - 1;
+                p = __ALportVal(port);
+
+                /*
+                 * compute number of samples
+                 */
+                objSize = _Size(anObject) - OHDR_SIZE;
+                if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
+                    cp = (char *)__InstPtr(anObject) + OHDR_SIZE + offs;
+                    if (__INST(bitsPerSample) == __MKSMALLINT(16))
+                        nSamp = cnt / 2;
+                    else
+                        nSamp = cnt;
+                    ALwritesamps(p, cp, cnt);
+                    RETURN ( count );
+                }
+            }
+        }
+    }
+  }
+#endif /* SUPPORT_IRIS_AUDIO */
+%}.
+    self errorUnsupportedOperation 
+! !
+
+!SoundStream::PortAudio class methodsFor:'default values'!
+
+defaultSampleRate
+    "minimum, supported by all audio systems"
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    RETURN (__MKSMALLINT(PORTAUDIO_DEFAULT_FREQ));
+#endif
+%}.
+
+    ^ 8000
+! !
+
+!SoundStream::PortAudio class methodsFor:'documentation'!
+
+documentation
+"
+    documentation to be added.
+
+    class:
+        <a short class summary here, describing what instances represent>
+
+    responsibilities:    
+        <describing what my main role is>
+
+    collaborators:    
+        <describing with whom and how I talk to>
+
+    API:
+        <public api and main messages>
+        
+    example:
+        <a one-line examples on how to use - can also be in a separate example method>
+
+    implementation:
+        <implementation points>
+
+    [author:]
+        exept MBP
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!SoundStream::PortAudio class methodsFor:'initialization'!
+
+primitiveInitializeDevice
+    |errorMessageOrNil|
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    PaError paErr = 0;
+
+    if (DEBUGGING) {
+        fprintf(stderr, "calling Pa_Initialize...\n");
+    }
+    if ((paErr = Pa_Initialize()) != paNoError ) {
+        errorMessageOrNil = __MKSTRING(Pa_GetErrorText( paErr ) );
+        fprintf(stderr, "SoundStream [error]: Pa_Initialize failed\n");
+    };
+#endif
+%}.
+    errorMessageOrNil notNil ifTrue:[
+        self error:'failed to initialize audio device: ',errorMessageOrNil
+    ].
+
+! !
+
+!SoundStream::PortAudio class methodsFor:'queries'!
+
+isSupported
+%{
+#ifdef SUPPORT_PORTAUDIO
+    RETURN(true);
+#endif
+%}.
+    ^ false.
+! !
+
+!SoundStream::PortAudio methodsFor:'misc'!
+
+flush
+    "wait until all sound has been played"
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    OBJ str;
+    if ((str = __INST(handle1)) != nil) {
+        struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
+
+        while (paStreamData->currentBuffer != NULL) {
+            struct timespec a;
+            a.tv_sec  = 0;
+            a.tv_nsec = 1 * 1000000; // 1 milliseconds asNanoseconds -> 1000000
+            nanosleep( &a, NULL );
+        }
+    }
+#endif /* SUPPORT_PORTAUDIO */
+%}.
+
+! !
+
+!SoundStream::PortAudio methodsFor:'open & close'!
+
+closeFile
+    "a stream has been collected - close the file"
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    OBJ str;
+    if ((str = __INST(handle1)) != nil) {
+        struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
+        struct paBuffer* buffer;
+
+        if (DEBUGGING) {
+            fprintf(stderr, "pa close\n");
+        }
+        __externalAddressVal(str) = NULL;
+        __INST(handle1) = nil;
+        // Pa_StopStream( paStreamData->stream );
+        Pa_CloseStream( paStreamData->stream );
+
+        LOCK(paStreamData->lock);
+
+        buffer = paStreamData->currentBuffer;
+        paStreamData->currentBuffer = NULL;
+        paStreamData->lastBuffer = NULL;
+        while (buffer != NULL) {
+            struct paBuffer* nextBuffer = buffer->nextBuffer;
+            free(buffer->sampleData);
+            free(buffer);
+            buffer = nextBuffer;
+        }
+        buffer = paStreamData->freeList;
+        paStreamData->freeList = NULL;
+        while (buffer != NULL) {
+            struct paBuffer* nextBuffer = buffer->nextBuffer;
+            free(buffer->sampleData);
+            free(buffer);
+            buffer = nextBuffer;
+        }
+
+        UNLOCK(paStreamData->lock);
+        RELEASELOCK(paStreamData->lock);
+        free(paStreamData);
+    }
+    RETURN (self);
+#endif // SUPPORT_PORTAUDIO
+%}.
+!
+
+openWithMode:aMode attributes:attributeSpec
+    |ok error errorStringOrNil|
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    static PaStreamParameters outputParameters;
+    PaStream *stream;
+    PaError paErr;
+    struct paStreamData* paStreamData;
+    int nChannels, sampleRate, bytesPerSample;
+#   define FRAMES_PER_BUFFER 128
+
+    ok = false;
+
+    /* default output device */
+    outputParameters.device = Pa_GetDefaultOutputDevice();
+    if (outputParameters.device == paNoDevice) {
+        fprintf(stderr, "SoundStream [warning]: No default output device.\n");
+        errorStringOrNil = __MKSTRING("No default output device");
+        goto out;
+    }
+
+    if (__isSmallInteger(__INST(numberOfChannels))) {
+        nChannels = __intVal(__INST(numberOfChannels));
+    } else {
+        nChannels = 1;
+    }
+    outputParameters.channelCount = nChannels;
+    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+    outputParameters.hostApiSpecificStreamInfo = NULL;
+
+    // The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8
+    // and aUInt8 are usually implemented by all implementations.
+    // The floating point representation (paFloat32) uses +1.0 and -1.0 as the
+    // maximum and minimum respectively.
+    // paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+
+    if (__INST(audioFormat) == @symbol(S16)) {
+        outputParameters.sampleFormat = paInt16;
+        bytesPerSample = 2;
+    } else if (__INST(audioFormat) == @symbol(S32)) {
+        outputParameters.sampleFormat = paInt32;
+        bytesPerSample = 4;
+    } else if (__INST(audioFormat) == @symbol(S24)) {
+        outputParameters.sampleFormat = paInt24;
+        bytesPerSample = 3;
+    } else if (__INST(audioFormat) == @symbol(S8)) {
+        outputParameters.sampleFormat = paInt8;
+        bytesPerSample = 1;
+    } else if (__INST(audioFormat) == @symbol(F32)) {
+        outputParameters.sampleFormat = paFloat32;
+        bytesPerSample = 4;
+    } else if (__INST(audioFormat) == @symbol(U8)) {
+        outputParameters.sampleFormat = paUInt8;
+        bytesPerSample = 1;
+    } else {
+        fprintf(stderr, "SoundStream [warning]: unknown format - using U8\n");
+        outputParameters.sampleFormat = paUInt8;
+        bytesPerSample = 1;
+    }
+
+    if (__isSmallInteger(__INST(sampleRate))) {
+        sampleRate = __intVal(__INST(sampleRate));
+    } else {
+        fprintf(stderr, "SoundStream [warning]: using default sampleRate 8000\n");
+        sampleRate = 8000;
+    }
+
+    paStreamData = (struct paStreamData*)malloc(sizeof(struct paStreamData));
+    if (paStreamData == NULL) {
+        fprintf(stderr, "SoundStream [warning]: failed to allocate paStream\n");
+        errorStringOrNil = __MKSTRING("failed to allocate paStream");
+        goto out;
+    }
+
+    paErr = Pa_OpenStream(
+              &stream,
+              NULL, /* no input */
+              &outputParameters,
+              sampleRate,
+              FRAMES_PER_BUFFER,
+              paClipOff,      /* we won't output out of range samples so don't bother clipping them */
+              paCallback,
+              paStreamData );
+
+    if (paErr != paNoError) {
+        fprintf(stderr, "SoundStream [warning]: openStream: %s\n", Pa_GetErrorText( paErr ));
+        free(paStreamData);
+        errorStringOrNil = __MKSTRING(Pa_GetErrorText( paErr ));
+        goto out;
+    }
+    paStreamData->stream = stream;
+    INITLOCK(paStreamData->lock);
+    paStreamData->readOffset = 0;
+    paStreamData->bytesPerSample = bytesPerSample;
+    paStreamData->nChannels = nChannels;
+
+    paStreamData->currentBuffer = NULL;
+    paStreamData->lastBuffer = NULL;
+    paStreamData->freeList = NULL;
+    paStreamData->hasFinished = 0;
+
+    {
+        OBJ t;
+        t = __MKEXTERNALADDRESS(paStreamData); __INST(handle1) = t; __STORE(self, t);
+    }
+    __INST(binary) = true;
+
+    paErr = Pa_SetStreamFinishedCallback( stream, &paStreamFinished );
+    if( paErr != paNoError ) {
+        fprintf(stderr, "SoundStream [warning]: setFinishedCallback: %s\n", Pa_GetErrorText( paErr ));
+        free(paStreamData);
+        errorStringOrNil = __MKSTRING(Pa_GetErrorText( paErr ));
+        goto out;
+    };
+
+    ok = true;
+out:;
+#endif /* SUPPORT_PORTAUDIO */
+
+%}.
+    ok == false ifTrue:[
+        lastErrorString := errorStringOrNil.
+        lastErrorNumber := error ? -1.
+        self openError:error.
+        "normally not reached"
+        ^ nil.
+    ].
+    self registerForFinalization.
+
+! !
+
+!SoundStream::PortAudio methodsFor:'private'!
+
+initialize
+    "initialize for least common mode"
+
+    super initialize.
+
+    (IsInitialized ? false) ifFalse:[
+        self class primitiveInitializeDevice
+    ].
+
+    "Created: 17.11.1995 / 17:28:14 / cg"
+! !
+
+!SoundStream::PortAudio methodsFor:'queries'!
+
+supportedAudioFormats
+    "return a collection of supported audio formats.
+     possibly returned symbols are:
+        U8        unsigned 8bit samples
+        S8        signed 8bit samples
+        U16       unsigned 16bit samples in native format
+        U16_LE    unsigned 16bit big endian samples
+        U16_BE    unsigned 16bit big endian samples
+        S16       signed 16bit little endian samples in native format
+        S16_LE    signed 16bit little endian samples
+        S16_BE    signed 16bit big endian samples
+        S24       signed 24bit little endian samples in native format
+        S24_LE    signed 24bit little endian samples
+        S24_BE    signed 24bit big endian samples
+        S32       signed 32bit little endian samples in native format
+        S32_LE    signed 32bit little endian samples
+        S32_BE    signed 32bit big endian samples
+        F32       float samples
+        MPEG      audio mpeg encoded
+        MU_LAW    u-law encoded 8bit samples
+        A_LAW     a-law encoded 8bit samples
+        IMA_ADPCM adpcm encoded
+     the set of returned symbols depends on the underlying sound hardware.
+    "
+
+    |fd audioFormatMask
+     supportedFormats
+     supports_MU_LAW supports_A_LAW supports_MPEG
+     supports_IMA_ADPCM
+     supports_S8 supports_U8
+     supports_S16_LE supports_S16_BE
+     supports_U16_LE supports_U16_BE
+     supports_U32_LE supports_U32_BE
+     supports_S24_LE supports_S24_BE
+     supports_S32_LE supports_S32_BE
+     supports_F32
+    |
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    supports_U8 = true;
+    supports_S8 = true;
+    supports_S16_LE = true;
+    supports_S24_LE = true;
+    supports_S32_LE = true;
+    supports_F32 = true;
+#endif
+%}.
+    supportedFormats := IdentitySet new.
+    (supports_MU_LAW ? false) ifTrue:[
+        supportedFormats add:#'MU_LAW'
+    ].
+    (supports_A_LAW ? false)  ifTrue:[
+        supportedFormats add:#'A_LAW'
+    ].
+    (supports_IMA_ADPCM ? false)  ifTrue:[
+        supportedFormats add:#'IMA_ADPCM'
+    ].
+    (supports_MPEG ? false)  ifTrue:[
+        supportedFormats add:#'MPEG'
+    ].
+    (supports_S8 ? false)  ifTrue:[
+        supportedFormats add:#'S8'
+    ].
+    (supports_U8 ? false)  ifTrue:[
+        supportedFormats add:#'U8'
+    ].
+    (supports_S16_LE ? false)  ifTrue:[
+        supportedFormats add:#'S16_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'S16'.
+        ]
+    ].
+    (supports_S16_BE ? false)  ifTrue:[
+        supportedFormats add:#'S16_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'S16'.
+        ]
+    ].
+    (supports_S24_LE ? false)  ifTrue:[
+        supportedFormats add:#'S24_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'S24'.
+        ]
+    ].
+    (supports_S24_BE ? false)  ifTrue:[
+        supportedFormats add:#'S24_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'S24'.
+        ]
+    ].
+    (supports_S32_LE ? false)  ifTrue:[
+        supportedFormats add:#'S32_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'S32'.
+        ]
+    ].
+    (supports_S32_BE ? false)  ifTrue:[
+        supportedFormats add:#'S32_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'S32'.
+        ]
+    ].
+    (supports_U16_LE ? false)  ifTrue:[
+        supportedFormats add:#'U16_LE'.
+        UninterpretedBytes isBigEndian ifFalse:[
+            supportedFormats add:#'U16'.
+        ]
+    ].
+    (supports_U16_BE ? false)  ifTrue:[
+        supportedFormats add:#'U16_BE'.
+        UninterpretedBytes isBigEndian ifTrue:[
+            supportedFormats add:#'U16'.
+        ]
+    ].
+    (supports_F32 ? false)  ifTrue:[
+        supportedFormats add:#'F32'
+    ].
+    ^ supportedFormats.
+
+    "
+     |s formats|
+
+     s := self writing.
+     formats := s supportedAudioFormats.
+     s close.
+     formats
+    "
+! !
+
+!SoundStream::PortAudio methodsFor:'reading'!
+
+nextBytes:count into:anObject startingAt:start
+    "read the next count bytes into an object and return the number of
+     bytes read or nil on error.
+     Use with ByteArrays only."
+
+    self errorUnsupportedOperation
+! !
+
+!SoundStream::PortAudio methodsFor:'writing'!
+
+nextPutBytes:count from:anObject startingAt:start
+    "write count bytes from an object starting at index start.
+     return the number of bytes written or nil on error.
+     Redefined, since IRIS audio library cannot be used with stdio.
+     (at least I don't know). Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_PORTAUDIO
+    OBJ str;
+
+    if ((str = __INST(handle1)) != nil) {
+        if (__INST(mode) != @symbol(readonly)) {
+            if (__bothSmallInteger(count, start)) {
+                // allocate a buffer
+                struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
+                int cnt = __intVal(count);
+                int offs = __intVal(start) - 1;
+                int objSize;
+
+                objSize = _Size(anObject) - OHDR_SIZE;
+                if ( (offs >= 0) && (cnt >= 0) && (objSize >= (cnt + offs)) ) {
+                    struct paBuffer* newBuffer;
+                    struct paBuffer* toFree;
+                    int mustStart = 0;
+                    unsigned char* newSampleData;
+
+                    // try freeList
+                    LOCK(paStreamData->lock);
+                    if ((paStreamData->freeList != NULL)
+                     && (paStreamData->freeList->bufferSize == cnt)) {
+                        // reuse
+                        newBuffer = paStreamData->freeList;
+                        paStreamData->freeList = newBuffer->nextBuffer;
+                        newSampleData = newBuffer->sampleData;
+                        toFree = NULL;
+                        if (DEBUGGING) {
+                            fprintf(stderr, "from free: %p (->%p)\n", newBuffer, newBuffer->sampleData);
+                        }
+                    } else {
+                        // free them all
+                        toFree = paStreamData->freeList;
+                        paStreamData->freeList = NULL;
+                        newBuffer = malloc(sizeof(struct paBuffer));
+                        newSampleData = malloc(cnt);
+                        newBuffer->sampleData = newSampleData;
+                        newBuffer->bufferSize = cnt;
+                        if (DEBUGGING) {
+                            fprintf(stderr, "alloc: %p (->%p)\n", newBuffer, newBuffer->sampleData);
+                        }
+                    }
+
+                    memcpy(newSampleData, (__ByteArrayInstPtr(anObject)->ba_element)+offs, cnt);
+                    newBuffer->nextBuffer = NULL;
+
+                    if (paStreamData->lastBuffer == NULL) {
+                        // start stream's buffer list
+                        paStreamData->currentBuffer = newBuffer;
+                        mustStart = 1;
+                    } else {
+                        // append to stream's buffer list
+                        paStreamData->lastBuffer->nextBuffer = newBuffer;
+                    }
+                    paStreamData->lastBuffer = newBuffer;
+                    paStreamData->hasFinished = 0;
+                    UNLOCK(paStreamData->lock);
+
+                    if (mustStart) {
+                        PaError paErr = Pa_StartStream( paStreamData->stream );
+                        if ( paErr != paNoError ) {
+                            if (DEBUGGING) {
+                                fprintf(stderr, "start error\n");
+                            }
+                            RETURN (0);
+                        };
+                    }
+                    RETURN (count);
+                }
+            }
+        }
+    }
+#endif /* SUPPORT_PORTAUDIO */
+
+%}.
+    self errorUnsupportedOperation 
+! !
+
+!SoundStream::Win32DirectSound class methodsFor:'documentation'!
+
+documentation
+"
+    documentation to be added.
+
+    class:
+        <a short class summary here, describing what instances represent>
+
+    responsibilities:    
+        <describing what my main role is>
+
+    collaborators:    
+        <describing with whom and how I talk to>
+
+    API:
+        <public api and main messages>
+        
+    example:
+        <a one-line examples on how to use - can also be in a separate example method>
+
+    implementation:
+        <implementation points>
+
+    [author:]
+        exept MBP
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!SoundStream::Win32DirectSound class methodsFor:'queries'!
+
+isSupported
+%{
+#ifdef SUPPORT_WIN32_DIRECTSOUND
+    RETURN(true);
+#endif
+%}.
+    ^ false.
+! !
+
+!SoundStream::Win32DirectSound methodsFor:'misc'!
+
+flush
+    "wait until all sound has been played"
+
+    "/ as yet unimplemented
+    ^ self
+! !
+
+!SoundStream::Win32DirectSound methodsFor:'open & close'!
+
+closeFile
+    "a stream has been collected - close the file"
+
+%{
+#ifdef SUPPORT_WIN32_DIRECTSOUND
+    OBJ oDirectSound, oDSBuffer;
+    LPDIRECTSOUND       t_pDirectSound;
+    LPDIRECTSOUNDBUFFER t_pDSBuffer;
+
+    if ((oDSBuffer = __INST(pDSBuffer)) != nil) {
+        __INST(pDSBuffer) = nil;
+        t_pDSBuffer = __DSBufferVal(oDSBuffer);
+        if (t_pDSBuffer) {
+            IDirectSoundBuffer_Stop(t_pDSBuffer);
+            IDirectSoundBuffer_Release(t_pDSBuffer);
+        }
+    }
+    if ((oDirectSound = __INST(pDirectSound)) != nil) {
+        __INST(pDirectSound) = nil;
+        t_pDirectSound = __DirectSoundVal(oDirectSound);
+        if (t_pDirectSound) {
+            IDirectSound_Release(t_pDirectSound);
+        }
+    }
+    RETURN (self);
+#endif /* SUPPORT_WIN32_DIRECTSOUND */
+%}.
+
+!
+
+openWithMode:aMode attributes:attributeSpec
+    |ok error errorStringOrNil|
+
+%{
+#ifdef SUPPORT_WIN32_DIRECTSOUND
+    HRESULT result;
+    LPDIRECTSOUND       t_pDirectSound;
+    LPDIRECTSOUNDBUFFER t_pDSBuffer, t_pDSPrimeBuffer;
+    WAVEFORMATEX        wfFormat;
+    DSBUFFERDESC        dsbdDesc, primarydsbDesc;
+    BYTE                *pDSBuffData;
+    int                 t_cbBufSize;
+    int                 dwDataLen;
+
+    ok = false;
+
+    /* Create the DS object */
+    if ((result = DirectSoundCreate(NULL, &t_pDirectSound, NULL)) != DS_OK) {
+        console_fprintf(stderr,"SoundStream: Cannot open default sound device!!\n");
+        goto out;
+    }
+
+    /* Define the wave format structure */
+    wfFormat.wFormatTag = WAVE_FORMAT_PCM;
+    wfFormat.nChannels = __intVal(__INST(numberOfChannels));
+    wfFormat.nSamplesPerSec = __intVal(__INST(sampleRate));
+    wfFormat.wBitsPerSample = __intVal(__INST(bitsPerSample));
+    wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
+    wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
+    wfFormat.cbSize = 0;
+
+#  if 0
+    /* Setup the primary DS buffer description */
+    ZeroMemory(&primarydsbDesc, sizeof(DSBUFFERDESC));
+    primarydsbDesc.dwSize = sizeof(DSBUFFERDESC);
+    primarydsbDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
+    primarydsbDesc.dwBufferBytes = 0;
+    primarydsbDesc.lpwfxFormat = NULL;
+
+    /* Create the primary DS buffer */
+    if ((result = IDirectSound_CreateSoundBuffer(t_pDirectSound, &primarydsbDesc,
+                                                 &t_pDSPrimeBuffer, NULL)) != DS_OK) {
+        console_fprintf(stderr,"SoundStream: Cannot get the primary DS buffer address!\n");
+        IDirectSound_Release(t_pDirectSound);
+        goto out;
+    }
+
+    /* Set the primary DS buffer sound format.  We have to do this because
+       the default primary buffer is 8-bit, 22kHz! */
+    if ((result = IDirectSoundBuffer_SetFormat(t_pDSPrimeBuffer, &wfFormat)) != DS_OK) {
+        console_fprintf(stderr,"SoundStream: Cannot set the primary DS buffer to proper sound format (%x) (%d)!\n", result, result);
+        IDirectSoundBuffer_Stop(t_pDSPrimeBuffer);
+        IDirectSoundBuffer_Release(t_pDSPrimeBuffer);
+        IDirectSound_Release(t_pDirectSound);
+        goto out;
+    }
+#  endif /* 0 */
+
+    /* Setup the secondary DS buffer description */
+    t_cbBufSize = RT_BUFFER_SIZE * sizeof(short) * NBUFS;
+    __INST(bufferSize) = __MKSMALLINT(t_cbBufSize);
+
+    ZeroMemory(&dsbdDesc, sizeof(DSBUFFERDESC));
+    dsbdDesc.dwSize = sizeof(DSBUFFERDESC);
+    dsbdDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
+    dsbdDesc.dwBufferBytes = t_cbBufSize;
+    dsbdDesc.lpwfxFormat = &wfFormat;
+
+    /* Create the secondary DS buffer */
+    if ((result = IDirectSound_CreateSoundBuffer(t_pDirectSound, &dsbdDesc, &t_pDSBuffer, NULL)) != DS_OK) {
+        console_fprintf(stderr,"SoundStream: couldn't create sound buffer!\n");
+        IDirectSoundBuffer_Stop(t_pDSPrimeBuffer);
+        IDirectSoundBuffer_Release(t_pDSPrimeBuffer);
+        IDirectSound_Release(t_pDirectSound);
+        goto out;
+    }
+
+    /* Lock the DS buffer */
+    if ((result = IDirectSoundBuffer_Lock(t_pDSBuffer, 0, t_cbBufSize, (LPLPVOID)&pDSBuffData,
+                                          &dwDataLen, NULL, NULL, 0)) != DS_OK) {
+        console_fprintf(stderr,"SoundStream: couldn't lock sound buffer!\n");
+        goto errorAndOut;
+    }
+
+    /* Zero the DS buffer */
+    ZeroMemory(pDSBuffData, dwDataLen);
+
+    /* Unlock the DS buffer */
+    if ((result = IDirectSoundBuffer_Unlock(t_pDSBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) {
+        console_fprintf(stderr,"SoundStream: couldn't unlock sound buffer!\n");
+        goto errorAndOut;
+    }
+
+    __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)) {
+        console_fprintf(stderr,"SoundStream: couldn't play sound buffer!\n");
+
+errorAndOut:
+        IDirectSoundBuffer_Stop(t_pDSBuffer);
+        IDirectSoundBuffer_Stop(t_pDSPrimeBuffer);
+        IDirectSoundBuffer_Release(t_pDSPrimeBuffer);
+        IDirectSound_Release(t_pDirectSound);
+        goto out;
+    }
+
+    {
+        OBJ t;
+
+        t = __MKEXTERNALADDRESS(t_pDSBuffer); __INST(pDSBuffer) = t; __STORE(self, t);
+        t = __MKEXTERNALADDRESS(t_pDirectSound); __INST(pDirectSound) = t; __STORE(self, t);
+    }
+    ok = true;
+out:;
+#endif /* SUPPORT_WIN32_DIRECTSOUND */
+
+%}.
+    ok == false ifTrue:[
+        lastErrorString := errorStringOrNil.
+        lastErrorNumber := error ? -1.
+        self openError:error.
+        "normally not reached"
+        ^ nil.
+    ].
+    self registerForFinalization.
+! !
+
+!SoundStream::Win32DirectSound methodsFor:'queries'!
+
+supportedAudioFormats
+    "return a collection of supported audio formats.
+     possibly returned symbols are:
+        U8        unsigned 8bit samples
+        S8        signed 8bit samples
+        U16       unsigned 16bit samples in native format
+        U16_LE    unsigned 16bit big endian samples
+        U16_BE    unsigned 16bit big endian samples
+        S16       signed 16bit little endian samples in native format
+        S16_LE    signed 16bit little endian samples
+        S16_BE    signed 16bit big endian samples
+        S24       signed 24bit little endian samples in native format
+        S24_LE    signed 24bit little endian samples
+        S24_BE    signed 24bit big endian samples
+        S32       signed 32bit little endian samples in native format
+        S32_LE    signed 32bit little endian samples
+        S32_BE    signed 32bit big endian samples
+        F32       float samples
+        MPEG      audio mpeg encoded
+        MU_LAW    u-law encoded 8bit samples
+        A_LAW     a-law encoded 8bit samples
+        IMA_ADPCM adpcm encoded
+     the set of returned symbols depends on the underlying sound hardware.
+    "
+
+    ^ #(S16_LE S16)
+
+    "
+     |s formats|
+
+     s := self writing.
+     formats := s supportedAudioFormats.
+     s close.
+     formats
+    "
+! !
+
+!SoundStream::Win32DirectSound methodsFor:'reading'!
+
+nextBytes:count into:anObject startingAt:start
+    "read the next count bytes into an object and return the number of
+     bytes read or nil on error.
+     Use with ByteArrays only."
+
+    self errorUnsupportedOperation
+! !
+
+!SoundStream::Win32DirectSound methodsFor:'writing'!
+
+nextPutBytes:count from:anObject startingAt:start
+    "write count bytes from an object starting at index start.
+     return the number of bytes written or nil on error.
+     Redefined, since IRIS audio library cannot be used with stdio.
+     (at least I don't know). Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_WIN32_DIRECTSOUND
+  {
+    HRESULT hr;
+    DWORD status;
+    LPVOID lpbuf1 = NULL;
+    LPVOID lpbuf2 = NULL;
+    DWORD dwsize1 = 0;
+    DWORD dwsize2 = 0;
+    DWORD playPos, safePos, endWrite;
+    DWORD millis;
+    OBJ oDirectSound, oDSBuffer;
+    LPDIRECTSOUND       t_pDirectSound = (LPDIRECTSOUND)0;
+    LPDIRECTSOUNDBUFFER t_pDSBuffer = (LPDIRECTSOUNDBUFFER)0;
+    int t_cbBufOffset, t_cbBufSize;
+    short *buf;
+    int cnt, offs;
+
+    if ((oDSBuffer = __INST(pDSBuffer)) != nil) {
+        t_pDSBuffer = __DSBufferVal(oDSBuffer);
+    }
+    if ((oDirectSound = __INST(pDirectSound)) != nil) {
+        t_pDirectSound = __DirectSoundVal(oDirectSound);
+    }
+
+    if (!t_pDSBuffer || !t_pDirectSound) {
+        console_fprintf(stderr, "SoundStream not open!\n");
+        RETURN (0);
+    }
+    t_cbBufOffset = __intVal(__INST(bufferOffset));
+    t_cbBufSize = __intVal(__INST(bufferSize));
+
+    cnt = __intVal(count);
+    offs = __intVal(start) - 1;
+    buf = (short *)__InstPtr(anObject) + OHDR_SIZE + offs;
+
+    // Should be playing, right?
+    hr = IDirectSoundBuffer_GetStatus(t_pDSBuffer, &status );
+    if (!(status && DSBSTATUS_PLAYING)) {
+        console_fprintf(stderr, "Buffer not playing!\n");
+        RETURN (0);
+    }
+
+    // Sleep until we have enough room in buffer.
+    hr = IDirectSoundBuffer_GetCurrentPosition(t_pDSBuffer, &playPos, &safePos );
+    if( hr != DS_OK ) {
+        console_fprintf(stderr, "Cannot get position!\n");
+        RETURN (0);
+    }
+    if( playPos < t_cbBufOffset ) playPos += t_cbBufSize;
+
+    endWrite = t_cbBufOffset + (cnt * sizeof(short));
+    while ( playPos < endWrite ) {
+        // Calculate number of milliseconds until we will have room, as
+        // time = distance * (milliseconds/second) / ((bytes/sample) * (samples/second)),
+        // rounded up.
+        millis = (DWORD) (1.0 + ((endWrite - playPos) * 1000.0) / ( sizeof(short) * __intVal(__INST(sampleRate))));
+
+        // Sleep for that long
+        Sleep( millis );
+
+        // Wake up, find out where we are now
+        hr = IDirectSoundBuffer_GetCurrentPosition(t_pDSBuffer, &playPos, &safePos );
+        if( hr != DS_OK ) {
+            console_fprintf(stderr, "Cannot get position!\n");
+            RETURN (0);
+        }
+        if( playPos < t_cbBufOffset ) playPos += t_cbBufSize; // unwrap offset
+    }
+
+    // Lock free space in the DS
+    hr = IDirectSoundBuffer_Lock(t_pDSBuffer, t_cbBufOffset, cnt * sizeof(short), &lpbuf1, &dwsize1, &lpbuf2, &dwsize2, 0);
+    if (hr == DS_OK) {
+        // Copy the buffer into the DS
+        CopyMemory(lpbuf1, buf, dwsize1);
+        if(NULL != lpbuf2) CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
+
+        // Update our buffer offset and unlock sound buffer
+        t_cbBufOffset = (t_cbBufOffset + dwsize1 + dwsize2) % t_cbBufSize;
+        IDirectSoundBuffer_Unlock(t_pDSBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+    }
+    __INST(buffferOffset) = __MKSMALLINT(t_cbBufOffset);
+
+    RETURN (count);
+  }
+#endif /* SUPPORT_WIN32_DIRECTSOUND */
+
+%}.
+    self errorUnsupportedOperation 
+! !
+
+!SoundStream::Win32WaveSound class methodsFor:'documentation'!
+
+documentation
+"
+    documentation to be added.
+
+    class:
+        <a short class summary here, describing what instances represent>
+
+    responsibilities:    
+        <describing what my main role is>
+
+    collaborators:    
+        <describing with whom and how I talk to>
+
+    API:
+        <public api and main messages>
+        
+    example:
+        <a one-line examples on how to use - can also be in a separate example method>
+
+    implementation:
+        <implementation points>
+
+    [author:]
+        exept MBP
+
+    [instance variables:]
+
+    [class variables:]
+
+    [see also:]
+
+"
+! !
+
+!SoundStream::Win32WaveSound class methodsFor:'queries'!
+
+isSupported
+%{
+#ifdef SUPPORT_WIN32_WAVESOUND
+    RETURN(true);
+#endif
+%}.
+    ^ false.
+! !
+
+!SoundStream::Win32WaveSound methodsFor:'misc'!
+
+flush
+    "wait until all sound has been played"
+
+    "/ as yet unimplemented
+    ^ self
+! !
+
+!SoundStream::Win32WaveSound methodsFor:'open & close'!
+
+closeFile
+    "a stream has been collected - close the file"
+
+%{
+#ifdef SUPPORT_WIN32_WAVESOUND
+    struct buf *bp, *next;
+    int r;
+    HWAVEOUT t_waveHandle;
+    OBJ oWaveHandle;
+
+    if ((oWaveHandle = __INST(waveHandle)) != nil) {
+        t_waveHandle = __WaveHandleVal(oWaveHandle);
+
+# ifdef NO_WAIT_IN_CLOSE
+        /* Force cancellation of any pending buffers */
+        (void)waveOutReset(t_waveHandle);
+# endif
+
+        /* Wait until all pending buffers have been freed */
+        while (free_buffers < total_buffers) {
+            WaitForSingleObject(free_buffer_event, INFINITE);
+        }
+
+# ifndef NO_WAIT_IN_CLOSE
+        /* Force cancellation of any pending buffers */
+        (void)waveOutReset(t_waveHandle);
+# endif
+
+        /* Close the device */
+        if ((r = waveOutClose(t_waveHandle)) != 0) {
+            console_printf("waveOutClose\n");
+            RETURN(self);
+        }
+
+        EnterCriticalSection(&free_list_lock);
+
+        /* Free allocated buffers */
+        for (bp = free_list; bp != NULL; bp = next) {
+            next = bp->next;
+            (void)free(bp);
+        }
+        free_list = NULL;
+
+        LeaveCriticalSection(&free_list_lock);
+
+        __INST(waveHandle) = nil;
+    }
+    RETURN (self);
+#endif /* SUPPORT_WIN32_WAVESOUND */
+%}.
+
+!
+
+openWithMode:aMode attributes:attributeSpec
+    |ok error errorStringOrNil|
+
+%{
+#ifdef SUPPORT_WIN32_WAVESOUND
+    PCMWAVEFORMAT waveFormat;
+    int r;
+    HWAVEOUT t_waveHandle;
+    OBJ oWaveHandle;
+
+    ok = false;
+
+    if ((oWaveHandle = __INST(waveHandle)) != nil) {
+        goto out;
+    }
+
+    waveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
+    waveFormat.wf.nChannels = __intVal(__INST(numberOfChannels));
+    waveFormat.wf.nSamplesPerSec = __intVal(__INST(sampleRate));
+    waveFormat.wBitsPerSample = __intVal(__INST(bitsPerSample));
+    waveFormat.wf.nBlockAlign = waveFormat.wf.nChannels * waveFormat.wBitsPerSample / 8;
+    waveFormat.wf.nAvgBytesPerSec = waveFormat.wf.nSamplesPerSec * waveFormat.wf.nBlockAlign;
+
+    r = waveOutOpen(&t_waveHandle,
+                    WAVE_MAPPER,
+                    (WAVEFORMAT *)&waveFormat,
+                    (DWORD_PTR)waveCallBack,
+                    (DWORD_PTR)0,
+                    CALLBACK_FUNCTION);
+    if (r != 0) {
+        console_printf("waveOutOpen\n");
+        goto out;
+    }
+
+    (void)waveOutReset(t_waveHandle);
+
+    free_list = NULL;
+    InitializeCriticalSection(&free_list_lock);
+    free_buffers = 0;
+    free_buffer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    total_buffers = 0;
+
+    {
+        OBJ t;
+
+        t = __MKEXTERNALADDRESS(t_waveHandle); __INST(waveHandle) = t; __STORE(self, t);
+    }
+
+# if 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);
+    }
+# endif /* 0 */
+    ok = true;
+
+out:;
+
+#endif /* !SUPPORT_WIN32_DIRECTSOUND */
+%}.
+    ok == false ifTrue:[
+        lastErrorString := errorStringOrNil.
+        lastErrorNumber := error ? -1.
+        self openError:error.
+        "normally not reached"
+        ^ nil.
+    ].
+    self registerForFinalization.
+! !
+
+!SoundStream::Win32WaveSound methodsFor:'queries'!
+
+supportedAudioFormats
+    "return a collection of supported audio formats.
+     possibly returned symbols are:
+        U8        unsigned 8bit samples
+        S8        signed 8bit samples
+        U16       unsigned 16bit samples in native format
+        U16_LE    unsigned 16bit big endian samples
+        U16_BE    unsigned 16bit big endian samples
+        S16       signed 16bit little endian samples in native format
+        S16_LE    signed 16bit little endian samples
+        S16_BE    signed 16bit big endian samples
+        S24       signed 24bit little endian samples in native format
+        S24_LE    signed 24bit little endian samples
+        S24_BE    signed 24bit big endian samples
+        S32       signed 32bit little endian samples in native format
+        S32_LE    signed 32bit little endian samples
+        S32_BE    signed 32bit big endian samples
+        F32       float samples
+        MPEG      audio mpeg encoded
+        MU_LAW    u-law encoded 8bit samples
+        A_LAW     a-law encoded 8bit samples
+        IMA_ADPCM adpcm encoded
+     the set of returned symbols depends on the underlying sound hardware.
+    "
+
+    ^ #(S16_LE S16)
+
+    "
+     |s formats|
+
+     s := self writing.
+     formats := s supportedAudioFormats.
+     s close.
+     formats
+    "
+! !
+
+!SoundStream::Win32WaveSound methodsFor:'reading'!
+
+nextBytes:count into:anObject startingAt:start
+    "read the next count bytes into an object and return the number of
+     bytes read or nil on error.
+     Use with ByteArrays only."
+
+    self errorUnsupportedOperation
+! !
+
+!SoundStream::Win32WaveSound methodsFor:'writing'!
+
+nextPutBytes:count from:anObject startingAt:start
+    "write count bytes from an object starting at index start.
+     return the number of bytes written or nil on error.
+     Redefined, since IRIS audio library cannot be used with stdio.
+     (at least I don't know). Use with ByteArrays only."
+
+%{
+#ifdef SUPPORT_WIN32_WAVESOUND
+  {
+    struct buf *bp;
+    int len, i, r;
+    int dataLen, offs;
+    short *buf;
+
+    HWAVEOUT t_waveHandle;
+    OBJ oWaveHandle;
+
+    if ((oWaveHandle = __INST(waveHandle)) == nil) {
+        RETURN(0);
+    }
+    t_waveHandle = __WaveHandleVal(oWaveHandle);
+
+    dataLen = __intVal(count);
+    offs = __intVal(start) - 1;
+    buf = (short *)__InstPtr(anObject) + OHDR_SIZE + offs;
+
+    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(t_waveHandle, &bp->hdr, sizeof(WAVEHDR));
+            if (r != 0) {
+                console_printf("waveOutUnprepareHeader\n");
+                RETURN(self);
+            }
+        }
+        len = min(dataLen, DATALEN);
+        bp->hdr.lpData = (char *)bp->data;
+        bp->hdr.dwBufferLength = len;
+        bp->hdr.dwBytesRecorded = len;
+        bp->hdr.dwUser = (INT)(bp);
+        bp->hdr.dwFlags = 0;
+        bp->hdr.dwLoops = 0;
+        r = waveOutPrepareHeader(t_waveHandle, &bp->hdr, sizeof(WAVEHDR));
+        if (r != 0) {
+            console_printf("waveOutPrepareHeader\n");
+            RETURN(self);
+        }
+        for (i = 0; i < len; i++) {
+            bp->data[i] = buf[i];
+        }
+        r = waveOutWrite(t_waveHandle, &bp->hdr, sizeof(WAVEHDR));
+        if (r != 0) {
+            console_printf("waveOutWrite\n");
+            RETURN(self);
+        }
+        buf += len;
+        dataLen -= len;
+    }
+    RETURN (count);
+  }
+#endif /* SUPPORT_WIN32_WAVESOUND */
+%}.
+    self errorUnsupportedOperation 
+! !
+
 !SoundStream class methodsFor:'documentation'!
 
 version