--- a/SoundStream.st Sun Jan 05 17:26:45 2020 +0100
+++ b/SoundStream.st Sun Jan 05 17:35:48 2020 +0100
@@ -38,6 +38,13 @@
privateIn:SoundStream
!
+SoundStream subclass:#JackAudio
+ instanceVariableNames:''
+ classVariableNames:''
+ poolDictionaries:''
+ privateIn:SoundStream
+!
+
SoundStream subclass:#PortAudio
instanceVariableNames:''
classVariableNames:''
@@ -64,42 +71,40 @@
#include "stxOSDefs.h"
-#ifdef __win32__
-# ifndef NO_SOUND
+#ifndef NO_SOUND
+
+# ifdef __win32__
# define xxxSUPPORT_WIN32_DIRECTSOUND
# ifndef SUPPORT_WIN32_WAVESOUND
# define SUPPORT_WIN32_WAVESOUND
# endif
-# endif
-#endif
-
-#ifdef __iris__
-# ifndef IRIX5
-# ifndef SUPPORT_IRIS_AUDIO
-# define SUPPORT_IRIS_AUDIO
-# endif
-# endif
-#endif
-
-#ifndef SUPPORT_IRIS_AUDIO
-# ifndef SUPPORT_ALSA_AUDIO
-# ifdef LINUX
-# ifndef SUPPORT_DEV_AUDIO
-# define SUPPORT_DEV_AUDIO
+# endif /* __win32__ */
+
+# ifdef __iris__
+# ifndef IRIX5
+# ifndef SUPPORT_IRIS_AUDIO
+# define SUPPORT_IRIS_AUDIO
# endif
# endif
-# endif
-#endif
-
-#ifndef NO_SOUND
-# ifndef USED_AUDIO
-# ifdef __osx__
-# ifndef SUPPORT_PORTAUDIO
-# define SUPPORT_PORTAUDIO
-# endif
+# endif // __iris__
+
+# ifndef SUPPORT_IRIS_AUDIO
+# ifndef SUPPORT_ALSA_AUDIO
+# ifdef LINUX
+# ifndef SUPPORT_DEV_AUDIO
+# define SUPPORT_DEV_AUDIO
+# endif
+# endif // LINUX
# endif
-# endif
-#endif
+# endif // SUPPORT_IRIS_AUDIO
+
+# ifdef __osx__
+# ifndef SUPPORT_PORTAUDIO
+# define SUPPORT_PORTAUDIO
+# endif
+# endif // __osx__
+
+#endif /* NO_SOUND */
#ifdef SUPPORT_IRIS_AUDIO
# include <audio.h>
@@ -177,6 +182,10 @@
#endif // SUPPORT_PORTAUDIO
+#ifdef SUPPORT_JACKAUDIO
+# include "jack/jack.h"
+#endif // SUPPORT_JACKAUDIO
+
#ifdef __win32__
# define _WIN32
@@ -301,6 +310,12 @@
%}
! !
+!SoundStream primitiveVariables!
+%{
+static int DEBUGGING = 0;
+%}
+! !
+
!SoundStream primitiveFunctions!
%{
@@ -330,8 +345,6 @@
#ifdef SUPPORT_PORTAUDIO
-static int DEBUGGING = 0;
-
struct paBuffer {
void* sampleData;
int bufferSize;
@@ -352,7 +365,7 @@
/*
* This routine will be called by the PortAudio engine when audio is needed.
- * It may called at interrupt level on some machines so don't do anything
+ * It may called at interrupt level on some machines, so don't do anything
* that could mess up the system like calling malloc() or free().
*/
static int
@@ -362,29 +375,29 @@
PaStreamCallbackFlags statusFlags,
void *userData )
{
- struct paStreamData *paStreamData = (struct paStreamData *)userData;
- struct paBuffer *paBuffer = paStreamData->currentBuffer;
- int nBytesToOutput = paStreamData->bytesPerSample * paStreamData->nChannels * framesPerBuffer;
+ struct paStreamData *streamData = (struct paStreamData *)userData;
+ struct paBuffer *buffer = streamData->currentBuffer;
+ int nBytesToOutput = streamData->bytesPerSample * streamData->nChannels * framesPerBuffer;
int nBytesLeftInBuffer;
int readOffset;
int writeOffset = 0;
int nSent;
int retVal = paContinue;
- readOffset = paStreamData->readOffset;
+ readOffset = streamData->readOffset;
again:
- if (paBuffer != NULL) {
- nBytesLeftInBuffer = paBuffer->bufferSize - readOffset;
+ if (buffer != NULL) {
+ nBytesLeftInBuffer = buffer->bufferSize - readOffset;
if (DEBUGGING) {
fprintf(stderr, "pa: %d from %p[%d] to [%d]; next: %p last: %p)\n",
- nBytesLeftInBuffer, paBuffer, readOffset, writeOffset,
- paBuffer->nextBuffer, paStreamData->lastBuffer);
+ nBytesLeftInBuffer, buffer, readOffset, writeOffset,
+ buffer->nextBuffer, streamData->lastBuffer);
}
} else {
nBytesLeftInBuffer = 0;
}
if (nBytesLeftInBuffer >= nBytesToOutput) {
- memcpy(outputBuffer+writeOffset, paBuffer->sampleData+readOffset, nBytesToOutput);
+ memcpy(outputBuffer+writeOffset, buffer->sampleData+readOffset, nBytesToOutput);
nSent = nBytesToOutput;
if (DEBUGGING) {
fprintf(stderr, "pa: %d from buffer\n", nSent);
@@ -394,7 +407,7 @@
} else {
nSent = nBytesLeftInBuffer;
if (nSent > 0) {
- memcpy(outputBuffer+writeOffset, paBuffer->sampleData+readOffset, nBytesLeftInBuffer);
+ memcpy(outputBuffer+writeOffset, buffer->sampleData+readOffset, nBytesLeftInBuffer);
if (DEBUGGING) {
fprintf(stderr, "pa: %d from buffer\n", nBytesLeftInBuffer);
}
@@ -402,33 +415,33 @@
readOffset += nBytesLeftInBuffer;
}
}
- if (paBuffer != NULL) {
- paStreamData->readOffset = readOffset;
- if (readOffset >= paBuffer->bufferSize) {
- LOCK(paStreamData->lock);
+ if (buffer != NULL) {
+ streamData->readOffset = readOffset;
+ if (readOffset >= buffer->bufferSize) {
+ LOCK(streamData->lock);
// next buffer
- paStreamData->currentBuffer = paBuffer->nextBuffer;
- paStreamData->readOffset = readOffset = 0;
+ streamData->currentBuffer = buffer->nextBuffer;
+ streamData->readOffset = readOffset = 0;
// this buffer onto freeList
- paBuffer->nextBuffer = paStreamData->freeList;
- paStreamData->freeList = paBuffer;
+ buffer->nextBuffer = streamData->freeList;
+ streamData->freeList = buffer;
if (DEBUGGING) {
- fprintf(stderr, "pa: put on freelist: %p\n", paBuffer);
+ fprintf(stderr, "pa: put on freelist: %p\n", buffer);
}
- if (paStreamData->currentBuffer == NULL) {
+ if (streamData->currentBuffer == NULL) {
if (DEBUGGING) {
fprintf(stderr, "pa: done with last buffer\n");
}
- paStreamData->lastBuffer = NULL;
+ streamData->lastBuffer = NULL;
retVal = paComplete;
}
- UNLOCK(paStreamData->lock);
+ UNLOCK(streamData->lock);
if (nBytesToOutput > 0) {
writeOffset += nSent;
- if (paStreamData->currentBuffer == NULL) {
+ if (streamData->currentBuffer == NULL) {
memset(outputBuffer+writeOffset, 0, nBytesToOutput);
} else {
- paBuffer = paStreamData->currentBuffer;
+ buffer = streamData->currentBuffer;
readOffset = 0;
if (DEBUGGING) {
fprintf(stderr, "pa: %d more\n", nBytesToOutput);
@@ -448,9 +461,9 @@
static void
paStreamFinished( void* userData )
{
- struct paStreamData *paStreamData = (struct paStreamData *)userData;
-
- paStreamData->hasFinished = 1;
+ struct paStreamData *streamData = (struct paStreamData *)userData;
+
+ streamData->hasFinished = 1;
if (DEBUGGING) {
fprintf(stderr, "pa: Stream Completed\n" );
}
@@ -458,6 +471,132 @@
#endif /* SUPPORT_PORTAUDIO */
+#ifdef SUPPORT_JACKAUDIO
+
+struct jackBuffer {
+ void* sampleData;
+ int bufferSize;
+ struct jackBuffer* nextBuffer;
+};
+
+struct jackStreamData {
+ jack_port_t *jack_input_port;
+ jack_port_t *jack_output_port;
+ jack_client_t *jack_client;
+ MUTEX lock;
+ int readOffset;
+ int bytesPerSample; // bytesPerSample (1, 2 or 4)
+ int nChannels; // num channels (1 or 2)
+ int hasFinished;
+ struct jackBuffer* currentBuffer;
+ struct jackBuffer* lastBuffer;
+ struct jackBuffer* freeList;
+};
+
+/*
+ * This routine will be called by the Jack engine when audio is needed.
+ * It may called at interrupt level on some machines, so don't do anything
+ * that could mess up the system like calling malloc() or free().
+ */
+static int
+jack_callback(jack_nframes_t nframes, void *userData)
+{
+ struct jackStreamData *streamData = (struct jackStreamData*)userData;
+ struct jackBuffer *buffer = streamData->currentBuffer;
+ int nBytesToOutput = streamData->bytesPerSample * streamData->nChannels * nframes;
+ // int nBytesToOutput = sizeof (jack_default_audio_sample_t) * nframes;
+ int nBytesLeftInBuffer;
+ int readOffset;
+ int writeOffset = 0;
+ int nSent;
+ int retVal = paContinue;
+ jack_default_audio_sample_t *in, *out;
+
+ in = jack_port_get_buffer (streamData->jack_input_port, nframes);
+ out = jack_port_get_buffer (streamData->jack_output_port, nframes);
+
+ readOffset = streamData->readOffset;
+ again:
+ if (buffer != NULL) {
+ nBytesLeftInBuffer = buffer->bufferSize - readOffset;
+ if (DEBUGGING) {
+ fprintf(stderr, "jack: %d from %p[%d] to [%d]; next: %p last: %p)\n",
+ nBytesLeftInBuffer, buffer, readOffset, writeOffset,
+ buffer->nextBuffer, streamData->lastBuffer);
+ }
+ } else {
+ nBytesLeftInBuffer = 0;
+ }
+ if (nBytesLeftInBuffer >= nBytesToOutput) {
+ memcpy(out+writeOffset, buffer->sampleData+readOffset, nBytesToOutput);
+ nSent = nBytesToOutput;
+ if (DEBUGGING) {
+ fprintf(stderr, "jack: %d from buffer\n", nSent);
+ }
+ nBytesToOutput = 0;
+ readOffset += nSent;
+ } else {
+ nSent = nBytesLeftInBuffer;
+ if (nSent > 0) {
+ memcpy(out+writeOffset, buffer->sampleData+readOffset, nBytesLeftInBuffer);
+ if (DEBUGGING) {
+ fprintf(stderr, "jack: %d from buffer\n", nBytesLeftInBuffer);
+ }
+ nBytesToOutput -= nSent;
+ readOffset += nBytesLeftInBuffer;
+ }
+ }
+ if (buffer != NULL) {
+ streamData->readOffset = readOffset;
+ if (readOffset >= buffer->bufferSize) {
+ LOCK(streamData->lock);
+ // next buffer
+ streamData->currentBuffer = buffer->nextBuffer;
+ streamData->readOffset = readOffset = 0;
+ // this buffer onto freeList
+ buffer->nextBuffer = streamData->freeList;
+ streamData->freeList = buffer;
+ if (DEBUGGING) {
+ fprintf(stderr, "jack: put on freelist: %p\n", buffer);
+ }
+ if (streamData->currentBuffer == NULL) {
+ if (DEBUGGING) {
+ fprintf(stderr, "jack: done with last buffer\n");
+ }
+ streamData->lastBuffer = NULL;
+ retVal = paComplete;
+ }
+ UNLOCK(streamData->lock);
+ if (nBytesToOutput > 0) {
+ writeOffset += nSent;
+ if (streamData->currentBuffer == NULL) {
+ memset(out+writeOffset, 0, nBytesToOutput);
+ } else {
+ buffer = streamData->currentBuffer;
+ readOffset = 0;
+ if (DEBUGGING) {
+ fprintf(stderr, "jack: %d more\n", nBytesToOutput);
+ }
+ goto again;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * JACK calls this shutdown_callback if the server ever shuts down or
+ * decides to disconnect the client.
+ */
+void
+jack_shutdown (void *userData)
+{
+ struct jackStreamData *streamData = (struct jackStreamData*)userData;
+}
+
+#endif /* SUPPORT_JACKAUDIO */
+
%}
! !
@@ -516,24 +655,28 @@
determineConcreteClass
self allSubclassesDo:[:each |
- each isAbstract ifFalse:[
- each isSupported ifTrue:[
- ^ each
- ]
- ]
+ each isAbstract ifFalse:[
+ each isSupported ifTrue:[
+ ^ each
+ ]
+ ]
].
^ nil
+
+ "
+ self determineConcreteClass
+ "
!
new
self == SoundStream ifTrue:[
- ConcreteClass isNil ifTrue:[
- ConcreteClass := self determineConcreteClass.
- ConcreteClass isNil ifTrue:[
- self openErrorSignal raiseErrorString:'missing sound support'.
- ].
- ].
- ^ ConcreteClass new.
+ ConcreteClass isNil ifTrue:[
+ ConcreteClass := self determineConcreteClass.
+ ConcreteClass isNil ifTrue:[
+ OpenError raiseErrorString:'missing sound support'.
+ ].
+ ].
+ ^ ConcreteClass new.
].
^ self basicNew initialize
@@ -1128,36 +1271,53 @@
!SoundStream class methodsFor:'queries'!
+defaultClass
+ ^ ConcreteClass
+
+ "
+ SoundStream defaultClass:(SoundStream::JackAudio)
+ "
+!
+
+defaultClass:aClass
+ self assert:(aClass isSupported).
+ ConcreteClass := aClass.
+
+ "
+ SoundStream defaultClass:(SoundStream::JackAudio)
+ "
+!
+
isSupported
^ false.
!
noteToHertz:noteName
"notename is one of:
- a1, b2, f3, c#3 etc."
+ a1, b2, f3, c#3 etc."
|octave lastDigit note f sharp|
octave := 4.
(lastDigit := noteName last) isDigit ifTrue:[
- octave := lastDigit digitValue
+ octave := lastDigit digitValue
].
note := noteName first.
sharp := (noteName size > 1) and:[noteName second == $#].
note = $a ifTrue:[
- f := sharp ifTrue:[466.2] ifFalse:[440]
+ f := sharp ifTrue:[466.2] ifFalse:[440]
] ifFalse:[ note = $b ifTrue:[
- f := 493.8
+ f := 493.8
] ifFalse:[ note = $c ifTrue:[
- f := sharp ifTrue:[277.2] ifFalse:[261.6]
+ f := sharp ifTrue:[277.2] ifFalse:[261.6]
] ifFalse:[ note = $d ifTrue:[
- f := sharp ifTrue:[311.1] ifFalse:[293.6]
+ f := sharp ifTrue:[311.1] ifFalse:[293.6]
] ifFalse:[ note = $e ifTrue:[
- f := 329.6
+ f := 329.6
] ifFalse:[ note = $f ifTrue:[
- f := sharp ifTrue:[370] ifFalse:[349.2]
+ f := sharp ifTrue:[370] ifFalse:[349.2]
] ifFalse:[ note = $g ifTrue:[
- f := sharp ifTrue:[415.3] ifFalse:[392]
+ f := sharp ifTrue:[415.3] ifFalse:[392]
]]]]]]].
f := f * (2 raisedTo:octave-4).
@@ -1165,10 +1325,10 @@
"
SoundStream noteToHertz:'a'
- SoundStream noteToHertz:'g4'
- SoundStream noteToHertz:'e5'
- SoundStream noteToHertz:'b3'
- SoundStream noteToHertz:'c#3'
+ SoundStream noteToHertz:'g4'
+ SoundStream noteToHertz:'e5'
+ SoundStream noteToHertz:'b3'
+ SoundStream noteToHertz:'c#3'
"
"Modified: / 31.1.1999 / 12:06:27 / cg"
@@ -1521,21 +1681,21 @@
"allocate memory for 1 sec playing time"
numSamples := self sampleRate.
audioFormat == #U16 ifTrue:[
- buffer := WordArray new:numSamples withAll:16r8000.
+ buffer := WordArray new:numSamples withAll:16r8000.
] ifFalse:[ audioFormat == #S16 ifTrue:[
- buffer := SignedWordArray new:numSamples withAll:0.
+ buffer := SignedWordArray new:numSamples withAll:0.
] ifFalse:[ audioFormat == #F32 ifTrue:[
- buffer := FloatArray new:numSamples withAll:0.0.
- ] ifFalse:[
- self halt
+ buffer := FloatArray new:numSamples withAll:0.0.
+ ] ifFalse:[
+ self halt
]]].
1 to:nSeconds truncated do:[:s |
- self nextPutBytes:(numSamples*2) from:buffer startingAt:1
+ self nextPutBytes:(numSamples*2) from:buffer startingAt:1
].
restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
restSamples > 0 ifTrue:[
- self nextPutBytes:(restSamples*2) from:buffer startingAt:1
+ self nextPutBytes:(restSamples*2) from:buffer startingAt:1
].
!
@@ -1671,8 +1831,8 @@
g 0.5
g 0.5
) pairWiseDo:[:note :duration |
- self playSine:(self class noteToHertz:note) forSeconds:duration.
- self pause:0.05.
+ self playSine:(self class noteToHertz:note) forSeconds:duration.
+ self pause:0.05.
].
"
@@ -1685,11 +1845,11 @@
testOctaves
3 timesRepeat:[
- self playSine:220 forSeconds:0.5.
- self playSine:440 forSeconds:0.5.
- self playSine:880 forSeconds:0.5.
- self playSine:1760 forSeconds:0.5.
- self playSine:3520 forSeconds:0.5.
+ self playSine:220 forSeconds:0.5.
+ self playSine:440 forSeconds:0.5.
+ self playSine:880 forSeconds:0.5.
+ self playSine:1760 forSeconds:0.5.
+ self playSine:3520 forSeconds:0.5.
]
"
@@ -1726,18 +1886,18 @@
|buffer numSamples val scale restSamples|
(audioFormat startsWith:#U16) ifFalse:[
- (audioFormat startsWith:#S16) ifFalse:[
- self error:'must be in 16bit mode' mayProceed:true.
- ^ self
- ]
+ (audioFormat startsWith:#S16) ifFalse:[
+ self error:'must be in 16bit mode' mayProceed:true.
+ ^ self
+ ]
].
"allocate memory for 1 sec playing time"
numSamples := self sampleRate.
audioFormat == #U16 ifTrue:[
- buffer := WordArray new:numSamples.
+ buffer := WordArray new:numSamples.
] ifFalse:[
- buffer := SignedWordArray new:numSamples.
+ buffer := SignedWordArray new:numSamples.
].
"fill it with a sine wave"
@@ -1746,20 +1906,20 @@
"/ each of which is 0 .. 2pi
scale := freq * 2 * (Float pi) / numSamples.
1 to:numSamples do:[:i |
- val := (scale * (i-1)) sin.
- val := (val * 16r7FFF) rounded.
- audioFormat == #U16 ifTrue:[
- val := val + 16r8000
- ].
- buffer at:i put:val
+ val := (scale * (i-1)) sin.
+ val := (val * 16r7FFF) rounded.
+ audioFormat == #U16 ifTrue:[
+ val := val + 16r8000
+ ].
+ buffer at:i put:val
].
1 to:nSeconds truncated do:[:s |
- self nextPutBytes:(numSamples*2) from:buffer startingAt:1
+ self nextPutBytes:(numSamples*2) from:buffer startingAt:1
].
restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
restSamples > 0 ifTrue:[
- self nextPutBytes:(restSamples*2) from:buffer startingAt:1
+ self nextPutBytes:(restSamples*2) from:buffer startingAt:1
].
"of course, the frequency should be below half the
@@ -1924,8 +2084,8 @@
|buffer numSamples val scale restSamples|
(audioFormat == #F32) ifFalse:[
- self error:'must be in f32 mode' mayProceed:true.
- ^ self
+ self error:'must be in f32 mode' mayProceed:true.
+ ^ self
].
"allocate memory for 1sec playing time"
@@ -1936,16 +2096,16 @@
scale := freq * 2 * (Float pi) / numSamples.
1 to:numSamples do:[:i |
- val := (scale * i) sin.
- buffer at:i put:val
+ val := (scale * i) sin.
+ buffer at:i put:val
].
1 to:nSeconds truncated do:[:s |
- self nextPutBytes:(numSamples*4) from:buffer startingAt:1
+ self nextPutBytes:(numSamples*4) from:buffer startingAt:1
].
restSamples := ((nSeconds - nSeconds truncated) * numSamples) truncated.
restSamples > 0 ifTrue:[
- self nextPutBytes:(restSamples*4) from:buffer startingAt:1
+ self nextPutBytes:(restSamples*4) from:buffer startingAt:1
].
"of course, the frequency should be below half the
@@ -3301,6 +3461,162 @@
self errorUnsupportedOperation
! !
+!SoundStream::JackAudio class methodsFor:'queries'!
+
+isSupported
+%{
+#ifdef SUPPORT_JACKAUDIO
+ RETURN(true);
+#endif
+%}.
+ ^ false.
+! !
+
+!SoundStream::JackAudio methodsFor:'open & close'!
+
+closeFile
+ "a stream has been collected - close the file"
+
+%{
+#ifdef SUPPORT_JACKAUDIO
+ OBJ str;
+ if ((str = __INST(handle1)) != nil) {
+ struct jackStreamData* streamData = (struct jackStreamData*)__externalAddressVal(str);
+ struct jackBuffer* buffer;
+
+ if (DEBUGGING) {
+ fprintf(stderr, "jack close\n");
+ }
+ __externalAddressVal(str) = NULL;
+ __INST(handle1) = nil;
+ jack_client_close( streamData->jack_client );
+
+ LOCK(streamData->lock);
+
+ buffer = streamData->currentBuffer;
+ streamData->currentBuffer = NULL;
+ streamData->lastBuffer = NULL;
+ while (buffer != NULL) {
+ struct jackBuffer* nextBuffer = buffer->nextBuffer;
+ free(buffer->sampleData);
+ free(buffer);
+ buffer = nextBuffer;
+ }
+ buffer = streamData->freeList;
+ streamData->freeList = NULL;
+ while (buffer != NULL) {
+ struct jackBuffer* nextBuffer = buffer->nextBuffer;
+ free(buffer->sampleData);
+ free(buffer);
+ buffer = nextBuffer;
+ }
+
+ UNLOCK(streamData->lock);
+ RELEASELOCK(streamData->lock);
+ free(streamData);
+ }
+ RETURN (self);
+#endif // SUPPORT_JACKAUDIO
+%}.
+!
+
+openWithMode:aMode attributes:attributeSpec
+ |ok error errorStringOrNil|
+
+ openMode := aMode.
+ openAttributes := attributeSpec.
+%{
+#ifdef SUPPORT_JACKAUDIO
+ jack_options_t options = JackNullOption;
+ jack_client_t *client;
+ struct jackStreamData* streamData;
+ int nChannels, sampleRate, bytesPerSample;
+# define FRAMES_PER_BUFFER 128
+
+ ok = false;
+
+ if (__isSmallInteger(__INST(numberOfChannels))) {
+ nChannels = __intVal(__INST(numberOfChannels));
+ } else {
+ nChannels = 1;
+ }
+
+ if (__INST(audioFormat) == @symbol(F32)) {
+ bytesPerSample = 4;
+ } else {
+ fprintf(stderr, "SoundStream [warning]: only f32 supported with jack\n");
+ errorStringOrNil = __MKSTRING("audioFormat must be f32 with jack");
+ goto out;
+ }
+
+ if (__isSmallInteger(__INST(sampleRate))) {
+ sampleRate = __intVal(__INST(sampleRate));
+ } else {
+ fprintf(stderr, "SoundStream [warning]: using default sampleRate 8000\n");
+ sampleRate = 8000;
+ }
+
+ streamData = (struct jackStreamData*)malloc(sizeof(struct jackStreamData));
+ if (streamData == NULL) {
+ fprintf(stderr, "SoundStream [warning]: failed to allocate jackStream\n");
+ errorStringOrNil = __MKSTRING("failed to allocate jackStream");
+ goto out;
+ }
+
+ if ((client = jack_client_open ("stx", JackNullOption, NULL)) == 0) {
+ fprintf(stderr, "SoundStream [warning]: client_open\n");
+ free(streamData);
+ errorStringOrNil = __MKSTRING("client_open");
+ goto out;
+ }
+
+ streamData->jack_client = client;
+ INITLOCK(streamData->lock);
+ streamData->readOffset = 0;
+ streamData->bytesPerSample = bytesPerSample;
+ streamData->nChannels = nChannels;
+
+ streamData->currentBuffer = NULL;
+ streamData->lastBuffer = NULL;
+ streamData->freeList = NULL;
+ streamData->hasFinished = 0;
+
+ {
+ OBJ t;
+ t = __MKEXTERNALADDRESS(streamData); __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_JACKAUDIO */
+
+%}.
+ ok == false ifTrue:[
+ lastErrorString := errorStringOrNil.
+ lastErrorNumber := error ? -1.
+ self openError:error.
+ "normally not reached"
+ ^ nil.
+ ].
+ self registerForFinalization.
+
+!
+
+reopenStream
+ handle1 isNil ifTrue:[^ self].
+ self closeFile.
+ self openWithMode:openMode attributes:openAttributes
+! !
+
!SoundStream::PortAudio class methodsFor:'default values'!
defaultSampleRate
@@ -3392,8 +3708,8 @@
"wait until all sound has been played"
[self hasOutputPending] whileTrue:[
- Delay waitForMilliseconds:20.
- "/ Processor yield
+ Delay waitForMilliseconds:20.
+ "/ Processor yield
]
!
@@ -3402,9 +3718,9 @@
#ifdef SUPPORT_PORTAUDIO
OBJ str;
if ((str = __INST(handle1)) != nil) {
- struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
-
- RETURN ((paStreamData->currentBuffer != NULL) ? true : false);
+ struct paStreamData* streamData = (struct paStreamData*)__externalAddressVal(str);
+
+ RETURN ((streamData->currentBuffer != NULL) ? true : false);
}
#endif /* SUPPORT_PORTAUDIO */
%}.
@@ -3420,7 +3736,7 @@
#ifdef SUPPORT_PORTAUDIO
OBJ str;
if ((str = __INST(handle1)) != nil) {
- struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
+ struct paStreamData* streamData = (struct paStreamData*)__externalAddressVal(str);
struct paBuffer* buffer;
if (DEBUGGING) {
@@ -3428,22 +3744,22 @@
}
__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;
+ // Pa_StopStream( streamData->stream );
+ Pa_CloseStream( streamData->stream );
+
+ LOCK(streamData->lock);
+
+ buffer = streamData->currentBuffer;
+ streamData->currentBuffer = NULL;
+ streamData->lastBuffer = NULL;
while (buffer != NULL) {
struct paBuffer* nextBuffer = buffer->nextBuffer;
free(buffer->sampleData);
free(buffer);
buffer = nextBuffer;
}
- buffer = paStreamData->freeList;
- paStreamData->freeList = NULL;
+ buffer = streamData->freeList;
+ streamData->freeList = NULL;
while (buffer != NULL) {
struct paBuffer* nextBuffer = buffer->nextBuffer;
free(buffer->sampleData);
@@ -3451,9 +3767,9 @@
buffer = nextBuffer;
}
- UNLOCK(paStreamData->lock);
- RELEASELOCK(paStreamData->lock);
- free(paStreamData);
+ UNLOCK(streamData->lock);
+ RELEASELOCK(streamData->lock);
+ free(streamData);
}
RETURN (self);
#endif // SUPPORT_PORTAUDIO
@@ -3470,7 +3786,7 @@
static PaStreamParameters outputParameters;
PaStream *stream;
PaError paErr;
- struct paStreamData* paStreamData;
+ struct paStreamData* streamData;
int nChannels, sampleRate, bytesPerSample;
# define FRAMES_PER_BUFFER 128
@@ -3530,8 +3846,8 @@
sampleRate = 8000;
}
- paStreamData = (struct paStreamData*)malloc(sizeof(struct paStreamData));
- if (paStreamData == NULL) {
+ streamData = (struct paStreamData*)malloc(sizeof(struct paStreamData));
+ if (streamData == NULL) {
fprintf(stderr, "SoundStream [warning]: failed to allocate paStream\n");
errorStringOrNil = __MKSTRING("failed to allocate paStream");
goto out;
@@ -3545,35 +3861,35 @@
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
paCallback,
- paStreamData );
+ streamData );
if (paErr != paNoError) {
fprintf(stderr, "SoundStream [warning]: openStream: %s\n", Pa_GetErrorText( paErr ));
- free(paStreamData);
+ free(streamData);
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;
+ streamData->stream = stream;
+ INITLOCK(streamData->lock);
+ streamData->readOffset = 0;
+ streamData->bytesPerSample = bytesPerSample;
+ streamData->nChannels = nChannels;
+
+ streamData->currentBuffer = NULL;
+ streamData->lastBuffer = NULL;
+ streamData->freeList = NULL;
+ streamData->hasFinished = 0;
{
OBJ t;
- t = __MKEXTERNALADDRESS(paStreamData); __INST(handle1) = t; __STORE(self, t);
+ t = __MKEXTERNALADDRESS(streamData); __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);
+ free(streamData);
errorStringOrNil = __MKSTRING(Pa_GetErrorText( paErr ));
goto out;
};
@@ -3699,7 +4015,7 @@
if (__INST(mode) != @symbol(readonly)) {
if (__bothSmallInteger(count, start)) {
// allocate a buffer
- struct paStreamData* paStreamData = (struct paStreamData*)__externalAddressVal(str);
+ struct paStreamData* streamData = (struct paStreamData*)__externalAddressVal(str);
int cnt = __intVal(count);
int offs = __intVal(start) - 1;
int objSize;
@@ -3712,12 +4028,12 @@
unsigned char* newSampleData;
// try freeList
- LOCK(paStreamData->lock);
- if ((paStreamData->freeList != NULL)
- && (paStreamData->freeList->bufferSize == cnt)) {
+ LOCK(streamData->lock);
+ if ((streamData->freeList != NULL)
+ && (streamData->freeList->bufferSize == cnt)) {
// reuse
- newBuffer = paStreamData->freeList;
- paStreamData->freeList = newBuffer->nextBuffer;
+ newBuffer = streamData->freeList;
+ streamData->freeList = newBuffer->nextBuffer;
newSampleData = newBuffer->sampleData;
toFree = NULL;
if (DEBUGGING) {
@@ -3725,8 +4041,8 @@
}
} else {
// free them all
- toFree = paStreamData->freeList;
- paStreamData->freeList = NULL;
+ toFree = streamData->freeList;
+ streamData->freeList = NULL;
newBuffer = malloc(sizeof(struct paBuffer));
newSampleData = malloc(cnt);
newBuffer->sampleData = newSampleData;
@@ -3739,20 +4055,20 @@
memcpy(newSampleData, (__ByteArrayInstPtr(anObject)->ba_element)+offs, cnt);
newBuffer->nextBuffer = NULL;
- if (paStreamData->lastBuffer == NULL) {
+ if (streamData->lastBuffer == NULL) {
// start stream's buffer list
- paStreamData->currentBuffer = newBuffer;
+ streamData->currentBuffer = newBuffer;
mustStart = 1;
} else {
// append to stream's buffer list
- paStreamData->lastBuffer->nextBuffer = newBuffer;
+ streamData->lastBuffer->nextBuffer = newBuffer;
}
- paStreamData->lastBuffer = newBuffer;
- paStreamData->hasFinished = 0;
- UNLOCK(paStreamData->lock);
+ streamData->lastBuffer = newBuffer;
+ streamData->hasFinished = 0;
+ UNLOCK(streamData->lock);
if (mustStart) {
- PaError paErr = Pa_StartStream( paStreamData->stream );
+ PaError paErr = Pa_StartStream( streamData->stream );
if ( paErr != paNoError ) {
if (DEBUGGING) {
fprintf(stderr, "start error\n");