Platforms to show: All Mac Windows Linux Cross-Platform
/AVFoundation/AVAudioEngine/Player with AudioUnit for Level Meter
Required plugins for this example: MBS MacBase Plugin, MBS Main Plugin, MBS AVFoundation Plugin
You find this example project in your Plugins Download as a Xojo project file within the examples folder: /AVFoundation/AVAudioEngine/Player with AudioUnit for Level Meter
This example is the version from Mon, 20th Sep 2015.
Project "Player with AudioUnit for Level Meter.xojo_binary_project"
Class App Inherits Application
Const kEditClear = "&Delete"
Const kFileQuit = "&Quit"
Const kFileQuitShortcut = ""
End Class
Class Window1 Inherits Window
Control LoadButton Inherits PushButton
ControlInstance LoadButton Inherits PushButton
EventHandler Sub Action()
dim f as FolderItem = GetOpenFolderItem("")
if f = nil then Return
dim error as NSErrorMBS
dim a as new AVAudioFileMBS(f, error)
if error <> nil then
MsgBox error.LocalizedDescription
return
end if
NoEvents = true
dim ff as AVAudioFormatMBS = a.fileFormat
dim d as Double = a.Length/a.fileFormat.sampleRate
FileInfo.Text = f.DisplayName+": "+str(ff.sampleRate)+"Hz, "+str(ff.channelCount)+" channels, "+str(d, "0.00")+" seconds"
self.fileFormat = ff
self.AudioFile = a
self.File = f
PositionSlider.Value = 0
engine.reset
engine.connect(player, audioUnit, nil)
engine.connect(audioUnit, engine.mainMixerNode, nil)
player.scheduleFile(a, nil)
StartEngine
if not player.Playing then
player.play
end if
Finally
NoEvents = false
End EventHandler
End Control
Control FileInfo Inherits Label
ControlInstance FileInfo Inherits Label
End Control
Control PlayButton Inherits PushButton
ControlInstance PlayButton Inherits PushButton
EventHandler Sub Action()
if player.Playing then
player.pause
else
player.play
end if
End EventHandler
End Control
Control PlayStatus Inherits Label
ControlInstance PlayStatus Inherits Label
End Control
Control Timer1 Inherits Timer
ControlInstance Timer1 Inherits Timer
EventHandler Sub Action()
NoEvents = true
dim lines() as string
if player.Playing then
lines.Append "playing"
else
lines.Append "paused"
end if
if audiofile <> nil and fileFormat <> nil then
lines.Append str(audiofile.FramePosition / fileFormat.sampleRate)+" seconds"
end if
PlayStatus.Text = Join(lines, ", ")
if audiofile <> nil then
dim nodetime as AVAudioTimeMBS = self.player.lastRenderTime
if nodetime <> nil then
dim playerTime as AVAudioTimeMBS = self.player.playerTimeForNodeTime(nodetime)
if playerTime <> nil then
PositionSlider.Value = 1000.0 * (StartPos + playerTime.sampleTime) / audiofile.Length
end if
end if
end if
LabelVolume.Text = str(player.volume, "-0.0%")
Finally
NoEvents = False
End EventHandler
End Control
Control VolumeSlider Inherits Slider
ControlInstance VolumeSlider Inherits Slider
EventHandler Sub ValueChanged()
if NoEvents then Return
player.volume = me.Value / 100.0
End EventHandler
End Control
Control Label1 Inherits Label
ControlInstance Label1 Inherits Label
End Control
Control PositionSlider Inherits Slider
ControlInstance PositionSlider Inherits Slider
EventHandler Sub ValueChanged()
if NoEvents then Return
// restart at new position
dim playing as Boolean = player.Playing
player.stop
dim l as Int64 = audiofile.Length
dim x as Int64 = (me.Value * l) / 1000.0
dim r as int64 = audiofile.Length - x
player.scheduleSegment(audiofile, nil, x, r)
StartPos = x
if Playing then
player.play
end if
End EventHandler
End Control
Control LabelVolume Inherits Label
ControlInstance LabelVolume Inherits Label
End Control
Control LevelChannel0 Inherits ProgressBar
ControlInstance LevelChannel0 Inherits ProgressBar
End Control
Control LevelChannel1 Inherits ProgressBar
ControlInstance LevelChannel1 Inherits ProgressBar
End Control
Control LabelPan Inherits Label
ControlInstance LabelPan Inherits Label
End Control
EventHandler Sub Close()
player.removeTapOnBus 0
End EventHandler
EventHandler Sub Open()
NoEvents = true
// Needs OS X 10.10 or newer
Engine = new AVAudioEngineMBS
player = new myAVAudioPlayerNodeMBS
audioUnit = new AVAudioUnitTimePitchMBS
Engine.attachNode player
engine.attachNode audioUnit
AddHandler audioUnit.LevelMonitor, WeakAddressOf LevelMonitorHandler
audioUnit.installLevelMonitor 20
const kTimePitchParam_Pitch = 1
const kAudioUnitScope_Global = 0
const kAudioUnitProperty_SampleRate = 2
#if false then
// try parameter
dim pitchValue as single = audioUnit.GetParameter(kTimePitchParam_Pitch, kAudioUnitScope_Global, 0)
audioUnit.SetParameter(kTimePitchParam_Pitch, kAudioUnitScope_Global, 0, 100)
dim pitchValue2 as single = audioUnit.GetParameter(kTimePitchParam_Pitch, kAudioUnitScope_Global, 0)
#endif
#if false then
// try property
// 8 bytes and Writeable
dim WriteAble as Boolean
dim Size as integer = audioUnit.GetPropertyInfo(kAudioUnitProperty_SampleRate, kAudioUnitScope_Global, 0, WriteAble)
// query it
dim m as MemoryBlock = audioUnit.GetProperty(kAudioUnitProperty_SampleRate, kAudioUnitScope_Global, 0)
dim SampleRate as Double = m.DoubleValue(0)
#endif
Finally
NoEvents = false
End EventHandler
Sub LevelMonitorHandler(v as AVAudioUnitTimeEffectMBS , Level0 as Double, Level1 as Double, Level2 as Double, Level3 as Double, Level4 as Double, Level5 as Double, Level6 as Double, Level7 as Double, tag as Variant)
LevelChannel0.Value = level0 * 100.0
LevelChannel1.Value = level1 * 100.0
System.DebugLog str(level0, "0.00")+" "+str(Microseconds, "0")
#pragma Unused v
#pragma Unused Level2
#pragma Unused Level3
#pragma Unused Level4
#pragma Unused Level5
#pragma Unused Level6
#pragma Unused Level7
#pragma Unused tag
End Sub
Sub OutputLevel(m as AVAudioNodeMBS, bus as integer, frameLength as Integer, Level0 as Double, Level1 as Double, Level2 as Double, Level3 as Double, Level4 as Double, Level5 as Double, Level6 as Double, Level7 as Double, tag as variant)
LevelChannel0.Value = level0 * 100.0
LevelChannel1.Value = level1 * 100.0
#pragma Unused m
#pragma Unused bus
#pragma Unused frameLength
#pragma Unused Level2
#pragma Unused Level3
#pragma Unused Level4
#pragma Unused Level5
#pragma Unused Level6
#pragma Unused Level7
#pragma Unused tag
End Sub
Sub StartEngine()
if not engine.running then
dim e as NSErrorMBS
if engine.startAndReturnError(e) then
// ok
else
MsgBox "Failed: "+e.localizedDescription
end if
end if
End Sub
Function StereoFormat() As AVAudioFormatMBS
// stereo format with standard layout tag
dim layout as new AVAudioChannelLayoutMBS(QTAudioChannelLayoutMBS.kAudioChannelLayoutTag_Stereo)
dim pf as new AVAudioFormatMBS(44100, layout)
Return pf
End Function
Function StereoLeftFormat() As AVAudioFormatMBS
// stereo format, left channel only
dim qlayout as new QTAudioChannelLayoutMBS
dim d1 as new QTAudioChannelDescriptionMBS
dim d2 as new QTAudioChannelDescriptionMBS
d1.ChannelFlags = QTAudioChannelDescriptionMBS.kAudioChannelFlags_AllOff
d1.ChannelLabel = QTAudioChannelDescriptionMBS.kAudioChannelLabel_Discrete_3
d2.ChannelFlags = QTAudioChannelDescriptionMBS.kAudioChannelFlags_AllOff
d2.ChannelLabel = QTAudioChannelDescriptionMBS.kAudioChannelLabel_Unused
qlayout.ChannelLayoutTag = QTAudioChannelLayoutMBS.kAudioChannelLayoutTag_UseChannelDescriptions
qlayout.NumberChannelDescriptions=2
qlayout.ChannelDescriptions(0)=d1
qlayout.ChannelDescriptions(1)=d2
dim layout as new AVAudioChannelLayoutMBS(qlayout)
dim pf as new AVAudioFormatMBS(44100, layout)
Return pf
End Function
Function StereoRightFormat() As AVAudioFormatMBS
// stereo format, left channel only
dim qlayout as new QTAudioChannelLayoutMBS
dim d1 as new QTAudioChannelDescriptionMBS
dim d2 as new QTAudioChannelDescriptionMBS
d1.ChannelFlags = QTAudioChannelDescriptionMBS.kAudioChannelFlags_AllOff
d1.ChannelLabel = QTAudioChannelDescriptionMBS.kAudioChannelLabel_Unused
d2.ChannelFlags = QTAudioChannelDescriptionMBS.kAudioChannelFlags_AllOff
d2.ChannelLabel = QTAudioChannelDescriptionMBS.kAudioChannelLabel_Right
qlayout.ChannelLayoutTag = QTAudioChannelLayoutMBS.kAudioChannelLayoutTag_UseChannelDescriptions
qlayout.NumberChannelDescriptions=2
qlayout.ChannelDescriptions(0)=d1
qlayout.ChannelDescriptions(1)=d2
dim layout as new AVAudioChannelLayoutMBS(qlayout)
dim pf as new AVAudioFormatMBS(44100, layout)
Return pf
End Function
Property Engine As AVAudioEngineMBS
Property NoEvents As Boolean
Property StartPos As int64
Property audioUnit As AVAudioUnitTimePitchMBS
Property audiofile As AVAudioFileMBS
Property file As FolderItem
Property fileFormat As AVAudioFormatMBS
Property player As AVAudioPlayerNodeMBS
End Class
MenuBar MainMenuBar
MenuItem FileMenu = "&File"
MenuItem FileQuit = "#App.kFileQuit"
MenuItem EditMenu = "&Edit"
MenuItem EditUndo = "&Undo"
MenuItem EditSeparator1 = "-"
MenuItem EditCut = "Cu&t"
MenuItem EditCopy = "&Copy"
MenuItem EditPaste = "&Paste"
MenuItem EditClear = "#App.kEditClear"
MenuItem EditSeparator2 = "-"
MenuItem EditSelectAll = "Select &All"
End MenuBar
Class MyAVAudioPlayerNodeMBS Inherits AVAudioPlayerNodeMBS
EventHandler Sub scheduleFileCompleted(file as AVAudioFileMBS, time as AVAudioTimeMBS, tag as Variant)
MsgBox "Playing finished."
#pragma Unused file
#pragma Unused time
#pragma Unused tag
End EventHandler
End Class
End Project
See also:
The items on this page are in the following plugins: MBS AVFoundation Plugin.