Drone player using GPScript

After a lot of effort, I got a “drone player” working with GPScript.

It uses two instances of Audio File Player - each lane has a sound file loaded which plays the drone in a particular key (lanes 1-8 for C-G in one, and lanes 1-4 for G#-B in the other).

There is a button widget for each key and a volume control for the drone volume.
As keys are changed it cross fades between them and fades out when you stop playing.

If anyone is interested I am happy to share my script.

1 Like

Sure ! Always welcome!

I did something similar with an Xkey, you can take a look :wink:

Of course we are interested. We like to read nice GP scripts :wink:

2 Likes

I wouldn’t claim it is nice :smiley:
I am sure it could be better but nonetheless…

//$<AutoDeclare>
// DO NOT EDIT THIS SECTION MANUALLY
Var
   AudioFilePlayer : PluginBlock
   AudioFilePlayer2 : PluginBlock
   PlayBtn1 : Widget
   PlayBtn2 : Widget
   PlayFromBeg1 : Widget
   PlayFromBeg2 : Widget
   Lane1Btn : Widget
   Lane2Btn : Widget
   Lane3Btn : Widget
   Lane4Btn : Widget
   Lane5Btn : Widget
   Lane6Btn : Widget
   Lane7Btn : Widget
   Lane8Btn : Widget
   Lane9Btn : Widget
   Lane10Btn : Widget
   Lane11Btn : Widget
   Lane12Btn : Widget
   DroneVol : Widget
   PlayCBtn : Widget
   Lane1CBtn : Widget
   Lane2CBtn : Widget
   Lane3CBtn : Widget
   Lane4CBtn : Widget
   Lane6CBtn : Widget
   Lane5CBtn : Widget
   Lane7CBtn : Widget
   Lane8CBtn : Widget
   Lane9CBtn : Widget
   Lane10CBtn : Widget
   Lane11CBtn : Widget
   Lane12CBtn : Widget
   Lane1Vol : Widget
   Lane2Vol : Widget
   Lane3Vol : Widget
   Lane4Vol : Widget
   Lane5Vol : Widget
   Lane6Vol : Widget
   Lane7Vol : Widget
   Lane8Vol : Widget
   Lane9Vol : Widget
   Lane10Vol : Widget
   Lane11Vol : Widget
   Lane12Vol : Widget
//$</AutoDeclare>
   LANE : Widget Array
   LANEVOL: Widget Array
   LANECTL: Widget Array
   SilentCallback: boolean[12]  // Array for making a silent callback
   VolRamp: Ramp
   TargetVol: double
   VolRampFadeTime: integer
   VolRampCoarseness: integer
   FadeInTargetVol: double
   SourceName: string
   FadeRunning: boolean
   Activated: boolean

initialization
var
  i: integer
  
  SetGeneratorOneShot(VolRamp, true)
  VolRampFadeTime = 10000
  VolRampCoarseness = 100
  VolRamp.SetGeneratorLength(VolRampFadeTime);
  VolRamp.SetGeneratorCoarseness(VolRampCoarseness);
  LANE = [ Lane1Btn, Lane2Btn, Lane3Btn, Lane4Btn, Lane5Btn, Lane6Btn, Lane7Btn, Lane8Btn, Lane9Btn, Lane10Btn, Lane11Btn, Lane12Btn ]
  LANEVOL = [ Lane1Vol, Lane2Vol, Lane3Vol, Lane4Vol, Lane5Vol, Lane6Vol, Lane7Vol, Lane8Vol, Lane9Vol, Lane10Vol, Lane11Vol, Lane12Vol ]
  LANECTL = [ Lane1CBtn, Lane2CBtn, Lane3CBtn, Lane4CBtn, Lane5CBtn, Lane6CBtn, Lane7CBtn, Lane8CBtn, Lane9CBtn, Lane10CBtn, Lane11CBtn, Lane12CBtn ]
  TargetVol = GetWidgetValue(DroneVol)
  
  for i = 0; i < Size(LANE); i = i + 1 do
    SilentCallback[i] = true
    SetWidgetValue(LANECTL[i], 0.0)
    SetWidgetValue(LANEVOL[i], 0.0)
    SetWidgetValue(PlayBtn1, GetWidgetValue(PlayCBtn))
    SetWidgetValue(PlayBtn2, GetWidgetValue(PlayCBtn))
  end
  Activated = true
end

Function GetLanePlaying() Returns integer
var
  returnval : integer
  i : Integer

  returnval = -1
    
  for i = 0; i < Size(LANECTL); i = i + 1 do
    if (GetWidgetValue(LANECTL[i]) > 0.5) then
      returnval = i
    end
  end
  
  result = returnval
end

Function Fade(source: string)
  SourceName = source

  FadeRunning = true
    
  VolRamp.EnableGenerator(true)
  SetTimersRunning(true)
end

On TimePassing(timeX: integer, amplitudeY: double) from VolRamp
var
  curVol: double
  newVol : double
  i: integer
  LaneCtlValue: double
  steps: double
  VolStep: double
  
  for i = 0; i < Size(LANE); i = i + 1 do
    curVol = GetWidgetValue(LANEVOL[i])
    steps = (VolRampFadeTime - timeX) / VolRampCoarseness
    if SourceName == "PlayBtn" or (GetWidgetValue(LANECTL[i]) == 0.0 and curVol > 0.0) then
      // Turning off PlayBtn or Lane turned off and volume not already 0
      VolStep = curVol / steps
      newVol = curVol - VolStep
      SetWidgetValue(LANEVOL[i], newVol)
    elsif GetWidgetValue(LANECTL[i]) == 1.0 and curVol < TargetVol then
      VolStep = (TargetVol - curVol) / steps
      newVol = curVol + VolStep
      SetWidgetValue(LANEVOL[i], newVol)
    end
  end

  if timeX >= VolRampFadeTime - VolRampCoarseness - 50 then
    VolRamp.EnableGenerator(false)
    SetTimersRunning(false)

    if SourceName == "PlayBtn" then
      SetWidgetValue(PlayBtn1, 0) 
      SetWidgetValue(PlayBtn2, 0) 
    else
      for i = 0; i < Size(LANE); i = i + 1 do
        LaneCtlValue = GetWidgetValue(LANECTL[i])

        if GetWidgetValue(LANE[i]) != LaneCtlValue then  
          SetWidgetValue(LANE[i], LaneCtlValue)
        end

        if LaneCtlValue == 1.0 and GetWidgetValue(LANEVOL[i]) != TargetVol then
          SetWidgetValue(LANEVOL[i], TargetVol)
        end
      end
    end
    FadeRunning = false
  end
end

On WidgetValueChanged(newValue: double) from DroneVol
var
  LanePlaying: integer
  
  TargetVol := newValue
  
  LanePlaying = GetLanePlaying()

  if not FadeRunning and (LanePlaying != -1) then
    SetWidgetValue(LANEVOL[LanePlaying], newValue)
  end
end

On WidgetValueChanged(newValue: double) from PlayCBtn
var
  LanePlaying: integer
  
  if (GetWidgetValue(PlayBtn1) != newValue) or
     (GetWidgetValue(PlayBtn2) != newValue) then
    if newValue == 1.0 then
      SetWidgetValue(PlayFromBeg1, 1.0)
      SetWidgetValue(PlayBtn1, 1.0)
      SetWidgetValue(PlayFromBeg2, 1.0)
      SetWidgetValue(PlayBtn2, 1.0)
      Fade("PlayCBtn")  /// use different source because we don't want to turn off play btn at end of fade
    else
      Fade("PlayBtn")
    end 
  end
end

Function LaneCBtnChanged(LaneNo: integer, newValue: double)
var
  i : integer
  
  if SilentCallback[LaneNo] or not Activated then
    SilentCallback[LaneNo] = false
  else
    if newValue == 1.0 then
      for i = 0; i < Size(LANE); i = i + 1 do
        if i != LaneNo then // not this button
          SilentCallback[i] = true
          SetWidgetValue(LANECTL[i], 0.0) // turn off other ctl buttons
        end
      end

      SetWidgetValue(LANE[LaneNo], 1.0)
      Fade("Lane"+(LaneNo+1)+"Btn")
    else
      Fade("Lane"+(LaneNo+1)+"Btn")
    end 
  end
end

On WidgetValueChanged(newValue: double) from Lane1CBtn
  LaneCBtnChanged(0, newValue)
end

On WidgetValueChanged(newValue: double) from Lane2CBtn  
  LaneCBtnChanged(1, newValue)
end

On WidgetValueChanged(newValue: double) from Lane3CBtn  
  LaneCBtnChanged(2, newValue)
end

On WidgetValueChanged(newValue: double) from Lane4CBtn  
  LaneCBtnChanged(3, newValue)
end

On WidgetValueChanged(newValue: double) from Lane5CBtn  
  LaneCBtnChanged(4, newValue)
end

On WidgetValueChanged(newValue: double) from Lane6CBtn  
  LaneCBtnChanged(5, newValue)
end

On WidgetValueChanged(newValue: double) from Lane7CBtn  
  LaneCBtnChanged(6, newValue)
end

On WidgetValueChanged(newValue: double) from Lane8CBtn  
  LaneCBtnChanged(7, newValue)
end

On WidgetValueChanged(newValue: double) from Lane9CBtn  
  LaneCBtnChanged(8, newValue)
end

On WidgetValueChanged(newValue: double) from Lane10CBtn  
  LaneCBtnChanged(9, newValue)
end

On WidgetValueChanged(newValue: double) from Lane11CBtn  
  LaneCBtnChanged(10, newValue)
end

On WidgetValueChanged(newValue: double) from Lane12CBtn  
  LaneCBtnChanged(11, newValue)
end

On Activate
  FadeRunning = false
  TargetVol = GetWidgetValue(DroneVol)
  SetWidgetValue(PlayBtn1, GetWidgetValue(PlayCBtn))
  SetWidgetValue(PlayBtn2, GetWidgetValue(PlayCBtn))
  Activated = true;
end

I think maybe so many widgets might not be needed - maybe SetParameter would be more elegant but I wasn’t sure how to work out the right parameter numbers.

This is the basic idea:
Lane1Btn…Lane12Btn - each mapped to a lane in the Audio File Player - used to turn on/off the lane
PlayBtn1 & PlayBtn2 - mapped to the play/pause for each instance of Audio File Player
PlayCBtn - a control button widget not mapped to anything that is used to control play/pause both Audio File Players
Lane1CBtn…Lane12CBtn - Lane control buttons not mapped to anything but used to control which lane is currently activated
Lane1Vol…Lan12Vol - a volume knob widget mapped to the Lane volume in Audio File Player
DroveVol - a master volume knob widget not mapped to anything but used to set the target volume for the drones

When a lane is switched or turned on/off a fade is started by calling the Fade function which then initiates the volume ramp. This then adjusts the volumes of all lanes - if they are playing then it will fade up to the target volume, if not it will fade to 0.

All comments and suggestions are welcome.
I hope it could be useful to someone.

Very nice, I like it. :smiley:

1 Like

Yes of course, and probably even more if you post a screenshot and the gigfile. Nice job :wink:

Sure @David-san, I will do that…I’ll just create a gig without anything else in it first and then attach them.

1 Like

Drone Player.gig (51.4 KB)

See attached screenshot and gig file

2 Likes

Thanks for sharing!
We can now drone away… :wink:

1 Like

WoW!! It is Very nice! Lots of fun to be had!
Intricate script/functionality…

Now, Im looking around my studio, what “cool” buttons to use with your Drone Player :face_with_monocle:
More to come…

1 Like