Using Oscillators
[Using the SetValueAtTime Procedure] [Using a Delay Node]
This example reproduces the notes from Ihsan Fazal's Pascal program Mazer. The data for the note frequencies and start and stop times are held in parallel arrays to facilitate assignment to the corresponding properties of the oscillators by a loop. You can compile this code and the other two examples on this page with Version 3.0 of Smart Mobile Studio and listen to the output using a Firefox or Microsoft Edge browser.
unit Unit1; interface uses System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application, SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics, SmartCL.MediaElements, SmartCL.Time, W3C.WebAudio; type TCanvasProject = class(TW3CustomGameApplication) private const SOUND_LEVEL = 0.5; const StartTimes: array[0..26] of float = [0.0, 0.55, 0.8, 1.35, 1.9, 2.25, 2.95, 3.5, 3.75, 4.45, 5.0, 5.25, 5.7, 6.15, 6.7, 6.95, 7.65, 8.2, 8.45, 9.15, 9.7, 9.95, 10.65, 11.2, 11.45, 11.9, 12.12]; const StopTimes: array[0..26] of float = [0.5, 0.65, 1.35, 1.85, 2.0, 2.95, 3.45, 3.6, 4.45, 4.95, 5.1, 5.7, 6.15, 6.65, 6.8, 7.65, 8.15, 8.3, 9.15, 9.65, 9.8, 10.65, 11.15, 11.3, 11.9, 12.12, 12.37]; const Frequencies: array[0..26] of integer = [523, 523, 523, 587, 587, 587, 659, 659, 659, 784, 784, 784, 988, 523, 523, 523, 587, 587, 587, 659, 659, 659, 784, 784, 988, 880, 784]; FAudioContext: JAudioContext; Oscillators: array [0..26] of JOscillatorNode; FGain: JGainNode; public procedure ApplicationStarting; override; procedure ApplicationClosing; override; procedure PaintView(Canvas: TW3Canvas); override; end; implementation procedure TCanvasProject.ApplicationStarting; begin inherited; FAudioContext := new JAudioContext; FGain := FAudioContext.createGain; FGain.gain.value := SOUND_LEVEL; FGain.connect(FAudioContext.destination); for var i := 0 to 26 do begin Oscillators[i] := FAudioContext.createOscillator; Oscillators[i].frequency.value := Frequencies[i]; Oscillators[i].start(StartTimes[i]); Oscillators[i].stop(StopTimes[i]); Oscillators[i].connect(FGain); end; GameView.Delay := 5000; GameView.StartSession(False); end; procedure TCanvasProject.PaintView(Canvas: TW3Canvas); begin end; procedure TCanvasProject.ApplicationClosing; begin GameView.EndSession; inherited; end; end.
Using the SetValueAtTime Procedure
The SetValueAtTime procedure is useful for scheduling changes to frequencies and volumes as shown in this simple example. The frequencies of the octave (starting at Middle C) in an "equal tempered scale" are taken from Physics of Music. (Our trials with the ExponentialRampToValueAtTime and LinearRampToValueAtTime procedures seemed to give abrupt rather than gradual changes on our systems).
unit Unit1; interface uses System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application, SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics, SmartCL.MediaElements, W3C.WebAudio; type TCanvasProject = class(TW3CustomGameApplication) private FAudioContext: JAudioContext; Oscillator: JOscillatorNode; FGain: JGainNode; Frequencies: array[1..8] of float := [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]; public procedure ApplicationStarting; override; procedure PaintView(Canvas: TW3Canvas); override; end; implementation procedure TCanvasProject.ApplicationStarting; begin inherited; FAudioContext := new JAudioContext; FGain := FAudioContext.createGain; FGain.connect(FAudioContext.destination); Oscillator := FAudioContext.createOscillator; FGain.gain.value := 0.01; for var i := 1 to 8 do begin Oscillator.frequency.setValueAtTime(Frequencies[i], FAudioContext.currentTime + i); FGain.gain.setValueAtTime(1.0 - 0.1 * i, FAudioContext.currentTime + i); end; Oscillator.connect(FGain); Oscillator.start(0); Oscillator.stop(10); end; procedure TCanvasProject.PaintView(Canvas: TW3Canvas); begin end; end.
Using a Delay Node
In this example we connect an oscillator to the destination both directly and via a delay node to generate an echo effect.
unit Unit1; interface uses System.Types, SmartCL.System, SmartCL.Components, SmartCL.Application, SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics, SmartCL.MediaElements, SmartCL.Time, W3C.WebAudio; type TCanvasProject = class(TW3CustomGameApplication) private FDelay: JDelayNode; FAudioContext: JAudioContext; FOscillator: JOscillatorNode; FGain1, FGain2: JGainNode; public procedure ApplicationStarting; override; procedure ApplicationClosing; override; procedure PaintView(Canvas: TW3Canvas); override; end; implementation procedure TCanvasProject.ApplicationStarting; begin inherited; FAudioContext := new JAudioContext; FGain1 := FAudioContext.createGain; FGain2 := FAudioContext.createGain; FOscillator := FAudioContext.createOscillator; FOscillator.frequency.value := 523.2; FOscillator.connect(FGain1); FGain1.connect(FAudioContext.destination); FGain1.gain.setValueAtTime(0.5, 0.0); FGain1.gain.setValueAtTime(0.0, 0.25); FGain2.gain.value := 0.2; FDelay := FAudioContext.createDelay; FDelay.delayTime.value := 0.25; FGain1.connect(FDelay); FDelay.connect(FGain2); FGain2.connect(FAudioContext.destination); FOscillator.start(0.0); end; procedure TCanvasProject.PaintView(Canvas: TW3Canvas); begin end; procedure TCanvasProject.ApplicationClosing; begin GameView.EndSession; inherited; end; end.