**Mac OS X: volume control** [bll] 2017-2-16: This was a pain to figure out...and it is not quite working. When using a tclkit I built (rkeene's), I have the following problem. Using the MacPorts tclsh works fine. ====== % load macvolume.dylib dlopen(macvolume.dylib, 6): Symbol not found: _Tcl_CreateObjCommand Referenced from: macvolume.dylib Expected in: flat namespace in macvolume.dylib % load -global macvolume.dylib dlopen(macvolume.dylib, 10): Symbol not found: _Tcl_CreateObjCommand Referenced from: macvolume.dylib Expected in: flat namespace in macvolume.dylib ====== '''Example Usage''' ====== load [file join [pwd] macvolume[info sharedlibextension]] set vol [macvolume] ; # get the volume incr vol -10 set newvol [macvolume $vol] ; # set the volume, always returns the current volume. ====== '''mkvol.sh''' ====== #!/bin/bash set -x lpath=/Users/bll/tcl/build/tcl/Deployment ipath=/Users/bll/tcl/build/tcl/Tcl.framework/Versions/8.6/Headers tcllib=libtclstub8.6.a tcllibnm=tclstub8.6 swiftc -O -o macvolume volume.swift main.swift swiftc -O -emit-library \ -I$ipath -import-objc-header tclbridge.h \ volume.swift tclmacvol.swift \ -Xlinker -undefined -Xlinker dynamic_lookup \ -Xlinker -L$lpath \ -l$tcllibnm \ -o macvolume.dylib ====== '''volume.swift''' ====== import AudioToolbox func macvolume_cmd (set: Int32, vol: Int32) -> Int32 { var defaultOutputDeviceID = AudioDeviceID(0) var defaultOutputDeviceIDSize = UInt32(MemoryLayout.size(ofValue:defaultOutputDeviceID)) var getDefaultOutputDevicePropertyAddress = AudioObjectPropertyAddress( mSelector: AudioObjectPropertySelector(kAudioHardwarePropertyDefaultOutputDevice), mScope: AudioObjectPropertyScope(kAudioObjectPropertyScopeGlobal), mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)) AudioObjectGetPropertyData( AudioObjectID(kAudioObjectSystemObject), &getDefaultOutputDevicePropertyAddress, 0, nil, &defaultOutputDeviceIDSize, &defaultOutputDeviceID) var volume = Float32() var volumeSize = UInt32(MemoryLayout.size(ofValue:volume)) var volumePropertyAddress = AudioObjectPropertyAddress( mSelector: AudioObjectPropertySelector(kAudioHardwareServiceDeviceProperty_VirtualMasterVolume), mScope: AudioObjectPropertyScope(kAudioDevicePropertyScopeOutput), mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster)) if (set == 1) { volume = Float(vol) / 100.0 AudioHardwareServiceSetPropertyData( defaultOutputDeviceID, &volumePropertyAddress, 0, nil, volumeSize, &volume) } AudioHardwareServiceGetPropertyData( defaultOutputDeviceID, &volumePropertyAddress, 0, nil, &volumeSize, &volume) let ivol = Int32(round(volume*100.0)) return ivol } ====== '''main.swift''' ====== import Foundation var vol = Int32(0) var set = Int32(0) if (CommandLine.argc > 1) { vol = Int32((CommandLine.arguments[1] as NSString).integerValue) set = 1 } var rvol = Int32() rvol = macvolume_cmd (set:set, vol:vol) print ("\(rvol)"); ====== '''tclbridge.h''' ====== #include "tcl.h" ====== '''tclmacvol.swift''' ====== func Macvolume_Cmd(cdata: ClientData?, interp: UnsafeMutablePointer?, objc: Int32, objv: UnsafePointer?>?) -> Int32 { var vol = Int32(0) var rc = Int32(0) var set = Int32(0) if (objc != 1 && objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, nil) return TCL_ERROR } if (objc == 2) { rc = Tcl_GetIntFromObj (interp, objv![1], &vol); if (rc == 0) { } // clear compiler warning set = 1 } var rvol = Int32() rvol = macvolume_cmd (set:set, vol:vol) Tcl_SetObjResult(interp, Tcl_NewIntObj(rvol)) return TCL_OK } @_cdecl("Macvolume_Init") public func Macvolume_Init( interp: UnsafeMutablePointer) -> Int32 { if Tcl_InitStubs(interp, TCL_VERSION, 0) == nil { return TCL_ERROR; } Tcl_CreateObjCommand(interp, "::macvolume", Macvolume_Cmd, nil, nil); Tcl_PkgProvide(interp, "macvolume", "0.1"); return TCL_OK } ====== <>Mac | Multimedia