<div dir="ltr"><div>Cool. I've seen people asking about higher bit depth in Sound plugin. Maybe that will be easier to add now ?</div><div><br></div><div>Best,</div><div>Karl</div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Aug 1, 2020 at 4:45 AM <<a href="mailto:commits@source.squeak.org">commits@source.squeak.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> <br>
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:<br>
<a href="http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2785.mcz" rel="noreferrer" target="_blank">http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2785.mcz</a><br>
<br>
==================== Summary ====================<br>
<br>
Name: VMMaker.oscog-eem.2785<br>
Author: eem<br>
Time: 31 July 2020, 7:45:15.985473 pm<br>
UUID: 9fa77ef1-7255-47f3-9dd1-c500f9529cbb<br>
Ancestors: VMMaker.oscog-eem.2784<br>
<br>
Plugins: Clean up the SoundPlugin, eloiminating almost all cCode:'s, making it potentially simulateable once the internal API is implemented. Use the methodRetur...: API to simplify a number of primitives. Change primitiveSoundEnableAEC to take either 0, 1 or a boolean.<br>
<br>
Slang: eliminate the arguments to addressOf:put: blocks via nodeIsDeadCode:withParent:<br>
<br>
Simulation: implement unsigned coercion in cCoerce:to: to support this form in primitiveSoundEnableAEC<br>
(interpreterProxy isIntegerObject: (arg := interpreterProxy stackValue: 0))<br>
ifTrue:<br>
[arg := interpreterProxy integerValueOf: arg.<br>
(interpreterProxy cCoerce: arg to: #unsigned) > 1 ifTrue:<br>
[^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
trueOrFalse := arg = 1]<br>
ifFalse:<br>
[(interpreterProxy isBooleanObject: arg) ifFalse:<br>
[^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
trueOrFalse := interpreterProxy booleanValueOf: arg].<br>
<br>
=============== Diff against VMMaker.oscog-eem.2784 ===============<br>
<br>
Item was changed:<br>
----- Method: CCodeGenerator>>nodeIsDeadCode:withParent: (in category 'utilities') -----<br>
nodeIsDeadCode: aNode withParent: parentNode<br>
"Answer if aNode would not be generated due to dead code elimination."<br>
+ (aNode isLiteralBlock and: [parentNode isSend and: [parentNode selector == #addressOf:put:]]) ifTrue:<br>
+ [^true].<br>
^(self nilOrBooleanConditionFor: parentNode)<br>
ifNil: [false]<br>
ifNotNil:<br>
[:cond| | filter |<br>
filter := parentNode selector caseOf:<br>
{ "First element is accessor for filtered (eliminated) node if expression is true.<br>
Second element is accessor for filtered (eliminated) node if expression is false."<br>
[#ifFalse:] -> [#(first nil)].<br>
[#ifFalse:ifTrue:] -> [#(first last)].<br>
[#ifTrue:] -> [#(nil first)].<br>
[#ifTrue:ifFalse:] -> [#(last first)].<br>
[#and:] -> [#(nil first)].<br>
[#or:] -> [#(last nil)].<br>
[#cppIf:ifTrue:] -> [#(nil #second)].<br>
[#cppIf:ifTrue:ifFalse:] -> [#(third #second)] }.<br>
(cond ifTrue: [filter first] ifFalse: [filter last])<br>
ifNil: [false]<br>
ifNotNil: [:accessor| aNode == (parentNode args perform: accessor)]]!<br>
<br>
Item was changed:<br>
----- Method: Integer>>coerceTo:sim: (in category '*VMMaker-interpreter simulator') -----<br>
coerceTo: cTypeString sim: interpreter<br>
<br>
| unitSize |<br>
+ cTypeString last == $* ifTrue: "C pointer"<br>
- cTypeString last = $* ifTrue: "C pointer"<br>
[unitSize := cTypeString caseOf: {<br>
[#'char *'] -> [1].<br>
[#'short *'] -> [2].<br>
[#'int *'] -> [4].<br>
[#'long long *'] -> [8].<br>
[#'float *'] -> [^CFloatArray basicNew interpreter: interpreter address: self unitSize: 4; yourself].<br>
[#'double *'] -> [^CFloatArray basicNew interpreter: interpreter address: self unitSize: 8; yourself].<br>
[#'unsigned *'] -> [4].<br>
[#'unsigned int *'] -> [4].<br>
[#'unsigned char *'] -> [1].<br>
[#'signed char *'] -> [1].<br>
[#'unsigned short *'] -> [2].<br>
[#'unsigned long long *'] -> [8].<br>
[#'oop *'] -> [interpreter objectMemory bytesPerOop].<br>
}<br>
otherwise: [interpreter objectMemory wordSize].<br>
^CArray basicNew<br>
interpreter: interpreter address: self unitSize: unitSize;<br>
yourself].<br>
+ cTypeString first == $u ifTrue:<br>
+ [unitSize := cTypeString caseOf: {<br>
+ [#usqInt] -> [interpreter objectMemory wordSize].<br>
+ [#usqLong] -> [8].<br>
+ [#unsigned] -> [4].<br>
+ [#'unsigned int'] -> [4].<br>
+ [#'unsigned char'] -> [1].<br>
+ [#'unsigned long'] -> [6].<br>
+ [#'unsigned short'] -> [2].<br>
+ [#'unsigned long long'] -> [8].<br>
+ }<br>
+ otherwise: [self error: 'unknown unsigned type name'].<br>
+ ^self bitAnd: 1 << (8 * unitSize) - 1].<br>
+ ^self "C number (int, char, etc)"!<br>
- ^self "C number (int, char, float, etc)"!<br>
<br>
Item was added:<br>
+ ----- Method: InterpreterProxy>>cCoerce:to: (in category 'simulation only') -----<br>
+ cCoerce: value to: cTypeString<br>
+ "Type coercion. For translation a cast will be emitted. When running in Smalltalk<br>
+ answer a suitable wrapper for correct indexing."<br>
+ ^value<br>
+ ifNil: [value]<br>
+ ifNotNil: [value coerceTo: cTypeString sim: self]!<br>
<br>
Item was changed:<br>
----- Method: RePlugin>>rcvrMatchSpacePtr (in category 'rcvr linkage') -----<br>
rcvrMatchSpacePtr<br>
<br>
<inline: true><br>
<returnTypeC: 'int *'><br>
^self<br>
cCoerce: (interpreterProxy fetchArray: 7 ofObject: rcvr)<br>
+ to: #'int *'!<br>
- to: 'int *'.!<br>
<br>
Item was changed:<br>
----- Method: RePlugin>>rcvrPatternStrPtr (in category 'rcvr linkage') -----<br>
rcvrPatternStrPtr<br>
<br>
<inline: true><br>
<returnTypeC: 'char *'><br>
^self <br>
cCoerce: (interpreterProxy fetchArray: 0 ofObject: rcvr) <br>
+ to: #'char *'.!<br>
- to: 'char *'.!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveGetDefaultSoundPlayer (in category 'primitives') -----<br>
primitiveGetDefaultSoundPlayer<br>
"Answer a String with the operating system name of the default output device, or nil"<br>
"no arguments"<br>
- | cDeviceName sz newString newStringPtr |<br>
<export: true><br>
+ | cDeviceName |<br>
+ <var: #cDeviceName type: #'char*'><br>
- <var: #cDeviceName type: 'char*'><br>
- <var: #newStringPtr type: 'char*'><br>
<br>
- "Parse arguments"<br>
- interpreterProxy methodArgumentCount = 0 <br>
- ifFalse:[^interpreterProxy primitiveFail].<br>
- <br>
"Get the answer."<br>
+ cDeviceName := self getDefaultSoundPlayer.<br>
+ cDeviceName = 0 ifTrue:<br>
+ [^interpreterProxy methodReturnValue: interpreterProxy nilObject].<br>
- cDeviceName := self cCode: 'getDefaultSoundPlayer()'.<br>
- cDeviceName == 0 ifTrue: [<br>
- ^interpreterProxy pop: 1 thenPush: interpreterProxy nilObject<br>
- ].<br>
<br>
+ ^interpreterProxy methodReturnString: cDeviceName!<br>
- "Copy the answer to a Squeak String."<br>
- sz := self cCode: 'strlen(cDeviceName)'.<br>
- newString := interpreterProxy <br>
- instantiateClass: interpreterProxy classString<br>
- indexableSize: sz.<br>
- newStringPtr := interpreterProxy firstIndexableField: newString.<br>
- self cCode: 'strncpy(newStringPtr, cDeviceName, sz)'.<br>
- <br>
- self touch: newStringPtr.<br>
- self touch: cDeviceName.<br>
- "Pop the receiver, and answer the new string."<br>
- ^interpreterProxy pop: 1 thenPush: newString!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveGetDefaultSoundRecorder (in category 'primitives') -----<br>
primitiveGetDefaultSoundRecorder<br>
"Answer a String with the operating system name of the default input device, or nil"<br>
"no arguments"<br>
- | cDeviceName sz newString newStringPtr |<br>
<export: true><br>
+ | cDeviceName |<br>
+ <var: #cDeviceName type: #'char*'><br>
- <var: #cDeviceName type: 'char*'><br>
- <var: #newStringPtr type: 'char*'><br>
<br>
- "Parse arguments"<br>
- interpreterProxy methodArgumentCount = 0 <br>
- ifFalse:[^interpreterProxy primitiveFail].<br>
- <br>
"Get the answer."<br>
+ cDeviceName := self getDefaultSoundRecorder.<br>
+ cDeviceName = 0 ifTrue:<br>
+ [^interpreterProxy methodReturnValue: interpreterProxy nilObject].<br>
- cDeviceName := self cCode: 'getDefaultSoundRecorder()'.<br>
- cDeviceName == 0 ifTrue: [<br>
- ^interpreterProxy pop: 1 thenPush: interpreterProxy nilObject<br>
- ].<br>
<br>
+ ^interpreterProxy methodReturnString: cDeviceName!<br>
- "Copy the answer to a Squeak String."<br>
- sz := self cCode: 'strlen(cDeviceName)'.<br>
- newString := interpreterProxy <br>
- instantiateClass: interpreterProxy classString<br>
- indexableSize: sz.<br>
- newStringPtr := interpreterProxy firstIndexableField: newString.<br>
- self cCode: 'strncpy(newStringPtr, cDeviceName, sz)'.<br>
- <br>
- self touch: newStringPtr.<br>
- self touch: cDeviceName.<br>
- "Pop the receiver, and answer the new string."<br>
- ^interpreterProxy pop: 1 thenPush: newString!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveGetNumberOfSoundPlayerDevices (in category 'primitives') -----<br>
primitiveGetNumberOfSoundPlayerDevices<br>
- "arguments: name(type, stack offset)<br>
- dialString(String, 0)"<br>
- "answers an Integer"<br>
- | result |<br>
<export: true><br>
<br>
+ ^interpreterProxy methodReturnInteger: self getNumberOfSoundPlayerDevices!<br>
- "Parse arguments"<br>
- interpreterProxy methodArgumentCount = 0 <br>
- ifFalse:[^interpreterProxy primitiveFail].<br>
- <br>
- "get result"<br>
- result := self cCode: 'getNumberOfSoundPlayerDevices()'.<br>
- <br>
- "answer it"<br>
- result := interpreterProxy signed32BitIntegerFor: result.<br>
- ^interpreterProxy pop: 1 thenPush: result. "pop receiver, return result"!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveGetNumberOfSoundRecorderDevices (in category 'primitives') -----<br>
primitiveGetNumberOfSoundRecorderDevices<br>
- "arguments: name(type, stack offset)<br>
- dialString(String, 0)"<br>
- "answers an Integer"<br>
- | result |<br>
<export: true><br>
<br>
+ ^interpreterProxy methodReturnInteger: self getNumberOfSoundRecorderDevices!<br>
- "Parse arguments"<br>
- interpreterProxy methodArgumentCount = 0 <br>
- ifFalse:[^interpreterProxy primitiveFail].<br>
- <br>
- "get result"<br>
- result := self cCode: 'getNumberOfSoundRecorderDevices()'.<br>
- <br>
- "answer it"<br>
- result := interpreterProxy signed32BitIntegerFor: result.<br>
- ^interpreterProxy pop: 1 thenPush: result. "pop receiver, return result"!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveGetSoundPlayerDeviceName (in category 'primitives') -----<br>
primitiveGetSoundPlayerDeviceName<br>
"arguments: name(type, stack offset)<br>
deviceNumber(Integer, 0)"<br>
"answers a string or nil"<br>
- | deviceNumber sz cDeviceName newString newStringPtr |<br>
<export: true><br>
+ | deviceNumber cDeviceName |<br>
+ <var: #cDeviceName type: #'char *'><br>
- <var: #cDeviceName type: 'char*'><br>
- <var: #newStringPtr type: 'char*'><br>
<br>
"Parse arguments" <br>
+ interpreterProxy methodArgumentCount = 1 ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadNumArgs].<br>
- interpreterProxy methodArgumentCount = 1 <br>
- ifFalse:[^interpreterProxy primitiveFail].<br>
<br>
deviceNumber := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0).<br>
+ interpreterProxy failed ifTrue:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
- interpreterProxy failed ifTrue: [^nil].<br>
<br>
"Get the answer."<br>
+ cDeviceName := self getSoundPlayerDeviceName: deviceNumber - 1.<br>
+ cDeviceName = 0 ifTrue:<br>
+ [^interpreterProxy methodReturnValue: interpreterProxy nilObject].<br>
- cDeviceName := self cCode: 'getSoundPlayerDeviceName(deviceNumber - 1)'.<br>
- cDeviceName == 0 ifTrue: [<br>
- ^interpreterProxy pop: 2 thenPush: interpreterProxy nilObject<br>
- ].<br>
<br>
+ ^interpreterProxy methodReturnString: cDeviceName!<br>
- "Copy the answer to a Squeak String."<br>
- sz := self cCode: 'strlen(cDeviceName)'.<br>
- newString := interpreterProxy <br>
- instantiateClass: interpreterProxy classString<br>
- indexableSize: sz.<br>
- newStringPtr := interpreterProxy firstIndexableField: newString.<br>
- self cCode: 'strncpy(newStringPtr, cDeviceName, sz)'.<br>
- <br>
- self touch: deviceNumber.<br>
- self touch: newStringPtr.<br>
- self touch: cDeviceName.<br>
- "Pop the receiver and arg, and answer the new string."<br>
- ^interpreterProxy pop: 2 thenPush: newString!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveGetSoundRecorderDeviceName (in category 'primitives') -----<br>
primitiveGetSoundRecorderDeviceName<br>
"arguments: name(type, stack offset)<br>
deviceNumber(Integer, 0)"<br>
"answers a string or nil"<br>
- | deviceNumber sz cDeviceName newString newStringPtr |<br>
<export: true><br>
+ | deviceNumber cDeviceName |<br>
+ <var: #cDeviceName type: #'char *'><br>
- <var: #cDeviceName type: 'char*'><br>
- <var: #newStringPtr type: 'char*'><br>
<br>
"Parse arguments" <br>
+ interpreterProxy methodArgumentCount = 1 ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadNumArgs].<br>
- interpreterProxy methodArgumentCount = 1 <br>
- ifFalse:[^interpreterProxy primitiveFail].<br>
<br>
- <br>
deviceNumber := interpreterProxy positive32BitValueOf: (interpreterProxy stackValue: 0).<br>
+ interpreterProxy failed ifTrue:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
- interpreterProxy failed ifTrue: [^nil].<br>
<br>
"Get the answer."<br>
+ cDeviceName := self getSoundRecorderDeviceName: deviceNumber - 1.<br>
+ cDeviceName = 0 ifTrue:<br>
+ [^interpreterProxy methodReturnValue: interpreterProxy nilObject].<br>
- cDeviceName := self cCode: 'getSoundRecorderDeviceName(deviceNumber - 1)'.<br>
- cDeviceName == 0 ifTrue: [<br>
- ^interpreterProxy pop: 2 thenPush: interpreterProxy nilObject<br>
- ].<br>
<br>
+ ^interpreterProxy methodReturnString: cDeviceName!<br>
- "Copy the answer to a Squeak String."<br>
- sz := self cCode: 'strlen(cDeviceName)'.<br>
- newString := interpreterProxy <br>
- instantiateClass: interpreterProxy classString<br>
- indexableSize: sz.<br>
- newStringPtr := interpreterProxy firstIndexableField: newString.<br>
- self cCode: 'strncpy(newStringPtr, cDeviceName, sz)'.<br>
- <br>
- self touch: deviceNumber.<br>
- self touch: newStringPtr.<br>
- self touch: cDeviceName.<br>
- "Pop the receiver and arg, and answer the new string."<br>
- ^interpreterProxy pop: 2 thenPush: newString!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSetDefaultSoundPlayer (in category 'primitives') -----<br>
primitiveSetDefaultSoundPlayer<br>
"Tell the operating system to use the specified device name as the output device for sound."<br>
"arg at top of stack is the String"<br>
- | deviceName obj srcPtr sz |<br>
<export: true><br>
+ | deviceName obj srcPtr sz |<br>
<var: 'deviceName' declareC: 'char deviceName[257]'><br>
<var: 'srcPtr' type: #'char *'><br>
+ self cCode: [] inSmalltalk: [deviceName := ByteString new: 257].<br>
- <br>
"Parse arguments"<br>
interpreterProxy methodArgumentCount = 1 ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadNumArgs].<br>
+ ((interpreterProxy isBytes: (obj := interpreterProxy stackValue: 0))<br>
+ and: [(sz := interpreterProxy byteSizeOf: obj) <= 256]) ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
+ <br>
+ srcPtr := self cCoerce: (interpreterProxy firstIndexableField: obj) to: #'char *'.<br>
+ self strncpy: deviceName _: srcPtr _: sz.<br>
+ deviceName at: sz put: 0.<br>
+ self setDefaultSoundPlayer: deviceName.<br>
+ <br>
+ interpreterProxy failed ifFalse:<br>
+ [interpreterProxy methodReturnReceiver]!<br>
- [^interpreterProxy primitiveFail].<br>
- obj := interpreterProxy stackValue: 0.<br>
- (interpreterProxy isBytes: obj) ifFalse:<br>
- [^interpreterProxy primitiveFail].<br>
- (sz := interpreterProxy byteSizeOf: obj) <= 256 ifFalse:<br>
- [^interpreterProxy primitiveFail].<br>
- srcPtr := interpreterProxy firstIndexableField: obj.<br>
- self touch: srcPtr.<br>
- self touch: deviceName.<br>
- self touch: sz.<br>
- self cCode: 'strncpy(deviceName, srcPtr, sz)'.<br>
- self cCode: 'deviceName[sz] = 0'.<br>
- <br>
- "do the work"<br>
- self cCode: 'setDefaultSoundPlayer(deviceName)'.<br>
- interpreterProxy failed ifFalse: "pop arg, leave receiver"<br>
- [interpreterProxy pop: 1]!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSetDefaultSoundRecorder (in category 'primitives') -----<br>
primitiveSetDefaultSoundRecorder<br>
"Tell the operating system to use the specified device name as the input device for sound."<br>
"arg at top of stack is the String"<br>
- | deviceName obj srcPtr sz |<br>
<export: true><br>
+ | deviceName obj srcPtr sz |<br>
<var: 'deviceName' declareC: 'char deviceName[257]'><br>
<var: 'srcPtr' type: #'char *'><br>
+ self cCode: [] inSmalltalk: [deviceName := ByteString new: 257].<br>
- <br>
"Parse arguments"<br>
interpreterProxy methodArgumentCount = 1 ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadNumArgs].<br>
+ ((interpreterProxy isBytes: (obj := interpreterProxy stackValue: 0))<br>
+ and: [(sz := interpreterProxy byteSizeOf: obj) <= 256]) ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
+ <br>
+ srcPtr := self cCoerce: (interpreterProxy firstIndexableField: obj) to: #'char *'.<br>
+ self strncpy: deviceName _: srcPtr _: sz.<br>
+ deviceName at: sz put: 0.<br>
+ self setDefaultSoundRecorder: deviceName.<br>
+ <br>
+ interpreterProxy failed ifFalse:<br>
+ [interpreterProxy methodReturnReceiver]!<br>
- [^interpreterProxy primitiveFail].<br>
- obj := interpreterProxy stackValue: 0.<br>
- (interpreterProxy isBytes: obj) ifFalse:<br>
- [^interpreterProxy primitiveFail].<br>
- (sz := interpreterProxy byteSizeOf: obj) <= 256 ifFalse:<br>
- [^interpreterProxy primitiveFail].<br>
- srcPtr := interpreterProxy firstIndexableField: obj.<br>
- self touch: srcPtr.<br>
- self touch: deviceName.<br>
- self touch: sz.<br>
- self cCode: 'strncpy(deviceName, srcPtr, sz)'.<br>
- self cCode: 'deviceName[sz] = 0'.<br>
- <br>
- "do the work"<br>
- self cCode: 'setDefaultSoundRecorder(deviceName)'.<br>
- interpreterProxy failed ifFalse: "pop arg, leave receiver"<br>
- [interpreterProxy pop: 1]!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundAvailableSpace (in category 'primitives') -----<br>
primitiveSoundAvailableSpace<br>
+ "Returns the number of bytes of available sound output buffer space.<br>
+ This should be (frames*4) if the device is in stereo mode, or (frames*2) otherwise"<br>
- "Returns the number of bytes of available sound output buffer space. This should be (frames*4) if the device is in stereo mode, or (frames*2) otherwise"<br>
<br>
+ <export: true><br>
| frames |<br>
+ frames := self snd_AvailableSpace. "-1 if sound output not started"<br>
+ frames >= 0<br>
+ ifTrue: [interpreterProxy methodReturnInteger: frames]<br>
+ ifFalse: [interpreterProxy primitiveFail]!<br>
- self primitive: 'primitiveSoundAvailableSpace'.<br>
- frames := self cCode: 'snd_AvailableSpace()'. "-1 if sound output not started"<br>
- interpreterProxy success: frames >= 0.<br>
- ^frames asPositiveIntegerObj!<br>
<br>
Item was added:<br>
+ ----- Method: SoundPlugin>>primitiveSoundEnableAEC (in category 'primitives') -----<br>
+ primitiveSoundEnableAEC<br>
+ "Enable or disable acoustic echo-cancellation (AEC).<br>
+ Arg is a boolean or 1 for true and 0 for false."<br>
+ <export: true><br>
+ | arg trueOrFalse errorCode |<br>
+ interpreterProxy methodArgumentCount = 1 ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadNumArgs].<br>
+ "Parse arguments"<br>
+ (interpreterProxy isIntegerObject: (arg := interpreterProxy stackValue: 0))<br>
+ ifTrue:<br>
+ [arg := interpreterProxy integerValueOf: arg.<br>
+ (interpreterProxy cCoerce: arg to: #unsigned) > 1 ifTrue:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
+ trueOrFalse := arg = 1]<br>
+ ifFalse:<br>
+ [(interpreterProxy isBooleanObject: arg) ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
+ trueOrFalse := interpreterProxy booleanValueOf: arg].<br>
+ "Set AEC"<br>
+ (errorCode := self snd_EnableAEC: trueOrFalse) ~= 0 ifTrue:<br>
+ [interpreterProxy primitiveFailFor: (errorCode < 0 ifTrue: [PrimErrGenericFailure] ifFalse: [errorCode])]!<br>
<br>
Item was removed:<br>
- ----- Method: SoundPlugin>>primitiveSoundEnableAEC: (in category 'primitives') -----<br>
- primitiveSoundEnableAEC: trueOrFalse <br>
- "Enable or disable acoustic echo-cancellation (AEC). trueOrFalse should be 0 for false, and 1 for true."<br>
- | result |<br>
- self primitive: 'primitiveSoundEnableAEC' parameters: #(SmallInteger ).<br>
- interpreterProxy failed ifFalse: [<br>
- result := self cCode: 'snd_EnableAEC(trueOrFalse)'.<br>
- result == 0 ifFalse: [interpreterProxy primitiveFailFor: result].<br>
- ].!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundGetRecordLevel (in category 'primitives') -----<br>
primitiveSoundGetRecordLevel<br>
+ "Get the default input device's volume level in the range 0-1000."<br>
+ <export: true><br>
- "Get the sound input recording level in the range 0-1000."<br>
| level |<br>
<var: 'level' type: #int><br>
+ level := self snd_GetRecordLevel.<br>
+ ^level >= 0<br>
+ ifTrue: [interpreterProxy methodReturnInteger: level]<br>
+ ifFalse: [interpreterProxy primitiveFail]!<br>
- self primitive: 'primitiveSoundGetRecordLevel'.<br>
- level := self cCode: 'snd_GetRecordLevel()'.<br>
- ^level asPositiveIntegerObj<br>
- !<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundGetRecordingSampleRate (in category 'primitives') -----<br>
primitiveSoundGetRecordingSampleRate<br>
"Return a float representing the actual sampling rate during recording. Fail if not currently recording."<br>
<br>
+ <export: true><br>
| rate |<br>
+ <var: #rate type: #double><br>
+ rate := self snd_GetRecordingSampleRate. "fails if not recording"<br>
+ interpreterProxy failed ifFalse:<br>
+ [^interpreterProxy methodReturnFloat: rate]!<br>
- <var: #rate type: 'double '><br>
- self primitive: 'primitiveSoundGetRecordingSampleRate'.<br>
- rate := self cCode: 'snd_GetRecordingSampleRate()'. "fail if not recording"<br>
- ^rate asFloatObj!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundGetVolume (in category 'primitives') -----<br>
primitiveSoundGetVolume<br>
+ "Get the default output device's volume level as a left/right pair of floats in the range 0-1."<br>
+ <export: true><br>
+ | left right leftOop rightOop results |<br>
- "Get the sound input recording level."<br>
- | left right results |<br>
<var: #left type: #double><br>
<var: #right type: #double><br>
+ left := 0.0.<br>
+ right := 0.0.<br>
+ self snd_Volume: (self addressOf: left put: [:v| left := v]) _: (self addressOf: right put: [:v| right := v]).<br>
+ interpreterProxy failed ifTrue:<br>
+ [^self].<br>
+ results := interpreterProxy instantiateClass: interpreterProxy classArray indexableSize: 2.<br>
+ results ifNil:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrNoMemory].<br>
+ self remapOop: results in:<br>
+ [leftOop := interpreterProxy floatObjectOf: left.<br>
+ self remapOop: leftOop in:<br>
+ [rightOop := interpreterProxy floatObjectOf: right]].<br>
+ interpreterProxy<br>
+ storePointer: 0 ofObject: results withValue: leftOop;<br>
+ storePointer: 1 ofObject: results withValue: rightOop;<br>
+ methodReturnValue: results!<br>
- self primitive: 'primitiveSoundGetVolume'<br>
- parameters: #( ).<br>
- left := 0.<br>
- right := 0.<br>
- self cCode: 'snd_Volume((double *) &left,(double *) &right)'.<br>
- interpreterProxy pushRemappableOop: (right asOop: Float).<br>
- interpreterProxy pushRemappableOop: (left asOop: Float).<br>
- results := interpreterProxy instantiateClass: (interpreterProxy classArray) indexableSize: 2.<br>
- interpreterProxy storePointer: 0 ofObject: results withValue: interpreterProxy popRemappableOop.<br>
- interpreterProxy storePointer: 1 ofObject: results withValue: interpreterProxy popRemappableOop.<br>
- ^results!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundInsertSamples:from:leadTime: (in category 'primitives') -----<br>
primitiveSoundInsertSamples: frameCount from: buf leadTime: leadTime <br>
"Insert a buffer's worth of sound samples into the currently playing <br>
buffer. Used to make a sound start playing as quickly as possible. The <br>
new sound is mixed with the previously buffered sampled."<br>
"Details: Unlike primitiveSoundPlaySamples, this primitive always starts <br>
with the first sample the given sample buffer. Its third argument <br>
specifies the number of samples past the estimated sound output buffer <br>
position the inserted sound should start. If successful, it returns the <br>
number of samples inserted."<br>
| framesPlayed |<br>
self primitive: 'primitiveSoundInsertSamples'<br>
+ parameters: #(SmallInteger WordArray SmallInteger).<br>
+ frameCount <= (interpreterProxy slotSizeOf: buf cPtrAsOop) ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
- parameters: #(SmallInteger WordArray SmallInteger ).<br>
- interpreterProxy success: frameCount <= (interpreterProxy slotSizeOf: buf cPtrAsOop).<br>
<br>
+ framesPlayed := self snd_InsertSamplesFromLeadTime: frameCount _: buf _: leadTime.<br>
+ framesPlayed >= 0<br>
+ ifTrue: [interpreterProxy methodReturnInteger: framesPlayed]<br>
+ ifFalse: [interpreterProxy primitiveFail]!<br>
- interpreterProxy failed<br>
- ifFalse: [framesPlayed := self cCode: 'snd_InsertSamplesFromLeadTime(frameCount, (void *)buf, leadTime)'.<br>
- interpreterProxy success: framesPlayed >= 0].<br>
- ^ framesPlayed asPositiveIntegerObj!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundPlaySamples:from:startingAt: (in category 'primitives') -----<br>
primitiveSoundPlaySamples: frameCount from: buf startingAt: startIndex <br>
"Output a buffer's worth of sound samples."<br>
| framesPlayed |<br>
self primitive: 'primitiveSoundPlaySamples'<br>
+ parameters: #(SmallInteger WordArray SmallInteger).<br>
+ (startIndex >= 1 and: [startIndex + frameCount - 1 <= (interpreterProxy slotSizeOf: buf cPtrAsOop)]) ifTrue:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadArgument].<br>
- parameters: #(SmallInteger WordArray SmallInteger ).<br>
- interpreterProxy success: (startIndex >= 1 and: [startIndex + frameCount - 1 <= (interpreterProxy slotSizeOf: buf cPtrAsOop)]).<br>
<br>
+ framesPlayed := self snd_PlaySamplesFromAtLength: frameCount _: buf _: startIndex - 1.<br>
+ framesPlayed >= 0<br>
+ ifTrue: [interpreterProxy methodReturnInteger: framesPlayed]<br>
+ ifFalse: [interpreterProxy primitiveFail]!<br>
- interpreterProxy failed<br>
- ifFalse: [framesPlayed := self cCode: 'snd_PlaySamplesFromAtLength(frameCount, (void *)buf, startIndex - 1)'.<br>
- interpreterProxy success: framesPlayed >= 0].<br>
- ^ framesPlayed asPositiveIntegerObj!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundPlaySilence (in category 'primitives') -----<br>
primitiveSoundPlaySilence<br>
"Output a buffer's worth of silence. Returns the number of sample frames played."<br>
<br>
+ <export: true><br>
| framesPlayed |<br>
+ framesPlayed := self snd_PlaySilence. "-1 if sound output not started"<br>
+ framesPlayed >= 0<br>
+ ifTrue: [interpreterProxy methodReturnInteger: framesPlayed]<br>
+ ifFalse: [interpreterProxy primitiveFail]!<br>
- self primitive: 'primitiveSoundPlaySilence'.<br>
- framesPlayed := self cCode: 'snd_PlaySilence()'. "-1 if sound output not started"<br>
- interpreterProxy success: framesPlayed >= 0.<br>
- ^framesPlayed asPositiveIntegerObj!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundRecordSamplesInto:startingAt: (in category 'primitives') -----<br>
primitiveSoundRecordSamplesInto: buf startingAt: startWordIndex <br>
"Record a buffer's worth of 16-bit sound samples."<br>
+ | bufSizeInBytes samplesRecorded bufPtr byteOffset |<br>
- | bufSizeInBytes samplesRecorded bufPtr byteOffset bufLen |<br>
<var: #bufPtr type: #'char*'><br>
self primitive: 'primitiveSoundRecordSamples'<br>
+ parameters: #(WordArray SmallInteger).<br>
- parameters: #(WordArray SmallInteger ).<br>
<br>
+ bufSizeInBytes := (interpreterProxy slotSizeOf: buf cPtrAsOop) * 4.<br>
+ byteOffset := (startWordIndex - 1) * 2.<br>
- interpreterProxy failed ifFalse:<br>
- [bufSizeInBytes := (interpreterProxy slotSizeOf: buf cPtrAsOop) * 4.<br>
- interpreterProxy success: (startWordIndex >= 1 and: [startWordIndex - 1 * 2 < bufSizeInBytes])].<br>
<br>
+ (startWordIndex >= 1 and: [byteOffset < bufSizeInBytes]) ifFalse:<br>
+ [^interpreterProxy primitiveFailFor: PrimErrBadIndex].<br>
- interpreterProxy failed ifFalse:[<br>
- byteOffset := (startWordIndex - 1) * 2.<br>
- bufPtr := (self cCoerce: buf to: 'char*') + byteOffset.<br>
- bufLen := bufSizeInBytes - byteOffset.<br>
- samplesRecorded := self cCode: 'snd_RecordSamplesIntoAtLength(bufPtr, 0, bufLen)' inSmalltalk:[bufPtr. bufLen. 0].<br>
- ].<br>
<br>
+ bufPtr := (self cCoerce: buf to: #'char *') + byteOffset.<br>
+ samplesRecorded := self snd_RecordSamplesIntoAtLength: bufPtr _: 0 _: bufSizeInBytes - byteOffset.<br>
+ interpreterProxy failed ifFalse:<br>
+ [^samplesRecorded asPositiveIntegerObj]!<br>
- ^ samplesRecorded asPositiveIntegerObj!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundSetLeftVolume:rightVolume: (in category 'primitives') -----<br>
primitiveSoundSetLeftVolume: aLeftVolume rightVolume: aRightVolume<br>
"Set the sound input recording level."<br>
<br>
self primitive: 'primitiveSoundSetLeftVolume'<br>
parameters: #(Float Float).<br>
+ self snd_SetVolume: aLeftVolume _: aRightVolume!<br>
- interpreterProxy failed ifFalse: [self cCode: 'snd_SetVolume(aLeftVolume,aRightVolume)'].<br>
- !<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundSetRecordLevel: (in category 'primitives') -----<br>
primitiveSoundSetRecordLevel: level <br>
"Set the sound input recording level."<br>
self primitive: 'primitiveSoundSetRecordLevel'<br>
+ parameters: #(SmallInteger).<br>
+ self snd_SetRecordLevel: level!<br>
- parameters: #(SmallInteger ).<br>
- interpreterProxy failed ifFalse: [self cCode: 'snd_SetRecordLevel(level)']!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundStartBufferSize:rate:stereo: (in category 'primitives') -----<br>
primitiveSoundStartBufferSize: bufFrames rate: samplesPerSec stereo: stereoFlag<br>
"Start the double-buffered sound output with the given buffer size, sample rate, and stereo flag."<br>
<br>
self primitive: 'primitiveSoundStart'<br>
parameters: #(SmallInteger SmallInteger Boolean).<br>
+ interpreterProxy success: (self snd_Start: bufFrames _: samplesPerSec _: stereoFlag _: 0)!<br>
- interpreterProxy success: (self cCode: 'snd_Start(bufFrames, samplesPerSec, stereoFlag, 0)')!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundStartBufferSize:rate:stereo:semaIndex: (in category 'primitives') -----<br>
primitiveSoundStartBufferSize: bufFrames rate: samplesPerSec stereo: stereoFlag semaIndex: semaIndex<br>
"Start the double-buffered sound output with the given buffer size, sample rate, stereo flag, and semaphore index."<br>
<br>
self primitive: 'primitiveSoundStartWithSemaphore'<br>
parameters: #(SmallInteger SmallInteger Boolean SmallInteger).<br>
+ interpreterProxy success: (self snd_Start: bufFrames _: samplesPerSec _: stereoFlag _: semaIndex)!<br>
- interpreterProxy success: (self cCode: 'snd_Start(bufFrames, samplesPerSec, stereoFlag, semaIndex)')!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundStartRecordingDesiredSampleRate:stereo:semaIndex: (in category 'primitives') -----<br>
primitiveSoundStartRecordingDesiredSampleRate: desiredSamplesPerSec stereo: stereoFlag semaIndex: semaIndex<br>
"Start recording sound with the given parameters."<br>
<br>
self primitive: 'primitiveSoundStartRecording'<br>
parameters: #(SmallInteger Boolean SmallInteger).<br>
+ self snd_StartRecording: desiredSamplesPerSec _: stereoFlag _: semaIndex!<br>
- self cCode: 'snd_StartRecording(desiredSamplesPerSec, stereoFlag, semaIndex)'!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundStop (in category 'primitives') -----<br>
primitiveSoundStop<br>
"Stop double-buffered sound output."<br>
+ <export: true><br>
+ self snd_Stop!<br>
- <br>
- self primitive: 'primitiveSoundStop'.<br>
- <br>
- self cCode: 'snd_Stop()'. "leave rcvr on stack"!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundStopRecording (in category 'primitives') -----<br>
primitiveSoundStopRecording<br>
"Stop recording sound."<br>
+ <export: true><br>
+ self snd_StopRecording!<br>
- <br>
- self primitive: 'primitiveSoundStopRecording'.<br>
- self cCode: 'snd_StopRecording()'. "leave rcvr on stack"!<br>
<br>
Item was changed:<br>
----- Method: SoundPlugin>>primitiveSoundSupportsAEC (in category 'primitives') -----<br>
primitiveSoundSupportsAEC<br>
+ "Answer if the OS/hardware supports echo-cancellation."<br>
+ <export: true><br>
- "Answer true if the OS/hardware supports echo-cancellation, and false otherwise."<br>
| result |<br>
+ result := self snd_SupportsAEC.<br>
+ interpreterProxy failed ifFalse:<br>
+ [interpreterProxy methodReturnBool: result ~= 0]!<br>
- self primitive: 'primitiveSoundSupportsAEC'.<br>
- interpreterProxy failed ifFalse: [<br>
- result := self cCode: 'snd_SupportsAEC()'.<br>
- result == 0 ifTrue: [^interpreterProxy falseObject] ifFalse: [^interpreterProxy trueObject]<br>
- ].<br>
- !<br>
<br>
Item was changed:<br>
----- Method: VMClass>>cCoerce:to: (in category 'memory access') -----<br>
cCoerce: value to: cTypeString<br>
+ "Type coercion. For translation a cast will be emitted. When running in Smalltalk<br>
- "Type coercion. For translation a cast will be emmitted. When running in Smalltalk<br>
answer a suitable wrapper for correct indexing."<br>
<doNotGenerate><br>
^value<br>
ifNil: [value]<br>
ifNotNil: [value coerceTo: cTypeString sim: self]!<br>
<br>
Item was changed:<br>
----- Method: VMPluginCodeGenerator>>shouldGenerateAsInterpreterProxySend: (in category 'utilities') -----<br>
shouldGenerateAsInterpreterProxySend: aSendNode<br>
"Answer if this send should be generated as interpreterProxy->foo or its moral equivalent (*).<br>
(*) since we now use function pointers declared in each external plugin we only indirect through<br>
interopreterProxy at plugin initialization. But we still have to find the set of sends a plugin uses."<br>
| selector |<br>
(aSendNode receiver isVariable and: ['interpreterProxy' = aSendNode receiver name]) ifFalse: [^false].<br>
selector := aSendNode selector.<br>
"baseHeaderSize, minSmallInteger et al are #defined in each VM's interp.h"<br>
(VMBasicConstants mostBasicConstantSelectors includes: selector) ifTrue: [^false].<br>
"Only include genuine InterpreterProxy methods, excluding things not understood<br>
+ by InterpreterProxy and things in its initialize, private and simulation protocols."<br>
+ ^(#(initialize private #'simulation only') includes: (InterpreterProxy compiledMethodAt: selector ifAbsent: [^false]) protocol) not!<br>
- by InterpreterProxy and things in its initialize and private protocols."<br>
- ^(#(initialize private) includes: (InterpreterProxy compiledMethodAt: selector ifAbsent: [^false]) protocol) not!<br>
<br>
</blockquote></div>