diff --git a/Makefile b/Makefile index a66bf3f..678aecc 100644 --- a/Makefile +++ b/Makefile @@ -38,6 +38,9 @@ ifneq (,$(wildcard $(CURDIR)/bin/vst/cabbage-Additive.so)) cp -r bin/vst/* $(DESTDIR)$(PREFIX)/lib/vst/ endif + # install protoplug files + cp -r ports/protoplug/ProtoplugFiles $(DESTDIR)$(PREFIX)/share/ + # ----------------------------------------- # clean diff --git a/ports/Makefile b/ports/Makefile index b08034c..80d5b31 100644 --- a/ports/Makefile +++ b/ports/Makefile @@ -14,6 +14,8 @@ lv2: $(MAKE) -C cabbage/LV2-fx $(MAKE) -C cabbage/LV2-ins $(MAKE) -C cabbage/LV2-midi + $(MAKE) -C protoplug/LV2-fx + $(MAKE) -C protoplug/LV2-gen # ----------------------------------------- # vst @@ -24,6 +26,8 @@ vst: $(MAKE) -C cabbage/VST-fx $(MAKE) -C cabbage/VST-ins $(MAKE) -C cabbage/VST-midi + $(MAKE) -C protoplug/VST-fx + $(MAKE) -C protoplug/VST-gen # ----------------------------------------- # clean @@ -34,12 +38,16 @@ clean: $(MAKE) clean -C cabbage/LV2-fx $(MAKE) clean -C cabbage/LV2-ins $(MAKE) clean -C cabbage/LV2-midi + $(MAKE) clean -C protoplug/LV2-fx + $(MAKE) clean -C protoplug/LV2-gen # VST $(MAKE) clean -C argotlunar/VST $(MAKE) clean -C cabbage/VST-fx $(MAKE) clean -C cabbage/VST-ins $(MAKE) clean -C cabbage/VST-midi + $(MAKE) clean -C protoplug/VST-fx + $(MAKE) clean -C protoplug/VST-gen rm -rf */LV2/intermediate rm -rf */VST/intermediate diff --git a/ports/protoplug/LV2-fx/premake.lua b/ports/protoplug/LV2-fx/premake.lua new file mode 100644 index 0000000..8953973 --- /dev/null +++ b/ports/protoplug/LV2-fx/premake.lua @@ -0,0 +1,24 @@ + +dofile("../../../scripts/make-project.lua") + +package = make_juce_lv2_project("protoplug-fx") + +package.defines = { + package.defines, + "PROTOPLUGFX=1" +} + +package.includepaths = { + package.includepaths, + "../Source", + "../JuceLibraryCode" +} + +package.files = { + matchfiles ( + "../Source/*.cpp", + "../Source/guiclasses/*.cpp", + "../Source/vflib/*.cpp", + "../../../libs/juce-plugin/JucePluginMain.cpp" + ) +} diff --git a/ports/protoplug/LV2-gen/premake.lua b/ports/protoplug/LV2-gen/premake.lua new file mode 100644 index 0000000..995a6ab --- /dev/null +++ b/ports/protoplug/LV2-gen/premake.lua @@ -0,0 +1,24 @@ + +dofile("../../../scripts/make-project.lua") + +package = make_juce_lv2_project("protoplug-gen") + +package.defines = { + package.defines, + "PROTOPLUGFX=0" +} + +package.includepaths = { + package.includepaths, + "../Source", + "../JuceLibraryCode" +} + +package.files = { + matchfiles ( + "../Source/*.cpp", + "../Source/guiclasses/*.cpp", + "../Source/vflib/*.cpp", + "../../../libs/juce-plugin/JucePluginMain.cpp" + ) +} diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.AffineTransform.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.AffineTransform.html new file mode 100644 index 0000000..0fdcd91 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.AffineTransform.html @@ -0,0 +1,469 @@ + + + + + protoplug: Class juce.AffineTransform + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.AffineTransform

+

A geometric transformation.

+

+ +

Is converted to a JUCE AffineTransform.

+ +

The default constructor makes an identity transform, so all kinds of + transformations can be created as follows :

+
rot180 = juce.AffineTransform():rotated(math.pi)
+chainey = juce.AffineTransform():scaled(2.5):translated(140,140)
+
+

+ + +

Constructors

+ + + + + +
juce.AffineTransform (mat00, mat01, mat02, mat10, mat11, mat12)Constuctor.
+

Methods

+ + + + + + + + + + + + + + + + + +
juce.AffineTransform:translated (dx, dy)Translated.
juce.AffineTransform:rotated (rad)Rotated.
juce.AffineTransform:scaled (scaleX[, scaleY=scaleX])Scaled.
juce.AffineTransform:followedBy (other)Followed by.
+

Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + +
juce.AffineTransform.mat00Matrix [0] [0]
juce.AffineTransform.mat01Matrix [0] [1]
juce.AffineTransform.mat02Matrix [0] [2]
juce.AffineTransform.mat10Matrix [1] [0]
juce.AffineTransform.mat11Matrix [1] [1]
juce.AffineTransform.mat12Matrix [1] [2]
+

Predefined values

+ + + + + +
juce.AffineTransform.identityIdentity.
+ +
+
+ + +

Constructors

+
+
+ + juce.AffineTransform (mat00, mat01, mat02, mat10, mat11, mat12) +
+
+ +

Constuctor. + parameters thusly define a transformation matrix :

+ +
(mat00 mat01 mat02)
+(mat10 mat11 mat12)
+(0     0     1)
+
+ + + + +

Parameters:

+
    +
  • mat00 + + + +
  • +
  • mat01 + + + +
  • +
  • mat02 + + + +
  • +
  • mat10 + + + +
  • +
  • mat11 + + + +
  • +
  • mat12 + + + +
  • +
+ + + + + +
+
+

Methods

+
+
+ + juce.AffineTransform:translated (dx, dy) +
+
+ Translated. + + + +

Parameters:

+
    +
  • dx + the horizontal offset +
  • +
  • dy + the vertical offset +
  • +
+ +

Returns:

+
    + + a translated version of this transform +
+ + + + +
+
+ + juce.AffineTransform:rotated (rad) +
+
+ Rotated. + + + +

Parameters:

+
    +
  • rad + the degree of rotation in radians +
  • +
+ +

Returns:

+
    + + a rotated version of this transform +
+ + + + +
+
+ + juce.AffineTransform:scaled (scaleX[, scaleY=scaleX]) +
+
+ Scaled. + + + +

Parameters:

+
    +
  • scaleX + + + +
  • +
  • scaleY + + + + (default scaleX) +
  • +
+ +

Returns:

+
    + + a scaled version of this transform +
+ + + + +
+
+ + juce.AffineTransform:followedBy (other) +
+
+ Followed by. + + + +

Parameters:

+
    +
  • other + + + +
  • +
+ +

Returns:

+
    + + a version of this transform followed by another +
+ + + + +
+
+

Fields

+
+
+ + juce.AffineTransform.mat00 +
+
+ Matrix [0] [0] + + + + + + + + +
+
+ + juce.AffineTransform.mat01 +
+
+ Matrix [0] [1] + + + + + + + + +
+
+ + juce.AffineTransform.mat02 +
+
+ Matrix [0] [2] + + + + + + + + +
+
+ + juce.AffineTransform.mat10 +
+
+ Matrix [1] [0] + + + + + + + + +
+
+ + juce.AffineTransform.mat11 +
+
+ Matrix [1] [1] + + + + + + + + +
+
+ + juce.AffineTransform.mat12 +
+
+ Matrix [1] [2] + + + + + + + + +
+
+

Predefined values

+
+
+ + juce.AffineTransform.identity +
+
+ Identity. + The non-transform. + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.AudioFormatReader.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.AudioFormatReader.html new file mode 100644 index 0000000..11d4451 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.AudioFormatReader.html @@ -0,0 +1,389 @@ + + + + + protoplug: Class juce.AudioFormatReader + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.AudioFormatReader

+

Class to read audio files.

+

Example usage: soundfile-test.lua.

+ +

Reads the formats that JUCE supports, namely: WAV, AIFF, Flac, Ogg-Vorbis, Windows Media codecs, + CoreAudio codecs, MP3.

+ +

Is a pointer to a JUCE AudioFormatReader, + and wraps some AudioFormatManager + functionality.

+ + +

Constructors

+ + + + + +
juce.AudioFormatReader (filename)Load a sound file as an AudioFormatReader.
+

Methods

+ + + + + + + + + + + + + +
juce.AudioFormatReader:read
(destSamples, numDestChannels, startSampleInSource, numSamplesToRead[, fillLeftoverChannelsWithCopies=true])
Read samples.
juce.AudioFormatReader:readToFloat
([nChannels=2[, resample=true]])
Read entire wave to float array.
juce.AudioFormatReader:readToDouble
([nChannels=2[, resample=true]])
Read entire wave to double array.
+

Fields

+ + + + + + + + + + + + + + + + + + + + + +
juce.AudioFormatReader.sampleRateSample rate
juce.AudioFormatReader.bitsPerSampleBits per sample
juce.AudioFormatReader.lengthInSamplesLength in samples
juce.AudioFormatReader.numChannelsNumber of channels
juce.AudioFormatReader.usesFloatingPointDataUses floating point data (boolean)
+ +
+
+ + +

Constructors

+
+
+ + juce.AudioFormatReader (filename) +
+
+ Load a sound file as an AudioFormatReader. + The path can be absolute or relative to the protoplug directory. + Returns nil if unsuccessful. The file will remain open until the + AudioFormatReader is unset or otherwise garbage-collected. + + + +

Parameters:

+
    +
  • filename + + + +
  • +
+ + + + + +
+
+

Methods

+
+
+ + juce.AudioFormatReader:read
(destSamples, numDestChannels, startSampleInSource, numSamplesToRead[, fillLeftoverChannelsWithCopies=true])
+
+
+ Read samples.
+ Copies a number of samples from the file into the provided array. + + + +

Parameters:

+
    +
  • destSamples + a cdata array of pointers to buffers for each channel (int * const *) +
  • +
  • numDestChannels + the number of elements in destSamples +
  • +
  • startSampleInSource + + + +
  • +
  • numSamplesToRead + + + +
  • +
  • fillLeftoverChannelsWithCopies + boolean + used if destSamples has more channels than the source. + (default true) +
  • +
+ +

Returns:

+
    + + boolean + success +
+ + + + +
+
+ + juce.AudioFormatReader:readToFloat
([nChannels=2[, resample=true]])
+
+
+ Read entire wave to float array.
+ A simplified wrapper function for read + + + +

Parameters:

+
    +
  • nChannels + number of channels to be returned + (default 2) +
  • +
  • resample + whether to perform samplerate conversion to match the host's sample rate. + If true, the length of the returned array may not be the wave's original lengthInSamples . + It will be given by the second returned value. + (default true) +
  • +
+ +

Returns:

+
    +
  1. + a two-dimensional cdata array of channels containing samples (float [nChannels][nSamples])
  2. +
  3. + the number of samples in each channel of the returned array
  4. +
+ + + + +
+
+ + juce.AudioFormatReader:readToDouble
([nChannels=2[, resample=true]])
+
+
+ Read entire wave to double array.
+ This wraps readToFloat and returns an array containing double-precision numbers. + This takes twice as much space, but it may be faster to use, as this is the native Lua type. + + + +

Parameters:

+
    +
  • nChannels + number of channels to be returned + (default 2) +
  • +
  • resample + whether to perform samplerate conversion to match the host's sample rate. + If true, the length of the returned array may not be the wave's original lengthInSamples . + It will be given by the second returned value. + (default true) +
  • +
+ +

Returns:

+
    +
  1. + a two-dimensional cdata array of channels containing samples (double [nChannels][nSamples])
  2. +
  3. + the number of samples in each channel of the returned array
  4. +
+ + + + +
+
+

Fields

+
+
+ + juce.AudioFormatReader.sampleRate +
+
+ Sample rate + + + + + + + + +
+
+ + juce.AudioFormatReader.bitsPerSample +
+
+ Bits per sample + + + + + + + + +
+
+ + juce.AudioFormatReader.lengthInSamples +
+
+ Length in samples + + + + + + + + +
+
+ + juce.AudioFormatReader.numChannels +
+
+ Number of channels + + + + + + + + +
+
+ + juce.AudioFormatReader.usesFloatingPointData +
+
+ Uses floating point data (boolean) + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Colour.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Colour.html new file mode 100644 index 0000000..0887fd6 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Colour.html @@ -0,0 +1,381 @@ + + + + + protoplug: Class juce.Colour + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Colour

+

A simple colour class.

+

Is converted to a JUCE Colour

+ + +

Constructors

+ + + + + + + + + +
juce.Colour (r, g, b[, a])Constuctor with classical arguments.
juce.Colour (args)Constuctor with named arguments.
+

Fields

+ + + + + + + + + + + + + + + + + +
juce.Colour.rRed (0-255)
juce.Colour.gGreen (0-255)
juce.Colour.bBlue (0-255)
juce.Colour.aAlpha (0-255)
+

Predefined values

+ + + + + + + + + + + + + + + + + + + + + +
juce.Colour.black + +
juce.Colour.white + +
juce.Colour.red + +
juce.Colour.green + +
juce.Colour.blue + +
+ +
+
+ + +

Constructors

+
+
+ + juce.Colour (r, g, b[, a]) +
+
+ Constuctor with classical arguments. + + + +

Parameters:

+
    +
  • r + red +
  • +
  • g + green +
  • +
  • b + blue +
  • +
  • a + alpha +
  • +
+ + + + + +
+
+ + juce.Colour (args) +
+
+ Constuctor with named arguments. + Every field is optional. + + + +

Parameters:

+
    +
  • args + + +
      +
    • r + red +
    • +
    • g + green +
    • +
    • b + blue, +
    • +
    • a + alpha +
    • +
    +
+ + + + + +
+
+

Fields

+
+
+ + juce.Colour.r +
+
+ Red (0-255) + + + + + + + + +
+
+ + juce.Colour.g +
+
+ Green (0-255) + + + + + + + + +
+
+ + juce.Colour.b +
+
+ Blue (0-255) + + + + + + + + +
+
+ + juce.Colour.a +
+
+ Alpha (0-255) + + + + + + + + +
+
+

Predefined values

+
+
+ + juce.Colour.black +
+
+ + + + + + + + + +
+
+ + juce.Colour.white +
+
+ + + + + + + + + +
+
+ + juce.Colour.red +
+
+ + + + + + + + + +
+
+ + juce.Colour.green +
+
+ + + + + + + + + +
+
+ + juce.Colour.blue +
+
+ + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.ColourGradient.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.ColourGradient.html new file mode 100644 index 0000000..5e32a49 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.ColourGradient.html @@ -0,0 +1,371 @@ + + + + + protoplug: Class juce.ColourGradient + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.ColourGradient

+

Colour Gradient.

+

Is a pointer to a JUCE ColourGradient

+ + +

Constructors

+ + + + + +
juce.ColourGradient (colour1, x1, y1, colour2, x2, y2, isRadial)Constuctor.
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
juce.ColourGradient:addColour
(proportionAlongGradient, colour)
Add colour.
juce.ColourGradient:removeColour (index)Remove colour.
juce.ColourGradient:multiplyOpacity (multiplier)Multiply opacity.
juce.ColourGradient:getNumColours ()Get number colour.
juce.ColourGradient:getColour (index)Get colour.
juce.ColourGradient:setColour (index, newColour)Get colour.
juce.ColourGradient:getColourAtPosition (position)Get interpolated colour
+ +
+
+ + +

Constructors

+
+
+ + juce.ColourGradient (colour1, x1, y1, colour2, x2, y2, isRadial) +
+
+ Constuctor. + + + +

Parameters:

+
    +
  • colour1 + juce.Colour + colour at the beginning of the gradient +
  • +
  • x1 + coordinates of colour1 +
  • +
  • y1 + coordinates of colour1 +
  • +
  • colour2 + juce.Colour + colour at the end of the gradient +
  • +
  • x2 + coordinates of colour2 +
  • +
  • y2 + coordinates of colour2 +
  • +
  • isRadial + boolean + whether the gradient should be linear or radial +
  • +
+ + + + + +
+
+

Methods

+
+
+ + juce.ColourGradient:addColour
(proportionAlongGradient, colour)
+
+
+ Add colour. + Any number of colours can be added between the start and end of the gradient. + + + +

Parameters:

+
    +
  • proportionAlongGradient + + + +
  • +
  • colour + juce.Colour + + + +
  • +
+ +

Returns:

+
    + + the new colour's index +
+ + + + +
+
+ + juce.ColourGradient:removeColour (index) +
+
+ Remove colour. + + + +

Parameters:

+
    +
  • index + colour index between 0 and getNumColours() - 1 +
  • +
+ + + + + +
+
+ + juce.ColourGradient:multiplyOpacity (multiplier) +
+
+ Multiply opacity. + + + +

Parameters:

+
    +
  • multiplier + factor to multiply the alpha values by +
  • +
+ + + + + +
+
+ + juce.ColourGradient:getNumColours () +
+
+ Get number colour. + + + + +

Returns:

+
    + + the number of colours +
+ + + + +
+
+ + juce.ColourGradient:getColour (index) +
+
+ Get colour. + + + +

Parameters:

+
    +
  • index + colour index between 0 and getNumColours() - 1 +
  • +
+ +

Returns:

+
    + + juce.Colour + the coulour at the specified index +
+ + + + +
+
+ + juce.ColourGradient:setColour (index, newColour) +
+
+ Get colour. + + + +

Parameters:

+
    +
  • index + colour index between 0 and getNumColours() - 1 +
  • +
  • newColour + juce.Colour + + + +
  • +
+ + + + + +
+
+ + juce.ColourGradient:getColourAtPosition (position) +
+
+ Get interpolated colour + + + +

Parameters:

+
    +
  • position + the position between 0 and 1 +
  • +
+ +

Returns:

+
    + + juce.Colour + the interpolated colour at the specified position +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Component.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Component.html new file mode 100644 index 0000000..6766722 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Component.html @@ -0,0 +1,249 @@ + + + + + protoplug: Class juce.Component + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Component

+

JUCE Component.

+

Is a pointer to a JUCE Component

+ +

As of now, components can't be created by protoplug scripts. This is mainly + for accessing the custom GUI component using gui.getComponent.

+ + +

Methods

+ + + + + + + + + + + + + + + + + +
juce.Component:repaint ()Request total repaint.
juce.Component:repaint (area)Request partial repaint.
juce.Component:repaint (x, y, width, height)Request partial repaint.
juce.Component:createComponentSnapshot
(areaToGrab[, clipImageToComponentBounds=true[, scaleFactor=1]])
Create component snapshot.
+ +
+
+ + +

Methods

+
+
+ + juce.Component:repaint () +
+
+ Request total repaint. + Tell the operating system that the component is "dirty" and needs to be redrawn. + The component's paint method will be called asynchronously (gui.paint) + + + + + + + + +
+
+ + juce.Component:repaint (area) +
+
+ Request partial repaint. + Tell the operating system that a portion of the component is "dirty" and needs to be redrawn. + The component's paint method will be called asynchronously (gui.paint). The dirty region will be accessible + with Graphics.getClipBounds(). + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + the region needing the be redrawn +
  • +
+ + + + + +
+
+ + juce.Component:repaint (x, y, width, height) +
+
+ Request partial repaint. + Tell the operating system that a portion of the component is "dirty" and needs to be redrawn. + The component's paint method will be called asynchronously (gui.paint). The dirty region will be accessible + with Graphics.getClipBounds(). + + + +

Parameters:

+
    +
  • x + the region needing the be redrawn +
  • +
  • y + the region needing the be redrawn +
  • +
  • width + the region needing the be redrawn +
  • +
  • height + the region needing the be redrawn +
  • +
+ + + + + +
+
+ + juce.Component:createComponentSnapshot
(areaToGrab[, clipImageToComponentBounds=true[, scaleFactor=1]])
+
+
+ Create component snapshot. + Paint the component into a virtual buffer and return it as an image. + + + +

Parameters:

+
    +
  • areaToGrab + juce.Rectangle_int + the region to the be drawn +
  • +
  • clipImageToComponentBounds + + + + (default true) +
  • +
  • scaleFactor + + + + (default 1) +
  • +
+ +

Returns:

+
    + + juce.Image + + + +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.FillType.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.FillType.html new file mode 100644 index 0000000..8026f5f --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.FillType.html @@ -0,0 +1,315 @@ + + + + + protoplug: Class juce.FillType + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.FillType

+

Fill Type.

+

Is a pointer to a JUCE FillType. + Can be used by juce.Graphics for fill operations.

+ + +

Constructors

+ + + + + + + + + +
juce.FillType (Colour)Constuct from a juce.Colour.
juce.FillType (Gradient)Constuct from a juce.ColourGradient.
+

Methods

+ + + + + +
juce.FillType:setOpacity (newOpacity)Set Overall Opacity.
+

Predefined values

+ + + + + + + + + + + + + + + + + + + + + +
juce.FillType.black + +
juce.FillType.white + +
juce.FillType.red + +
juce.FillType.green + +
juce.FillType.blue + +
+ +
+
+ + +

Constructors

+
+
+ + juce.FillType (Colour) +
+
+ Constuct from a juce.Colour. + + + +

Parameters:

+ + + + + + +
+
+ + juce.FillType (Gradient) +
+
+ Constuct from a juce.ColourGradient. + + + +

Parameters:

+ + + + + + +
+
+

Methods

+
+
+ + juce.FillType:setOpacity (newOpacity) +
+
+ Set Overall Opacity. + + + +

Parameters:

+
    +
  • newOpacity + + + +
  • +
+ + + + + +
+
+

Predefined values

+
+
+ + juce.FillType.black +
+
+ + + + + + + + + +
+
+ + juce.FillType.white +
+
+ + + + + + + + + +
+
+ + juce.FillType.red +
+
+ + + + + + + + + +
+
+ + juce.FillType.green +
+
+ + + + + + + + + +
+
+ + juce.FillType.blue +
+
+ + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Font.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Font.html new file mode 100644 index 0000000..50ae974 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Font.html @@ -0,0 +1,203 @@ + + + + + protoplug: Class juce.Font + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Font

+

Font.

+

Is a pointer to a JUCE Font. + Can be used by juce.Graphics for text operations.

+ + +

Constructors

+ + + + + +
juce.Font (typefaceName, fontHeight[, styleFlags=0[, hinted=false]])Constuctor.
+

Tables

+ + + + + +
juce.Font.stylesFont styles.
+ +
+
+ + +

Constructors

+
+
+ + juce.Font (typefaceName, fontHeight[, styleFlags=0[, hinted=false]]) +
+
+ Constuctor. + Caveat : on OSX and Linux, hinting only works for protoplug's + built-in hinted fonts (DejaVu Sans Mono and Source Code Pro). On + Windows it's available for every font. Cross-platform hinting is on the be + todo list. + + + +

Parameters:

+
    +
  • typefaceName + string + + + +
  • +
  • fontHeight + number + + + +
  • +
  • styleFlags + any combination of styles + (default 0) +
  • +
  • hinted + bool + + + + (default false) +
  • +
+ + + + + +
+
+

Tables

+
+
+ + juce.Font.styles +
+
+ Font styles. + + + +

Fields:

+
    +
  • plain + 0 +
  • +
  • bold + 1 +
  • +
  • italic + 2 +
  • +
  • underlined + 4 +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Graphics.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Graphics.html new file mode 100644 index 0000000..7a8a137 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Graphics.html @@ -0,0 +1,2220 @@ + + + + + protoplug: Class juce.Graphics + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Graphics

+

Graphics drawing target.

+

Is a pointer to a JUCE Graphics object. + Received in gui.paint as an argument.

+ + +

Constructors

+ + + + + +
juce.Graphics (imageToDrawOnto)Constuct from a juce.Image.
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
juce.Graphics:setColour (newColour)Set working colour.
juce.Graphics:setOpacity (newOpacity)Set working opacity.
juce.Graphics:setGradientFill (gradient)Set working Gradient.
juce.Graphics:setTiledImageFill
(imageToUse, anchorX, anchorY, opacity)
Set Tiled Image Fill.
juce.Graphics:setFillType (newFill)Set Fill.
juce.Graphics:setFont (newFont)Set Font.
juce.Graphics:setFont (newFontHeight)Set Font.
juce.Graphics:getCurrentFont ()Get Current Font.
juce.Graphics:drawSingleLineText
(text, startX, baselineY[, justification=Justification.left])
Draw single line of text.
juce.Graphics:drawMultiLineText
(text, startX, baselineY, maximumLineWidth)
Draw multiline text.
juce.Graphics:drawText
(x, y, width, height[, justification=Justification.left[, useEllipsesIfTooBig=false]])
Draw text.
juce.Graphics:drawText
(area[, justification=Justification.left[, useEllipsesIfTooBig=false]])
Draw text.
juce.Graphics:drawFittedText
(x, y, width, height, justification, maximumNumberOfLines[, minimumHorizontalScale=0.7])
Draw fitted text.
juce.Graphics:drawFittedText
(area, justification, maximumNumberOfLines[, minimumHorizontalScale=0.7])
Draw fitted text.
juce.Graphics:fillAll ([colourToUse])Fill the entire graphics target.
juce.Graphics:fillRect (x, y, width, height)Fill rectangle with current fill type.
juce.Graphics:fillRect (area)Fill rectangle with current fill type.
juce.Graphics:fillRect_float (x, y, width, height)Fill rectangle (sub-pixel accuracy).
juce.Graphics:fillRoundedRectangle
(x, y, width, height, cornerSize)
Fill rounded rectangle.
juce.Graphics:fillRoundedRectangle (area, cornerSize)Fill rounded rectangle.
juce.Graphics:fillCheckerBoard
(area, checkWidth, checkHeight, colour1, colour2)
Fill chequerboard.
juce.Graphics:drawRect
(x, y, width, height[, lineThickness=1])
Draw rectangle.
juce.Graphics:drawRect (area[, lineThickness=1])Draw rectangle.
juce.Graphics:drawRect_float
(x, y, width, height[, lineThickness=1])
Draw rect (sub-pixel accuracy).
juce.Graphics:drawRect_float (area[, lineThickness=1])Draw rect (sub-pixel accuracy).
juce.Graphics:drawRoundedRectangle
(x, y, width, height, cornerSize[, lineThickness=1])
Draw rounded rectangle.
juce.Graphics:drawRoundedRectangle
(area, cornerSize[, lineThickness=1])
Draw rounded rectangle.
juce.Graphics:setPixel (x, y)Set pixel with current colour.
juce.Graphics:fillEllipse (x, y, width, height)Fill ellipse with current fill.
juce.Graphics:drawEllipse
(x, y, width, height[, lineThickness=1])
Draw ellipse with current colour.
juce.Graphics:drawLine
(startX, startY, endX, endY[, lineThickness=1])
Draw line.
juce.Graphics:drawLine (line[, lineThickness=1])Draw line.
juce.Graphics:drawDashedLine
(line, dashLengths, numDashLengths[, lineThickness=1[, dashIndexToStartFrom=0]])
Draw dashed line.
juce.Graphics:drawVerticalLine (x, top, bottom)Draw vertical line.
juce.Graphics:drawHorizontalLine (y, left, right)Draw horizontal line.
juce.Graphics:fillPath
(path[, transform=juce.AffineTransform.identity])
Fill path.
juce.Graphics:strokePath (path[, args])Stroke path.
juce.Graphics:drawArrow
(line, lineThickness, arrowheadWidth, arrowheadLength)
Draw arrow.
juce.Graphics:setImageResamplingQuality (newQuality)Set image resampling quality.
juce.Graphics:drawImageAt
(imageToDraw, topLeftX, topLeftY[, fillAlphaChannelWithCurrentBrush=false])
Draw unscaled image at location.
juce.Graphics:drawImage
(imageToDraw, destX, destY, destWidth, destHeight, sourceX, sourceY, sourceWidth, sourceHeight[, fillAlphaChannelWithCurrentBrush=false])
Draw a portion of an image, stretched into a target rectangle.
juce.Graphics:drawImageTransformed
(imageToDraw, transform[, fillAlphaChannelWithCurrentBrush=false])
Draw transformed image.
juce.Graphics:drawImageWithin
(imageToDraw, destX, destY, destWidth, destHeight[, placementWithinTarget=juce.RectanglePlacement.centred[, fillAlphaChannelWithCurrentBrush=false]])
Draw image within.
juce.Graphics:getClipBounds ()Get clip bounds.
juce.Graphics:clipRegionIntersects ()Clip region intersects.
juce.Graphics:isClipEmpty ()Is clipping region empty.
juce.Graphics:saveState ()Save state.
juce.Graphics:restoreState ()Restore state.
juce.Graphics:beginTransparencyLayer ()Begin transparency layer.
juce.Graphics:endTransparencyLayer ()End transparency layer.
juce.Graphics:setOrigin (newOriginX, newOriginY)Set origin.
juce.Graphics:addTransform (transform)Add a transformation matrix.
juce.Graphics:resetToDefaultState ()Reset to default state.
juce.Graphics:isVectorDevice ()Is vector device.
+

Tables

+ + + + + +
juce.Graphics.ResamplingQualityResampling qualities.
+ +
+
+ + +

Constructors

+
+
+ + juce.Graphics (imageToDrawOnto) +
+
+ Constuct from a juce.Image. + Use this constructor to draw directly onto an juce.Image in memory.

+ +

A typical use is to can create a juce.Image object and use it as a + backbuffer for pre-rendering graphics. + + + +

Parameters:

+ + + + + + +
+
+

Methods

+
+
+ + juce.Graphics:setColour (newColour) +
+
+ Set working colour. + Set the colour to be used for subsequent calls such as drawRect and drawText. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:setOpacity (newOpacity) +
+
+ Set working opacity. + Set the opacity to be used for subsequent calls. + + + +

Parameters:

+
    +
  • newOpacity + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:setGradientFill (gradient) +
+
+ Set working Gradient. + Use a gradient as fill for subsequent calls such as fillRect. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:setTiledImageFill
(imageToUse, anchorX, anchorY, opacity)
+
+
+ Set Tiled Image Fill. + Use a tiled image as fill for subsequent calls such as fillRect. + + + +

Parameters:

+
    +
  • imageToUse + juce.Image + + + +
  • +
  • anchorX + + + +
  • +
  • anchorY + + + +
  • +
  • opacity + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:setFillType (newFill) +
+
+ Set Fill. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:setFont (newFont) +
+
+ Set Font. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:setFont (newFontHeight) +
+
+ Set Font. + + + +

Parameters:

+
    +
  • newFontHeight + number + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:getCurrentFont () +
+
+ Get Current Font. + treturn juce.Font the current font + + + + + + + + +
+
+ + juce.Graphics:drawSingleLineText
(text, startX, baselineY[, justification=Justification.left])
+
+
+ Draw single line of text. + + + +

Parameters:

+
    +
  • text + string + + + +
  • +
  • startX + + + +
  • +
  • baselineY + + + +
  • +
  • justification + juce.Justification + + + + (default Justification.left) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawMultiLineText
(text, startX, baselineY, maximumLineWidth)
+
+
+ Draw multiline text. + + + +

Parameters:

+
    +
  • text + string + + + +
  • +
  • startX + + + +
  • +
  • baselineY + + + +
  • +
  • maximumLineWidth + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:drawText
(x, y, width, height[, justification=Justification.left[, useEllipsesIfTooBig=false]])
+
+
+ Draw text. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • justification + juce.Justification + + + + (default Justification.left) +
  • +
  • useEllipsesIfTooBig + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawText
(area[, justification=Justification.left[, useEllipsesIfTooBig=false]])
+
+
+ Draw text. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • justification + juce.Justification + + + + (default Justification.left) +
  • +
  • useEllipsesIfTooBig + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawFittedText
(x, y, width, height, justification, maximumNumberOfLines[, minimumHorizontalScale=0.7])
+
+
+ Draw fitted text. + Awkwardly squishes the font (up to minimumHorizontalScale) if necessary. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • justification + juce.Justification + + + +
  • +
  • maximumNumberOfLines + + + +
  • +
  • minimumHorizontalScale + + + + (default 0.7) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawFittedText
(area, justification, maximumNumberOfLines[, minimumHorizontalScale=0.7])
+
+
+ Draw fitted text. + Awkwardly squishes the font (up to minimumHorizontalScale) if necessary. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • justification + juce.Justification + + + +
  • +
  • maximumNumberOfLines + + + +
  • +
  • minimumHorizontalScale + + + + (default 0.7) +
  • +
+ + + + + +
+
+ + juce.Graphics:fillAll ([colourToUse]) +
+
+ Fill the entire graphics target. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:fillRect (x, y, width, height) +
+
+ Fill rectangle with current fill type. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillRect (area) +
+
+ Fill rectangle with current fill type. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillRect_float (x, y, width, height) +
+
+ Fill rectangle (sub-pixel accuracy). + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillRoundedRectangle
(x, y, width, height, cornerSize)
+
+
+ Fill rounded rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • cornerSize + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillRoundedRectangle (area, cornerSize) +
+
+ Fill rounded rectangle. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • cornerSize + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillCheckerBoard
(area, checkWidth, checkHeight, colour1, colour2)
+
+
+ Fill chequerboard. + (and i thought juce used British spelling) + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • checkWidth + + + +
  • +
  • checkHeight + + + +
  • +
  • colour1 + juce.Colour + + + +
  • +
  • colour2 + juce.Colour + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:drawRect
(x, y, width, height[, lineThickness=1])
+
+
+ Draw rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawRect (area[, lineThickness=1]) +
+
+ Draw rectangle. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawRect_float
(x, y, width, height[, lineThickness=1])
+
+
+ Draw rect (sub-pixel accuracy). + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawRect_float (area[, lineThickness=1]) +
+
+ Draw rect (sub-pixel accuracy). + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawRoundedRectangle
(x, y, width, height, cornerSize[, lineThickness=1])
+
+
+ Draw rounded rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • cornerSize + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawRoundedRectangle
(area, cornerSize[, lineThickness=1])
+
+
+ Draw rounded rectangle. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_int + + + +
  • +
  • cornerSize + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:setPixel (x, y) +
+
+ Set pixel with current colour. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillEllipse (x, y, width, height) +
+
+ Fill ellipse with current fill. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:drawEllipse
(x, y, width, height[, lineThickness=1])
+
+
+ Draw ellipse with current colour. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawLine
(startX, startY, endX, endY[, lineThickness=1])
+
+
+ Draw line. + + + +

Parameters:

+
    +
  • startX + + + +
  • +
  • startY + + + +
  • +
  • endX + + + +
  • +
  • endY + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawLine (line[, lineThickness=1]) +
+
+ Draw line. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawDashedLine
(line, dashLengths, numDashLengths[, lineThickness=1[, dashIndexToStartFrom=0]])
+
+
+ Draw dashed line. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • dashLengths + (const float* ctype) +
  • +
  • numDashLengths + + + +
  • +
  • lineThickness + + + + (default 1) +
  • +
  • dashIndexToStartFrom + + + + (default 0) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawVerticalLine (x, top, bottom) +
+
+ Draw vertical line. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • top + + + +
  • +
  • bottom + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:drawHorizontalLine (y, left, right) +
+
+ Draw horizontal line. + + + +

Parameters:

+
    +
  • y + + + +
  • +
  • left + + + +
  • +
  • right + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:fillPath
(path[, transform=juce.AffineTransform.identity])
+
+
+ Fill path. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:strokePath (path[, args]) +
+
+ Stroke path. + All named arguments are optional + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:drawArrow
(line, lineThickness, arrowheadWidth, arrowheadLength)
+
+
+ Draw arrow. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • lineThickness + + + +
  • +
  • arrowheadWidth + + + +
  • +
  • arrowheadLength + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:setImageResamplingQuality (newQuality) +
+
+ Set image resampling quality. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:drawImageAt
(imageToDraw, topLeftX, topLeftY[, fillAlphaChannelWithCurrentBrush=false])
+
+
+ Draw unscaled image at location. + + + +

Parameters:

+
    +
  • imageToDraw + juce.Image + + + +
  • +
  • topLeftX + + + +
  • +
  • topLeftY + + + +
  • +
  • fillAlphaChannelWithCurrentBrush + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawImage
(imageToDraw, destX, destY, destWidth, destHeight, sourceX, sourceY, sourceWidth, sourceHeight[, fillAlphaChannelWithCurrentBrush=false])
+
+
+ Draw a portion of an image, stretched into a target rectangle. + + + +

Parameters:

+
    +
  • imageToDraw + juce.Image + + + +
  • +
  • destX + + + +
  • +
  • destY + + + +
  • +
  • destWidth + + + +
  • +
  • destHeight + + + +
  • +
  • sourceX + + + +
  • +
  • sourceY + + + +
  • +
  • sourceWidth + + + +
  • +
  • sourceHeight + + + +
  • +
  • fillAlphaChannelWithCurrentBrush + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Graphics:drawImageTransformed
(imageToDraw, transform[, fillAlphaChannelWithCurrentBrush=false])
+
+
+ Draw transformed image. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:drawImageWithin
(imageToDraw, destX, destY, destWidth, destHeight[, placementWithinTarget=juce.RectanglePlacement.centred[, fillAlphaChannelWithCurrentBrush=false]])
+
+
+ Draw image within. + + + +

Parameters:

+
    +
  • imageToDraw + juce.Image + + + +
  • +
  • destX + + + +
  • +
  • destY + + + +
  • +
  • destWidth + + + +
  • +
  • destHeight + + + +
  • +
  • placementWithinTarget + + + + (default juce.RectanglePlacement.centred) +
  • +
  • fillAlphaChannelWithCurrentBrush + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Graphics:getClipBounds () +
+
+ Get clip bounds. + Get the portion of the graphics target that needs to be redrawn. + + + + +

Returns:

+
    + + juce.Rectangle_int + Clipping area +
+ + + + +
+
+ + juce.Graphics:clipRegionIntersects () +
+
+ Clip region intersects. + Check if a rectangle intersects with the redrawing region + + + + +

Returns:

+
    +
  1. + juce.Rectangle_int + Clipping area
  2. +
  3. + boolean + intersection check
  4. +
+ + + + +
+
+ + juce.Graphics:isClipEmpty () +
+
+ Is clipping region empty. + + + + +

Returns:

+
    + + boolean + whether the redrawing area is empty +
+ + + + +
+
+ + juce.Graphics:saveState () +
+
+ Save state. + Saves the current state of the graphics target on a stack. + This does not save the actual graphic's contents but its current + colour, transform, origin, etc. + + + + + + + + +
+
+ + juce.Graphics:restoreState () +
+
+ Restore state. + Restores a state of the graphics target from the stack. + Useful to cancel any previous uses + of addTransform, setColour, etc. + + + + + + + + +
+
+ + juce.Graphics:beginTransparencyLayer () +
+
+ Begin transparency layer. + Saves the current state and begins drawing on a temporary layer, + to be applied with the specified final transparency. + + + + + + + + +
+
+ + juce.Graphics:endTransparencyLayer () +
+
+ End transparency layer. + Applies the transparency layer that was started with beginTransparencyLayer. + + + + + + + + +
+
+ + juce.Graphics:setOrigin (newOriginX, newOriginY) +
+
+ Set origin. + + + +

Parameters:

+
    +
  • newOriginX + + + +
  • +
  • newOriginY + + + +
  • +
+ + + + + +
+
+ + juce.Graphics:addTransform (transform) +
+
+ Add a transformation matrix. + The matrix will be chained onto the current one, and affect all + subsequent graphics operations. Use saveState and restoreState + to apply a temporary transform. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Graphics:resetToDefaultState () +
+
+ Reset to default state. + + + + + + + + +
+
+ + juce.Graphics:isVectorDevice () +
+
+ Is vector device. + + + + +

Returns:

+
    + + boolean + whether the target is a vector device. +
+ + + + +
+
+

Tables

+
+
+ + juce.Graphics.ResamplingQuality +
+
+ Resampling qualities. + + + +

Fields:

+
    +
  • low + + + +
  • +
  • medium + + + +
  • +
  • high + + + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Image.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Image.html new file mode 100644 index 0000000..e97ef5b --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Image.html @@ -0,0 +1,260 @@ + + + + + protoplug: Class juce.Image + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Image

+

Image.

+

Images can be loaded from a file, or created as temporary graphics targets.

+ +

Is a pointer to a JUCE Image, + and wraps some JUCE ImageFileFormat + functionality.

+ + +

Constructors

+ + + + + + + + + +
juce.Image (filename)Load an image from a file.
juce.Image (pixelFormat, imageWidth, imageHeight, clearImage)Create a temporary in-memory image.
+

Methods

+ + + + + +
juce.Image:isValid ()Check Image validity.
+

Tables

+ + + + + +
juce.Image.PixelFormatPixel formats.
+ +
+
+ + +

Constructors

+
+
+ + juce.Image (filename) +
+
+ Load an image from a file. + The path can be absolute or relative to the protoplug directory. + To check if the file was loaded successfully, use isValid. + + + +

Parameters:

+
    +
  • filename + + + +
  • +
+ + + + + +
+
+ + juce.Image (pixelFormat, imageWidth, imageHeight, clearImage) +
+
+ Create a temporary in-memory image. + + + +

Parameters:

+
    +
  • pixelFormat + juce.Image.PixelFormat + + + +
  • +
  • imageWidth + + + +
  • +
  • imageHeight + + + +
  • +
  • clearImage + boolean + fill the image with black +
  • +
+ + + + + +
+
+

Methods

+
+
+ + juce.Image:isValid () +
+
+ Check Image validity. + + + + +

Returns:

+
    + + boolean + whether the image is valid and can be used. +
+ + + + +
+
+

Tables

+
+
+ + juce.Image.PixelFormat +
+
+ Pixel formats. + + + +

Fields:

+
    +
  • UnknownFormat + 0 +
  • +
  • RGB + 1 +
  • +
  • ARGB + 2 +
  • +
  • SingleChannel + 3 +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Justification.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Justification.html new file mode 100644 index 0000000..29d4790 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Justification.html @@ -0,0 +1,214 @@ + + + + + protoplug: Class juce.Justification + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Justification

+

Justification.

+

Is converted to a JUCE Justification

+ + +

Tables

+ + + + + +
juce.JustificationJustification Constants.
+ +
+
+ + +

Tables

+
+
+ + juce.Justification +
+
+ Justification Constants. + + + +

Fields:

+
    +
  • left + + + +
  • +
  • right + + + +
  • +
  • horizontallyCentred + + + +
  • +
  • top + + + +
  • +
  • bottom + + + +
  • +
  • verticallyCentred + + + +
  • +
  • horizontallyJustified + + + +
  • +
  • centred + + + +
  • +
  • centredLeft + + + +
  • +
  • centredRight + + + +
  • +
  • centredTop + + + +
  • +
  • centredBottom + + + +
  • +
  • topLeft + + + +
  • +
  • topRight + + + +
  • +
  • bottomLeft + + + +
  • +
  • bottomRight + + + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.LagrangeInterpolator.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.LagrangeInterpolator.html new file mode 100644 index 0000000..ff4e40f --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.LagrangeInterpolator.html @@ -0,0 +1,180 @@ + + + + + protoplug: Class juce.LagrangeInterpolator + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.LagrangeInterpolator

+

Lagrange Interpolator.

+

Is converted to a JUCE LagrangeInterpolator

+ + +

Constructors

+ + + + + +
juce.LagrangeInterpolator ()Constuctor.
+

Methods

+ + + + + +
juce.LagrangeInterpolator:process
(speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce)
Interpolate.
+ +
+
+ + +

Constructors

+
+
+ + juce.LagrangeInterpolator () +
+
+ Constuctor. + + + + + + + + +
+
+

Methods

+
+
+ + juce.LagrangeInterpolator:process
(speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce)
+
+
+ Interpolate. + + + +

Parameters:

+
    +
  • speedRatio + number of input samples per output sample (input/output) +
  • +
  • inputSamples + pointer to a cdata float array +
  • +
  • outputSamples + pointer to a cdata float array +
  • +
  • numOutputSamplesToProduce + + + +
  • +
+ +

Returns:

+
    + + number + number of input samples that were processed +
+ + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Line.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Line.html new file mode 100644 index 0000000..16a43bf --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Line.html @@ -0,0 +1,284 @@ + + + + + protoplug: Class juce.Line + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Line

+

Line.

+

Is converted to a JUCE Line

+ + +

Constructors

+ + + + + + + + + +
juce.Line (x1, y1, x2, y2)Constuctor
juce.Line (args)Constuctor
+

Fields

+ + + + + + + + + + + + + + + + + +
juce.Line.x1Point 1 X position
juce.Line.y1Point 1 Y position
juce.Line.x2Point 2 X position
juce.Line.y2Point 2 Y position
+ +
+
+ + +

Constructors

+
+
+ + juce.Line (x1, y1, x2, y2) +
+
+ Constuctor + + + +

Parameters:

+
    +
  • x1 + + + +
  • +
  • y1 + + + +
  • +
  • x2 + + + +
  • +
  • y2 + + + +
  • +
+ + + + + +
+
+ + juce.Line (args) +
+
+ Constuctor + + + +

Parameters:

+
    +
  • args + + +
      +
    • x1 + + + +
    • +
    • y1 + + + +
    • +
    • x2 + + + +
    • +
    • y2 + + + +
    • +
    +
+ + + + + +
+
+

Fields

+
+
+ + juce.Line.x1 +
+
+ Point 1 X position + + + + + + + + +
+
+ + juce.Line.y1 +
+
+ Point 1 Y position + + + + + + + + +
+
+ + juce.Line.x2 +
+
+ Point 2 X position + + + + + + + + +
+
+ + juce.Line.y2 +
+
+ Point 2 Y position + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Path.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Path.html new file mode 100644 index 0000000..93b41c4 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Path.html @@ -0,0 +1,2076 @@ + + + + + protoplug: Class juce.Path + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Path

+

Path.

+

Is a pointer to a JUCE Path.

+ + +

Constructors

+ + + + + +
juce.Path ()Constuctor
+

Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
juce.Path:getBounds ()Get bounds.
juce.Path:getBoundsTransformed (transform)Get bounds transformed.
juce.Path:contains (pointX, pointY[, tolerance=1])Contains.
juce.Path:contains (point[, tolerance=1])Contains.
juce.Path:intersectsLine (line[, tolerance=1])Intersects line.
juce.Path:getClippedLine (line, keepSectionOutsidePath)Get clipped line.
juce.Path:getLength
([transform=juce.AffineTransform.identity])
Get length.
juce.Path:getPointAlongPath
(distanceFromStart[, transform=juce.AffineTransform.identity])
Get point along path.
juce.Path:getNearestPoint
(targetPoint[, transform=juce.AffineTransform.identity])
Get nearest point.
juce.Path:clear ()Clear.
juce.Path:startNewSubPath (startX, startY)Start new sub path.
juce.Path:startNewSubPath (start)Start new sub path.
juce.Path:closeSubPath ()Close sub path.
juce.Path:lineTo (endX, endY)Line to.
juce.Path:lineTo (endpoint)Line to.
juce.Path:quadraticTo
(controlPointX, controlPointY, endPointX, endPointY)
Quadratic to.
juce.Path:quadraticTo2 (controlPoint, endPoint)Quadratic to2.
juce.Path:cubicTo
(controlPoint1X, controlPoint1Y, controlPoint2X, controlPoint2Y, endPointX, endPointY)
Cubic to.
juce.Path:cubicTo (controlPoint1, controlPoint2, endPoint)Cubic to.
juce.Path:getCurrentPosition ()Get current position.
juce.Path:addRectangle (x, y, width, height)Add rectangle.
juce.Path:addRectangle (rectangle)Add rectangle.
juce.Path:addRoundedRectangle
(x, y, width, height, cornerSize)
Add rounded rectangle.
juce.Path:addRoundedRectangle
(x, y, width, height, cornerSizeX, cornerSizeY)
Add rounded rectangle.
juce.Path:addRoundedRectangle
(x, y, width, height, cornerSizeX, cornerSizeY, curveTopLeft, curveTopRight, curveBottomLeft, curveBottomRight)
Add rounded rectangle.
juce.Path:addRoundedRectangle
(rectangle, cornerSizeX, cornerSizeY)
Add rounded rectangle.
juce.Path:addRoundedRectangle (rectangle, cornerSize)Add rounded rectangle.
juce.Path:addTriangle (x1, y1, x2, y2, x3, y3)Add triangle.
juce.Path:addQuadrilateral (x1, y1, x2, y2, x3, y3, x4, y4)Add quadrilateral.
juce.Path:addEllipse (x, y, width, height)Add ellipse.
juce.Path:addArc
(x, y, width, height, fromRadians, toRadians[, startAsNewSubPath=false])
Add arc.
juce.Path:addCentredArc
(centreX, centreY, radiusX, radiusY, rotationOfEllipse, fromRadians, toRadians[, startAsNewSubPath=false])
Add centred arc.
juce.Path:addPieSegment
(x, y, width, height, fromRadians, toRadians[, innerCircleProportionalSize=0])
Add pie segment.
juce.Path:addLineSegment (line, lineThickness)Add line segment.
juce.Path:addArrow
(line, lineThickness, arrowheadWidth, arrowheadLength)
Add arrow.
juce.Path:addPolygon
(centre, numberOfSides, radius[, startAngle=0])
Add polygon.
juce.Path:addStar
(centre, numberOfPoints, innerRadius, outerRadius[, startAngle=0])
Add star.
juce.Path:addBubble
(bodyArea, maximumArea, arrowTipPosition, cornerSize, arrowBaseWidth)
Add bubble.
juce.Path:addPath
(pathToAppend[, transform=juce.AffineTransform.identity])
Add path.
juce.Path:applyTransform (transform)Apply transform.
juce.Path:scaleToFit
(x, y, width, height, preserveProportions)
Scale to fit.
juce.Path:getTransformToScaleToFit
(x, y, width, height, preserveProportions[, justification=Justification.centred])
Get transform to scale to fit.
juce.Path:getTransformToScaleToFit
(area, preserveProportions[, justification=Justification.centred])
Get transform to scale to fit.
juce.Path:createPathWithRoundedCorners (cornerRadius)Create path with rounded corners.
juce.Path:setUsingNonZeroWinding (isNonZeroWinding)Set using non zero winding.
juce.Path:isUsingNonZeroWinding ()Is using non zero winding.
+

Tables

+ + + + + + + + + +
juce.Path.JointStyleJoint styles.
juce.Path.EndCapStyleEnd cap styles.
+ +
+
+ + +

Constructors

+
+
+ + juce.Path () +
+
+ Constuctor + + + + + + + + +
+
+

Methods

+
+
+ + juce.Path:getBounds () +
+
+ Get bounds. + + + + +

Returns:

+
    + + Rectangle_float + rectangle containing the path +
+ + + + +
+
+ + juce.Path:getBoundsTransformed (transform) +
+
+ Get bounds transformed. + + + +

Parameters:

+ + +

Returns:

+
    + + Rectangle_float + rectangle containing the transformed path +
+ + + + +
+
+ + juce.Path:contains (pointX, pointY[, tolerance=1]) +
+
+ Contains. + + + +

Parameters:

+
    +
  • pointX + + + +
  • +
  • pointY + + + +
  • +
  • tolerance + + + + (default 1) +
  • +
+ +

Returns:

+
    + + boolean + whether the path contains the point +
+ + +

See also:

+ + + +
+
+ + juce.Path:contains (point[, tolerance=1]) +
+
+ Contains. + + + +

Parameters:

+
    +
  • point + juce.Point + + + +
  • +
  • tolerance + + + + (default 1) +
  • +
+ +

Returns:

+
    + + boolean + whether the path contains the point +
+ + +

See also:

+ + + +
+
+ + juce.Path:intersectsLine (line[, tolerance=1]) +
+
+ Intersects line. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • tolerance + + + + (default 1) +
  • +
+ +

Returns:

+
    + + boolean + whether the path intersects the line +
+ + + + +
+
+ + juce.Path:getClippedLine (line, keepSectionOutsidePath) +
+
+ Get clipped line. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • keepSectionOutsidePath + boolean + + + +
  • +
+ +

Returns:

+
    + + juce.Line_float + the line clipped by the path +
+ + + + +
+
+ + juce.Path:getLength
([transform=juce.AffineTransform.identity])
+
+
+ Get length. + + + +

Parameters:

+ + +

Returns:

+
    + + length of the path +
+ + + + +
+
+ + juce.Path:getPointAlongPath
(distanceFromStart[, transform=juce.AffineTransform.identity])
+
+
+ Get point along path. + + + +

Parameters:

+
    +
  • distanceFromStart + + + +
  • +
  • transform + juce.AffineTransform + + + + (default juce.AffineTransform.identity) +
  • +
+ +

Returns:

+
    + + Point_float + the point on the path +
+ + + + +
+
+ + juce.Path:getNearestPoint
(targetPoint[, transform=juce.AffineTransform.identity])
+
+
+ Get nearest point. + Get the nearest on-path point to an arbitrary point, and + the distance between the points + + + +

Parameters:

+ + +

Returns:

+
    +
  1. + distance
  2. +
  3. + juce.Point + pointOnPath
  4. +
+ + + + +
+
+ + juce.Path:clear () +
+
+ Clear. + + + + + + + + +
+
+ + juce.Path:startNewSubPath (startX, startY) +
+
+ Start new sub path. + + + +

Parameters:

+
    +
  • startX + + + +
  • +
  • startY + + + +
  • +
+ + + + + +
+
+ + juce.Path:startNewSubPath (start) +
+
+ Start new sub path. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Path:closeSubPath () +
+
+ Close sub path. + + + + + + + + +
+
+ + juce.Path:lineTo (endX, endY) +
+
+ Line to. + + + +

Parameters:

+
    +
  • endX + + + +
  • +
  • endY + + + +
  • +
+ + + + + +
+
+ + juce.Path:lineTo (endpoint) +
+
+ Line to. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Path:quadraticTo
(controlPointX, controlPointY, endPointX, endPointY)
+
+
+ Quadratic to. + + + +

Parameters:

+
    +
  • controlPointX + + + +
  • +
  • controlPointY + + + +
  • +
  • endPointX + + + +
  • +
  • endPointY + + + +
  • +
+ + + + + +
+
+ + juce.Path:quadraticTo2 (controlPoint, endPoint) +
+
+ Quadratic to2. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Path:cubicTo
(controlPoint1X, controlPoint1Y, controlPoint2X, controlPoint2Y, endPointX, endPointY)
+
+
+ Cubic to. + + + +

Parameters:

+
    +
  • controlPoint1X + + + +
  • +
  • controlPoint1Y + + + +
  • +
  • controlPoint2X + + + +
  • +
  • controlPoint2Y + + + +
  • +
  • endPointX + + + +
  • +
  • endPointY + + + +
  • +
+ + + + + +
+
+ + juce.Path:cubicTo (controlPoint1, controlPoint2, endPoint) +
+
+ Cubic to. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Path:getCurrentPosition () +
+
+ Get current position. + + + + +

Returns:

+
    + + juce.Point + the current path construction position +
+ + + + +
+
+ + juce.Path:addRectangle (x, y, width, height) +
+
+ Add rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
+ + + + + +
+
+ + juce.Path:addRectangle (rectangle) +
+
+ Add rectangle. + + + +

Parameters:

+
    +
  • rectangle + juce.Rectangle_float + + + +
  • +
+ + + + + +
+
+ + juce.Path:addRoundedRectangle
(x, y, width, height, cornerSize)
+
+
+ Add rounded rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • cornerSize + + + +
  • +
+ + + + + +
+
+ + juce.Path:addRoundedRectangle
(x, y, width, height, cornerSizeX, cornerSizeY)
+
+
+ Add rounded rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • cornerSizeX + + + +
  • +
  • cornerSizeY + + + +
  • +
+ + + + + +
+
+ + juce.Path:addRoundedRectangle
(x, y, width, height, cornerSizeX, cornerSizeY, curveTopLeft, curveTopRight, curveBottomLeft, curveBottomRight)
+
+
+ Add rounded rectangle. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • cornerSizeX + + + +
  • +
  • cornerSizeY + + + +
  • +
  • curveTopLeft + boolean + + + +
  • +
  • curveTopRight + boolean + + + +
  • +
  • curveBottomLeft + boolean + + + +
  • +
  • curveBottomRight + boolean + + + +
  • +
+ + + + + +
+
+ + juce.Path:addRoundedRectangle
(rectangle, cornerSizeX, cornerSizeY)
+
+
+ Add rounded rectangle. + + + +

Parameters:

+
    +
  • rectangle + juce.Rectangle_float + + + +
  • +
  • cornerSizeX + + + +
  • +
  • cornerSizeY + + + +
  • +
+ + + + + +
+
+ + juce.Path:addRoundedRectangle (rectangle, cornerSize) +
+
+ Add rounded rectangle. + + + +

Parameters:

+
    +
  • rectangle + juce.Rectangle_float + + + +
  • +
  • cornerSize + + + +
  • +
+ + + + + +
+
+ + juce.Path:addTriangle (x1, y1, x2, y2, x3, y3) +
+
+ Add triangle. + + + +

Parameters:

+
    +
  • x1 + + + +
  • +
  • y1 + + + +
  • +
  • x2 + + + +
  • +
  • y2 + + + +
  • +
  • x3 + + + +
  • +
  • y3 + + + +
  • +
+ + + + + +
+
+ + juce.Path:addQuadrilateral (x1, y1, x2, y2, x3, y3, x4, y4) +
+
+ Add quadrilateral. + + + +

Parameters:

+
    +
  • x1 + + + +
  • +
  • y1 + + + +
  • +
  • x2 + + + +
  • +
  • y2 + + + +
  • +
  • x3 + + + +
  • +
  • y3 + + + +
  • +
  • x4 + + + +
  • +
  • y4 + + + +
  • +
+ + + + + +
+
+ + juce.Path:addEllipse (x, y, width, height) +
+
+ Add ellipse. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
+ + + + + +
+
+ + juce.Path:addArc
(x, y, width, height, fromRadians, toRadians[, startAsNewSubPath=false])
+
+
+ Add arc. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • fromRadians + the start angle, clockwise from the top +
  • +
  • toRadians + the end angle +
  • +
  • startAsNewSubPath + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Path:addCentredArc
(centreX, centreY, radiusX, radiusY, rotationOfEllipse, fromRadians, toRadians[, startAsNewSubPath=false])
+
+
+ Add centred arc. + + + +

Parameters:

+
    +
  • centreX + + + +
  • +
  • centreY + + + +
  • +
  • radiusX + + + +
  • +
  • radiusY + + + +
  • +
  • rotationOfEllipse + the ellipse inclination +
  • +
  • fromRadians + the start angle, clockwise from the top +
  • +
  • toRadians + the end angle +
  • +
  • startAsNewSubPath + + + + (default false) +
  • +
+ + + + + +
+
+ + juce.Path:addPieSegment
(x, y, width, height, fromRadians, toRadians[, innerCircleProportionalSize=0])
+
+
+ Add pie segment. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • fromRadians + the start angle, clockwise from the top +
  • +
  • toRadians + the end angle +
  • +
  • innerCircleProportionalSize + band proportion size, if specified + (default 0) +
  • +
+ + + + + +
+
+ + juce.Path:addLineSegment (line, lineThickness) +
+
+ Add line segment. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • lineThickness + + + +
  • +
+ + + + + +
+
+ + juce.Path:addArrow
(line, lineThickness, arrowheadWidth, arrowheadLength)
+
+
+ Add arrow. + + + +

Parameters:

+
    +
  • line + juce.Line + + + +
  • +
  • lineThickness + + + +
  • +
  • arrowheadWidth + + + +
  • +
  • arrowheadLength + + + +
  • +
+ + + + + +
+
+ + juce.Path:addPolygon
(centre, numberOfSides, radius[, startAngle=0])
+
+
+ Add polygon. + + + +

Parameters:

+
    +
  • centre + juce.Point + + + +
  • +
  • numberOfSides + + + +
  • +
  • radius + + + +
  • +
  • startAngle + + + + (default 0) +
  • +
+ + + + + +
+
+ + juce.Path:addStar
(centre, numberOfPoints, innerRadius, outerRadius[, startAngle=0])
+
+
+ Add star. + + + +

Parameters:

+
    +
  • centre + juce.Point + + + +
  • +
  • numberOfPoints + + + +
  • +
  • innerRadius + + + +
  • +
  • outerRadius + + + +
  • +
  • startAngle + + + + (default 0) +
  • +
+ + + + + +
+
+ + juce.Path:addBubble
(bodyArea, maximumArea, arrowTipPosition, cornerSize, arrowBaseWidth)
+
+
+ Add bubble. + + + +

Parameters:

+
    +
  • bodyArea + + + +
  • +
  • maximumArea + + + +
  • +
  • arrowTipPosition + + + +
  • +
  • cornerSize + + + +
  • +
  • arrowBaseWidth + + + +
  • +
+ + + + + +
+
+ + juce.Path:addPath
(pathToAppend[, transform=juce.AffineTransform.identity])
+
+
+ Add path. + + + +

Parameters:

+
    +
  • pathToAppend + + + +
  • +
  • transform + juce.AffineTransform + + + + (default juce.AffineTransform.identity) +
  • +
+ + + + + +
+
+ + juce.Path:applyTransform (transform) +
+
+ Apply transform. + + + +

Parameters:

+ + + + + + +
+
+ + juce.Path:scaleToFit
(x, y, width, height, preserveProportions)
+
+
+ Scale to fit. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • preserveProportions + + + +
  • +
+ + + + + +
+
+ + juce.Path:getTransformToScaleToFit
(x, y, width, height, preserveProportions[, justification=Justification.centred])
+
+
+ Get transform to scale to fit. + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
  • width + + + +
  • +
  • height + + + +
  • +
  • preserveProportions + boolean + + + +
  • +
  • justification + juce.Justification + + + + (default Justification.centred) +
  • +
+ +

Returns:

+
    + + juce.AffineTransform + the required transform +
+ + + + +
+
+ + juce.Path:getTransformToScaleToFit
(area, preserveProportions[, justification=Justification.centred])
+
+
+ Get transform to scale to fit. + + + +

Parameters:

+
    +
  • area + juce.Rectangle_float + + + +
  • +
  • preserveProportions + boolean + + + +
  • +
  • justification + juce.Justification + + + + (default Justification.centred) +
  • +
+ +

Returns:

+
    + + juce.AffineTransform + the required transform +
+ + + + +
+
+ + juce.Path:createPathWithRoundedCorners (cornerRadius) +
+
+ Create path with rounded corners. + + + +

Parameters:

+
    +
  • cornerRadius + + + +
  • +
+ +

Returns:

+
    + + juce.Path + the rounded path +
+ + + + +
+
+ + juce.Path:setUsingNonZeroWinding (isNonZeroWinding) +
+
+ Set using non zero winding. + + + +

Parameters:

+
    +
  • isNonZeroWinding + boolean + + + +
  • +
+ + + + + +
+
+ + juce.Path:isUsingNonZeroWinding () +
+
+ Is using non zero winding. + + + + +

Returns:

+
    + + boolean + whether the path is using non-zero winding +
+ + + + +
+
+

Tables

+
+
+ + juce.Path.JointStyle +
+
+ Joint styles. + for use with juce.Graphics.strokePath + + + +

Fields:

+
    +
  • mitered + + + +
  • +
  • curved + + + +
  • +
  • beveled + + + +
  • +
+ + + + + +
+
+ + juce.Path.EndCapStyle +
+
+ End cap styles. + for use with juce.Graphics.strokePath + + + +

Fields:

+
    +
  • butt + + + +
  • +
  • square + + + +
  • +
  • rounded + + + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Point.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Point.html new file mode 100644 index 0000000..0590018 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Point.html @@ -0,0 +1,226 @@ + + + + + protoplug: Class juce.Point + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Point

+

Point.

+

Is converted to a JUCE Point

+ + +

Constructors

+ + + + + + + + + +
juce.Point (x, y)Constuctor
juce.Point (args)Constuctor
+

Fields

+ + + + + + + + + +
juce.Point.xPoint X position
juce.Point.yPoint Y position
+ +
+
+ + +

Constructors

+
+
+ + juce.Point (x, y) +
+
+ Constuctor + + + +

Parameters:

+
    +
  • x + + + +
  • +
  • y + + + +
  • +
+ + + + + +
+
+ + juce.Point (args) +
+
+ Constuctor + + + +

Parameters:

+
    +
  • args + + +
      +
    • x + + + +
    • +
    • y + + + +
    • +
    +
+ + + + + +
+
+

Fields

+
+
+ + juce.Point.x +
+
+ Point X position + + + + + + + + +
+
+ + juce.Point.y +
+
+ Point Y position + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.RectanglePlacement.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.RectanglePlacement.html new file mode 100644 index 0000000..73519fe --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.RectanglePlacement.html @@ -0,0 +1,194 @@ + + + + + protoplug: Class juce.RectanglePlacement + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.RectanglePlacement

+

Rectangle Placement.

+

Is converted to a JUCE RectanglePlacement

+ + +

Tables

+ + + + + +
juce.RectanglePlacementRectangle Placement Constants.
+ +
+
+ + +

Tables

+
+
+ + juce.RectanglePlacement +
+
+ Rectangle Placement Constants. + + + +

Fields:

+
    +
  • xLeft + + + +
  • +
  • xRight + + + +
  • +
  • xMid + + + +
  • +
  • yTop + + + +
  • +
  • yBottom + + + +
  • +
  • yMid + + + +
  • +
  • stretchToFit + + + +
  • +
  • fillDestination + + + +
  • +
  • onlyReduceInSize + + + +
  • +
  • onlyIncreaseInSize + + + +
  • +
  • doNotResize + + + +
  • +
  • centred + + + +
  • +
+ + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Rectangle_float.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Rectangle_float.html new file mode 100644 index 0000000..be905fa --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Rectangle_float.html @@ -0,0 +1,386 @@ + + + + + protoplug: Class juce.Rectangle_float + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Rectangle_float

+

A floating-point (sub-pixel) rectangle.

+

Is converted to a JUCE Rectangle

+ + +

Constructors

+ + + + + + + + + +
juce.Rectangle_float (x, y, w, h)Constuctor with classical arguments.
juce.Rectangle_float (args)Constuctor with named arguments.
+

Methods

+ + + + + + + + + + + + + + + + + +
juce.Rectangle_float:toInt ()To int.
juce.Rectangle_float:contains (point)Contains.
juce.Rectangle_float:getR ()Get right.
juce.Rectangle_float:getB ()Get bottom.
+

Fields

+ + + + + + + + + + + + + + + + + +
juce.Rectangle_float.xLeft position
juce.Rectangle_float.yTop position
juce.Rectangle_float.wWidth
juce.Rectangle_float.hHeight
+ +
+
+ + +

Constructors

+
+
+ + juce.Rectangle_float (x, y, w, h) +
+
+ Constuctor with classical arguments. + + + +

Parameters:

+
    +
  • x + left position +
  • +
  • y + top position +
  • +
  • w + width +
  • +
  • h + height +
  • +
+ + + + + +
+
+ + juce.Rectangle_float (args) +
+
+ Constuctor with named arguments. + Every field is optional. + + + +

Parameters:

+
    +
  • args + + +
      +
    • x + left position +
    • +
    • y + top position +
    • +
    • w + width +
    • +
    • h + height +
    • +
    +
+ + + + + +
+
+

Methods

+
+
+ + juce.Rectangle_float:toInt () +
+
+ To int. + Convert to a pixel-aligned rectangle + + + + +

Returns:

+
    + + juce.Rectangle_int + + + +
+ + + + +
+
+ + juce.Rectangle_float:contains (point) +
+
+ Contains. + + + +

Parameters:

+ + +

Returns:

+
    + + boolean + whether the rectangle contains the point +
+ + + + +
+
+ + juce.Rectangle_float:getR () +
+
+ Get right. + + + + +

Returns:

+
    + + the rectangle's right position on the X axis +
+ + + + +
+
+ + juce.Rectangle_float:getB () +
+
+ Get bottom. + + + + +

Returns:

+
    + + the rectangle's bottom position on the Y axis +
+ + + + +
+
+

Fields

+
+
+ + juce.Rectangle_float.x +
+
+ Left position + + + + + + + + +
+
+ + juce.Rectangle_float.y +
+
+ Top position + + + + + + + + +
+
+ + juce.Rectangle_float.w +
+
+ Width + + + + + + + + +
+
+ + juce.Rectangle_float.h +
+
+ Height + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/classes/juce.Rectangle_int.html b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Rectangle_int.html new file mode 100644 index 0000000..0c7892f --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/classes/juce.Rectangle_int.html @@ -0,0 +1,386 @@ + + + + + protoplug: Class juce.Rectangle_int + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Class juce.Rectangle_int

+

An integer (pixel-aligned) rectangle.

+

Is converted to a JUCE Rectangle

+ + +

Constructors

+ + + + + + + + + +
juce.Rectangle_int (x, y, w, h)Constuctor with classical arguments.
juce.Rectangle_int (args)Constuctor with named arguments.
+

Methods

+ + + + + + + + + + + + + + + + + +
juce.Rectangle_int:toFloat ()To float.
juce.Rectangle_int:contains (point)Contains.
juce.Rectangle_int:getR ()Get right.
juce.Rectangle_int:getB ()Get bottom.
+

Fields

+ + + + + + + + + + + + + + + + + +
juce.Rectangle_int.xLeft position
juce.Rectangle_int.yTop position
juce.Rectangle_int.wWidth
juce.Rectangle_int.hHeight
+ +
+
+ + +

Constructors

+
+
+ + juce.Rectangle_int (x, y, w, h) +
+
+ Constuctor with classical arguments. + + + +

Parameters:

+
    +
  • x + left position +
  • +
  • y + top position +
  • +
  • w + width +
  • +
  • h + height +
  • +
+ + + + + +
+
+ + juce.Rectangle_int (args) +
+
+ Constuctor with named arguments. + Every field is optional. + + + +

Parameters:

+
    +
  • args + + +
      +
    • x + left position +
    • +
    • y + top position +
    • +
    • w + width +
    • +
    • h + height +
    • +
    +
+ + + + + +
+
+

Methods

+
+
+ + juce.Rectangle_int:toFloat () +
+
+ To float. + Convert to a sub-pixel rectangle + + + + +

Returns:

+
    + + juce.Rectangle_float + + + +
+ + + + +
+
+ + juce.Rectangle_int:contains (point) +
+
+ Contains. + + + +

Parameters:

+ + +

Returns:

+
    + + boolean + whether the rectangle contains the point +
+ + + + +
+
+ + juce.Rectangle_int:getR () +
+
+ Get right. + + + + +

Returns:

+
    + + the rectangle's right position on the X axis +
+ + + + +
+
+ + juce.Rectangle_int:getB () +
+
+ Get bottom. + + + + +

Returns:

+
    + + the rectangle's bottom position on the Y axis +
+ + + + +
+
+

Fields

+
+
+ + juce.Rectangle_int.x +
+
+ Left position + + + + + + + + +
+
+ + juce.Rectangle_int.y +
+
+ Top position + + + + + + + + +
+
+ + juce.Rectangle_int.w +
+
+ Width + + + + + + + + +
+
+ + juce.Rectangle_int.h +
+
+ Height + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/examples/classic-filter.lua.html b/ports/protoplug/ProtoplugFiles/doc/examples/classic-filter.lua.html new file mode 100644 index 0000000..ba76f3b --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/examples/classic-filter.lua.html @@ -0,0 +1,168 @@ + + + + + protoplug: Example classic-filter.lua + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +
+--[[
+name: Classic Filter
+description: >
+  Straightforward application of RBJ's cookbook filters. Formulae by
+  Robert Bristow-Johnson, implementation from Worp by Ico Doornekamp.
+author: osar.fr
+--]]
+
+require "include/protoplug"
+local cbFilter = require "include/pac/cookbook filters"
+local filters = {}
+
+stereoFx.init()
+
+function stereoFx.Channel:init()
+	-- create per-channel fields (filters)
+	self.filter = cbFilter
+	{
+		-- initialize filters with current param values
+		type 	= params[1].getValue();
+		f 		= params[2].getValue()/2;
+		gain 	= params[3].getValue();
+		Q 		= params[4].getValue();
+	}
+	table.insert(filters, self.filter)
+end
+
+function stereoFx.Channel:processBlock(s, smax)
+	for i = 0,smax do
+		s[i] = self.filter.process(s[i])
+	end
+end
+
+local function updateFilters(args)
+	for _, f in pairs(filters) do
+		f.update(args)
+	end
+end
+
+params = plugin.manageParams {
+	-- automatable VST/AU parameters
+	-- note the new 1.3 way of declaring them
+	{
+		name = "Type";
+		type = "list";
+		values = {"hp"; "lp"; "bp"; "bs"; "ls"; "hs"; "ap"; "eq"};
+		default = "hp";
+		changed = function(val) updateFilters{type=val} end;
+	};
+	{
+		name = "Frequency";
+		min = 10;
+		max = 20000;
+		default = 440;
+		changed = function(val) updateFilters{f=val} end;
+	};
+	{
+		name = "Gain";
+		min = -30;
+		max = 30;
+		default = 0;
+		changed = function(val) updateFilters{gain=val} end;
+	};
+	{
+		name = "Resonance";
+		min = 0.1;
+		max = 30;
+		default = 1;
+		changed = function(val) updateFilters{Q=val} end;
+	};
+}
+
+-- Reset the plugin parameters like this :
+-- params.resetToDefaults()
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/examples/midi-chordify.lua.html b/ports/protoplug/ProtoplugFiles/doc/examples/midi-chordify.lua.html new file mode 100644 index 0000000..bf93b2d --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/examples/midi-chordify.lua.html @@ -0,0 +1,142 @@ + + + + + protoplug: Example midi-chordify.lua + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +
+--[[
+name: midi chordify
+description: MIDI processor VST/AU. Notes go in, chords come out.
+author: osar.fr
+--]]
+
+require "include/protoplug"
+
+-- what kind of chord ?
+local chordStructure = {0, 3, 5, 7, 11}
+local blockEvents = {}
+
+function plugin.processBlock(samples, smax, midiBuf)
+	blockEvents = {}
+	-- analyse midi buffer and prepare a chord for each note
+	for ev in midiBuf:eachEvent() do
+		if ev:isNoteOn() then
+			chordOn(ev)
+		elseif ev:isNoteOff() then
+			chordOff(ev)
+		end
+	end
+	-- fill midi buffer with prepared notes
+	midiBuf:clear()
+	if #blockEvents>0 then
+		for _,e in ipairs(blockEvents) do
+			midiBuf:addEvent(e)
+		end
+	end
+end
+
+function chordOn(root)
+	for _, offset in ipairs(chordStructure) do
+		local newEv = midi.Event.noteOn(
+			root:getChannel(),
+			root:getNote()+offset,
+			root:getVel())
+		table.insert(blockEvents, newEv)
+	end
+end
+
+function chordOff(root)
+	for _, offset in ipairs(chordStructure) do
+		local newEv = midi.Event.noteOff(
+			root:getChannel(),
+			root:getNote()+offset)
+		table.insert(blockEvents, newEv)
+	end
+end
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/examples/sine-organ.lua.html b/ports/protoplug/ProtoplugFiles/doc/examples/sine-organ.lua.html new file mode 100644 index 0000000..3886369 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/examples/sine-organ.lua.html @@ -0,0 +1,138 @@ + + + + + protoplug: Example sine-organ.lua + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +
+--[[
+name: sine organ
+description: A simple organ-like sinewave VST/AU.
+author: osar.fr
+--]]
+
+require "include/protoplug"
+
+local release = 10000
+local decayRate = 1/release
+
+polyGen.initTracks(8)
+
+function polyGen.VTrack:init()
+	-- create per-track fields here
+	self.phase = 0
+	self.releasePos = release
+end
+
+function polyGen.VTrack:addProcessBlock(samples, smax)
+	local amp = 1
+	for i = 0,smax do
+		if not self.noteIsOn then
+			-- release is finished : idle track
+			if self.releasePos>=release then break end
+			-- release is under way
+			amp = 1-self.releasePos*decayRate
+			self.releasePos = self.releasePos+1
+		end
+		self.phase = self.phase + (self.noteFreq*math.pi*2)
+		-- math.sin is slow but once per sample is no tragedy
+		local trackSample = math.sin(self.phase)*amp*0.3
+		samples[0][i] = samples[0][i] + trackSample -- left
+		samples[1][i] = samples[1][i] + trackSample -- right
+	end
+end
+
+function polyGen.VTrack:noteOff(note, ev)
+	self.releasePos = 0
+end
+
+function polyGen.VTrack:noteOn(note, vel, ev)
+	-- start the sinewave at 0 for a clickless attack
+	self.phase = 0
+end
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/examples/sinemouse-demo.lua.html b/ports/protoplug/ProtoplugFiles/doc/examples/sinemouse-demo.lua.html new file mode 100644 index 0000000..b58391c --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/examples/sinemouse-demo.lua.html @@ -0,0 +1,140 @@ + + + + + protoplug: Example sinemouse-demo.lua + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +
+--[[
+name: sinemouse demo
+description: >
+  Custom GUI demonstration : Drag your mouse around in the
+  frame to control the sine wave's amplitude and frequency.
+author: osar.fr
+--]]
+
+require "include/protoplug"
+
+local freq,amp = 440, 0
+local delta, phase = 0.06, 0
+
+function plugin.processBlock(samples, smax)
+	for i=0,smax do
+		local s = math.sin(phase)*amp
+		samples[0][i] = s -- left
+		samples[1][i] = s -- right
+		phase = phase + delta
+	end
+end
+
+local J = juce
+local frame = J.Rectangle_int(20,20,400,300)
+local sideways = J.AffineTransform():rotated(math.pi*0.5)
+
+function gui.paint(g)
+	g:fillAll()
+	g:setColour(J.Colour.green)
+	g:drawRect(frame)
+	g:drawText("Frequency", 20, 320, 400, 20, J.Justification.centred)
+	g:addTransform(sideways)
+	g:drawText("amplitude", 20, -440, 300, 20, J.Justification.centred)
+end
+
+local function mouseHandler(event)
+	if not frame:contains(J.Point(event.x,event.y)) then
+		return
+	end
+	freq = event.x + 80
+	amp = (320-event.y)/300
+	local sr = plugin.isSampleRateKnown() and plugin.getSampleRate() or 44100
+	delta = 2*math.pi*freq/sr
+end
+
+gui.addHandler("mouseDrag", mouseHandler)
+gui.addHandler("mouseDown", mouseHandler)
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/examples/soundfile-test.lua.html b/ports/protoplug/ProtoplugFiles/doc/examples/soundfile-test.lua.html new file mode 100644 index 0000000..d176f9a --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/examples/soundfile-test.lua.html @@ -0,0 +1,132 @@ + + + + + protoplug: Example soundfile-test.lua + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +
+--[[
+name: soundfile test
+description: A simple demo that plays an audio file.
+author: osar.fr
+--]]
+
+require "include/protoplug"
+
+local path = "C:\\temp\\pluck44.wav"
+local wave, len
+
+-- 'prepareToPlay' will be triggered when the host sample rate is known,
+-- so we can load sound files with automatic sample rate conversion:
+plugin.addHandler('prepareToPlay', function()
+	local readr = juce.AudioFormatReader(path)
+	if readr==nil then error ("can't open wave: "..path) end
+	wave, len = readr:readToFloat(2) -- require 2 channels
+end)
+
+polyGen.initTracks(8)
+
+function polyGen.VTrack:noteOn(note, vel, ev)
+	self.playing = true
+	self.wavepos = 0
+end
+
+function polyGen.VTrack:noteOff(note, ev)
+	self.playing = false
+end
+
+function polyGen.VTrack:addProcessBlock(samples, smax)
+	for i = 0,smax do
+		if self.playing and self.wavepos < len then
+			self.wavepos = self.wavepos + 1
+			samples[0][i] = samples[0][i] + wave[0][self.wavepos] -- left
+			samples[1][i] = samples[1][i] + wave[1][self.wavepos] -- right
+		end
+	end
+end
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/index.html b/ports/protoplug/ProtoplugFiles/doc/index.html new file mode 100644 index 0000000..110c089 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/index.html @@ -0,0 +1,212 @@ + + + + + Protoplug Lua API Reference + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ + +

Protoplug Lua API Reference

+ +

Modules

+ + + + + + + + + + + + + + + + + + + + + + + + + +
pluginUse plugin to define the AU/VST audio plugin's behaviour.
scriptUse script to handle script events, libraries and files.
midimidi contains MIDI-related classes and functions.
guiUse gui to define your script's custom graphical user interface.
polyGenUse this module to create a polyphonic generator with virtual tracks.
stereoFxUse this module to create a stereo effect.
+

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
juce.AffineTransformA geometric transformation.
juce.AudioFormatReaderClass to read audio files.
juce.ColourA simple colour class.
juce.ColourGradientColour Gradient.
juce.ComponentJUCE Component.
juce.FillTypeFill Type.
juce.FontFont.
juce.GraphicsGraphics drawing target.
juce.ImageImage.
juce.JustificationJustification.
juce.LagrangeInterpolatorLagrange Interpolator.
juce.LineLine.
juce.PathPath.
juce.PointPoint.
juce.RectanglePlacementRectangle Placement.
juce.Rectangle_floatA floating-point (sub-pixel) rectangle.
juce.Rectangle_intAn integer (pixel-aligned) rectangle.
+

Examples

+ + + + + + + + + + + + + + + + + + + + + +
classic-filter.lua
sine-organ.lua
midi-chordify.lua
sinemouse-demo.lua
soundfile-test.lua
+ +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/ldoc.css b/ports/protoplug/ProtoplugFiles/doc/ldoc.css new file mode 100644 index 0000000..66fc8bd --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/ldoc.css @@ -0,0 +1,333 @@ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +body { + text-align: center; +} +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + list-style: bullet; + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 10px 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { + border-bottom: 2px solid #ccc; + font-size: 1.25em; + margin: 19px 0 12px; +} +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: Consolas, monaco, monospace; + padding-top: 1em; +} + +pre.example { + background-color: rgb(245, 245, 245); + border: 1px solid silver; + padding: 10px; + margin: 10px 0 10px 0; + font-family: Consolas, monaco, monospace; + font-size: .85em; +} + +pre { + background-color: rgb(245,245,255); + border: 1px solid #cccccc; + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: Consolas, monaco, monospace; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + font-size: 14px; +} + + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + /*margin-left: 1em; + margin-right: 1em; + background-color: #f4f4ff;*/ + display: inline-block; + margin: 0 auto; + text-align: left; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color:#FFFFFF; + /*border-left: 2px solid #cccccc;*/ +} + +#navigation { + float: left; + width: 14em; + vertical-align: top; + background-color:#FFFFFF; + overflow: visible; +} + +#navigation h2 { + background-color:#FFFFFF; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + /*border-top:1px solid #dddddd;*/ + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; + word-wrap: break-word; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + width: 700px; + border-left: 2px solid #cccccc; + /*border-right: 2px solid #cccccc;*/ + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: Consolas, monaco, monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f4f4ff; ; min-width: 200px; } +table.module_list td.summary { width: 100%; } + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; padding: 7px 5px; } +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt { + background-color: #f4f4ff; + border-bottom: 1px solid #ccc; + border-left: 1px solid #ccc; + border-top: 1px solid #ccc; + padding: 0.7em 0 0.5em 1em; +} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +ul.nowrap { + overflow:auto; + whitespace:nowrap; +} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* styles for prettification of source */ +pre .comment { color: #558817; } +pre .constant { color: #a8660d; } +pre .escape { color: #844631; } +pre .keyword { color: #2239a8; font-weight: bold; } +pre .library { color: #0e7c6b; } +pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +pre .string { color: #a8660d; } +pre .number { color: #f8660d; } +pre .operator { color: #2239a8; font-weight: bold; } +pre .preprocessor, pre .prepro { color: #a33243; } +pre .global { color: #800080; } +pre .prompt { color: #558817; } +pre .url { color: #272fc2; text-decoration: underline; } + +.wrapman { display: inline-block; white-space: normal; min-width: 460px; } +.proto_subtitle {color: #888; position: relative; top: -12px;} +.function_list .proto_prefix {color: #789;} +.osarlogo { + display: block; + width: 132px; + height: 121px; + background: url("osar-121.png") no-repeat scroll 0 0 transparent; + margin: 0 auto; +} diff --git a/ports/protoplug/ProtoplugFiles/doc/modules/gui.html b/ports/protoplug/ProtoplugFiles/doc/modules/gui.html new file mode 100644 index 0000000..da77a1d --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/modules/gui.html @@ -0,0 +1,677 @@ + + + + + protoplug: Module gui + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module gui

+

Use gui to define your script's custom graphical user interface.

+

+ +

Custom GUI example : sinemouse-demo.lua

+ +

The gui global is available to every protoplug script after including the + main protoplug header :

+
require "include/protoplug"
+
+

+ + +

Functions

+ + + + + + + + + + + + + +
gui.addHandler (event, handler)Add a handler for a GUI event.
gui.paint (g)Override to paint a custom GUI.
gui.getComponent ()Get GUI Component.
+

Tables

+ + + + + + + + + +
gui.FocusCauseFocus change causes.
gui.ModifierKeysKeyboard and mouse modifiers.
+

Class gui.MouseEvent

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
gui.MouseEvent.xX.
gui.MouseEvent.yY.
gui.MouseEvent.modsModifier keys.
gui.MouseEvent.eventComponentEvent component.
gui.MouseEvent.originalComponentOriginal component.
gui.MouseEvent.eventTimeTime.
gui.MouseEvent.mouseDownTimeMouse down time.
gui.MouseEvent.mouseDownPosMouse down position.
gui.MouseEvent.numberOfClicksNumber of clicks.
gui.MouseEvent.wasMovedSinceMouseDownWas moved since mouse down.
+

Class gui.MouseWheelDetails

+ + + + + + + + + + + + + + + + + +
gui.MouseWheelDetails.deltaXX delta.
gui.MouseWheelDetails.deltaYY delta.
gui.MouseWheelDetails.isReversedIs reversed.
gui.MouseWheelDetails.isSmoothIs smooth.
+

Class gui.KeyPress

+ + + + + + + + + + + + + +
gui.KeyPress.keyCodeKey code.
gui.KeyPress.modsModifier Keys.
gui.KeyPress.textCharacterText character.
+ +
+
+ + +

Functions

+
+
+ + gui.addHandler (event, handler) +
+
+ Add a handler for a GUI event.

+ +

Here's a list of the events and their parameters, showing how they +should be received :

+
gui.addHandler("resized",               function() ... end)
+gui.addHandler("focusGained",           function(focusCause) ... end)
+gui.addHandler("focusLost",             function(focusCause) ... end)
+gui.addHandler("modifierKeysChanged",   function(modifierKeys) ... end)
+gui.addHandler("mouseMove",             function(mouseEvent) ... end)
+gui.addHandler("mouseEnter",            function(mouseEvent) ... end)
+gui.addHandler("mouseExit",             function(mouseEvent) ... end)
+gui.addHandler("mouseDown",             function(mouseEvent) ... end)
+gui.addHandler("mouseDrag",             function(mouseEvent) ... end)
+gui.addHandler("mouseUp",               function(mouseEvent) ... end)
+gui.addHandler("mouseDoubleClick",      function(mouseEvent) ... end)
+gui.addHandler("mouseWheelMove",        function(mouseEvent, mouseWheelDetails) ... end)
+gui.addHandler("keyPressed",            function(keyPress, srcComponent) ... end)
+gui.addHandler("keyStateChanged",       function(keyPress, srcComponent) ... end)
+
+

Parameters received by the event handlers are of +type FocusCause, ModifierKeys, MouseEvent, MouseWheelDetails, +and KeyPress. + + + +

Parameters:

+
    +
  • event + string + the event to handle +
  • +
  • handler + function + a function to add the event's handlers +
  • +
+ + + +

See also:

+ + + +
+
+ + gui.paint (g) +
+
+ Override to paint a custom GUI. + Define this function to paint something in the custom GUI space. + + + +

Parameters:

+ + + + + + +
+
+ + gui.getComponent () +
+
+ Get GUI Component. + + + + +

Returns:

+
    + + the current GUI component, or nil if the GUI + has not been opened yet. +
+ + + + +
+
+

Tables

+
+
+ + gui.FocusCause +
+
+ Focus change causes. + Values received by the focusGained and focusLost handlers. + + + +

Fields:

+
    +
  • focusChangedByMouseClick + 0 +
  • +
  • focusChangedByTabKey + 1 +
  • +
  • focusChangedDirectly + 2 +
  • +
+ + + +

See also:

+ + + +
+
+ + gui.ModifierKeys +
+
+ Keyboard and mouse modifiers. + Contained in every gui.MouseEvent and received by the + modifierKeysChanged handler. + + + +

Fields:

+
    +
  • noModifiers + 0 +
  • +
  • shiftModifier + 1 +
  • +
  • ctrlModifier + 2 +
  • +
  • altModifier + 4 +
  • +
  • leftButtonModifier + 16 +
  • +
  • rightButtonModifier + 32 +
  • +
  • middleButtonModifier + 64 +
  • +
  • commandModifier + 8 +
  • +
  • ctrlAltCommandModifiers + 14 +
  • +
+ + + + + +
+
+

Class gui.MouseEvent

+ + A mouse event as received by GUI handlers (see gui.addHandler) +

+
+
+ + gui.MouseEvent.x +
+
+ X. + + + + + + + + +
+
+ + gui.MouseEvent.y +
+
+ Y. + + + + + + + + +
+
+ + gui.MouseEvent.mods +
+
+ Modifier keys. + Values defined in gui.ModifierKeys + + + + + + + + +
+
+ + gui.MouseEvent.eventComponent +
+
+ Event component. + + + + + + + + +
+
+ + gui.MouseEvent.originalComponent +
+
+ Original component. + + + + + + + + +
+
+ + gui.MouseEvent.eventTime +
+
+ Time. + + + + + + + + +
+
+ + gui.MouseEvent.mouseDownTime +
+
+ Mouse down time. + + + + + + + + +
+
+ + gui.MouseEvent.mouseDownPos +
+
+ Mouse down position. + + + + + + + + +
+
+ + gui.MouseEvent.numberOfClicks +
+
+ Number of clicks. + + + + + + + + +
+
+ + gui.MouseEvent.wasMovedSinceMouseDown +
+
+ Was moved since mouse down. + + + + + + + + +
+
+

Class gui.MouseWheelDetails

+ + As received by the mouseWheelMove handler (see gui.addHandler) +

+
+
+ + gui.MouseWheelDetails.deltaX +
+
+ X delta. + + + + + + + + +
+
+ + gui.MouseWheelDetails.deltaY +
+
+ Y delta. + + + + + + + + +
+
+ + gui.MouseWheelDetails.isReversed +
+
+ Is reversed. + + + + + + + + +
+
+ + gui.MouseWheelDetails.isSmooth +
+
+ Is smooth. + + + + + + + + +
+
+

Class gui.KeyPress

+ + As received by the keyPressed and keyStateChanged handlers (see gui.addHandler) +

+
+
+ + gui.KeyPress.keyCode +
+
+ Key code. + (undecipherable for now) + + + + + + + + +
+
+ + gui.KeyPress.mods +
+
+ Modifier Keys. + + + + + + + + +
+
+ + gui.KeyPress.textCharacter +
+
+ Text character. + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/modules/midi.html b/ports/protoplug/ProtoplugFiles/doc/modules/midi.html new file mode 100644 index 0000000..479b931 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/modules/midi.html @@ -0,0 +1,865 @@ + + + + + protoplug: Module midi + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module midi

+

midi contains MIDI-related classes and functions.

+

+ +

Example of receiving MIDI input : sine-organ.lua.

+ +

Example of producing MIDI output : midi-chordify.lua.

+ +

The midi global is available to every protoplug script after including the + main protoplug header :

+
require "include/protoplug"
+
+

+ + +

Functions

+ + + + + +
midi.noteToFreq (note)Convert a MIDI note number to frequency.
+

Class midi.Buffer

+ + + + + + + + + + + + + +
midi.Buffer:eachEvent ()Iterate over each midi.Event in the buffer.
midi.Buffer:clear ()Remove all MIDI events from the buffer.
midi.Buffer:addEvent (event)Add a MIDI event.
+

Class midi.Event

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
midi.Event (other)Constructor : copy another event.
midi.Event (time, dataSize[, data])Constructor : create a custom event.
midi.Event.noteOn (channel, note, vel[, pos=0])Constructor : note on.
midi.Event.noteOff (channel, note[, vel=0[, pos=0]])Constructor : note off.
midi.Event.pitchBend (channel, pitch[, pos=0])Constructor : pitch bend.
midi.Event.control (channel, number, value[, pos=0])Constructor : Control change.
midi.Event:getChannel ()Get channel.
midi.Event:setChannel (channel)Set channel.
midi.Event:isNoteOn ()Is a note on event.
midi.Event:isNoteOff ()Is a note off event.
midi.Event:getNote ()Get note.
midi.Event:setNote (note)Set note.
midi.Event:getVel ()Get velocity.
midi.Event:setVel (vel)Set velocity.
midi.Event:isPitchBend ()Is a pitch bend event.
midi.Event:getPitchBendValue ()Get pitch bend value.
midi.Event:isControl ()Is a Control Change event.
midi.Event:getControlNumber ()Get control number.
midi.Event:getControlValue ()Get control value.
midi.Event.timeSample position relatively to the start of the block.
midi.Event.dataSizeSize of the MIDI message in bytes
midi.Event.dataThe raw MIDI message + (const uint8_t* cdata)
+ +
+
+ + +

Functions

+
+
+ + midi.noteToFreq (note) +
+
+ Convert a MIDI note number to frequency. + Call this function to get a note's frequency. + + + +

Parameters:

+
    +
  • note + the MIDI note (0-127) +
  • +
+ +

Returns:

+
    + + the frequency in samples^-1 +
+ + + + +
+
+

Class midi.Buffer

+ + A buffer containing midi events, as received by plugin.processBlock +

+
+
+ + midi.Buffer:eachEvent () +
+
+ Iterate over each midi.Event in the buffer. + + + + + + + +

Usage:

+
    +
    for ev in myBuffer:eachEvent() do print(ev:getNote()) end
    +
+ +
+
+ + midi.Buffer:clear () +
+
+ Remove all MIDI events from the buffer. + + + + + + + + +
+
+ + midi.Buffer:addEvent (event) +
+
+ Add a MIDI event. + + + +

Parameters:

+ + + + + + +
+
+

Class midi.Event

+ + A single midi event as returned by Buffer:eachEvent +

+
+
+ + midi.Event (other) +
+
+ Constructor : copy another event. + + + +

Parameters:

+ + + + + + +
+
+ + midi.Event (time, dataSize[, data]) +
+
+ Constructor : create a custom event. + Create an event from given bytes (or zeros if not supplied) + + + +

Parameters:

+
    +
  • time + + + +
  • +
  • dataSize + + + +
  • +
  • data + + + +
  • +
+ + + + +

Usage:

+
    +
    myEv = midi.Event(0, 3, {0x90, 0x30, 0x7f}) -- note on
    +
+ +
+
+ + midi.Event.noteOn (channel, note, vel[, pos=0]) +
+
+ Constructor : note on. + + + +

Parameters:

+
    +
  • channel + (1-16) +
  • +
  • note + (0-127) +
  • +
  • vel + (1-127) +
  • +
  • pos + sample offset + (default 0) +
  • +
+ +

Returns:

+
    + + midi.Event + + + +
+ + + + +
+
+ + midi.Event.noteOff (channel, note[, vel=0[, pos=0]]) +
+
+ Constructor : note off. + + + +

Parameters:

+
    +
  • channel + (1-16) +
  • +
  • note + (0-127) +
  • +
  • vel + (0-127) + (default 0) +
  • +
  • pos + sample offset + (default 0) +
  • +
+ +

Returns:

+
    + + midi.Event + + + +
+ + + + +
+
+ + midi.Event.pitchBend (channel, pitch[, pos=0]) +
+
+ Constructor : pitch bend. + + + +

Parameters:

+
    +
  • channel + (1-16) +
  • +
  • pitch + bend value (0-16383) +
  • +
  • pos + sample offset + (default 0) +
  • +
+ +

Returns:

+
    + + midi.Event + + + +
+ + + + +
+
+ + midi.Event.control (channel, number, value[, pos=0]) +
+
+ Constructor : Control change. + + + +

Parameters:

+
    +
  • channel + (1-16) +
  • +
  • number + control number (0-247) +
  • +
  • value + control value (0-127) +
  • +
  • pos + sample offset + (default 0) +
  • +
+ +

Returns:

+
    + + midi.Event + + + +
+ + + + +
+
+ + midi.Event:getChannel () +
+
+ Get channel. + + + + +

Returns:

+
    + + the MIDI channel (1-16) +
+ + + + +
+
+ + midi.Event:setChannel (channel) +
+
+ Set channel. + + + +

Parameters:

+
    +
  • channel + the MIDI channel (1-16) +
  • +
+ + + + + +
+
+ + midi.Event:isNoteOn () +
+
+ Is a note on event. + + + + +

Returns:

+
    + + boolean + whether event is a note on. +
+ + + + +
+
+ + midi.Event:isNoteOff () +
+
+ Is a note off event. + + + + +

Returns:

+
    + + boolean + whether event is a note off. +
+ + + + +
+
+ + midi.Event:getNote () +
+
+ Get note. + + + + +

Returns:

+
    + + the MIDI note number (0-127) +
+ + + + +
+
+ + midi.Event:setNote (note) +
+
+ Set note. + + + +

Parameters:

+
    +
  • note + the MIDI note number (0-127) +
  • +
+ + + + + +
+
+ + midi.Event:getVel () +
+
+ Get velocity. + + + + +

Returns:

+
    + + the MIDI velocity (1-127) +
+ + + + +
+
+ + midi.Event:setVel (vel) +
+
+ Set velocity. + + + +

Parameters:

+
    +
  • vel + the MIDI velocity (1-127) +
  • +
+ + + + + +
+
+ + midi.Event:isPitchBend () +
+
+ Is a pitch bend event. + + + + +

Returns:

+
    + + boolean + whether event is a pitch bend on. +
+ + + + +
+
+ + midi.Event:getPitchBendValue () +
+
+ Get pitch bend value. + + + + +

Returns:

+
    + + pitch bend value (0-16383). +
+ + + + +
+
+ + midi.Event:isControl () +
+
+ Is a Control Change event. + + + + +

Returns:

+
    + + boolean + whether event is a control change. +
+ + + + +
+
+ + midi.Event:getControlNumber () +
+
+ Get control number. + + + + +

Returns:

+
    + + control number (0-247). +
+ + + + +
+
+ + midi.Event:getControlValue () +
+
+ Get control value. + + + + +

Returns:

+
    + + control value (0-127). +
+ + + + +
+
+ + midi.Event.time +
+
+ Sample position relatively to the start of the block. + This value is often 0 because most hosts call plugin.processBlock at the + beginning of beats and beat divisions. It is never higher than the + current plugin.processBlock's smax and any events created by the script + should respect this rule. + + + + + + + + +
+
+ + midi.Event.dataSize +
+
+ Size of the MIDI message in bytes + + + + + + + + +
+
+ + midi.Event.data +
+
+ The raw MIDI message + (const uint8_t* cdata) + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/modules/plugin.html b/ports/protoplug/ProtoplugFiles/doc/modules/plugin.html new file mode 100644 index 0000000..86e9949 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/modules/plugin.html @@ -0,0 +1,792 @@ + + + + + protoplug: Module plugin + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module plugin

+

Use plugin to define the AU/VST audio plugin's behaviour.

+

+ +

The plugin global is available to every protoplug script after including the + main protoplug header :

+
require "include/protoplug"
+
+

+ + +

Callback functions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
plugin.manageParams (paramList)Automatically set up a list of parameters.
plugin.setParameter (index, value)Set (automate) a parameter's value.
plugin.getParameter (index)Get a parameter's value.
plugin.getCurrentPosition ()Get host position info, if available.
plugin.getSampleRate ()Get host samplerate.
plugin.isSampleRateKnown ()Check if the samplerate is known.
plugin.addHandler (event, handler)Add a handler for a VST/AU event.
+

Override functions

+ + + + + + + + + + + + + + + + + + + + + +
plugin.processBlock (samples, smax, midiBuf)Process Audio Block.
plugin.getParameterName (index)Return the name of a parameter.
plugin.getParameterText (index)Return the representation of a parameter's value.
plugin.paramChanged (index)Handle parameter changes.
plugin.getTailLengthSeconds ()Return the tail length in seconds (effects only).
+

Class plugin.PositionInfo

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
plugin.PositionInfo.bpmHost tempo (beats per minute)
plugin.PositionInfo.timeSigNumeratorTime signature numerator ie.
plugin.PositionInfo.timeSigDenominatorTime signature denominator ie.
plugin.PositionInfo.timeInSamplesCurrent position on the host's timeline (samples)
plugin.PositionInfo.timeInSecondsCurrent position on the host's timeline (seconds)
plugin.PositionInfo.editOriginTimePosition of the start of the edit region on the host's timeline
plugin.PositionInfo.ppqPositionCurrent position on the host's timeline (pulses-per-quarter-note)
plugin.PositionInfo.ppqPositionOfLastBarStartPosition of the last bar start (pulses-per-quarter-note).
plugin.PositionInfo.frameRateVideo frame rate
plugin.PositionInfo.isPlayingIs playing
plugin.PositionInfo.isRecordingIs recording
plugin.PositionInfo.ppqLoopStartPosition of the loop start (pulses-per-quarter-note).
plugin.PositionInfo.ppqLoopEndPosition of the loop end (pulses-per-quarter-note).
plugin.PositionInfo.isLoopingIs looping
+ +
+
+ + +

Callback functions

+ + Functions that your script can call. +

+
+
+ + plugin.manageParams (paramList) +
+
+ Automatically set up a list of parameters. + Call this function with a table containing parameter definitions as argument, and + it will perform the repetitive task of defining all the parameter-related overrides.

+ +

The format of the parameter list is demonstrated in classic-filter.lua + + + +

Parameters:

+
    +
  • paramList + a table with parameter definitions (see example) +
  • +
+ + + + + +
+
+ + plugin.setParameter (index, value) +
+
+ Set (automate) a parameter's value. + The value must be normalized to be between 0 and 1. + + + +

Parameters:

+
    +
  • index + parameter index (0-126) +
  • +
  • value + parameter value (0-1) +
  • +
+ + + + + +
+
+ + plugin.getParameter (index) +
+
+ Get a parameter's value. + The values are between 0 and 1, but different minimums and maximums can + be easily simulated using plugin.manageParams. + + + +

Parameters:

+
    +
  • index + parameter index (0-126) +
  • +
+ + + + + +
+
+ + plugin.getCurrentPosition () +
+
+ Get host position info, if available. + Only call this from within processBlock. + + + + +

Returns:

+
    + + plugin.PositionInfo + current position info, or nil depending on the host. +
+ + + + +
+
+ + plugin.getSampleRate () +
+
+ Get host samplerate. + The value is unknown until the plugin prepareToPlay event has been emitted. + The value is always known in processBlock. An error is caused if an + attempt is made to access the sample rate prematurely. + + + + +

Returns:

+
    + + current samplerate. +
+ + +

See also:

+ + + +
+
+ + plugin.isSampleRateKnown () +
+
+ Check if the samplerate is known. + + + + +

Returns:

+
    + + boolean + + + +
+ + + + +
+
+ + plugin.addHandler (event, handler) +
+
+ +

Add a handler for a VST/AU event. + The following events are available :

+ +
    +
  • "prepareToPlay" - Emitted before the first call to processBlock, when the samplerate is known.
  • +
+ + + + +

Parameters:

+
    +
  • event + string + the event to handle +
  • +
  • handler + function + a function to add the event's handlers +
  • +
+ + + +

See also:

+ + + +
+
+

Override functions

+ + Define these functions and the host will call them. +

+
+
+ + plugin.processBlock (samples, smax, midiBuf) +
+
+ Process Audio Block. + Override this function to input and output audio and MIDI data.

+ +

This override is handled automatically if stereoFx or polyGen are used. + Use this function to handle the raw data instead. + + + +

Parameters:

+
    +
  • samples + a C float** pointing to two channels of samples, serving as input and output +
  • +
  • smax + the maximum sample index (nSamples - 1) +
  • +
  • midiBuf + midi.Buffer + the MIDI data for this block, serving as input and output +
  • +
+ + + + +

Usage:

+
    +
     function plugin.processBlock (samples, smax) -- let's ignore midi for this example
    +     for i = 0, smax do
    +         samples[0][i] = sin(myTime) -- left channel
    +         samples[1][i] = sin(myTime) -- right channel
    +         myTime = myTime + myDelta
    +     end
    + end
    +
+ +
+
+ + plugin.getParameterName (index) +
+
+ Return the name of a parameter.

+ +

This override is handled automatically if manageParams is used. + + + +

Parameters:

+
    +
  • index + parameter index (0-126) +
  • +
+ +

Returns:

+
    + + string + the parameter's name +
+ + + + +
+
+ + plugin.getParameterText (index) +
+
+ Return the representation of a parameter's value. + Override this function to choose how each parameter's value should + be displayed by the host. The parameter's current value can be obtained + using plugin.getParameter

+ +

This override is handled automatically if manageParams is used. + + + +

Parameters:

+
    +
  • index + parameter index (0-126) +
  • +
+ +

Returns:

+
    + + string + a string representation of the parameter's current value +
+ + + + +
+
+ + plugin.paramChanged (index) +
+
+ Handle parameter changes. + Override this function to do something when a parameter changes + The parameter's current value can be obtained using plugin.getParameter

+ +

This override is handled automatically if manageParams is used. + + + +

Parameters:

+
    +
  • index + parameter index (0-126) +
  • +
+ + + + + +
+
+ + plugin.getTailLengthSeconds () +
+
+ Return the tail length in seconds (effects only). + Override this function to define the effect's audio tail length. + + + + +

Returns:

+
    + + the tail length in seconds +
+ + + + +
+
+

Class plugin.PositionInfo

+ + A container type for host-related information as returned by plugin.getCurrentPosition

+ +

Is a JUCE AudioPlayHead::CurrentPositionInfo +

+

+
+ + plugin.PositionInfo.bpm +
+
+ Host tempo (beats per minute) + + + + + + + + +
+
+ + plugin.PositionInfo.timeSigNumerator +
+
+ Time signature numerator ie. 3/4 + + + + + + + + +
+
+ + plugin.PositionInfo.timeSigDenominator +
+
+ Time signature denominator ie. 3/4 + + + + + + + + +
+
+ + plugin.PositionInfo.timeInSamples +
+
+ Current position on the host's timeline (samples) + + + + + + + + +
+
+ + plugin.PositionInfo.timeInSeconds +
+
+ Current position on the host's timeline (seconds) + + + + + + + + +
+
+ + plugin.PositionInfo.editOriginTime +
+
+ Position of the start of the edit region on the host's timeline + + + + + + + + +
+
+ + plugin.PositionInfo.ppqPosition +
+
+ Current position on the host's timeline (pulses-per-quarter-note) + + + + + + + + +
+
+ + plugin.PositionInfo.ppqPositionOfLastBarStart +
+
+ Position of the last bar start (pulses-per-quarter-note). + (or zero if unavailable.) + + + + + + + + +
+
+ + plugin.PositionInfo.frameRate +
+
+ Video frame rate + + + + + + + + +
+
+ + plugin.PositionInfo.isPlaying +
+
+ Is playing + + + + + + + + +
+
+ + plugin.PositionInfo.isRecording +
+
+ Is recording + + + + + + + + +
+
+ + plugin.PositionInfo.ppqLoopStart +
+
+ Position of the loop start (pulses-per-quarter-note). + (or zero if unavailable.) + + + + + + + + +
+
+ + plugin.PositionInfo.ppqLoopEnd +
+
+ Position of the loop end (pulses-per-quarter-note). + (or zero if unavailable.) + + + + + + + + +
+
+ + plugin.PositionInfo.isLooping +
+
+ Is looping + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/modules/polyGen.html b/ports/protoplug/ProtoplugFiles/doc/modules/polyGen.html new file mode 100644 index 0000000..01cd33e --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/modules/polyGen.html @@ -0,0 +1,378 @@ + + + + + protoplug: Module polyGen + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module polyGen

+

Use this module to create a polyphonic generator with virtual tracks.

+

+ +

Example at sine-organ.lua.

+ +

This module facilitates the creation of polyphonic instruments. It acts + as a layer that covers the plugin.processBlock function, receives MIDI + notes and dispatches them to virtual tracks. The polyGen.VTrack prototype + is exposed for you to define audio processing in a simple, + monophonic, per-note fashion. Initialize this module by calling polyGen.initTracks .

+ +

The polyGen global is available to every protoplug script after including the + main protoplug header :

+
require "include/protoplug"
+
+

+ + +

Functions

+ + + + + +
polyGen.initTracks ([n=8])Set up virtual tracks.
+

Class polyGen.VTrack

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
polyGen.VTrack:addProcessBlock (samples, smax)Override to additively process an audio block.
polyGen.VTrack:noteOn (note, vel)Override to recieve note on.
polyGen.VTrack:noteOff (note)Override to recieve note off.
polyGen.VTrack:init ()Override to allow initialisation.
polyGen.VTrack.iTrack number.
polyGen.VTrack.noteCurrent MIDI note.
polyGen.VTrack.noteFreqCurrent note frequency.
polyGen.VTrack.notePeriodCurrent note period.
polyGen.VTrack.noteIsOnNote is on.
+ +
+
+ + +

Functions

+
+
+ + polyGen.initTracks ([n=8]) +
+
+ Set up virtual tracks. + This function must be called by any script that wishes to use this module. + + + +

Parameters:

+
    +
  • n + the number of virtual tracks to use (aka. voices or polyphony) + (default 8) +
  • +
+ + + + + +
+
+

Class polyGen.VTrack

+ + Virtual track. A monophonic voice that defines the instrument's sound. +

+
+
+ + polyGen.VTrack:addProcessBlock (samples, smax) +
+
+ Override to additively process an audio block. + Define the output of a virtual track in this method. + Use self.noteIsOn, self.noteFreq, or any fields you defined to + determine current the state of the calling track.

+ +

This method is called successively on every track, + which should add their output to samples. + + + +

Parameters:

+
    +
  • samples + a C float** pointing to two channels of samples to add to. +
  • +
  • smax + the maximum sample index (nSamples - 1) +
  • +
+ + + +

See also:

+ + + +
+
+ + polyGen.VTrack:noteOn (note, vel) +
+
+ Override to recieve note on. + Override this method to handle a note getting dispatched to a virtual track. + + + +

Parameters:

+
    +
  • note + the MIDI note number (0-127) +
  • +
  • vel + the MIDI velocity (0-127) +
  • +
+ + + + + +
+
+ + polyGen.VTrack:noteOff (note) +
+
+ Override to recieve note off. + Override this method to handle a note off on a virtual track. + + + +

Parameters:

+
    +
  • note + a reminder of the MIDI note number +
  • +
+ + + + + +
+
+ + polyGen.VTrack:init () +
+
+ Override to allow initialisation. + Override this method to perform initialisation tasks on each track, + for example to create any per-track fields. + + + + + + + + +
+
+ + polyGen.VTrack.i +
+
+ Track number. + Use self.i to check which virtual track is being called. + + + + + + + + +
+
+ + polyGen.VTrack.note +
+
+ Current MIDI note. + The MIDI note number that is currently being played by this track, + or -1 if in note off state. + + + + + + + + +
+
+ + polyGen.VTrack.noteFreq +
+
+ Current note frequency. + The note frequency that is currently being played by this track. + + + + + + + + +
+
+ + polyGen.VTrack.notePeriod +
+
+ Current note period. + 1/noteFreq + + + + + + + + +
+
+ + polyGen.VTrack.noteIsOn +
+
+ Note is on. + Whether the track is playing a note (boolean). + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/modules/script.html b/ports/protoplug/ProtoplugFiles/doc/modules/script.html new file mode 100644 index 0000000..d522581 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/modules/script.html @@ -0,0 +1,304 @@ + + + + + protoplug: Module script + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module script

+

Use script to handle script events, libraries and files.

+

+ +

The script global is available to every protoplug script after including the + main protoplug header :

+
require "include/protoplug"
+
+

+ + +

Functions

+ + + + + + + + + + + + + + + + + +
script.addHandler (event, handler)Add a handler for a script event.
script.saveData ()Save script data.
script.loadData (data)Load script data.
script.ffiLoad (libName[, ...])Load shared libraries.
+

Predefined values

+ + + + + +
script.protoplugDirCurrent protoplug directory.
+ +
+
+ + +

Functions

+
+
+ + script.addHandler (event, handler) +
+
+ +

Add a handler for a script event. + The following events are available :

+ +
    +
  • "init" - Emitted after the script has been compiled and run.
  • +
  • "preClose" - Emitted before the script state gets destroyed.
  • +
+ + + + +

Parameters:

+
    +
  • event + string + the event to handle +
  • +
  • handler + function + a function to add the event's handlers +
  • +
+ + + +

See also:

+ + + +
+
+ + script.saveData () +
+
+ Save script data. + Override this function to save any custom data.

+ +

This gets called : + - when the host saves the plugin's state (eg. when saving a project) + - right before the script is recompiled, to keep custom data across compilations. + + + + +

Returns:

+
    + + string + the data to be saved +
+ + + + +
+
+ + script.loadData (data) +
+
+ Load script data. + Override this function to load any custom data. + Be warned that the data might originate from another script, so it's a good + idea to start the data with a header confirming the format.

+ +

This gets called : + - when the host loads the plugin's state (eg. when loading a project) + - right after the script is recompiled, to keep custom data across compilations. + + + +

Parameters:

+
    +
  • data + string + the data to be loaded +
  • +
+ + + + + +
+
+ + script.ffiLoad (libName[, ...]) +
+
+ Load shared libraries. + Protoplug scripts should use this wrapper function instead of LuaJIT's + ffi.load. + It has the same behaviour as ffi.load, but it adds protoplug/lib as a + search path, and can accept multiple arguments to test for different + library names. The names are tested from left to right until one load + successfully. If none of them work, an error is raised.

+
sdl = script.ffiLoad("sdl")
+
+

This looks for libsdl.so or sdl.dll in protoplug's lib folder and + in the system paths.

+ +
fftw = script.ffiLoad("libfftw3.so.3", "libfftw3-3.dll")
+
+

This looks for the supplied names in the same locations as above. This is + necessary for libs like FFTW, that have has platform-dependent names. + + + +

Parameters:

+
    +
  • libName + string + + + +
  • +
  • ... + string + alternate names for the same library +
  • +
+ +

Returns:

+
    + + The library's ffi namespace +
+ + + + +
+
+

Predefined values

+
+
+ + script.protoplugDir +
+
+ Current protoplug directory. + The full path of the protoplug directory currently being used. It should + be alongside the protoplug fx and gen dynamic libraries. + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/modules/stereoFx.html b/ports/protoplug/ProtoplugFiles/doc/modules/stereoFx.html new file mode 100644 index 0000000..bef3959 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/modules/stereoFx.html @@ -0,0 +1,204 @@ + + + + + protoplug: Module stereoFx + + + + +
+ +
+ +
+
+
+ + +
+ + + + + + +
+ +

Module stereoFx

+

Use this module to create a stereo effect.

+

+ +

Example at classic-filter.lua.

+ +

This module acts as a layer that conceals the plugin.processBlock function, + manages stereo channels, and exposes the stereoFx.Channel prototype for you + define per-channel audio processing. Initialize it by calling stereoFx.init .

+ +

The stereoFx global is available to every protoplug script after including the + main protoplug header :

+
require "include/protoplug"
+
+

+ + +

Functions

+ + + + + +
stereoFx.init ()Set up channels.
+

Class stereoFx.Channel

+ + + + + + + + + +
stereoFx.Channel:processBlock (samples, smax)Override to process a channel's audio block.
stereoFx.Channel:init ()Override to handle initialisation.
+ +
+
+ + +

Functions

+
+
+ + stereoFx.init () +
+
+ Set up channels. + This function must be called by any script that wishes to use this module. + + + + + + + + +
+
+

Class stereoFx.Channel

+ + This class represents a channel (ie. left or right). +

+
+
+ + stereoFx.Channel:processBlock (samples, smax) +
+
+ Override to process a channel's audio block. + Define the audio processing of a single channel in this function. + + + +

Parameters:

+
    +
  • samples + a C float* serving as input and output +
  • +
  • smax + the maximum sample index (nSamples - 1) +
  • +
+ + + + + +
+
+ + stereoFx.Channel:init () +
+
+ Override to handle initialisation. + Override this method to perform initialisation tasks on each channel, + for example to create any per-channel fields. + + + + + + + + +
+
+ + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/doc/osar-121.png b/ports/protoplug/ProtoplugFiles/doc/osar-121.png new file mode 100644 index 0000000..e9e0dcc Binary files /dev/null and b/ports/protoplug/ProtoplugFiles/doc/osar-121.png differ diff --git a/ports/protoplug/ProtoplugFiles/doc/src/build protoplug docs.bat b/ports/protoplug/ProtoplugFiles/doc/src/build protoplug docs.bat new file mode 100644 index 0000000..547f249 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/src/build protoplug docs.bat @@ -0,0 +1,3 @@ +cd "C:\Users\pac\Documents\Visual Studio 2010\Projects\protoplug\ProtoplugFiles\doc\src" +lua c:\SDKs\ldoc\ldoc.lua -d ../ . +pause \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/doc/src/config.ld b/ports/protoplug/ProtoplugFiles/doc/src/config.ld new file mode 100644 index 0000000..68314b0 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/src/config.ld @@ -0,0 +1,77 @@ +-- ldoc configuration file +-- works with ldoc 1.4.2 (http://stevedonovan.github.io/ldoc/) + +title = "Protoplug Lua API Reference" +project = "protoplug" +description = [[ +Protoplug Lua API Reference +]] + +local function softenPrefix(s) + if s:find("^%b<>.-[%.:][^%.%:]-$") then + -- already wrapped function : leave wrap outisde + return s:gsub("^(%b<>)(.-)([%.:])([^%.%:]-)%((.-)$", "%1%2%3%4%(%5") + elseif s:find("^.-[%.:][^%.%:]-%(.-$") then + -- function : allow for dots in optional parameter values + return s:gsub("^(.-)([%.:])([^%.%:]-)%((.-)$", "%1%2%3%(%4") + elseif s:find("[%.:][^%.%:]-$") then + return ""..s:gsub("([%.:])([^%.%:]-)$", "%1%2") + else + return s + end +end + +local forcePrefix = {"plugin", "script", "gui", "midi", "polyGen", "stereoFx"} +local function formatName(item, default_display_name) + for _, v in ipairs(forcePrefix) do + if item.module.name == v then + -- display the prefix on globals to be more explicit + if item.tags.display then + return item.tags.display[1].." "..item.args + else + return item.module.name.."."..default_display_name(item) + end + end + end + if item.tags.constructor then + -- constructors that are a metatable __call + return item.module.name.." "..item.args + elseif #default_display_name(item) >100 then + -- auto wrap ridiculously long names (it's ugly but better than nothing) + return ''..(item.display_name or item.name)..'
'..item.args..'
' + elseif #default_display_name(item) >60 then + -- manually wrap slightly long names + return (item.display_name or item.name)..'
'..item.args + end + -- mostly class/classmod methods fall into the default display + return default_display_name(item) +end + +custom_display_name_handler = function(item, default_display_name) + return softenPrefix(formatName(item, default_display_name)) +end + +custom_tags = { { "display", hidden = true } } +new_type("simplefield","Fields") +new_type("predefined","Predefined values") + +file = { + '../../include/core/plugin.lua'; + '../../include/core/script.lua'; + '../../include/core/midi.lua'; + '../../include/core/gui.lua'; + '../../include/core/polygen.lua'; + '../../include/core/stereofx.lua'; + '../../include/protojuce'; +} +examples = { + '../../effects/classic-filter.lua'; + '../../generators/sine-organ.lua'; + '../../generators/midi-chordify.lua'; + '../../generators/sinemouse-demo.lua'; + '../../generators/soundfile-test.lua'; +} + +format = 'markdown' +style = true +template = true diff --git a/ports/protoplug/ProtoplugFiles/doc/src/ldoc.css b/ports/protoplug/ProtoplugFiles/doc/src/ldoc.css new file mode 100644 index 0000000..66fc8bd --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/src/ldoc.css @@ -0,0 +1,333 @@ +/* BEGIN RESET + +Copyright (c) 2010, Yahoo! Inc. All rights reserved. +Code licensed under the BSD License: +http://developer.yahoo.com/yui/license.html +version: 2.8.2r1 +*/ +html { + color: #000; + background: #FFF; +} +body { + text-align: center; +} +body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td { + margin: 0; + padding: 0; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +fieldset,img { + border: 0; +} +address,caption,cite,code,dfn,em,strong,th,var,optgroup { + font-style: inherit; + font-weight: inherit; +} +del,ins { + text-decoration: none; +} +li { + list-style: bullet; + margin-left: 20px; +} +caption,th { + text-align: left; +} +h1,h2,h3,h4,h5,h6 { + font-size: 100%; + font-weight: bold; +} +q:before,q:after { + content: ''; +} +abbr,acronym { + border: 0; + font-variant: normal; +} +sup { + vertical-align: baseline; +} +sub { + vertical-align: baseline; +} +legend { + color: #000; +} +input,button,textarea,select,optgroup,option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; +} +input,button,textarea,select {*font-size:100%; +} +/* END RESET */ + +body { + margin-left: 1em; + margin-right: 1em; + font-family: arial, helvetica, geneva, sans-serif; + background-color: #ffffff; margin: 0px; +} + +code, tt { font-family: monospace; } +span.parameter { font-family:monospace; } +span.parameter:after { content:":"; } +span.types:before { content:"("; } +span.types:after { content:")"; } +.type { font-weight: bold; font-style:italic } + +body, p, td, th { font-size: .95em; line-height: 1.2em;} + +p, ul { margin: 10px 0 0 0px;} + +strong { font-weight: bold;} + +em { font-style: italic;} + +h1 { + font-size: 1.5em; + margin: 10px 0 20px 0; +} +h2, h3, h4 { margin: 15px 0 10px 0; } +h2 { + border-bottom: 2px solid #ccc; + font-size: 1.25em; + margin: 19px 0 12px; +} +h3 { font-size: 1.15em; } +h4 { font-size: 1.06em; } + +a:link { font-weight: bold; color: #004080; text-decoration: none; } +a:visited { font-weight: bold; color: #006699; text-decoration: none; } +a:link:hover { text-decoration: underline; } + +hr { + color:#cccccc; + background: #00007f; + height: 1px; +} + +blockquote { margin-left: 3em; } + +ul { list-style-type: disc; } + +p.name { + font-family: Consolas, monaco, monospace; + padding-top: 1em; +} + +pre.example { + background-color: rgb(245, 245, 245); + border: 1px solid silver; + padding: 10px; + margin: 10px 0 10px 0; + font-family: Consolas, monaco, monospace; + font-size: .85em; +} + +pre { + background-color: rgb(245,245,255); + border: 1px solid #cccccc; + padding: 10px; + margin: 10px 0 10px 0; + overflow: auto; + font-family: Consolas, monaco, monospace; + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + font-size: 14px; +} + + +table.index { border: 1px #00007f; } +table.index td { text-align: left; vertical-align: top; } + +#container { + /*margin-left: 1em; + margin-right: 1em; + background-color: #f4f4ff;*/ + display: inline-block; + margin: 0 auto; + text-align: left; +} + +#product { + text-align: center; + border-bottom: 1px solid #cccccc; + background-color: #ffffff; +} + +#product big { + font-size: 2em; +} + +#main { + background-color:#FFFFFF; + /*border-left: 2px solid #cccccc;*/ +} + +#navigation { + float: left; + width: 14em; + vertical-align: top; + background-color:#FFFFFF; + overflow: visible; +} + +#navigation h2 { + background-color:#FFFFFF; + font-size:1.1em; + color:#000000; + text-align: left; + padding:0.2em; + /*border-top:1px solid #dddddd;*/ + border-bottom:1px solid #dddddd; +} + +#navigation ul +{ + font-size:1em; + list-style-type: none; + margin: 1px 1px 10px 1px; +} + +#navigation li { + text-indent: -1em; + display: block; + margin: 3px 0px 0px 22px; + word-wrap: break-word; +} + +#navigation li li a { + margin: 0px 3px 0px -1em; +} + +#content { + margin-left: 14em; + padding: 1em; + width: 700px; + border-left: 2px solid #cccccc; + /*border-right: 2px solid #cccccc;*/ + background-color: #ffffff; +} + +#about { + clear: both; + padding: 5px; + border-top: 2px solid #cccccc; + background-color: #ffffff; +} + +@media print { + body { + font: 12pt "Times New Roman", "TimeNR", Times, serif; + } + a { font-weight: bold; color: #004080; text-decoration: underline; } + + #main { + background-color: #ffffff; + border-left: 0px; + } + + #container { + margin-left: 2%; + margin-right: 2%; + background-color: #ffffff; + } + + #content { + padding: 1em; + background-color: #ffffff; + } + + #navigation { + display: none; + } + pre.example { + font-family: Consolas, monaco, monospace; + font-size: 10pt; + page-break-inside: avoid; + } +} + +table.module_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.module_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.module_list td.name { background-color: #f4f4ff; ; min-width: 200px; } +table.module_list td.summary { width: 100%; } + +table.function_list { + border-width: 1px; + border-style: solid; + border-color: #cccccc; + border-collapse: collapse; +} +table.function_list td { + border-width: 1px; + padding: 3px; + border-style: solid; + border-color: #cccccc; +} +table.function_list td.name { background-color: #f6f6ff; ; min-width: 200px; padding: 7px 5px; } +table.function_list td.summary { width: 100%; } + +dl.table dt, dl.function dt { + background-color: #f4f4ff; + border-bottom: 1px solid #ccc; + border-left: 1px solid #ccc; + border-top: 1px solid #ccc; + padding: 0.7em 0 0.5em 1em; +} +dl.table dd, dl.function dd {padding-bottom: 1em; margin: 10px 0 0 20px;} +dl.table h3, dl.function h3 {font-size: .95em;} + +ul.nowrap { + overflow:auto; + whitespace:nowrap; +} + +/* stop sublists from having initial vertical space */ +ul ul { margin-top: 0px; } +ol ul { margin-top: 0px; } +ol ol { margin-top: 0px; } +ul ol { margin-top: 0px; } + +/* styles for prettification of source */ +pre .comment { color: #558817; } +pre .constant { color: #a8660d; } +pre .escape { color: #844631; } +pre .keyword { color: #2239a8; font-weight: bold; } +pre .library { color: #0e7c6b; } +pre .marker { color: #512b1e; background: #fedc56; font-weight: bold; } +pre .string { color: #a8660d; } +pre .number { color: #f8660d; } +pre .operator { color: #2239a8; font-weight: bold; } +pre .preprocessor, pre .prepro { color: #a33243; } +pre .global { color: #800080; } +pre .prompt { color: #558817; } +pre .url { color: #272fc2; text-decoration: underline; } + +.wrapman { display: inline-block; white-space: normal; min-width: 460px; } +.proto_subtitle {color: #888; position: relative; top: -12px;} +.function_list .proto_prefix {color: #789;} +.osarlogo { + display: block; + width: 132px; + height: 121px; + background: url("osar-121.png") no-repeat scroll 0 0 transparent; + margin: 0 auto; +} diff --git a/ports/protoplug/ProtoplugFiles/doc/src/ldoc.ltp b/ports/protoplug/ProtoplugFiles/doc/src/ldoc.ltp new file mode 100644 index 0000000..230c425 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/doc/src/ldoc.ltp @@ -0,0 +1,340 @@ + + +# -- pac : fix ldoc ordering issues (?) +# if module then +# local function startsWith(a, b) +# return (a:sub(1, b:len()) == b) +# end +# local finalOrder = { +# "Callback"; +# "Override"; +# "Constructors"; +# "Functions"; +# "Methods"; +# "Tables"; +# "Fields"; +# "Predefined"; +# "Class"; +# ""; +# } +# local sorted = {} +# local twodim = {} +# for k, v in ldoc.ipairs(finalOrder) do twodim[k] = {} end +# for kind, items in module.kinds() do +# for k, v in ldoc.ipairs(finalOrder) do +# if startsWith(kind, v) then +# twodim[k][#twodim[k]+1] = {kind, items} +# break +# end +# end +# end +# for k, v in ldoc.ipairs(twodim) do +# for k2, v2 in ldoc.ipairs(v) do +# sorted[#sorted+1] = v2 +# end +# end +# function getKinds() +# local i = 0 +# return function () +# i = i + 1 +# if sorted[i] then +# return sorted[i][1], sorted[i][2] +# end +# end +# end +# end + + +# if module then + $(ldoc.project): $(ldoc.module_typename(module)) $(module.name) +# else + $(ldoc.title) +# end + + + + +
+ +
+ +
+
+
+ + +
+ +# local no_spaces = ldoc.no_spaces +# local use_li = ldoc.use_li +# local display_name = ldoc.display_name +# local iter = ldoc.modules.iter +# local function M(txt,item) return ldoc.markup(txt,item,ldoc.plain) end +# local nowrap = ldoc.wrap and '' or 'nowrap' + + + + + +
+ +# if ldoc.body then -- verbatim HTML as contents; 'non-code' entries + $(ldoc.body) +# elseif module then -- module documentation +

$(ldoc.module_typename(module)) $(module.name)

+

$(M(module.summary,module))

+

$(M(module.description,module))

+# if module.usage then +# local li,il = use_li(module.usage) +

Usage:

+
    +# for usage in iter(module.usage) do + $(li)
    $(ldoc.escape(usage))
    $(il) +# end -- for +
+# end -- if usage +# if module.info then +

Info:

+
    +# for tag, value in module.info:iter() do +
  • $(tag): $(M(value,module))
  • +# end +
+# end -- if module.info + + +# if not ldoc.no_summary then +# -- bang out the tables of item types for this module (e.g Functions, Tables, etc) +# for kind, items in getKinds() do +

$(kind)

+ +# for item in items() do + + + + +# end -- for items +
$(display_name(item))$(M(item.summary,item))
+#end -- for kinds + +
+
+ +#end -- if not no_summary + +# --- currently works for both Functions and Tables. The params field either contains +# --- function parameters or table fields. +# local show_return = not ldoc.no_return_or_parms +# local show_parms = show_return +# for kind, items in getKinds() do +# local kitem = module.kinds:get_item(kind) +

$(kind)

+#-- $(M(module.kinds:get_section_description(kind),nil)) +# if kitem then + $(M(ldoc.descript(kitem),kitem)) +# if kitem.usage then +

Usage:

+
$(ldoc.prettify(kitem.usage[1]))
+# end +# end +
+# for item in items() do +
+ + $(display_name(item)) +
+
+ $(M(ldoc.descript(item),item)) + +# if ldoc.custom_tags then +# for custom in iter(ldoc.custom_tags) do +# local tag = item.tags[custom[1]] +# if tag and not custom.hidden then +# local li,il = use_li(tag) +

$(custom.title or custom[1]):

+
    +# for value in iter(tag) do + $(li)$(custom.format and custom.format(value) or M(value))$(il) +# end -- for +# end -- if tag +
+# end -- iter tags +# end + +# if show_parms and item.params and #item.params > 0 then +# local subnames = module.kinds:type_of(item).subnames +# if subnames then +

$(subnames):

+# end +
    +# for parm in iter(item.params) do +# local param,sublist = item:subparam(parm) +# if sublist then +
  • $(sublist)$(M(item.params[sublist],item)) +
      +# end +# for p in iter(param) do +# local name,tp,def = item:display_name_of(p), ldoc.typename(item:type_of_param(p)), item:default_of_param(p) +
    • $(name) +# if tp ~= '' then + $(tp) +# end + $(M(item.params[p],item)) +# if def then + (default $(def)) +# end +# if item:readonly(p) then + readonly +# end +
    • +# end +# if sublist then +
    +# end +# end -- for +
+# end -- if params + +# if show_return and item.retgroups then local groups = item.retgroups +

Returns:

+# for i,group in ldoc.ipairs(groups) do local li,il = use_li(group) +
    +# for r in group:iter() do local type, ctypes = item:return_type(r); local rt = ldoc.typename(type) + $(li) +# if rt ~= '' then + $(rt) +# end + $(M(r.text,item))$(il) +# if ctypes then +
      +# for c in ctypes:iter() do +
    • $(c.name) + $(ldoc.typename(c.type)) + $(M(c.comment,item))
    • +# end +
    +# end -- if ctypes +# end -- for r +
+# if i < #groups then +

Or

+# end +# end -- for group +# end -- if returns + +# if show_return and item.raise then +

Raises:

+ $(M(item.raise,item)) +# end + +# if item.see then +# local li,il = use_li(item.see) +

See also:

+
    +# for see in iter(item.see) do + $(li)$(see.label)$(il) +# end -- for +
+# end -- if see + +# if item.usage then +# local li,il = use_li(item.usage) +

Usage:

+
    +# for usage in iter(item.usage) do + $(li)
    $(ldoc.prettify(usage))
    $(il) +# end -- for +
+# end -- if usage + +
+# end -- for items +
+# end -- for kinds + +# else -- if module; project-level contents + +# if ldoc.description then +

$(M(ldoc.description,nil))

+# end +# if ldoc.full_description then +

$(M(ldoc.full_description,nil))

+# end + +# for kind, mods in ldoc.kinds() do +

$(kind)

+# kind = kind:lower() + +# for m in mods() do + + + + +# end -- for modules +
$(m.name)$(M(m.summary,m))
+# end -- for kinds +# end -- if module + +
+
+
+generated by LDoc 1.4.2 +
+
+ + diff --git a/ports/protoplug/ProtoplugFiles/effects/classic-filter.lua b/ports/protoplug/ProtoplugFiles/effects/classic-filter.lua new file mode 100644 index 0000000..19bbd06 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/classic-filter.lua @@ -0,0 +1,74 @@ +--[[ +name: Classic Filter +description: > + Straightforward application of RBJ's cookbook filters. Formulae by + Robert Bristow-Johnson, implementation from Worp by Ico Doornekamp. +author: osar.fr +--]] + +require "include/protoplug" +local cbFilter = require "include/pac/cookbook filters" +local filters = {} + +stereoFx.init() + +function stereoFx.Channel:init() + -- create per-channel fields (filters) + self.filter = cbFilter + { + -- initialize filters with current param values + type = params[1].getValue(); + f = params[2].getValue()/2; + gain = params[3].getValue(); + Q = params[4].getValue(); + } + table.insert(filters, self.filter) +end + +function stereoFx.Channel:processBlock(s, smax) + for i = 0,smax do + s[i] = self.filter.process(s[i]) + end +end + +local function updateFilters(args) + for _, f in pairs(filters) do + f.update(args) + end +end + +params = plugin.manageParams { + -- automatable VST/AU parameters + -- note the new 1.3 way of declaring them + { + name = "Type"; + type = "list"; + values = {"hp"; "lp"; "bp"; "bs"; "ls"; "hs"; "ap"; "eq"}; + default = "hp"; + changed = function(val) updateFilters{type=val} end; + }; + { + name = "Frequency"; + min = 10; + max = 20000; + default = 440; + changed = function(val) updateFilters{f=val} end; + }; + { + name = "Gain"; + min = -30; + max = 30; + default = 0; + changed = function(val) updateFilters{gain=val} end; + }; + { + name = "Resonance"; + min = 0.1; + max = 30; + default = 1; + changed = function(val) updateFilters{Q=val} end; + }; +} + +-- Reset the plugin parameters like this : +-- params.resetToDefaults() diff --git a/ports/protoplug/ProtoplugFiles/effects/default.lua b/ports/protoplug/ProtoplugFiles/effects/default.lua new file mode 100644 index 0000000..03b0151 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/default.lua @@ -0,0 +1,3 @@ +require "include/protoplug" + +--Welcome to Lua Protoplug effect (version 1.3.0) \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/effects/delay line.lua b/ports/protoplug/ProtoplugFiles/effects/delay line.lua new file mode 100644 index 0000000..68685ca --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/delay line.lua @@ -0,0 +1,59 @@ +--[[ +name: Delay Line +description: Simple delay line effect with DC removal +author: osar.fr +--]] + +require "include/protoplug" + +local length, feedback + +stereoFx.init() + +-- everything is per stereo channel +function stereoFx.Channel:init() + self.buf = ffi.new("double[512]") + self.it = 0 -- iterator + self.dc1, self.dc2 = 0,0 +end + +function stereoFx.Channel:goBack() + local nit = self.it-length + if nit<0 then nit = nit+512 end + local o = self.buf[nit] + nit = nit-1 + if nit<0 then nit = nit+512 end + o = o+self.buf[nit] + o = o*0.4992*feedback + return o +end + +function stereoFx.Channel:dcRemove(s) + self.dc1 = self.dc1 + (s - self.dc2) * 0.000002 + self.dc2 = self.dc2 + self.dc1 + self.dc1 = self.dc1 * 0.96 + return s-self.dc2 +end + +function stereoFx.Channel:processBlock(samples, smax) + for i = 0,smax do + samples[i] = samples[i]+self:dcRemove(samples[i]+self:goBack()) + self.buf[self.it] = samples[i] + self.it = self.it+1 + if self.it>=512 then self.it=0 end + end +end + +params = plugin.manageParams { + { + name = "Length"; + type = "int"; + max = 510; + changed = function(val) length = val end; + }; + { + name = "Feedback"; + max = 1; + changed = function(val) feedback = val end; + }; +} diff --git a/ports/protoplug/ProtoplugFiles/effects/distortion - power.lua b/ports/protoplug/ProtoplugFiles/effects/distortion - power.lua new file mode 100644 index 0000000..28e25b9 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/distortion - power.lua @@ -0,0 +1,37 @@ +--[[ +name: Badass Distortion +description: The one from the website +author: osar.fr +--]] +require "include/protoplug" +local cbFilter = require "include/pac/cookbook filters" + +local power + +local function dist (x) + if x<0 then return -1*math.pow (-1*x,power) end + return math.pow (x,power) +end + +stereoFx.init () +function stereoFx.Channel:init () + -- create per-channel fields (filters) + self.low = cbFilter {type = "lp"; f = 100; gain = 0; Q = 0.3} + self.high = cbFilter {type = "hp"; f = 50; gain = 0; Q = 0.3} +end + +function stereoFx.Channel:processBlock (samples, smax) + for i = 0, smax do + local s = dist (self.high.process (samples[i])) + samples[i] = s + self.low.process (samples[i])*2 + end +end + +params = plugin.manageParams { + { + name = "Power"; + min = 1; + max = 0.01; + changed = function (val) power = val end; + }; +} diff --git a/ports/protoplug/ProtoplugFiles/effects/pitch distort.lua b/ports/protoplug/ProtoplugFiles/effects/pitch distort.lua new file mode 100644 index 0000000..165460f --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/pitch distort.lua @@ -0,0 +1,189 @@ +--[[ +name: Pitch Distort +description: > + graphical pitch distortion, + shifts each frequency band by a different factor +author: osar.fr +--]] + +require "include/protoplug" +require "include/Pickle" + +stereoFx.init() + +fftlib = script.ffiLoad("libfftw3.so.3", "libfftw3-3") + + +ffi.cdef[[ +typedef double fftw_complex[2]; +void *fftw_plan_dft_r2c_1d(int n, double *in, fftw_complex *out, unsigned int flags); +void *fftw_plan_dft_c2r_1d(int n, fftw_complex *in, double *out, unsigned int flags); +void fftw_execute(void *plan); +]] + +-- settings +local fftSize = 1024 -- 1024 seems good +local steps = 8 -- 4=low-fi, 16=high cpu +local xPixels = 400 +local yPixels = 300 + +-- useful constants +local lineMax = fftSize +local rescale = 0.5/(fftSize*steps) +local cplxSize = math.floor(fftSize/2+1) +local stepSize = fftSize/steps +local expct = 2*math.pi*stepSize/fftSize; + +-- global buffers +local graph = ffi.new ("double[?]", cplxSize) +for i = 0,cplxSize-1 do graph[i] = 0.25 end +local dbuf = ffi.new("double[?]", fftSize) +local spectrum = ffi.new("fftw_complex[?]", cplxSize) +local r2c = fftlib.fftw_plan_dft_r2c_1d(fftSize, dbuf, spectrum, 64) +local c2r = fftlib.fftw_plan_dft_c2r_1d(fftSize, spectrum, dbuf, 64) +local anaMagn = ffi.new("double[?]", cplxSize) +local anaFreq = ffi.new("double[?]", cplxSize) +local synMagn = ffi.new("double[?]", cplxSize) +local synFreq = ffi.new("double[?]", cplxSize) +local hw = ffi.new("double[?]", fftSize) -- Hann window +for i = 0,fftSize-1 do + hw[i] = (1 - math.cos(2*math.pi*i/(fftSize-1)))*rescale +end + +local function ApplyWindow (samples) + for i = 0,fftSize-1 do + samples[i] = samples[i] * hw[i] + end +end + +-- channel buffers +function stereoFx.Channel:init() + self.inbuf = ffi.new("double[?]", lineMax) + self.outbuf = ffi.new("double[?]", lineMax) + self.bufi = 0 + self.inphase = ffi.new("double[?]", cplxSize) + self.outphase = ffi.new("double[?]", cplxSize) +end + +-- filter the "spectrum" global given a channel's phases +local function ApplyFilter (inphase, outphase) + -- setup + for i=0,cplxSize-1 do + synMagn[i] = 0 + synFreq[i] = 0 + end + -- analysis + for i=0,cplxSize-1 do + local real = spectrum[i][0] + local imag = spectrum[i][1] + local magn = 2*math.sqrt(real*real+imag*imag) + local phase = math.atan2(imag, real) + local x = phase - inphase[i] + inphase[i] = phase + x = x - i*expct + x = (x+math.pi)%(math.pi*2)-math.pi + x = steps*x/(2*math.pi) + x = i + x + anaMagn[i] = magn + anaFreq[i] = x + end + -- processing + for i=0,cplxSize-1 do + local shift = graph[i]*2+0.5 + local i2 = math.floor(i*shift) + if i20 then + synMagn[i2] = anaMagn[i] + synMagn[i2] + synFreq[i2] = anaFreq[i] * shift + end + end + -- resynthesis + for i=0,cplxSize-1 do + local magn = synMagn[i] + x = synFreq[i] + x = x - i + x = 2*math.pi*x/steps + x = x + i*expct + outphase[i] = outphase[i] + x + local phase = outphase[i] + spectrum[i][0] = magn * math.cos(phase) + spectrum[i][1] = magn * math.sin(phase) + end +end + +function wrap (i) + return (i>lineMax-1) and i-lineMax or i +end + +function stereoFx.Channel:processBlock(s, smax) + for i = 0,smax do + self.inbuf[self.bufi] = s[i] + s[i] = self.outbuf[self.bufi] + self.outbuf[self.bufi] = 0 + if self.bufi%stepSize==0 then + for j=0,fftSize-1 do + dbuf[j] = self.inbuf[wrap(self.bufi+j)] + end + -- revive cdata (inexplicably required, todo-narrow down the cause): + tostring(dbuf); tostring(spectrum) + fftlib.fftw_execute(r2c) + ApplyFilter (self.inphase, self.outphase) + fftlib.fftw_execute(c2r) + ApplyWindow(dbuf) + for j=0,fftSize-1 do + self.outbuf[wrap(self.bufi+j)] = + self.outbuf[wrap(self.bufi+j)] + dbuf[j] + end + end + self.bufi = wrap(self.bufi+1) + end +end + + +-- Graphics -- +local Freqgraph = require "include/pac/freqgraph" +local J = require "include/protojuce" + +local fg = Freqgraph { + title = "Pitch distortion"; + data = graph; + dataSize = cplxSize; + yAxis = { + name = "shift (%)"; + values = { + [0] = "50"; + [0.25] = "100"; + [0.5] = "150"; + [1] = "250"; + } + } +} + +function gui.paint(g) + g:fillAll() + fg:paint(g) +end + + +-- Save & load -- +local header = "pac pitch distort 1" + +function script.loadData(data) + -- check data begins with our header + if string.sub(data, 1, string.len(header)) ~= header then return end + data = unpickle(string.sub(data, string.len(header)+1, -1)) + -- check string was turned into a table without errors + if data==nil then return end + for i=0,cplxSize-1 do + if data[i] ~= nil then + graph[i] = data[i] + end + end +end + +function script.saveData() + local picktable = {} + for i=0,cplxSize-1 do + picktable[i] = graph[i] + end + return header..pickle(picktable) +end \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/effects/pitch shift - bernsee algo.lua b/ports/protoplug/ProtoplugFiles/effects/pitch shift - bernsee algo.lua new file mode 100644 index 0000000..5ae245c --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/pitch shift - bernsee algo.lua @@ -0,0 +1,157 @@ +--[[ +name: Pitch Shift - Bernsee Algo +description: "Simple" FFT pitch shifter after S.Bernsee's famous article. +author: osar.fr +--]] + +require "include/protoplug" + +stereoFx.init() + +fftlib = script.ffiLoad("libfftw3.so.3", "libfftw3-3") + +-- params +local shift = 1 -- param=0.5 -> shift=1.0 (no shift) + +-- settings +local fftSize = 1024 -- 1024 seems good +local steps = 8 -- 4=low-fi, 16=high cpu + +-- useful constants +local lineMax = fftSize +local rescale = 1/(fftSize*steps) +local cplxSize = math.floor(fftSize/2+1) +local stepSize = fftSize/steps +local expct = 2*math.pi*stepSize/fftSize; + +ffi.cdef[[ +typedef double fftw_complex[2]; +void *fftw_plan_dft_r2c_1d(int n, double *in, fftw_complex *out, unsigned int flags); +void *fftw_plan_dft_c2r_1d(int n, fftw_complex *in, double *out, unsigned int flags); +void fftw_execute(void *plan); +]] + +-- global buffers +local dbuf = ffi.new("double[?]", fftSize) +local spectrum = ffi.new("fftw_complex[?]", cplxSize) +local anaMagn = ffi.new("double[?]", cplxSize) +local anaFreq = ffi.new("double[?]", cplxSize) +local synMagn = ffi.new("double[?]", cplxSize) +local synFreq = ffi.new("double[?]", cplxSize) +local hw = ffi.new("double[?]", fftSize) -- Hann window +for i = 0,fftSize-1 do + hw[i] = (1 - math.cos(2*math.pi*i/(fftSize-1)))*rescale +end + +local function applyWindow (samples) + for i = 0,fftSize-1 do + samples[i] = samples[i] * hw[i] + end +end + +-- fftw plans +local r2c = fftlib.fftw_plan_dft_r2c_1d(fftSize, dbuf, spectrum, 64) +local c2r = fftlib.fftw_plan_dft_c2r_1d(fftSize, spectrum, dbuf, 64) + +-- per-channel buffers +function stereoFx.Channel:init() + self.inbuf = ffi.new("double[?]", lineMax) + self.outbuf = ffi.new("double[?]", lineMax) + self.bufi = 0 + self.inphase = ffi.new("double[?]", cplxSize) + self.outphase = ffi.new("double[?]", cplxSize) +end + +-- shift data already in the "spectrum" global +local function applyFilter (inphase, outphase) + -- setup + for i=0,cplxSize-1 do + synMagn[i] = 0 + synFreq[i] = 0 + end + -- analysis + for i=0,cplxSize-1 do + local real = spectrum[i][0] + local imag = spectrum[i][1] + local magn = 2*math.sqrt(real*real+imag*imag) + local phase = math.atan2(imag, real) + local x = phase - inphase[i] + inphase[i] = phase + x = x - i*expct + x = (x+math.pi)%(math.pi*2)-math.pi + x = steps*x/(2*math.pi) + x = i + x + anaMagn[i] = magn + anaFreq[i] = x + end + -- loop-merging optimization, not sure if useful + if shift>=1 then + for i=0,cplxSize-1 do + shiftAndSynth(i, outphase) + end + else + for i=cplxSize-1,0,-1 do + shiftAndSynth(i, outphase) + end + end +end + +function shiftAndSynth(i, outphase) + -- processing + local i2 = math.floor(i*shift+0.5) -- bigger + if i20 then -- only for backward + synMagn[i2] = anaMagn[i] + synMagn[i2] + synFreq[i2] = anaFreq[i] * shift + end + -- resynthesis + local magn = synMagn[i] + x = synFreq[i] + x = x - i + x = 2*math.pi*x/steps + x = x + i*expct + outphase[i] = outphase[i] + x + local phase = outphase[i] + spectrum[i][0] = magn * math.cos(phase) + spectrum[i][1] = magn * math.sin(phase) +end + +function wrap (i) + return (i>lineMax-1) and i-lineMax or i +end + +function stereoFx.Channel:processBlock(s, smax) + for i = 0,smax do + self.inbuf[self.bufi] = s[i] + s[i] = self.outbuf[self.bufi] + self.outbuf[self.bufi] = 0 + if self.bufi%stepSize==0 then + for j=0,fftSize-1 do + dbuf[j] = self.inbuf[wrap(self.bufi+j)] + end + -- revive cdata (inexplicably required, todo narrow down the cause): + tostring(dbuf); tostring(spectrum) + fftlib.fftw_execute(r2c) + applyFilter (self.inphase, self.outphase) + fftlib.fftw_execute(c2r) + applyWindow(dbuf) + for j=0,fftSize-1 do + self.outbuf[wrap(self.bufi+j)] = + self.outbuf[wrap(self.bufi+j)] + dbuf[j] + end + end + self.bufi = wrap(self.bufi+1) + end +end + +plugin.manageParams { + { + name = "Shift"; + changed = function(val) + if val<0.5 then + shift = (val+0.1)/0.6 + else + shift = val*8-3 + end + end; + }; +} diff --git a/ports/protoplug/ProtoplugFiles/effects/spectral filter.lua b/ports/protoplug/ProtoplugFiles/effects/spectral filter.lua new file mode 100644 index 0000000..2692141 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/effects/spectral filter.lua @@ -0,0 +1,135 @@ +--[[ +name: Spectral Filter +description: graphical spectral filter using fftw +author: osar.fr +--]] + +require "include/protoplug" +require "include/Pickle" + +stereoFx.init() + +-- settings (change these here) +local fftSize = 512 +local xPixels = 400 +local yPixels = 300 + +-- open FFTW and define the stuff we need +fftlib = script.ffiLoad("libfftw3.so.3", "libfftw3-3") + +ffi.cdef[[ +typedef double fftw_complex[2]; +void *fftw_plan_dft_r2c_1d(int n, double *in, fftw_complex *out, unsigned int flags); +void *fftw_plan_dft_c2r_1d(int n, fftw_complex *in, double *out, unsigned int flags); +void fftw_execute(void *plan); +]] + +-- useful constants +local stepSize = math.floor(fftSize/2) +local cplxSize = stepSize+1 +local rescale = 1/fftSize-- no /2 because we use 200% as max + +-- global buffers : actual filter and Hann window +local graph = ffi.new ("double[?]", cplxSize) +for i = 0,cplxSize-2 do graph[i] = 0.5 end +graph[cplxSize-1] = 0 -- no one wants DC +local hw = ffi.new("double[?]", fftSize) +for i = 0,fftSize-1 do + hw[i] = (1 - math.cos(2*math.pi*i/(fftSize-1)))*rescale +end + +local function applyFilter (spectrum) + for i=0,cplxSize-1 do + spectrum[i][0] = spectrum[i][0]*graph[i] -- real + spectrum[i][1] = spectrum[i][1]*graph[i] -- imaginary + -- do more interesting stuff here :) + end +end + +local function applyWindow (samples) + for i = 0,fftSize-1 do + samples[i] = samples[i] * hw[i] + end +end + +-- global working buffers and their fftw plans +local samples = ffi.new("double[?]", fftSize) +local spectrum = ffi.new("fftw_complex[?]", cplxSize) +local r2c = fftlib.fftw_plan_dft_r2c_1d(fftSize, samples, spectrum, 64) +local c2r = fftlib.fftw_plan_dft_c2r_1d(fftSize, spectrum, samples, 64) + +-- per-channel buffers +function stereoFx.Channel:init() + self.inbuf = ffi.new("double[?]", fftSize) + self.outbuf = ffi.new("double[?]", fftSize) + self.bufi = 0 +end + +local function wrap (i) + return (i>fftSize-1) and i-fftSize or i +end + +function stereoFx.Channel:processBlock(s, smax) + for i = 0,smax do + self.inbuf[self.bufi] = s[i] + s[i] = self.outbuf[self.bufi] + self.outbuf[self.bufi] = 0 + if self.bufi%stepSize==0 then + for j=0,fftSize-1 do + samples[j] = self.inbuf[wrap(self.bufi+j)] + end + -- revive cdata (inexplicably required, todo narrow down the cause): + tostring(samples); tostring(spectrum) + fftlib.fftw_execute(r2c) + applyFilter (spectrum) + fftlib.fftw_execute(c2r) + applyWindow(samples) + for j=0,fftSize-1 do + self.outbuf[wrap(self.bufi+j)] = + self.outbuf[wrap(self.bufi+j)] + samples[j] + end + end + self.bufi = wrap(self.bufi+1) + end +end + + +-- Graphics -- +local Freqgraph = require "include/pac/freqgraph" +local J = require "include/protojuce" + +local fg = Freqgraph { + title = "Spectral Filter"; + data = graph; + dataSize = cplxSize-1; -- don't touch the last partial (DC) +} + +function gui.paint(g) + g:fillAll() + fg:paint(g) +end + + +-- Save & load -- +local header = "pac spectral filter 1" + +function script.loadData(data) + -- check data begins with our header + if string.sub(data, 1, string.len(header)) ~= header then return end + data = unpickle(string.sub(data, string.len(header)+1, -1)) + -- check string was turned into a table without errors + if data==nil then return end + for i=0,cplxSize-1 do + if data[i] ~= nil then + graph[i] = data[i] + end + end +end + +function script.saveData() + local picktable = {} + for i=0,cplxSize-1 do + picktable[i] = graph[i] + end + return header..pickle(picktable) +end \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/generators/default.lua b/ports/protoplug/ProtoplugFiles/generators/default.lua new file mode 100644 index 0000000..3e0a013 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/default.lua @@ -0,0 +1,3 @@ +require "include/protoplug" + +--Welcome to Lua Protoplug generator (version 1.3.0) \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/generators/fft sweeper.lua b/ports/protoplug/ProtoplugFiles/generators/fft sweeper.lua new file mode 100644 index 0000000..e3b1239 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/fft sweeper.lua @@ -0,0 +1,111 @@ +--[[ +name: FFT sweeper +description: testing +author: osar.fr +--]] + +require "include/protoplug" + +fftlib = script.ffiLoad("libfftw3.so.3", "libfftw3-3") + +ffi.cdef[[ +typedef enum { + FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2, + FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6, + FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10 +} fftw_r2r_kind; +void *fftw_plan_r2r_1d(int n, double *in, double *out, fftw_r2r_kind kind, unsigned int flags); +void fftw_execute(void *plan); +]] +fftsz = 1024 +winsz = 1000 +fd = ffi.new("double[?]", fftsz) -- halfcomplex freq domain +td1 = ffi.new("double[?]", fftsz) -- time domain +td2 = ffi.new("double[?]", fftsz) -- time domain (alternating) +hw = ffi.new("double[?]", fftsz) -- Hann window function +plan1 = fftlib.fftw_plan_r2r_1d(fftsz, fd, td1, 1, 64) +plan2 = fftlib.fftw_plan_r2r_1d(fftsz, fd, td2, 1, 64) + +-- prepare Hann window +for i = 0,winsz-1 do + hw[i] = 0.00003 * (1 - math.cos(2*math.pi*i/(winsz-1))); +end +function ApplyWindow (buf) + for i = 0,winsz-1 do + buf[i] = buf[i] * hw[i] + end +end + +cphase = 0 + +gapper = 0 + +function FillFD (buf) + local center = math.sin(cphase)*10+15 + gapper = gapper+1 + if gapper > 1 then gapper = 0 end + if gapper > 0 then + --for i = 0,fftsz-1 do + -- buf[i] = 0 + --end + --return + center = center*4 + end + for i = 0,fftsz-1 do + local sharm = math.sin(i-center) + local x = i/(fftsz*0.0004883) + buf[i] = 10000/((x-center)*(x-center)+10)*sharm*sharm + buf[i] = buf[i] + 33457/((x-center*8)*(x-center*8)+1000) + buf[i] = buf[i] + 34321/((x-center*12)*(x-center*12)+1000) + --buf[i] = buf[i] + 100/((i-center*2)*(i-center*2)+1) + --buf[i] = buf[i] + 10/((i-center*4)*(i-center*4)+1) + --if i
10 then buf[i] = 10 end + end + cphase = cphase + 0.01 +end + + +FillFD(fd) +fftlib.fftw_execute(plan1) +fftlib.fftw_execute(plan2) +ApplyWindow(td1) +ApplyWindow(td2) +tdpos1 = 0 +tdpos2 = winsz*0.5 +alt1 = false +alt2 = false + +function plugin.processBlock(s, smax) + for i = 0,smax do + s[0][i] = td1[tdpos1] + td2[tdpos2] + s[1][i] = td1[tdpos1] + td2[tdpos2] + tdpos1 = tdpos1+1 + tdpos2 = tdpos2+1 + if tdpos1 >= winsz then + tdpos1 = 0 + if alt1 then + alt1 = false + FillFD(fd) + fftlib.fftw_execute(plan1) + ApplyWindow(td1) + else + alt1 = true + end + end + if tdpos2 >= winsz then + tdpos2 = 0 + if alt2 then + alt2 = false + FillFD(fd) + fftlib.fftw_execute(plan2) + ApplyWindow(td2) + else + alt2 = true + end + end + end + return 1 +end diff --git a/ports/protoplug/ProtoplugFiles/generators/midi nonstop atonal V.lua b/ports/protoplug/ProtoplugFiles/generators/midi nonstop atonal V.lua new file mode 100644 index 0000000..5b40221 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/midi nonstop atonal V.lua @@ -0,0 +1,61 @@ +-- outputs a stream of semi-chaotic notes on MIDI channel 1 + +require "include/protoplug" + +--Welcome to Lua Protoplug generator (version 1.0.0) +x=0 +function plugin.processBlock(samples, smax, midiBuf) + newEvents = {} + if not interval then updateInterval() end + if not i then i = interval + 1 end + for s=0,smax do + if i>=interval then + local f1,v1 = magic(x) + local f2 = magic(x-5) + if f1 then noteOn(f1, v1) end + if f1 then noteOn(f1-5, v1) end + if f2 then noteOff(f2) end + if f2 then noteOff(f2-5) end + i = 0 + x = x + 1 + end + i = i + 1 + end + midiBuf:clear() + if #newEvents>0 then + for _,e in ipairs(newEvents) do + midiBuf:addEvent(e) + end + end +end + +function noteOn(n,v) + if n>100 then return end + table.insert(newEvents, midi.Event.noteOn(1, n, v)) +end +function noteOff(n) + table.insert(newEvents, midi.Event.noteOff(1, n, 0)) +end + +function magic(x) + if ((x%19)%11)%4==0 then + return 40+x%((x/6)%8+2)*8, 20+((x/6)%8+2)*8 + end +end + +function updateInterval() + local int = params[1].getValue() + bpm = plugin.getCurrentPosition().bpm + interval = math.floor((plugin.getSampleRate()*int)/(bpm)) +end + +params = plugin.manageParams { + { + name = "Interval"; + type = "int"; + min = 3; + max = 30; + default = 60; + changed = function(val) interval = nil end; + }; +} \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/generators/midi-chordify.lua b/ports/protoplug/ProtoplugFiles/generators/midi-chordify.lua new file mode 100644 index 0000000..0f7d900 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/midi-chordify.lua @@ -0,0 +1,49 @@ +--[[ +name: midi chordify +description: MIDI processor VST/AU. Notes go in, chords come out. +author: osar.fr +--]] + +require "include/protoplug" + +-- what kind of chord ? +local chordStructure = {0, 3, 5, 7, 11} +local blockEvents = {} + +function plugin.processBlock(samples, smax, midiBuf) + blockEvents = {} + -- analyse midi buffer and prepare a chord for each note + for ev in midiBuf:eachEvent() do + if ev:isNoteOn() then + chordOn(ev) + elseif ev:isNoteOff() then + chordOff(ev) + end + end + -- fill midi buffer with prepared notes + midiBuf:clear() + if #blockEvents>0 then + for _,e in ipairs(blockEvents) do + midiBuf:addEvent(e) + end + end +end + +function chordOn(root) + for _, offset in ipairs(chordStructure) do + local newEv = midi.Event.noteOn( + root:getChannel(), + root:getNote()+offset, + root:getVel()) + table.insert(blockEvents, newEv) + end +end + +function chordOff(root) + for _, offset in ipairs(chordStructure) do + local newEv = midi.Event.noteOff( + root:getChannel(), + root:getNote()+offset) + table.insert(blockEvents, newEv) + end +end diff --git a/ports/protoplug/ProtoplugFiles/generators/sine-organ.lua b/ports/protoplug/ProtoplugFiles/generators/sine-organ.lua new file mode 100644 index 0000000..6292279 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/sine-organ.lua @@ -0,0 +1,45 @@ +--[[ +name: sine organ +description: A simple organ-like sinewave VST/AU. +author: osar.fr +--]] + +require "include/protoplug" + +local release = 10000 +local decayRate = 1/release + +polyGen.initTracks(8) + +function polyGen.VTrack:init() + -- create per-track fields here + self.phase = 0 + self.releasePos = release +end + +function polyGen.VTrack:addProcessBlock(samples, smax) + local amp = 1 + for i = 0,smax do + if not self.noteIsOn then + -- release is finished : idle track + if self.releasePos>=release then break end + -- release is under way + amp = 1-self.releasePos*decayRate + self.releasePos = self.releasePos+1 + end + self.phase = self.phase + (self.noteFreq*math.pi*2) + -- math.sin is slow but once per sample is no tragedy + local trackSample = math.sin(self.phase)*amp*0.3 + samples[0][i] = samples[0][i] + trackSample -- left + samples[1][i] = samples[1][i] + trackSample -- right + end +end + +function polyGen.VTrack:noteOff(note, ev) + self.releasePos = 0 +end + +function polyGen.VTrack:noteOn(note, vel, ev) + -- start the sinewave at 0 for a clickless attack + self.phase = 0 +end \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/generators/sinemouse-demo.lua b/ports/protoplug/ProtoplugFiles/generators/sinemouse-demo.lua new file mode 100644 index 0000000..29a90f5 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/sinemouse-demo.lua @@ -0,0 +1,47 @@ +--[[ +name: sinemouse demo +description: > + Custom GUI demonstration : Drag your mouse around in the + frame to control the sine wave's amplitude and frequency. +author: osar.fr +--]] + +require "include/protoplug" + +local freq,amp = 440, 0 +local delta, phase = 0.06, 0 + +function plugin.processBlock(samples, smax) + for i=0,smax do + local s = math.sin(phase)*amp + samples[0][i] = s -- left + samples[1][i] = s -- right + phase = phase + delta + end +end + +local J = juce +local frame = J.Rectangle_int(20,20,400,300) +local sideways = J.AffineTransform():rotated(math.pi*0.5) + +function gui.paint(g) + g:fillAll() + g:setColour(J.Colour.green) + g:drawRect(frame) + g:drawText("Frequency", 20, 320, 400, 20, J.Justification.centred) + g:addTransform(sideways) + g:drawText("amplitude", 20, -440, 300, 20, J.Justification.centred) +end + +local function mouseHandler(event) + if not frame:contains(J.Point(event.x,event.y)) then + return + end + freq = event.x + 80 + amp = (320-event.y)/300 + local sr = plugin.isSampleRateKnown() and plugin.getSampleRate() or 44100 + delta = 2*math.pi*freq/sr +end + +gui.addHandler("mouseDrag", mouseHandler) +gui.addHandler("mouseDown", mouseHandler) diff --git a/ports/protoplug/ProtoplugFiles/generators/soundfile-test.lua b/ports/protoplug/ProtoplugFiles/generators/soundfile-test.lua new file mode 100644 index 0000000..1cf3748 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/generators/soundfile-test.lua @@ -0,0 +1,39 @@ +--[[ +name: soundfile test +description: A simple demo that plays an audio file. +author: osar.fr +--]] + +require "include/protoplug" + +local path = "C:\\temp\\pluck44.wav" +local wave, len + +-- 'prepareToPlay' will be triggered when the host sample rate is known, +-- so we can load sound files with automatic sample rate conversion: +plugin.addHandler('prepareToPlay', function() + local readr = juce.AudioFormatReader(path) + if readr==nil then error ("can't open wave: "..path) end + wave, len = readr:readToFloat(2) -- require 2 channels +end) + +polyGen.initTracks(8) + +function polyGen.VTrack:noteOn(note, vel, ev) + self.playing = true + self.wavepos = 0 +end + +function polyGen.VTrack:noteOff(note, ev) + self.playing = false +end + +function polyGen.VTrack:addProcessBlock(samples, smax) + for i = 0,smax do + if self.playing and self.wavepos < len then + self.wavepos = self.wavepos + 1 + samples[0][i] = samples[0][i] + wave[0][self.wavepos] -- left + samples[1][i] = samples[1][i] + wave[1][self.wavepos] -- right + end + end +end diff --git a/ports/protoplug/ProtoplugFiles/include/Pickle.lua b/ports/protoplug/ProtoplugFiles/include/Pickle.lua new file mode 100644 index 0000000..64adf08 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/Pickle.lua @@ -0,0 +1,88 @@ +---------------------------------------------- +-- Pickle.lua +-- A table serialization utility for lua +-- Steve Dekorte, http://www.dekorte.com, Apr 2000 +-- Freeware +---------------------------------------------- + +function pickle(t) + return Pickle:clone():pickle_(t) +end + +Pickle = { + clone = function (t) + local nt={}; + for i, v in pairs(t) do + nt[i]=v + end + return nt + end +} + +function Pickle:pickle_(root) + if type(root) ~= "table" then + error("can only pickle tables, not ".. type(root).."s") + end + self._tableToRef = {} + self._refToTable = {} + local savecount = 0 + self:ref_(root) + local s = "" + + while table.getn(self._refToTable) > savecount do + savecount = savecount + 1 + local t = self._refToTable[savecount] + s = s.."{\n" + for i, v in pairs(t) do + s = string.format("%s[%s]=%s,\n", s, self:value_(i), self:value_(v)) + end + s = s.."},\n" + end + + return string.format("{%s}", s) +end + +function Pickle:value_(v) + local vtype = type(v) + if vtype == "string" then return string.format("%q", v) + elseif vtype == "number" then return v + elseif vtype == "table" then return "{"..self:ref_(v).."}" + else --error("pickle a "..type(v).." is not supported") + end +end + +function Pickle:ref_(t) + local ref = self._tableToRef[t] + if not ref then + if t == self then error("can't pickle the pickle class") end + table.insert(self._refToTable, t) + ref = table.getn(self._refToTable) + self._tableToRef[t] = ref + end + return ref +end + +---------------------------------------------- +-- unpickle +---------------------------------------------- + +function unpickle(s) + if type(s) ~= "string" then + error("can't unpickle a "..type(s)..", only strings") + end + local gentables = loadstring("return "..s) + local tables = gentables() + + for tnum = 1, table.getn(tables) do + local t = tables[tnum] + local tcopy = {}; for i, v in pairs(t) do tcopy[i] = v end + for i, v in pairs(tcopy) do + local ni, nv + if type(i) == "table" then ni = tables[i[1]] else ni = i end + if type(v) == "table" then nv = tables[v[1]] else nv = v end + t[i] = nil + t[ni] = nv + end + end + return tables[1] +end diff --git a/ports/protoplug/ProtoplugFiles/include/core/gui.lua b/ports/protoplug/ProtoplugFiles/include/core/gui.lua new file mode 100644 index 0000000..f528d0f --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/gui.lua @@ -0,0 +1,268 @@ +--- Use `gui` to define your script's custom graphical user interface. +-- Custom GUI example : @{sinemouse-demo.lua} +-- +-- The `gui` global is available to every protoplug script after including the +-- main protoplug header : +-- require "include/protoplug" +-- @module gui + +local gui = {} + +--- Focus change causes. +-- Values received by the `focusGained` and `focusLost` handlers. +-- @see gui.addHandler +-- @table FocusCause +gui.FocusCause = +{ + focusChangedByMouseClick = 0; -- 0 + focusChangedByTabKey = 1; -- 1 + focusChangedDirectly = 2; -- 2 +}; + +--- Keyboard and mouse modifiers. +-- Contained in every @{gui.MouseEvent} and received by the +-- `modifierKeysChanged` handler. +-- @table ModifierKeys +gui.ModifierKeys = +{ + noModifiers = 0; -- 0 + shiftModifier = 1; -- 1 + ctrlModifier = 2; -- 2 + altModifier = 4; -- 4 + leftButtonModifier = 16; -- 16 + rightButtonModifier = 32; -- 32 + middleButtonModifier = 64; -- 64 + commandModifier = 8; -- 8 + ctrlAltCommandModifiers = 14; -- 14 +}; + +local script = require "include/core/script" + +--[[--- Add a handler for a GUI event. + +Here's a list of the events and their parameters, showing how they +should be received : + gui.addHandler("resized", function() ... end) + gui.addHandler("focusGained", function(focusCause) ... end) + gui.addHandler("focusLost", function(focusCause) ... end) + gui.addHandler("modifierKeysChanged", function(modifierKeys) ... end) + gui.addHandler("mouseMove", function(mouseEvent) ... end) + gui.addHandler("mouseEnter", function(mouseEvent) ... end) + gui.addHandler("mouseExit", function(mouseEvent) ... end) + gui.addHandler("mouseDown", function(mouseEvent) ... end) + gui.addHandler("mouseDrag", function(mouseEvent) ... end) + gui.addHandler("mouseUp", function(mouseEvent) ... end) + gui.addHandler("mouseDoubleClick", function(mouseEvent) ... end) + gui.addHandler("mouseWheelMove", function(mouseEvent, mouseWheelDetails) ... end) + gui.addHandler("keyPressed", function(keyPress, srcComponent) ... end) + gui.addHandler("keyStateChanged", function(keyPress, srcComponent) ... end) +Parameters received by the event handlers are of +type @{FocusCause}, @{ModifierKeys}, @{MouseEvent}, @{MouseWheelDetails}, +and @{KeyPress}. + +@see script.addHandler +@see plugin.addHandler +@tparam string event the event to handle +@tparam function handler a function to add the event's handlers +--]] +function gui.addHandler(event, handler) + if not gui[event] then gui[event] = {} end + table.insert(gui[event], handler) +end + +-- assumes handler existence already checked +local function gui_emit(event, ...) + for _,v in ipairs(gui[event]) do + v(...) + end +end + +-- returns nil if no handler (prevents useless definitions) +local function gui_getEmitter(event) + if not gui[event] then return end + return function (...) + gui_emit(event, ...) + end +end + +script.addHandler("init", function () + + --- Override to paint a custom GUI. + -- Define this function to paint something in the custom GUI space. + -- @tparam juce.Graphics g a JUCE graphics target + -- @function gui.paint + if type(gui.paint) == "function" then + function gui_paint(g) + g = ffi.typeof("pGraphics")(g) + gui.paint(g) + end + end + + gui_resized = gui_getEmitter("resized") + gui_focusGained = gui_getEmitter("focusGained") + gui_focusLost = gui_getEmitter("focusLost") + gui_modifierKeysChanged = gui_getEmitter("modifierKeysChanged") + + + -- event overrides with ffi conversion + if gui.mouseMove then + function gui_mouseMove(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseMove",event) + end + end + + if gui.mouseEnter then + function gui_mouseEnter(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseEnter", event) + end + end + + if gui.mouseExit then + function gui_mouseExit(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseExit", event) + end + end + + if gui.mouseDown then + function gui_mouseDown(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseDown", event) + end + end + + if gui.mouseDrag then + function gui_mouseDrag(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseDrag", event) + end + end + + if gui.mouseUp then + function gui_mouseUp(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseUp", event) + end + end + + if gui.mouseDoubleClick then + function gui_mouseDoubleClick(event) + event = ffi.typeof("MouseEvent*")(event) + gui_emit("mouseDoubleClick", event) + end + end + + if gui.mouseWheelMove then + function gui_mouseWheelMove(event, wheel) + event = ffi.typeof("MouseEvent*")(event) + wheel = ffi.typeof("MouseWheelDetails*")(wheel) + gui_emit("mouseWheelMove", event, wheel) + end + end + + if gui.keyPressed then + function gui_keyPressed(key, component) + key = ffi.typeof("KeyPress*")(key) + component = ffi.typeof("pComponent")(component) + gui_emit("keyPressed", key, component) + return true + end + end + + if gui.keyStateChanged then + function gui_keyStateChanged(isKeyDown, component) + component = ffi.typeof("pComponent")(component) + gui_emit("keyStateChanged", isKeyDown, component) + return true + end + end +end) + + +gui.ppcomponent = ffi.typeof("pComponent*")(gui_component) + +--- Get GUI Component. +-- @return the current GUI component, or `nil` if the GUI +-- has not been opened yet. + +function gui.getComponent() + if gui.ppcomponent[0].pointer~=nil then + return gui.ppcomponent[0] + end +end + + +--- Mouse Event. +-- A mouse event as received by GUI handlers (see @{gui.addHandler}) +--

+-- @type gui.MouseEvent + +--- X. +-- @field MouseEvent.x + +--- Y. +-- @field MouseEvent.y + +--- Modifier keys. +-- Values defined in @{gui.ModifierKeys} +-- @field MouseEvent.mods + +--- Event component. +-- @field MouseEvent.eventComponent + +--- Original component. +-- @field MouseEvent.originalComponent + +--- Time. +-- @field MouseEvent.eventTime + +--- Mouse down time. +-- @field MouseEvent.mouseDownTime + +--- Mouse down position. +-- @field MouseEvent.mouseDownPos + +--- Number of clicks. +-- @field MouseEvent.numberOfClicks + +--- Was moved since mouse down. +-- @field MouseEvent.wasMovedSinceMouseDown + + +--- Mouse Wheel Details. +-- As received by the `mouseWheelMove` handler (see @{gui.addHandler}) +--

+-- @type gui.MouseWheelDetails + +--- X delta. +-- @field MouseWheelDetails.deltaX + +--- Y delta. +-- @field MouseWheelDetails.deltaY + +--- Is reversed. +-- @field MouseWheelDetails.isReversed + +--- Is smooth. +-- @field MouseWheelDetails.isSmooth + + +--- Key Press. +-- As received by the `keyPressed` and `keyStateChanged` handlers (see @{gui.addHandler}) +--

+-- @type gui.KeyPress + +--- Key code. +-- (undecipherable for now) +-- @field KeyPress.keyCode + +--- Modifier Keys. +-- @field KeyPress.mods + +--- Text character. +-- @field KeyPress.textCharacter + + +return gui \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/core/manageparams.lua b/ports/protoplug/ProtoplugFiles/include/core/manageparams.lua new file mode 100644 index 0000000..a35f8eb --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/manageparams.lua @@ -0,0 +1,162 @@ +-- Manage Params +-- takes a list of parameter descriptions and manages all the parameter overrides. +--[[ example usage : + +params = plugin.manageParams { + Harshness = { + max = 510; + changed = function(val) DoSomethingWithNewValue(val) end; + }; + ["Wave Style"] = { + type = "list"; + values = {"peaky"; "siney"; "wavey"}; + changed = function(val) myVar = var end; + }; +} +--]] + +local util = require "include/luautil" +local script = require "include/core/script" + +local paramConstructors = +{ + double = function(param) + param.min = param.min or 0 + param.max = param.max or 1 + param.showDecimals = param.showDecimals or 4 + param.getText = function() + return tostring( + util.roundDecimal( + plugin.getParameter(param.index)*(param.max-param.min)+param.min + ,param.showDecimals) + ) + end + param.getValue = function() + return plugin.getParameter(param.index)*(param.max-param.min)+param.min + end + param.Value2Raw = function(val) + return (val-param.min)/(param.max-param.min) + end + return param + end; + + int = function(param) + param.min = param.min or 0 + param.max = param.max or 127 + param.getText = function() + return tostring( + math.floor(plugin.getParameter(param.index)*(param.max-param.min)+param.min) + ) + end + param.getValue = function() + return math.floor(plugin.getParameter(param.index)*(param.max-param.min)+param.min) + end + param.Value2Raw = function(val) + return (val-param.min)/(param.max-param.min) + end + return param + end; + + list = function(param) + param.getText = function() + local i = plugin.getParameter(param.index)*(#param.values-0.1)+1 + return tostring(param.values[math.floor(i)]) + end + param.getValue = function() + local i = plugin.getParameter(param.index)*(#param.values-0.1)+1 + return param.values[math.floor(i)] + end + param.getKey = function() + return plugin.getParameter(param.index)*(#param.values-0.1)+1 + end + param.Value2Raw = function(val) + for k,v in ipairs(param.values) do + if v==val then + return (k-1)/(#param.values-0.5) + end + end + error ("value "..val.." not in value list for "..param.key) + end + return param + end; +} + + +return function(args) + local params = {} + local index2param = {} + + for key, param in pairs(args) do + param.type = param.type or "double" + param.index = key - 1 + param = paramConstructors[param.type](param) + + if type(param.name) ~= "string" then + param.name = ("Param %i (%s)"):format(param.index, param.type) + end + + param.set = function(val) + plugin.setParameter(param.index, param.Value2Raw(val)) + param.changed(param.getValue()) + end + params[key] = param + index2param[param.index] = param + end + + function plugin.getParameterName(index) + local param = index2param[index] + if param then + return param.name + end + end + + function plugin.getParameterText(index) + local param = index2param[index] + if param then + return param.getText() + end + end + + function plugin.parameterText2Double(index, text) + local param = index2param[index] + if param then + return param.Value2Raw(text) + end + end + + function plugin.paramChanged(index) + local param = index2param[index] + if param and param.changed then + param.changed(param.getValue()) + end + end + + local function iter (params, cur) + local k,v = next(params, cur) + while v and type(v)~="table" do + k,v = next(params, k) + end + return k, v + end + + function params.each() + return iter, params, nil + end + + function params.resetToDefaults() + for key, param in pairs(args) do + if type(param)=="table" then + plugin.setParameter(param.index, param.Value2Raw(param.default)) + param.changed(param.getValue()) + end + end + end + + script.addHandler("init", function () + for key, param in params.each() do + param.changed(param.getValue()) + end + end) + + return params; +end diff --git a/ports/protoplug/ProtoplugFiles/include/core/midi.lua b/ports/protoplug/ProtoplugFiles/include/core/midi.lua new file mode 100644 index 0000000..6441b45 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/midi.lua @@ -0,0 +1,379 @@ +--- `midi` contains MIDI-related classes and functions. +-- Example of receiving MIDI input : @{sine-organ.lua}. +-- +-- Example of producing MIDI output : @{midi-chordify.lua}. +-- +-- The `midi` global is available to every protoplug script after including the +-- main protoplug header : +-- require "include/protoplug" +-- @module midi + +-- Bitte ein BitOp +local bnot = bit.bnot +local band, bor, bxor = bit.band, bit.bor, bit.bxor +local lshift, rshift, rol = bit.lshift, bit.rshift, bit.rol + +ffi.cdef [[ + +typedef struct pMidiBuffer +{ void *pointer; } pMidiBuffer; + +uint8_t *MidiBuffer_getDataPointer(pMidiBuffer mb); +int MidiBuffer_getDataSize(pMidiBuffer mb); +void MidiBuffer_resizeData(pMidiBuffer mb, int size); + +// artist's rendition of the juce::MidiBuffer internal format +// ("don't write code that relies on it!" -Jules) +typedef struct MidiEvent +{ + int32_t time; + const uint16_t dataSize; + uint8_t data[?]; +} MidiEvent; +]] + +local midi = {} + +--- Convert a MIDI note number to frequency. +-- Call this function to get a note's frequency. +-- @param note the MIDI note (0-127) +-- @return the frequency in samples^-1 +-- @function midi.noteToFreq +function midi.noteToFreq(n) + return 2^((n-69)/12)*440/plugin.getSampleRate() +end + + +--- Midi Event List. +-- A buffer containing midi events, as received by @{plugin.processBlock} +--

+-- @type midi.Buffer +midi.Buffer = ffi.typeof("pMidiBuffer") + +local locks = {} + +local Buffer_mt = { + -- methods + __index = { + + --- Iterate over each @{midi.Event} in the buffer. + -- @usage for ev in myBuffer:eachEvent() do print(ev:getNote()) end + -- @function Buffer:eachEvent + eachEvent = function (self) + -- COROUTINE ITERATOR IS EVIL ITERATOR + return coroutine.wrap(function () + local dataStart = protolib.MidiBuffer_getDataPointer(self) + local msg = dataStart + local nBytes = protolib.MidiBuffer_getDataSize(self) + self:lock() + while msg < dataStart + nBytes do + ret = ffi.cast("MidiEvent*",msg) + coroutine.yield(ret) + msg = msg + + ffi.sizeof"int32_t" + + ffi.sizeof"uint16_t" + + ffi.sizeof"uint8_t" * ret.dataSize + end + self:unlock() + end) + end; + + --- Remove all MIDI events from the buffer. + -- @function Buffer:clear + clear = function (self) + self:checkLock() + protolib.MidiBuffer_resizeData(self, 0) + end; + + --- Add a MIDI event. + -- @tparam midi.Event event + -- @function Buffer:addEvent + addEvent = function (self, event) + self:checkLock() + local nBytes = protolib.MidiBuffer_getDataSize(self) + protolib.MidiBuffer_resizeData(self, nBytes + event.dataSize+ffi.sizeof("int32_t")+ffi.sizeof("uint16_t")) + local dataStart = protolib.MidiBuffer_getDataPointer(self) + ffi.copy(dataStart + nBytes, event, event.dataSize+ffi.sizeof("int32_t")+ffi.sizeof("uint16_t")) + end; + + -- internal + lock = function (self) + local addr = tonumber(ffi.cast("int", protolib.MidiBuffer_getDataPointer(self))) + locks[addr] = locks[addr] and locks[addr] + 1 or 1 + end; + + unlock = function (self) + local addr = tonumber(ffi.cast("int", protolib.MidiBuffer_getDataPointer(self))) + if not locks[addr] then return end + locks[addr] = locks[addr] - 1 + if locks[addr] < 1 then locks[addr] = nil end + end; + + checkLock = function (self) + local addr = tonumber(ffi.cast("int", protolib.MidiBuffer_getDataPointer(self))) + if locks[addr] then + error "Cannot modify a midi.Buffer while iterating through it." + end + end; + + debug = function (self) + self:checkLock() + local o = "" + local max = protolib.MidiBuffer_getDataSize(self) + local addr = protolib.MidiBuffer_getDataPointer(self) + for i = 0,max-1 do + addr = addr + 1 + o = o..bit.tohex(addr[0],4).." " + end + print (o) + end; + + }; +} +ffi.metatype(midi.Buffer, Buffer_mt) + +--- Midi Event. +-- A single midi event as returned by @{Buffer:eachEvent} +--

+-- @type midi.Event + +midi.Event = setmetatable ({}, { + --- Constructor : copy another event. + -- @tparam midi.Event other + -- @display midi.Event + -- @function Event + + --- Constructor : create a custom event. + -- Create an event from given bytes (or zeros if not supplied) + -- @usage myEv = midi.Event(0, 3, {0x90, 0x30, 0x7f}) -- note on + -- @param time + -- @param dataSize + -- @param[opt] data + -- @display midi.Event + -- @function midi.Event + __call = function(self, ...) + if select("#", ...)==1 then + local o = ... + local n = ffi.new("MidiEvent", o.dataSize, o.time, o.dataSize) + ffi.copy(n.data, o.data, o.dataSize) + return n + elseif select("#", ...)==2 then + local time, dataSize, data = ... + local n = ffi.new("MidiEvent", dataSize, time, dataSize) + if data then + for k,v in ipairs(data) do n.data[k-1] = v end + else + ffi.fill(n.data, dataSize) + end + return n + end + end; +}) + +--- Constructor : note on. +-- @param channel (1-16) +-- @param note (0-127) +-- @param vel (1-127) +-- @param[opt=0] pos sample offset +-- @treturn midi.Event +-- @function Event.noteOn +midi.Event.noteOn = function (channel, note, vel, pos) + pos = pos or 0 + local n = midi.Event(pos, 3) + n.data[0] = bor(0x90, channel-1) + n.data[1] = band(note, 127) + n.data[2] = band(vel, 127) + return n +end + +--- Constructor : note off. +-- @param channel (1-16) +-- @param note (0-127) +-- @param[opt=0] vel (0-127) +-- @param[opt=0] pos sample offset +-- @treturn midi.Event +-- @function Event.noteOff +midi.Event.noteOff = function (channel, note, vel, pos) + pos = pos or 0 + vel = vel or 0 + local n = midi.Event(pos, 3) + n.data[0] = bor(0x80, channel-1) + n.data[1] = band(note, 127) + n.data[2] = band(vel, 127) + return n +end + +--- Constructor : pitch bend. +-- @param channel (1-16) +-- @param pitch bend value (0-16383) +-- @param[opt=0] pos sample offset +-- @treturn midi.Event +-- @function Event.pitchBend +midi.Event.pitchBend = function (channel, val, pos) + pos = pos or 0 + local n = midi.Event(pos, 3) + n.data[0] = bor(0xe0, channel-1) + n.data[1] = band(val, 127) + n.data[2] = band(rshift(val,7), 127) + return n +end + +--- Constructor : Control change. +-- @param channel (1-16) +-- @param number control number (0-247) +-- @param value control value (0-127) +-- @param[opt=0] pos sample offset +-- @treturn midi.Event +-- @function Event.control +midi.Event.control = function (channel, num, val, pos) + pos = pos or 0 + local n = midi.Event(pos, 3) + n.data[0] = bor(0xb0, channel-1) + n.data[1] = band(num, 127) + n.data[2] = band(val, 127) + return n +end + +local MidiEvent_mt = { + -- todo precalculate ? + -- status = band(self.data[0], 0xf0) + -- note = band(self.data[1], 0x7f) + -- vel = band(self.data[2], 0x7f) + -- also sanity check ? if msg.dataSize>=3 then + + -- methods + __index = { + + --- Get channel. + -- @return the MIDI channel (1-16) + -- @function Event:getChannel + getChannel = function (self) + if band(self.data[0], 0xf0) ~= 0xf0 then + return band(self.data[0], 0xf) + 1 + end + end; + + --- Set channel. + -- @param channel the MIDI channel (1-16) + -- @function Event:setChannel + setChannel = function (self, channel) + if band(self.data[0], 0xf0) ~= 0xf0 then + self.data[0] = + bor( + band(self.data[0], 0xf0), + channel-1 + ) + end + end; + + --- Is a note on event. + -- @treturn boolean whether event is a note on. + -- @function Event:isNoteOn + isNoteOn = function (self) + return (band(self.data[0], 0xf0)==0x90 and band(self.data[2], 0x7f)~=0) + end; + + --- Is a note off event. + -- @treturn boolean whether event is a note off. + -- @function Event:isNoteOff + isNoteOff = function (self) + return (band(self.data[0], 0xf0)==0x80 or (band(self.data[0], 0xf0)==0x90 and band(self.data[2], 0x7f)==0)) + end; + + --- Get note. + -- @return the MIDI note number (0-127) + -- @function Event:getNote + getNote = function (self) + return band(self.data[1], 0x7f) + end; + + --- Set note. + -- @param note the MIDI note number (0-127) + -- @function Event:setNote + setNote = function (self, note) + if self:isNoteOn() or self:isNoteOff() then + self.data[1] = band(note, 127) + end + end; + + --- Get velocity. + -- @return the MIDI velocity (1-127) + -- @function Event:getVel + getVel = function (self) + return band(self.data[2], 0x7f) + end; + + --- Set velocity. + -- @param vel the MIDI velocity (1-127) + -- @function Event:setVel + setVel = function (self, vel) + if self:isNoteOn() or self:isNoteOff() then + self.data[2] = vel + end + end; + + --- Is a pitch bend event. + -- @treturn boolean whether event is a pitch bend on. + -- @function Event:isPitchBend + isPitchBend = function (self) + return band(self.data[0], 0xf0)==0xe0 + end; + + --- Get pitch bend value. + -- @return pitch bend value (0-16383). + -- @function Event:getPitchBendValue + getPitchBendValue = function (self) + if not self:isPitchBend() then error "not a pitch bend event" end + return bor(self.data[1], lshift(self.data[2], 7)) + end; + + --- Is a Control Change event. + -- @treturn boolean whether event is a control change. + -- @function Event:isControl + isControl = function (self) + return band(self.data[0], 0xf0)==0xb0 + end; + + --- Get control number. + -- @return control number (0-247). + -- @function Event:getControlNumber + getControlNumber = function (self) + if not self:isControl() then error "not a control event" end + return self.data[1] + end; + + --- Get control value. + -- @return control value (0-127). + -- @function Event:getControlValue + getControlValue = function (self) + if not self:isControl() then error "not a control event" end + return self.data[2] + end; + + debug = function (self) + print (tonumber(self.time).." ".. + tonumber(self.dataSize).." ".. + bit.tohex(self.data[0],4).." ".. + bit.tohex(self.data[1],4).." ".. + bit.tohex(self.data[2],4)) + end; + }; +} + +--- Sample position relatively to the start of the block. +-- This value is often 0 because most hosts call @{plugin.processBlock} at the +-- beginning of beats and beat divisions. It is never higher than the +-- current @{plugin.processBlock}'s `smax` and any events created by the script +-- should respect this rule. +-- @field Event.time + +--- Size of the MIDI message in bytes +-- @field Event.dataSize + +--- The raw MIDI message +-- (`const uint8_t*` cdata) +-- @field Event.data + +ffi.metatype("MidiEvent", MidiEvent_mt) + +return midi diff --git a/ports/protoplug/ProtoplugFiles/include/core/plugin.lua b/ports/protoplug/ProtoplugFiles/include/core/plugin.lua new file mode 100644 index 0000000..9b3a8a4 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/plugin.lua @@ -0,0 +1,273 @@ +--- Use `plugin` to define the AU/VST audio plugin's behaviour. +-- The `plugin` global is available to every protoplug script after including the +-- main protoplug header : +-- require "include/protoplug" +-- @module plugin + +ffi.cdef [[ + +// pasted from juce_AudioPlayHead.h +typedef struct CurrentPositionInfo +{ + double bpm; + int timeSigNumerator; + int timeSigDenominator; + int64_t timeInSamples; + double timeInSeconds; + double editOriginTime; + double ppqPosition; + double ppqPositionOfLastBarStart; + int frameRate; + bool isPlaying; + bool isRecording; + double ppqLoopStart; + double ppqLoopEnd; + bool isLooping; +} CurrentPositionInfo; + +typedef struct pAudioPlayHead +{ void *pointer; } pAudioPlayHead; + +bool AudioPlayHead_getCurrentPosition(pAudioPlayHead self, CurrentPositionInfo& result); +]] + +local script = require "include/core/script" + +local plugin = {} + +local sampleRate + +script.addHandler("init", function () + --- Override functions. + -- Define these functions and the host will call them. + --

+ -- @section overrides + + + --- Process Audio Block. + -- Override this function to input and output audio and MIDI data. + -- + -- This override is handled automatically if @{stereoFx} or @{polyGen} are used. + -- Use this function to handle the raw data instead. + -- @param samples a C float** pointing to two channels of samples, serving as input and output + -- @param smax the maximum sample index (nSamples - 1) + -- @tparam midi.Buffer midiBuf the MIDI data for this block, serving as input and output + -- @usage function plugin.processBlock (samples, smax) -- let's ignore midi for this example + -- for i = 0, smax do + -- samples[0][i] = sin(myTime) -- left channel + -- samples[1][i] = sin(myTime) -- right channel + -- myTime = myTime + myDelta + -- end + -- end + -- @function plugin.processBlock + local dbged = false + if type(plugin.processBlock) == "function" then + local prepared = false + function plugin_processBlock(nSamples, samples, midiBuf, playHead, _sampleRate) + if not dbged then + dbged=true + end + sampleRate = _sampleRate + if not prepared then + prepared = true + if plugin.prepareToPlay then + for _,v in ipairs(plugin.prepareToPlay) do + v() + end + end + end + samples = ffi.typeof("float**")(samples) + midiBuf = ffi.typeof("pMidiBuffer")(midiBuf) + plugin.playHead = ffi.typeof("pAudioPlayHead")(playHead) + plugin.processBlock(samples, nSamples-1, midiBuf) + plugin.playHead = nil + end + end + + --- Return the name of a parameter. + -- + -- This override is handled automatically if @{manageParams} is used. + -- @param index parameter index (0-126) + -- @treturn string the parameter's name + -- @function plugin.getParameterName + plugin_getParameterName = plugin.getParameterName + + --- Return the representation of a parameter's value. + -- Override this function to choose how each parameter's value should + -- be displayed by the host. The parameter's current value can be obtained + -- using @{plugin.getParameter} + -- + -- This override is handled automatically if @{manageParams} is used. + -- @param index parameter index (0-126) + -- @treturn string a string representation of the parameter's current value + -- @function plugin.getParameterText + plugin_getParameterText = plugin.getParameterText + + --- Handle parameter changes. + -- Override this function to do something when a parameter changes + -- The parameter's current value can be obtained using @{plugin.getParameter} + -- + -- This override is handled automatically if @{manageParams} is used. + -- @param index parameter index (0-126) + -- @function plugin.paramChanged + plugin_paramChanged = plugin.paramChanged + + -- todo + plugin_parameterText2Double = plugin.parameterText2Double + + --- Return the tail length in seconds (effects only). + -- Override this function to define the effect's audio tail length. + -- @return the tail length in seconds + -- @function plugin.getTailLengthSeconds + plugin_getTailLengthSeconds = plugin.getTailLengthSeconds + +end) + + +--- Callback functions. +-- Functions that your script can call. +--

+-- @section callbacks + +--- Automatically set up a list of parameters. +-- Call this function with a table containing parameter definitions as argument, and +-- it will perform the repetitive task of defining all the parameter-related overrides. +-- +-- The format of the parameter list is demonstrated in @{classic-filter.lua} +-- @param paramList a table with parameter definitions (see example) +-- @function plugin.manageParams +plugin.manageParams = require "include/core/manageparams" + +--- Set (automate) a parameter's value. +-- The value must be normalized to be between 0 and 1. +-- @param index parameter index (0-126) +-- @param value parameter value (0-1) +-- @function plugin.setParameter +plugin.setParameter = plugin_setParameter + +--- Get a parameter's value. +-- The values are between 0 and 1, but different minimums and maximums can +-- be easily simulated using @{plugin.manageParams}. +-- @param index parameter index (0-126) +function plugin.getParameter(index) + return plugin_params[index] +end +plugin_params = ffi.typeof("const double *")(plugin_params) + +--- Get host position info, if available. +-- Only call this from within @{processBlock}. +-- @treturn plugin.PositionInfo current position info, or `nil` depending on the host. +-- @function plugin.getCurrentPosition +plugin.getCurrentPosition = function () + if not plugin.playHead then return end + local pos = ffi.new("CurrentPositionInfo") + local res = protolib.AudioPlayHead_getCurrentPosition(plugin.playHead, pos) + if res==true then + return pos + end +end + +--- Get host samplerate. +-- The value is unknown until the plugin `prepareToPlay` event has been emitted. +-- The value is always known in @{processBlock}. An error is caused if an +-- attempt is made to access the sample rate prematurely. +-- @see plugin.addHandler +-- @return current samplerate. +-- @function plugin.getSampleRate +plugin.getSampleRate = function () + if sampleRate == nil then + error ("Trying to use sampleRate when it is not yet known. " .. + "Use plugin.addHandler('prepareToPlay',...) to initialize and use the samplerate. ") + end + return sampleRate +end + +--- Check if the samplerate is known. +-- @treturn boolean +-- @function plugin.isSampleRateKnown +plugin.isSampleRateKnown = function () + return (sampleRate ~= nil) +end + +--- Add a handler for a VST/AU event. +-- The following events are available : +-- +-- - `"prepareToPlay"` - Emitted before the first call to @{processBlock}, when the samplerate is known. +-- @see script.addHandler +-- @see gui.addHandler +-- @tparam string event the event to handle +-- @tparam function handler a function to add the event's handlers +function plugin.addHandler(event, handler) + if not plugin[event] then plugin[event] = {} end + table.insert(plugin[event], handler) +end + + +--- Host position information. +-- A container type for host-related information as returned by @{plugin.getCurrentPosition} +-- +-- Is a [JUCE AudioPlayHead::CurrentPositionInfo](http://www.juce.com/api/structAudioPlayHead_1_1CurrentPositionInfo.html) +--

+--@type plugin.PositionInfo + +--- Host tempo (beats per minute) +-- @field PositionInfo.bpm + + +--- Time signature numerator ie. *3*/4 +-- @field PositionInfo.timeSigNumerator + + +--- Time signature denominator ie. 3/*4* +-- @field PositionInfo.timeSigDenominator + + +--- Current position on the host's timeline (samples) +-- @field PositionInfo.timeInSamples + + +--- Current position on the host's timeline (seconds) +-- @field PositionInfo.timeInSeconds + + +--- Position of the start of the edit region on the host's timeline +-- @field PositionInfo.editOriginTime + + +--- Current position on the host's timeline (pulses-per-quarter-note) +-- @field PositionInfo.ppqPosition + + +--- Position of the last bar start (pulses-per-quarter-note). +-- (or zero if unavailable.) +-- @field PositionInfo.ppqPositionOfLastBarStart + + +--- Video frame rate +-- @field PositionInfo.frameRate + + +--- Is playing +-- @field PositionInfo.isPlaying + + +--- Is recording +-- @field PositionInfo.isRecording + + +--- Position of the loop start (pulses-per-quarter-note). +-- (or zero if unavailable.) +-- @field PositionInfo.ppqLoopStart + + +--- Position of the loop end (pulses-per-quarter-note). +-- (or zero if unavailable.) +-- @field PositionInfo.ppqLoopEnd + + +--- Is looping +-- @field PositionInfo.isLooping + + + +return plugin diff --git a/ports/protoplug/ProtoplugFiles/include/core/polygen.lua b/ports/protoplug/ProtoplugFiles/include/core/polygen.lua new file mode 100644 index 0000000..cbabd78 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/polygen.lua @@ -0,0 +1,177 @@ +--- Use this module to create a polyphonic generator with virtual tracks. +-- Example at @{sine-organ.lua}. +-- +-- This module facilitates the creation of polyphonic instruments. It acts +-- as a layer that covers the @{plugin.processBlock} function, receives MIDI +-- notes and dispatches them to virtual tracks. The `polyGen.VTrack` prototype +-- is exposed for you to define audio processing in a simple, +-- monophonic, per-note fashion. Initialize this module by calling `polyGen.initTracks`. +-- +-- The `polyGen` global is available to every protoplug script after including the +-- main protoplug header : +-- require "include/protoplug" +-- @module polyGen + + + +--- Set up virtual tracks. +-- This function must be called by any script that wishes to use this module. +-- @param[opt=8] n the number of virtual tracks to use (aka. voices or polyphony) +-- @function polyGen.initTracks + +--- Virtual track. +-- Virtual track. A monophonic voice that defines the instrument's sound. +--

+-- @type polyGen.VTrack + + +--- Override to additively process an audio block. +-- Define the output of a virtual track in this method. +-- Use `self.noteIsOn`, `self.noteFreq`, or any fields you defined to +-- determine current the state of the calling track. +-- +-- This method is called successively on every track, +-- which should *add* their output to `samples`. +-- @param samples a C `float**` pointing to two channels of samples to add to. +-- @param smax the maximum sample index (nSamples - 1) +-- @see sine-organ.lua +-- @function VTrack:addProcessBlock + +--- Override to recieve note on. +-- Override this method to handle a note getting dispatched to a virtual track. +-- @param note the MIDI note number (0-127) +-- @param vel the MIDI velocity (0-127) +-- @function VTrack:noteOn + +--- Override to recieve note off. +-- Override this method to handle a note off on a virtual track. +-- @param note a reminder of the MIDI note number +-- @function VTrack:noteOff + +--- Override to allow initialisation. +-- Override this method to perform initialisation tasks on each track, +-- for example to create any per-track fields. +-- @function VTrack:init + +local polyGen = {} + +local script = require "include/core/script" + +local VTrack = {noteIsOn = false, noteFreq=0.01, notePeriod=100, age = 0, note = -1} +VTrack.__index = VTrack +VTrack.tracks = { } + +function VTrack.new(i) + local o = {} + setmetatable(o,VTrack) + o.i = i --same + return o +end + +local function processMidiEvent(msg) + if msg:isNoteOn() then + -- note on, choose the best track for a new note + local oldestPlaying_age, oldestPlaying_i = -1, -1 + local oldestReleased_age, oldestReleased_i = -1, -1 + for i=1,VTrack.numTracks do + vt = VTrack.tracks[i] + vt.age = vt.age+1 + if vt.note ~= -1 then + -- track note is on + if vt.age>oldestPlaying_age then + oldestPlaying_i = i + oldestPlaying_age = vt.age + end + else + -- track is free + if vt.age>oldestReleased_age then + oldestReleased_i = i + oldestReleased_age = vt.age + end + end + end + local chosentrack = {} + if oldestReleased_i ~= -1 then + chosentrack = VTrack.tracks[oldestReleased_i] + else + chosentrack = VTrack.tracks[oldestPlaying_i] + end + chosentrack.age = 0 + chosentrack.note = msg:getNote() + chosentrack.noteFreq = midi.noteToFreq(chosentrack.note) + chosentrack.notePeriod = 1/chosentrack.noteFreq + if VTrack.noteOn~=nil then + chosentrack:noteOn(chosentrack.note, msg:getVel(), msg) + end + chosentrack.noteIsOn = true + elseif msg:isNoteOff() then + -- note off + for i=1,VTrack.numTracks do + vt = VTrack.tracks[i] + if vt.note == msg:getNote() then + vt.age = 0 + vt.note = -1 + if VTrack.noteOff~=nil then + vt:noteOff(msg:getNote(), msg) + end + vt.noteIsOn = false + end + end + end +end + +function polyGen.initTracks(n) + VTrack.numTracks = n or 8 + for i=1,VTrack.numTracks do + VTrack.tracks[i] = VTrack.new(i) + end + + function plugin.processBlock (samples, smax, midiBuf) + for msg in midiBuf:eachEvent() do + processMidiEvent(msg) + end + for i=0,smax do + samples[0][i] = 0 + samples[1][i] = 0 + end + for i=1,VTrack.numTracks do + if VTrack.addProcessBlock~=nil then + VTrack.tracks[i]:addProcessBlock(samples, smax) + end + end + end + + script.addHandler("init", function () + if VTrack.init~=nil then + for i = 1,VTrack.numTracks do + VTrack.tracks[i]:init() + end + end + end) +end + +polyGen.VTrack = VTrack + +--- Track number. +-- Use `self.i` to check which virtual track is being called. +-- @field VTrack.i + +--- Current MIDI note. +-- The MIDI note number that is currently being played by this track, +-- or `-1` if in note off state. +-- @field VTrack.note + +--- Current note frequency. +-- The note frequency that is currently being played by this track. +-- @field VTrack.noteFreq + +--- Current note period. +-- `1/noteFreq` +-- @field VTrack.notePeriod + +--- Note is on. +-- Whether the track is playing a note (`boolean`). +-- @field VTrack.noteIsOn + + +return polyGen diff --git a/ports/protoplug/ProtoplugFiles/include/core/script.lua b/ports/protoplug/ProtoplugFiles/include/core/script.lua new file mode 100644 index 0000000..c03b47a --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/script.lua @@ -0,0 +1,136 @@ +--- Use `script` to handle script events, libraries and files. +-- The `script` global is available to every protoplug script after including the +-- main protoplug header : +-- require "include/protoplug" +-- @module script + +local script = {} + +--- Add a handler for a script event. +-- The following events are available : +-- +-- - `"init"` - Emitted after the script has been compiled and run. +-- - `"preClose"` - Emitted before the script state gets destroyed. +-- @see plugin.addHandler +-- @see gui.addHandler +-- @tparam string event the event to handle +-- @tparam function handler a function to add the event's handlers + +function script.addHandler(event, handler) + if not script[event] then script[event] = {} end + table.insert(script[event], handler) +end + +--- Save script data. +-- Override this function to save any custom data. +-- +-- This gets called : +-- - when the host saves the plugin's state (eg. when saving a project) +-- - right before the script is recompiled, to keep custom data across compilations. +-- @treturn string the data to be saved +-- @function script.saveData + +--- Load script data. +-- Override this function to load any custom data. +-- Be warned that the data might originate from another script, so it's a good +-- idea to start the data with a header confirming the format. +-- +-- This gets called : +-- - when the host loads the plugin's state (eg. when loading a project) +-- - right after the script is recompiled, to keep custom data across compilations. +-- @tparam string data the data to be loaded +-- @function script.loadData + + +--- Load shared libraries. +-- Protoplug scripts should use this wrapper function instead of LuaJIT's +-- [ffi.load](http://luajit.org/ext_ffi_api.html#ffi_load). +-- It has the same behaviour as `ffi.load`, but it adds `protoplug/lib` as a +-- search path, and can accept multiple arguments to test for different +-- library names. The names are tested from left to right until one load +-- successfully. If none of them work, an error is raised. +-- sdl = script.ffiLoad("sdl") +-- This looks for `libsdl.so` or `sdl.dll` in protoplug's lib folder and +-- in the system paths. +-- +-- fftw = script.ffiLoad("libfftw3.so.3", "libfftw3-3.dll") +-- This looks for the supplied names in the same locations as above. This is +-- necessary for libs like FFTW, that have has platform-dependent names. +-- @tparam string libName +-- @tparam[opt] string ... alternate names for the same library +-- @return The library's ffi namespace +-- @function script.ffiLoad +local function file_exists(name) + local f=io.open(name,"r") + if f~=nil then io.close(f) return true else return false end +end +local function tryLoad(lib) + if string.find(lib, "/") or string.find(lib, "\\") then + return ffi.load(lib) + end + local libfile = lib + if ffi.os=="Windows" then + if not string.find(lib, "%.") then + libfile = libfile..".dll" + end + else -- assuming posix + if not string.find(lib,"%.") then + libfile = libfile..".so" + end + if string.sub(lib, 1, 3) ~= "lib" then + libfile = "lib"..libfile + end + end + libfile = protoplug_dir.."/lib/"..libfile + if file_exists(libfile) then + return ffi.load(libfile) + end + local success, ret = pcall(ffi.load, lib) + if success then return ret end +end +function script.ffiLoad(...) + local args={...} + local ret + for _,lib in ipairs(args) do + ret = tryLoad(lib) + if ret then break end + end + return ret and ret or error("could not find library ".. + table.concat({...}, ", ")) +end + +--- Current protoplug directory. +-- The full path of the `protoplug` directory currently being used. It should +-- be alongside the protoplug fx and gen dynamic libraries. +-- @predefined protoplugDir +script.protoplugDir = protoplug_dir + +-- Wrap the raw global override called by protoplug +function script_init() + if script.preClose then + function script_preClose() + for _,v in ipairs(script.preClose) do + v() + end + end + end + + if script.init then + for _,v in ipairs(script.init) do + v() + end + end + script_saveData = script.saveData + script_loadData = script.loadData +end + +-- add handler to repaint gui after recompiling +script.addHandler("init", function () + local gui = require "include/core/gui" + local guiComp = gui.getComponent() + if guiComp ~= nil then + guiComp:repaint() + end +end) + +return script diff --git a/ports/protoplug/ProtoplugFiles/include/core/stereofx.lua b/ports/protoplug/ProtoplugFiles/include/core/stereofx.lua new file mode 100644 index 0000000..e6966ae --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/core/stereofx.lua @@ -0,0 +1,69 @@ +--- Use this module to create a stereo effect. +-- Example at @{classic-filter.lua}. +-- +-- This module acts as a layer that conceals the @{plugin.processBlock} function, +-- manages stereo channels, and exposes the `stereoFx.Channel` prototype for you +-- define per-channel audio processing. Initialize it by calling `stereoFx.init`. +-- +-- The `stereoFx` global is available to every protoplug script after including the +-- main protoplug header : +-- require "include/protoplug" +-- @module stereoFx + + + +--- Set up channels. +-- This function must be called by any script that wishes to use this module. +-- @function stereoFx.init + +--- Channel. +-- This class represents a channel (ie. left or right). +--

+-- @type stereoFx.Channel + + +--- Override to process a channel's audio block. +-- Define the audio processing of a single channel in this function. +-- @param samples a C float* serving as input and output +-- @param smax the maximum sample index (nSamples - 1) +-- @function Channel:processBlock + +--- Override to handle initialisation. +-- Override this method to perform initialisation tasks on each channel, +-- for example to create any per-channel fields. +-- @function Channel:init + +local stereoFx = {} + +local script = require "include/core/script" + +local Channel = { } +function Channel:new (o) + setmetatable(o, self) + self.__index = self + return o +end + +local LChannel = Channel:new{ } +local RChannel = Channel:new{ } + +function stereoFx.init() + function plugin.processBlock (samples, smax) + if Channel.processBlock==nil then return 0 end + LChannel:processBlock(samples[0], smax) + RChannel:processBlock(samples[1], smax) + end + + script.addHandler("init", function () + if Channel.init~=nil then + LChannel:init() + RChannel:init() + end + end) +end + +stereoFx.Channel = Channel +stereoFx.LChannel = LChannel +stereoFx.RChannel = RChannel + +return stereoFx \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/iluaembed.lua b/ports/protoplug/ProtoplugFiles/include/iluaembed.lua new file mode 100644 index 0000000..7a07338 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/iluaembed.lua @@ -0,0 +1,250 @@ +-- iluaembed.lua +-- based on Steve Donovan's executable ilua.lua (2007) +-- "A more friendly Lua interactive prompt +-- doesn't need '=' +-- will try to print out tables recursively, subject to the pretty_print_limit value." +-- +-- version by osar.fr to embed the interactive Lua console in C/C++ programs +-- creates a global function to be called by the host +-- + + +local pretty_print_limit = 20 +local max_depth = 7 +local table_clever = true +local prompt = '> ' +local verbose = false +local strict = true +-- suppress strict warnings +_ = true + +-- imported global functions +local sub = string.sub +local match = string.match +local find = string.find +local push = table.insert +local pop = table.remove +local append = table.insert +local concat = table.concat +local floor = math.floor +local write = io.write +local read = io.read + +local savef +local collisions = {} +local G_LIB = {} +local declared = {} +local line_handler_fn, global_handler_fn +local print_handlers = {} + +ilua = {} +local num_prec +local num_all + +local jstack = {} + + + +local function oprint(...) + if savef then + savef:write(concat({...},' '),'\n') + end + print(...) +end + +local function join(tbl,delim,limit,depth) + if not limit then limit = pretty_print_limit end + if not depth then depth = max_depth end + local n = #tbl + local res = '' + local k = 0 + -- very important to avoid disgracing ourselves with circular referencs... + if #jstack > depth then + return "..." + end + for i,t in ipairs(jstack) do + if tbl == t then + return "" + end + end + push(jstack,tbl) + -- this is a hack to work out if a table is 'list-like' or 'map-like' + -- you can switch it off with ilua.table_options {clever = false} + local is_list + if table_clever then + local index1 = n > 0 and tbl[1] + local index2 = n > 1 and tbl[2] + is_list = index1 and index2 + end + if is_list then + for i,v in ipairs(tbl) do + res = res..delim..ilua.val2str(v) + k = k + 1 + if k > limit then + res = res.." ... " + break + end + end + else + for key,v in pairs(tbl) do + if type(key) == 'number' then + key = '['..tostring(key)..']' + else + key = tostring(key) + end + res = res..delim..key..'='..ilua.val2str(v) + k = k + 1 + if k > limit then + res = res.." ... " + break + end + end + end + pop(jstack) + return sub(res,2) +end + + +function ilua.val2str(val) + local tp = type(val) + if print_handlers[tp] then + local s = print_handlers[tp](val) + return s or '?' + end + if tp == 'function' then + return tostring(val) + elseif tp == 'table' then + if val.__tostring then + return tostring(val) + else + return '{'..join(val,',')..'}' + end + elseif tp == 'string' then + return "'"..val.."'" + elseif tp == 'number' then + -- we try only to apply floating-point precision for numbers deemed to be floating-point, + -- unless the 3rd arg to precision() is true. + if num_prec and (num_all or floor(val) ~= val) then + return num_prec:format(val) + else + return tostring(val) + end + else + return tostring(val) + end +end + +function ilua.pretty_print(...) + local arg = {...} + for i,val in ipairs(arg) do + oprint(ilua.val2str(val)) + end + _G['_'] = arg[1] +end + +function ilua.compile(line) + if verbose then oprint(line) end + local f,err = loadstring(line,'local') + return err,f +end + +function ilua.evaluate(chunk) + local ok,res = pcall(chunk) + if not ok then + return res + end + return nil -- meaning, fine! +end + +function ilua.eval_lua(line) + if savef then + savef:write(prompt,line,'\n') + end + -- is the line handler interested? + if line_handler_fn then + line = line_handler_fn(line) + -- returning nil here means that the handler doesn't want + -- Lua to see the string + if not line then return end + end + -- is it an expression? + local err,chunk = ilua.compile('ilua.pretty_print('..line..')') + if err then + -- otherwise, a statement? + err,chunk = ilua.compile(line) + end + -- if compiled ok, then evaluate the chunk + if not err then + err = ilua.evaluate(chunk) + end + -- if there was any error, print it out + if err then + oprint(err) + end +end + + + +-- functions available in scripts +function ilua.precision(len,prec,all) + if not len then num_prec = nil + else + num_prec = '%'..len..'.'..prec..'f' + end + num_all = all +end + +function ilua.table_options(t) + if t.limit then pretty_print_limit = t.limit end + if t.depth then max_depth = t.depth end + if t.clever ~= nil then table_clever = t.clever end +end + +-- inject @tbl into the global namespace +function ilua.import(tbl,dont_complain,lib) + lib = lib or '' + if type(tbl) == 'table' then + for k,v in pairs(tbl) do + local key = rawget(_G,k) + -- NB to keep track of collisions! + if key and k ~= '_M' and k ~= '_NAME' and k ~= '_PACKAGE' and k ~= '_VERSION' then + append(collisions,{k,lib,G_LIB[k]}) + end + _G[k] = v + G_LIB[k] = lib + end + end + if not dont_complain and #collisions > 0 then + for i, coll in ipairs(collisions) do + local name,lib,oldlib = coll[1],coll[2],coll[3] + write('warning: ',lib,'.',name,' overwrites ') + if oldlib then + write(oldlib,'.',name,'\n') + else + write('global ',name,'\n') + end + end + end +end + +function ilua.print_handler(name,handler) + print_handlers[name] = handler +end + +function ilua.line_handler(handler) + line_handler_fn = handler +end + +function ilua.global_handler(handler) + global_handler_fn = handler +end + +function ilua.print_variables() + for name,v in pairs(declared) do + print(name,type(_G[name])) + end +end + +function ilua_runline(line) + ilua.eval_lua(line) +end diff --git a/ports/protoplug/ProtoplugFiles/include/luautil.lua b/ports/protoplug/ProtoplugFiles/include/luautil.lua new file mode 100644 index 0000000..3880824 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/luautil.lua @@ -0,0 +1,29 @@ +-- lua utils + +local util = {} + +-- include cdefs +function util.requireCdef(incpath) + local incfile = io.open(incpath) + if incfile==nil then + error ("can't open include file : "..incpath) + end + local incstring = incfile:read "*a" + incfile:close() + ffi.cdef (incstring) +end + +-- merge in modules or tables in general +function util.merge (src, dst) + for k,v in pairs(src) do + dst[k] = v + end +end + +-- round x to n decimal places +function util.roundDecimal(x, n) + local p = math.pow(10, n) + return math.floor(x*p+0.5)/p +end + +return util diff --git a/ports/protoplug/ProtoplugFiles/include/pac/cookbook filters float.lua b/ports/protoplug/ProtoplugFiles/include/pac/cookbook filters float.lua new file mode 100644 index 0000000..2b08312 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/pac/cookbook filters float.lua @@ -0,0 +1,111 @@ +-- Cookbook Filters Module FLOAT TEST +-- Based on Worp Filter.lua implementation by Ico Doornekamp. (https://github.com/zevv/worp) +-- Based on the Cookbook formulae by Robert Bristow-Johnson +-- osar.fr + +--[[ +example usage : + local f = Filter { + type = "lp" -- filter type, see below + f = 440; -- frequency(Hz), (0-20000) + gain = 0; -- filter gain(dB), (-60 to 60) + Q = 1; -- resonance, (0.1-100) + } + for sample in eachSample() + sample = f.process(sample) + end + +filter types : + hp: High pass + lp: Low pass + bp: Band pass + bs: Band stop (aka, Notch) + ls: Low shelf + hs: High shelf + ap: All pass + eq: Peaking EQ filter +--]] + +local Float = ffi.typeof("float[1]") +--[[local function Float (n) + return ffi.cast("float", n) +end--]] + +local function Filter(params) + local a0, a1, a2, b0, b1, b2 + local x0, x1, x2 = Float(0), Float(0), Float(0) + local y0, y1, y2 = Float(0), Float(0), Float(0) + local params = params or {type = "lp", f = 440, gain = 0, Q = 1} + + public = { + update = function (args) + for k,v in pairs(args) do + params[k] = v + end + --print ( + -- "type "..params.type.. + -- ", f "..params.f.. + -- ", gain "..params.gain.. + -- ", Q "..params.Q + --) + local w0 = 2 * math.pi * (params.f / plugin.getSampleRate()) + local alpha = math.sin(w0) / (2*params.Q) + local cos_w0 = math.cos(w0) + local A = math.pow(10, params.gain/40) + if params.type == "hp" then + b0, b1, b2 = (1 + cos_w0)/2, -(1 + cos_w0), (1 + cos_w0)/2 + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "lp" then + b0, b1, b2 = (1 - cos_w0)/2, 1 - cos_w0, (1 - cos_w0)/2 + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "bp" then + b0, b1, b2 = params.Q*alpha, 0, -params.Q*alpha + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "bs" then + b0, b1, b2 = 1, -2*cos_w0, 1 + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "ls" then + local ap1, am1, tsAa = A+1, A-1, 2 * math.sqrt(A) * alpha + local am1_cos_w0, ap1_cos_w0 = am1 * cos_w0, ap1 * cos_w0 + b0, b1, b2 = A*( ap1 - am1_cos_w0 + tsAa ), 2*A*( am1 - ap1_cos_w0 ), A*( ap1 - am1_cos_w0 - tsAa ) + a0, a1, a2 = ap1 + am1_cos_w0 + tsAa, -2*( am1 + ap1_cos_w0 ), ap1 + am1_cos_w0 - tsAa + + elseif params.type == "hs" then + local ap1, am1, tsAa = A+1, A-1, 2 * math.sqrt(A) * alpha + local am1_cos_w0, ap1_cos_w0 = am1 * cos_w0, ap1 * cos_w0 + b0, b1, b2 = A*( ap1 + am1_cos_w0 + tsAa ), -2*A*( am1 + ap1_cos_w0 ), A*( ap1 + am1_cos_w0 - tsAa ) + a0, a1, a2 = ap1 - am1_cos_w0 + tsAa, 2*( am1 - ap1_cos_w0 ), ap1 - am1_cos_w0 - tsAa + + elseif params.type == "eq" then + b0, b1, b2 = 1 + alpha*A, -2*cos_w0, 1 - alpha*A + a0, a1, a2 = 1 + alpha/A, -2*cos_w0, 1 - alpha/A + + elseif params.type == "ap" then + b0, b1, b2 = 1 - alpha, -2*cos_w0, 1 + alpha + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + else + error("Unsupported filter type " .. params.type) + end + print(a0) + a0, a1, a2, b0, b1, b2 = Float(a0), Float(a1), Float(a2), Float(b0), Float(b1), Float(b2) + print(a0[0]) + end; + + process = function (x0) + y2[0], y1[0] = y1[0], y0[0] + y0[0] = (b0[0] / a0[0]) * x0[0] + (b1[0] / a0[0]) * x1[0] + (b2[0] / a0[0]) * x2[0] - (a1[0] / a0[0]) * y1[0] - (a2[0] / a0[0]) * y2[0] + x2[0], x1[0] = x1[0], x0[0] + return y0[0] + end; + } + + public.update(params) + return public +end + +return Filter \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/pac/cookbook filters.lua b/ports/protoplug/ProtoplugFiles/include/pac/cookbook filters.lua new file mode 100644 index 0000000..e788e86 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/pac/cookbook filters.lua @@ -0,0 +1,108 @@ +-- Cookbook Filters Module +-- Based on Worp Filter.lua implementation by Ico Doornekamp. (https://github.com/zevv/worp) +-- Based on the Cookbook formulae by Robert Bristow-Johnson +-- osar.fr + +--[[ +example usage : + local f = Filter { + type = "lp" -- filter type, see below + f = 440; -- frequency(Hz), (0-20000) + gain = 0; -- filter gain(dB), (-60 to 60) + Q = 1; -- resonance, (0.1-100) + } + for sample in eachSample() + sample = f.process(sample) + end + +filter types : + hp: High pass + lp: Low pass + bp: Band pass + bs: Band stop (aka, Notch) + ls: Low shelf + hs: High shelf + ap: All pass + eq: Peaking EQ filter +--]] + +local function Filter(params) + local a0, a1, a2, b0, b1, b2 + local x0, x1, x2 = 0, 0, 0 + local y0, y1, y2 = 0, 0, 0 + local params = params or {type = "lp", f = 440, gain = 0, Q = 1} + + public = { + update = function (args) + args = args or {} + for k,v in pairs(args) do + params[k] = v + end + if params.f < 10 then params.f = 10 end + if not plugin.isSampleRateKnown() then return end + --print ( + -- "type "..params.type.. + -- ", f "..params.f.. + -- ", gain "..params.gain.. + -- ", Q "..params.Q + --) + local w0 = 2 * math.pi * (params.f / plugin.getSampleRate()) + local alpha = math.sin(w0) / (2*params.Q) + local cos_w0 = math.cos(w0) + local A = math.pow(10, params.gain/40) + if params.type == "hp" then + b0, b1, b2 = (1 + cos_w0)/2, -(1 + cos_w0), (1 + cos_w0)/2 + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "lp" then + b0, b1, b2 = (1 - cos_w0)/2, 1 - cos_w0, (1 - cos_w0)/2 + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "bp" then + b0, b1, b2 = params.Q*alpha, 0, -params.Q*alpha + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "bs" then + b0, b1, b2 = 1, -2*cos_w0, 1 + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + elseif params.type == "ls" then + local ap1, am1, tsAa = A+1, A-1, 2 * math.sqrt(A) * alpha + local am1_cos_w0, ap1_cos_w0 = am1 * cos_w0, ap1 * cos_w0 + b0, b1, b2 = A*( ap1 - am1_cos_w0 + tsAa ), 2*A*( am1 - ap1_cos_w0 ), A*( ap1 - am1_cos_w0 - tsAa ) + a0, a1, a2 = ap1 + am1_cos_w0 + tsAa, -2*( am1 + ap1_cos_w0 ), ap1 + am1_cos_w0 - tsAa + + elseif params.type == "hs" then + local ap1, am1, tsAa = A+1, A-1, 2 * math.sqrt(A) * alpha + local am1_cos_w0, ap1_cos_w0 = am1 * cos_w0, ap1 * cos_w0 + b0, b1, b2 = A*( ap1 + am1_cos_w0 + tsAa ), -2*A*( am1 + ap1_cos_w0 ), A*( ap1 + am1_cos_w0 - tsAa ) + a0, a1, a2 = ap1 - am1_cos_w0 + tsAa, 2*( am1 - ap1_cos_w0 ), ap1 - am1_cos_w0 - tsAa + + elseif params.type == "eq" then + b0, b1, b2 = 1 + alpha*A, -2*cos_w0, 1 - alpha*A + a0, a1, a2 = 1 + alpha/A, -2*cos_w0, 1 - alpha/A + + elseif params.type == "ap" then + b0, b1, b2 = 1 - alpha, -2*cos_w0, 1 + alpha + a0, a1, a2 = 1 + alpha, -2*cos_w0, 1 - alpha + + else + error("Unsupported filter type " .. params.type) + end + end; + + process = function (x0) + y2, y1 = y1, y0 + y0 = (b0 / a0) * x0 + (b1 / a0) * x1 + (b2 / a0) * x2 - (a1 / a0) * y1 - (a2 / a0) * y2 + x2, x1 = x1, x0 + return y0 + end; + } + + -- initialize when the samplerate in known + plugin.addHandler("prepareToPlay", public.update) + + return public +end + +return Filter \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/pac/delay line.lua b/ports/protoplug/ProtoplugFiles/include/pac/delay line.lua new file mode 100644 index 0000000..a193e19 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/pac/delay line.lua @@ -0,0 +1,38 @@ +-- delay line 1 +-- with dc filter and shitty linear interpolation + +-- todo test full float version +-- and possibly pointer arithmetic version + +local function blend(a,b,p) return (a*p + b*(1-p)) end + +function Line (bufSize) + local buf = ffi.new("double[?]", bufSize) + local pos = 0 -- todo int + local dc1, dc2 = 0, 0 + return { + goBack = function (dt) + -- todo assert dt=bufSize or (ipos1)<0 then error("accessed buf "..(ipos1)) end -- DEBUG + if (ipos2)>=bufSize or (ipos2)<0 then error("accessed buf "..(ipos2)) end -- DEBUG + return blend(buf[ipos2], buf[ipos1], frac) + end; + push = function (s) + pos = pos + 1 + if pos >= bufSize then pos = 0 end + dc1 = dc1 + (s - dc2) * 0.000002 + dc2 = dc2 + dc1 + dc1 = dc1 * 0.96 + if (pos)>=bufSize or (pos)<0 then error("accessed buf "..(pos)) end -- DEBUG + buf[pos] = s - dc2 + end; + } +end + +return Line diff --git a/ports/protoplug/ProtoplugFiles/include/pac/freqgraph.lua b/ports/protoplug/ProtoplugFiles/include/pac/freqgraph.lua new file mode 100644 index 0000000..097f5b8 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/pac/freqgraph.lua @@ -0,0 +1,259 @@ +-- pac freqgraph.lua +--[[ +an interactive histogram-ish frequency graph +used in "spectral filter" and "pitch distort" +usage : + local Freqgraph = require "include/pac/freqgraph" + local fg = Freqgraph { + -- required paramters : + -- an array (Lua or C) containing the values to be read and modified by the interactive graph + data = ; + -- number of elements in the array + dataSize = ; + -- optional paramters : + -- the position and size of the graph + bounds = juce.Rectangle_int{15,0,480,330}; + title = ""; + yAxis = { + name = "amplitude (%)"; + values = { + [0] = "0"; + [0.5] = "50"; + [1] = "100"; + } + } + -- colours : pageBack, pageFore, graphBack, graphFore + } + -- public methods : + -- paint the graph onto a pGraphics ctype + fg:paint(g) + -- change the graph's position + fg:setPos(x, y) + +--]] + +local J = require "include/protojuce" + +-- class +local M = { + -- default values + bounds = J.Rectangle_int{15,0,480,330}; + pageBack = J.Colour.black; + pageFore = J.Colour.green; + graphBack = J.Colour{r=0, g=0, b=160}; + graphFore = J.Colour.green; + yAxis = { + name = "amplitude (%)"; + values = { + [0] = "0"; + [0.25] = "50"; + [0.5] = "100"; + [0.75] = "150"; + [1] = "200"; + } + } +} +M.__index = M + +setmetatable(M, { + -- constructor + __call = function (_, arg) + local self = setmetatable(arg, M) + self.frame = J.Rectangle_int(4, 30, self.bounds.w-50, self.bounds.h-65) + self.outFrame = J.Rectangle_int(2, 28, self.frame.w+4, self.frame.h+4) + self.yAmp = 1/self.frame.h + -- display-coord quarters in data coordinates + self.q1 = self:x2bar(self.frame.w/4) + self.q2 = self:x2bar(self.frame.w/2) + self.bgFill = J.FillType(self.pageBack) + self.bgFill2 = J.FillType(self.graphBack) + self.fgFill = J.FillType(self.graphFore) + self:InitBackBuffer() + self.dirtyLeft, self.dirtyRight = 0, self.dataSize-1 + gui.addHandler("mouseDrag", function (event) + self:mouseDrag(event) + end) + gui.addHandler("mouseUp", function (event) + self:mouseUp(event) + end) + plugin.addHandler("prepareToPlay", function () + self:InitBackBuffer() + end) + return self + end; +}) + +-- Coordinate system conversion between displayed bars <-> data +-- cheap log-like scale made of 3 linear functions +function M:x2bar(x) + if xself.dataSize-1 then self.bar=self.dataSize-1 end + if self.amp<0 then self.amp=0 end + if self.amp>1 then self.amp=1 end + + -- interpolate and set + local x1, x2, y1, y2 = self.oldbar,self.bar,self.oldamp,self.amp + if x1 == nil or x1==x2 then + x1,y1 = x2,y2 + self.data[x2] = y2 + else + if x1>x2 then + x1, x2, y1, y2 = x2, x1, y2, y1 + end + for i=x1,x2 do + local x = (x2-i)/(x2-x1) + self.data[i] = y1*x + y2*(1-x) + end + end + -- create or enlarge the currently dirty area (ie. needing a repaint) + if self.dirtyLeft then + if x1self.dirtyRight then self.dirtyRight = x2 end + else + self.dirtyLeft, self.dirtyRight = x1, x2 + end + event.originalComponent:repaint() +end + +function M:mouseUp(event) + self.bar = nil + self.oldbar = nil +end + +-- create the backbuffer and draw all permanent parts of the graph +function M:InitBackBuffer() + self.backBuffer = J.Image( + J.Image.PixelFormat.RGB, + self.bounds.w, + self.bounds.h, true) + local g = J.Graphics(self.backBuffer) + g:fillAll(self.pageBack) + g:setColour(self.graphFore) + g:drawRect(self.outFrame, 1) + g:setColour(self.pageFore) + if self.title then + g:setFont(17) + g:drawText("== "..self.title.." ==", self.frame.x, 5, self.frame.w, 20, J.Justification.centred) + end + + -- draw the Y axis labels + g:saveState() + g:addTransform(J.AffineTransform(0, -1, self.bounds.w, 1, 0, self.frame.y)) + g:setFont(16) + g:drawText(self.yAxis.name, 0, 0, self.frame.h, 20, J.Justification.centred) + g:restoreState() + g:setFont(14) + for pos, label in pairs(self.yAxis.values) do + local y = self.frame.y+((self.frame.h-10)*(1-pos))-6 + g:drawText(tostring(label), self.frame:getR()+3, y, 33, 20) + end + + -- draw the X axis labels + g:setFont(16) + g:drawText("frequency (kHz)", self.frame.x, self.bounds.h-20, self.frame.w, 20, J.Justification.centred) + g:setFillType(self.fgFill) + local sr = 44100 + if plugin.isSampleRateKnown() then + sr = plugin.getSampleRate() + else + -- if the samplerate is unknown, call this again when it becomes known + plugin.addHandler('prepareToPlay', function() self:InitBackBuffer() end) + end + local f,fmax = 0, sr/2 + local function f2x(f) + return self:bar2x(f/fmax*self.dataSize)+self.frame.x + end + g:setFont(14) + while f +PROTO_API \1\(pPath self, \2\{\3\} + +pPath self, ) +(normal mode)-> +pPath self) + + +Prefix and create exported function bodies : +PROTO_API (.*?) (.*?)\(pPath self(.*?)\)\r\n\{\r\n\r\n\} +-> +PROTO_API \1 Path_\2\(\3\)\r\n\{\r\n\treturn self.p->\2\(\3\)\r\n\} + +(, +(normal mode)-> +( + +Remove "return" from void function bodies : +PROTO_API void (.*?)return +-> +PROTO_API void \1 + +Add "self" in definition arguments : +PROTO_API (.*?)\( +(disable . matches newline)-> +PROTO_API (.*?)\(pPath self, + +, ) +) + +add the ; which i forgot : +)\r\n} +);\r\n} + +Start removing types from function call arguments : +\{([^\}]*?)const (.*?)\} +(repeat until none left)-> +\{\1\2\} + +Remove default parameter values from call arguments : +\{([^\}]*?) = (.*?)([,\)])(.*?)\} +-> +\{\1\3\4\} + +More removing types and replacing them with conversions (repeat until done) : +\{([^\}]*?)AffineTransform& (.*?)([,)])(.*?)\} +(repeat until none left)-> +\{\1\2\.toJuceAff\(\)\3\4\} + +\{([^\}]*?)Point (.*?)([,)])(.*?)\} +\{\1\2\.toJucePoint\(\)\3\4\} + +Remove basic types from function call argument lists : +\{([^\}]*?)float (.*?)\} +\{\1\2\} + +Replace classes by structs in definition argument lists (and return type) : +PROTO_API ([^\)]*?)const AffineTransform& (.*?)\) +PROTO_API \1exAffineTransform \2\) + +PROTO_API ([^\)]*?)const Point (.*?)\) +PROTO_API \1exPoint_float \2\) + + +========== c++ export header to c ffi import header ========= +Remove ex, eg. exPoint_int -> Point_int : +' ex' +' ' + +Remove bodies (mwaha) : +PROTO_API (.*?)\)(.*?)\}\r\n +\1\);\r\n + +Remove default values : + = (.*?)([),]) +\2 + + +========== c ffi import header to lua wrapper ========= + +Remove all parameter types : last param : +,([^\),]*?) ([^ ]*?)\) +, \2\) + +Remove all paramter types : middle params in a line : +, ([^\), ]*?) ([^ ]*?), +, \2\, + +Remove all paramter types : middle params after newline : +\r\n([ ]+)(.*?) (.*?), +\r\n\1\3, + +Wrap it ! +\r\n\r\n([^\r\n]*?) Path_(.*?)\((.*?)\); +\2 = function \(\3\)\r\n\treturn\1 protolib\.Path_\2\(\3\)\r\nend;\r\n\r\n + +'returnvoid ' +'' + +return(.*?) +return + + + + + +ldoc madness (gradually remove parameters) : +\r\n\t\t(.*?) = function (\(self, +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?), +[ \r\n\t]*?([^\) \r\n\t].*?)\)) + +\r\n\t\t--- \1\. +\r\n\t\t-- @param \3 +\r\n\t\t-- @param \4 +\r\n\t\t-- @param \5 +\r\n\t\t-- @param \6 +\r\n\t\t-- @param \7 +\r\n\t\t-- @param \8 +\r\n\t\t-- @param \9 +\r\n\t\t-- @param ${10} +\r\n\t\t-- @param ${11} +\r\n\t\t-- @function \1 +\r\n\t\t\1 = function \2 \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/graphics.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/graphics.lua new file mode 100644 index 0000000..6ec2bba --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/graphics.lua @@ -0,0 +1,777 @@ +--- Graphics drawing target. +-- Is a pointer to a [JUCE Graphics](http://www.juce.com/api/classGraphics.html) object. +-- Received in @{gui.paint} as an argument. +-- @classmod juce.Graphics + +local script = require "include/core/script" +local util = require"include/luautil" +util.requireCdef(script.protoplugDir.."/include/protojuce/cdef/graphics.h") +local Justification = require"include/protojuce/justification" +local RectanglePlacement = require"include/protojuce/rectangleplacement" +local AffineTransform = require"include/protojuce/affinetransform" +local Path = require"include/protojuce/path" + +local Graphics = setmetatable({}, { + --- Constuct from a @{juce.Image}. + -- Use this constructor to draw directly onto an @{juce.Image} in memory. + -- + -- A typical use is to can create a @{juce.Image} object and use it as a + -- backbuffer for pre-rendering graphics. + -- @tparam juce.Image imageToDrawOnto + -- @within Constructors + -- @constructor + -- @function Graphics + __call = function (self, imageToDrawOnto) + return ffi.gc( + protolib.Graphics_new(imageToDrawOnto), + protolib.Graphics_delete) + end +}) + +local Graphics_mt = { + -- methods + __index = { + + --- Set working colour. + -- Set the colour to be used for subsequent calls such as @{drawRect} and @{drawText}. + -- @tparam juce.Colour newColour + -- @function setColour + setColour = function (self, newColour) + protolib.Graphics_setColour(self, newColour) + end; + + + + --- Set working opacity. + -- Set the opacity to be used for subsequent calls. + -- @param newOpacity + -- @function setOpacity + setOpacity = function (self, newOpacity) + protolib.Graphics_setOpacity(self, newOpacity) + end; + + + + --- Set working Gradient. + -- Use a gradient as fill for subsequent calls such as @{fillRect}. + -- @tparam juce.ColourGradient gradient + -- @function setGradientFill + setGradientFill = function (self, gradient) + protolib.Graphics_setGradientFill(self, gradient) + end; + + + --- Set Tiled Image Fill. + -- Use a tiled image as fill for subsequent calls such as @{fillRect}. + -- @tparam juce.Image imageToUse + -- @param anchorX + -- @param anchorY + -- @param opacity + -- @function setTiledImageFill + setTiledImageFill = function (self, imageToUse, + anchorX, anchorY, + opacity) + protolib.Graphics_setTiledImageFill(self, imageToUse, + anchorX, anchorY, + opacity) + end; + + + --- Set Fill. + -- @tparam juce.FillType newFill + -- @function setFillType + setFillType = function (self, newFill) + protolib.Graphics_setFillType(self, newFill) + end; + + + --- Set Font. + -- @tparam juce.Font newFont + -- @function setFont + + --- Set Font. + -- @tparam number newFontHeight + -- @function setFont + setFont = function (self, newFont) + if type(newFont) == "number" then -- height + protolib.Graphics_setFont2(self, newFont) + else + protolib.Graphics_setFont(self, newFont) + end + end; + + + --- Get Current Font. + -- treturn juce.Font the current font + -- @function getCurrentFont + getCurrentFont = function (self) + local f = protolib.Graphics_getCurrentFont(self) + f = ffi.gc(f, protolib.Font_delete) + return f + end; + + + --- Draw single line of text. + -- @tparam string text + -- @param startX + -- @param baselineY + -- @tparam[opt=Justification.left] juce.Justification justification + -- @function drawSingleLineText + drawSingleLineText = function (self, text, + startX, baselineY, + justification) + justification = justification or Justification.left + protolib.Graphics_drawSingleLineText(self, text, + startX, baselineY, + justification) + end; + + + --- Draw multiline text. + -- @tparam string text + -- @param startX + -- @param baselineY + -- @param maximumLineWidth + -- @function drawMultiLineText + drawMultiLineText = function (self, text, + startX, baselineY, + maximumLineWidth) + protolib.Graphics_drawMultiLineText(self, text, + startX, baselineY, + maximumLineWidth) + end; + + + --- Draw text. + -- @param x + -- @param y + -- @param width + -- @param height + -- @tparam[opt=Justification.left] juce.Justification justification + -- @param[opt=false] useEllipsesIfTooBig + -- @function drawText + + --- Draw text. + -- @tparam juce.Rectangle_int area + -- @tparam[opt=Justification.left] juce.Justification justification + -- @param[opt=false] useEllipsesIfTooBig + -- @function drawText + drawText = function (self, text, ...) + if select('#',...) >= 4 then + local x, y, width, height, justificationType, useEllipsesIfTooBig = ... + justificationType = justificationType or Justification.left + useEllipsesIfTooBig = useEllipsesIfTooBig or false + protolib.Graphics_drawText(self, text, + x, y, width, height, + justificationType, + useEllipsesIfTooBig) + else -- Rectangle_int + local area, justificationType, useEllipsesIfTooBig = ... + justificationType = justificationType or Justification.left + useEllipsesIfTooBig = useEllipsesIfTooBig or false + protolib.Graphics_drawText2(self, text, + area, + justificationType, + useEllipsesIfTooBig) + end + end; + + + --- Draw fitted text. + -- Awkwardly squishes the font (up to minimumHorizontalScale) if necessary. + -- @param x + -- @param y + -- @param width + -- @param height + -- @tparam juce.Justification justification + -- @param maximumNumberOfLines + -- @param[opt=0.7] minimumHorizontalScale + -- @function drawFittedText + + --- Draw fitted text. + -- Awkwardly squishes the font (up to minimumHorizontalScale) if necessary. + -- @tparam juce.Rectangle_int area + -- @tparam juce.Justification justification + -- @param maximumNumberOfLines + -- @param[opt=0.7] minimumHorizontalScale + -- @function drawFittedText + drawFittedText = function (self, text, ...) + if select('#',...) >= 6 then + local x, y, width, height, justificationFlags, maximumNumberOfLines, minimumHorizontalScale = ... + minimumHorizontalScale = minimumHorizontalScale or 0.7 + protolib.Graphics_drawFittedText(self, text, + x, y, width, height, + justificationFlags, + maximumNumberOfLines, + minimumHorizontalScale) + else + local area, justificationFlags, maximumNumberOfLines, minimumHorizontalScale = ... + minimumHorizontalScale = minimumHorizontalScale or 0.7 + protolib.Graphics_drawFittedText2(self, text, + area, + justificationFlags, + maximumNumberOfLines, + minimumHorizontalScale) + end + end; + + + --- Fill the entire graphics target. + -- @tparam[opt] juce.Colour colourToUse + -- @function fillAll + fillAll = function (self, colourToUse) + if colourToUse then + protolib.Graphics_fillAll2(self, colourToUse) + else + protolib.Graphics_fillAll(self) + end + end; + + + --- Fill rectangle with current fill type. + -- @param x + -- @param y + -- @param width + -- @param height + -- @function fillRect + + --- Fill rectangle with current fill type. + -- @tparam juce.Rectangle_int area + -- @function fillRect + fillRect = function (self, ...) + if select('#',...) == 4 then + local x, y, width, height = ... + protolib.Graphics_fillRect3(self, x, y, width, height) + else + local rectangle = ... + if ffi.istype("Rectangle_int", rectangle) then + protolib.Graphics_fillRect(self, rectangle) + else + protolib.Graphics_fillRect2(self, rectangle) + end + end + end; + + + fillRect_int = function (self, x, y, width, height) + protolib.Graphics_fillRect3(self, x, y, width, height) + end; + + + --- Fill rectangle (sub-pixel accuracy). + -- @param x + -- @param y + -- @param width + -- @param height + -- @function fillRect_float + fillRect_float = function (self, x, y, width, height) + protolib.Graphics_fillRect4(self, x, y, width, height) + end; + + + --- Fill rounded rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param cornerSize + -- @function fillRoundedRectangle + + --- Fill rounded rectangle. + -- @tparam juce.Rectangle_int area + -- @param cornerSize + -- @function fillRoundedRectangle + fillRoundedRectangle = function (self, ...) + if select('#',...) == 5 then + local x, y, width, height, cornerSize = ... + protolib.Graphics_fillRoundedRectangle(self, x, y, width, height, + cornerSize) + else + local rectangle, cornerSize = ... + protolib.Graphics_fillRoundedRectangle2(self, rectangle, + cornerSize) + end + end; + + + --- Fill *chequerboard*. + -- (and i thought juce used British spelling) + -- @tparam juce.Rectangle_int area + -- @param checkWidth + -- @param checkHeight + -- @tparam juce.Colour colour1 + -- @tparam juce.Colour colour2 + -- @function fillCheckerBoard + fillCheckerBoard = function (self, area, + checkWidth, checkHeight, + colour1, colour2) + protolib.Graphics_fillCheckerBoard(self, area, + checkWidth, checkHeight, + colour1, colour2) + end; + + + --- Draw rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param[opt=1] lineThickness + -- @function drawRect + + --- Draw rectangle. + -- @tparam juce.Rectangle_int area + -- @param[opt=1] lineThickness + -- @function drawRect + drawRect = function (self, ...) + if select('#',...) >= 4 then + local x, y, width, height, lineThickness = ... + lineThickness = lineThickness or 1 + protolib.Graphics_drawRect(self, x, y, width, height, lineThickness) + else + local rectangle, lineThickness = ... + lineThickness = lineThickness or 1 + protolib.Graphics_drawRect3(self, rectangle, lineThickness) + end + end; + + + --- Draw rect (sub-pixel accuracy). + -- @param x + -- @param y + -- @param width + -- @param height + -- @param[opt=1] lineThickness + -- @function drawRect_float + + --- Draw rect (sub-pixel accuracy). + -- @tparam juce.Rectangle_int area + -- @param[opt=1] lineThickness + -- @function drawRect_float + drawRect_float = function (self, ...) + if select('#',...) >= 4 then + local x, y, width, height, lineThickness = ... + lineThickness = lineThickness or 1 + protolib.Graphics_drawRect2(self, x, y, width, height, lineThickness) + else + local rectangle, lineThickness = ... + lineThickness = lineThickness or 1 + protolib.Graphics_drawRect4(self, rectangle, lineThickness) + end + end; + + + --- Draw rounded rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param cornerSize + -- @param[opt=1] lineThickness + -- @function drawRoundedRectangle + + --- Draw rounded rectangle. + -- @tparam juce.Rectangle_int area + -- @param cornerSize + -- @param[opt=1] lineThickness + -- @function drawRoundedRectangle + drawRoundedRectangle = function (self, ...) + if select('#',...) >= 5 then + local x, y, width, height, cornerSize, lineThickness = ... + lineThickness = lineThickness or 1 + protolib.Graphics_drawRoundedRectangle(self, x, y, width, height, cornerSize, lineThickness) + else + local rectangle, cornerSize, lineThickness = ... + lineThickness = lineThickness or 1 + protolib.Graphics_drawRoundedRectangle2(self, rectangle, cornerSize, lineThickness) + end + end; + + + --- Set pixel with current colour. + -- @param x + -- @param y + -- @function setPixel + setPixel = function (self, x, y) + protolib.Graphics_setPixel(self, x, y) + end; + + + --- Fill ellipse with current fill. + -- @param x + -- @param y + -- @param width + -- @param height + -- @function fillEllipse + fillEllipse = function (self, ...) + if select('#',...) == 4 then + local x, y, width, height = ... + protolib.Graphics_fillEllipse(self, x, y, width, height) + else + local area = ... + protolib.Graphics_fillEllipse2(self, area) + end + end; + + + --- Draw ellipse with current colour. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param[opt=1] lineThickness + -- @function drawEllipse + drawEllipse = function (self, x, y, width, height, + lineThickness) + lineThickness = lineThickness or 1 + protolib.Graphics_drawEllipse(self, x, y, width, height, + lineThickness) + end; + + + --- Draw line. + -- @param startX + -- @param startY + -- @param endX + -- @param endY + -- @param[opt=1] lineThickness + -- @function drawLine + + --- Draw line. + -- @tparam juce.Line line + -- @param[opt=1] lineThickness + -- @function drawLine + drawLine = function (self, ...) + if select('#',...) == 4 then + local startX, startY, endX, endY = ... + protolib.Graphics_drawLine(self, startX, startY, endX, endY) + elseif select('#',...) == 5 then + local startX, startY, endX, endY, lineThickness = ... + protolib.Graphics_drawLine2(self, startX, startY, endX, endY, lineThickness) + elseif select('#',...) == 1 then + local line = ... + protolib.Graphics_drawLine3(self, line) + else + local line, lineThickness = ... + protolib.Graphics_drawLine4(self, line, lineThickness) + end + end; + + + --- Draw dashed line. + -- @tparam juce.Line line + -- @param dashLengths (const float* ctype) + -- @param numDashLengths + -- @param[opt=1] lineThickness + -- @param[opt=0] dashIndexToStartFrom + -- @function drawDashedLine + drawDashedLine = function (self, line, + dashLengths, numDashLengths, + lineThickness, + dashIndexToStartFrom) + lineThickness = lineThickness or 1 + dashIndexToStartFrom = dashIndexToStartFrom or 0 + protolib.Graphics_drawDashedLine(self, line, + dashLengths, numDashLengths, + lineThickness, + dashIndexToStartFrom) + end; + + + --- Draw vertical line. + -- @param x + -- @param top + -- @param bottom + -- @function drawVerticalLine + drawVerticalLine = function (self, x, top, bottom) + protolib.Graphics_drawVerticalLine(self, x, top, bottom) + end; + + + --- Draw horizontal line. + -- @param y + -- @param left + -- @param right + -- @function drawHorizontalLine + drawHorizontalLine = function (self, y, left, right) + protolib.Graphics_drawHorizontalLine(self, y, left, right) + end; + + + --- Fill path. + -- @tparam juce.Path path + -- @tparam[opt=juce.AffineTransform.identity] juce.AffineTransform transform + -- @function fillPath + fillPath = function (self, path, + transform) + transform = transform or AffineTransform.identity + protolib.Graphics_fillPath(self, path, + transform) + end; + + + --- Stroke path. + -- All named arguments are optional + -- @tparam juce.Path path + -- @param[opt] args + -- @param args.thickness + -- @tparam juce.Path.JointStyle args.jointStyle *default* : juce.Path.JointStyle.mitered + -- @tparam juce.Path.EndCapStyle args.endCapStyle *default* : juce.Path.EndCapStyle.butt + -- @tparam juce.AffineTransform args.transform *default* : juce.AffineTransform.identity + -- @function strokePath + strokePath = function (self, path, args) + args = args or {} + args.thickness = args.thickness or 1 + args.jointStyle = args.jointStyle or Path.JointStyle.mitered + args.endCapStyle = args.endCapStyle or Path.EndCapStyle.butt + args.transform = args.transform or AffineTransform.identity + local strokeType = ffi.new("PathStrokeType", args.thickness, args.jointStyle, args.endCapStyle) + protolib.Graphics_strokePath(self, path, + strokeType, + args.transform) + end; + + + --- Draw arrow. + -- @tparam juce.Line line + -- @param lineThickness + -- @param arrowheadWidth + -- @param arrowheadLength + -- @function drawArrow + drawArrow = function (self, line, + lineThickness, + arrowheadWidth, + arrowheadLength) + protolib.Graphics_drawArrow(self, line, + lineThickness, + arrowheadWidth, + arrowheadLength) + end; + + + --- Set image resampling quality. + -- @tparam juce.Graphics.ResamplingQuality newQuality + -- @function setImageResamplingQuality + setImageResamplingQuality = function (self, newQuality) + protolib.Graphics_setImageResamplingQuality(self, newQuality) + end; + + + --- Draw unscaled image at location. + -- @tparam juce.Image imageToDraw + -- @param topLeftX + -- @param topLeftY + -- @param[opt=false] fillAlphaChannelWithCurrentBrush + -- @function drawImageAt + drawImageAt = function (self, imageToDraw, topLeftX, topLeftY, + fillAlphaChannelWithCurrentBrush) + fillAlphaChannelWithCurrentBrush = fillAlphaChannelWithCurrentBrush or false + protolib.Graphics_drawImageAt(self, imageToDraw, topLeftX, topLeftY, + fillAlphaChannelWithCurrentBrush) + end; + + + --- Draw a portion of an image, stretched into a target rectangle. + -- @tparam juce.Image imageToDraw + -- @param destX + -- @param destY + -- @param destWidth + -- @param destHeight + -- @param sourceX + -- @param sourceY + -- @param sourceWidth + -- @param sourceHeight + -- @param[opt=false] fillAlphaChannelWithCurrentBrush + -- @function drawImage + drawImage = function (self, imageToDraw, + destX, destY, destWidth, destHeight, + sourceX, sourceY, sourceWidth, sourceHeight, + fillAlphaChannelWithCurrentBrush) + fillAlphaChannelWithCurrentBrush = fillAlphaChannelWithCurrentBrush or false + protolib.Graphics_drawImage(self, imageToDraw, + destX, destY, destWidth, destHeight, + sourceX, sourceY, sourceWidth, sourceHeight, + fillAlphaChannelWithCurrentBrush) + end; + + + --- Draw transformed image. + -- @tparam juce.Image imageToDraw + -- @tparam juce.AffineTransform transform + -- @param[opt=false] fillAlphaChannelWithCurrentBrush + -- @function drawImageTransformed + drawImageTransformed = function (self, imageToDraw, + transform, + fillAlphaChannelWithCurrentBrush) + fillAlphaChannelWithCurrentBrush = fillAlphaChannelWithCurrentBrush or false + protolib.Graphics_drawImageTransformed(self, imageToDraw, + transform, + fillAlphaChannelWithCurrentBrush) + end; + + + --- Draw image within. + -- @tparam juce.Image imageToDraw + -- @param destX + -- @param destY + -- @param destWidth + -- @param destHeight + -- @param[opt=juce.RectanglePlacement.centred] placementWithinTarget + -- @param[opt=false] fillAlphaChannelWithCurrentBrush + -- @function drawImageWithin + drawImageWithin = function (self, imageToDraw, + destX, destY, destWidth, destHeight, + placementWithinTarget, + fillAlphaChannelWithCurrentBrush) + fillAlphaChannelWithCurrentBrush = fillAlphaChannelWithCurrentBrush or false + placementWithinTarget = placementWithinTarget or RectanglePlacement.centred + protolib.Graphics_drawImageWithin(self, imageToDraw, + destX, destY, destWidth, destHeight, + placementWithinTarget, + fillAlphaChannelWithCurrentBrush) + end; + + + --- Get clip bounds. + -- Get the portion of the graphics target that needs to be redrawn. + -- @treturn juce.Rectangle_int Clipping area + -- @function getClipBounds + getClipBounds = function (self) + return protolib.Graphics_getClipBounds(self) + end; + + + --- Clip region intersects. + -- Check if a rectangle intersects with the redrawing region + -- @treturn juce.Rectangle_int Clipping area + -- @treturn boolean intersection check + -- @function clipRegionIntersects + clipRegionIntersects = function (self, area) + return protolib.Graphics_clipRegionIntersects(self, area) + end; + + + reduceClipRegion = function (self, ...) + local control = select(1, ...) + if type(control)=="number" then + local x, y, width, height = ... + return protolib.Graphics_reduceClipRegion(self, x, y, width, height) + elseif ffi.istype("Rectangle_int", control) then + local area = ... + return protolib.Graphics_reduceClipRegion2(self, area) + elseif ffi.istype("pPath", control) then + local path, transform = ... + transform = transform or AffineTransform.identity + return protolib.Graphics_reduceClipRegion4(self, path, transform) + else -- pImage + local image, transform = ... + return protolib.Graphics_reduceClipRegion5(self, image, transform) + end + end; + + + excludeClipRegion = function (self, rectangleToExclude) + protolib.Graphics_excludeClipRegion(self, rectangleToExclude) + end; + + + --- Is clipping region empty. + -- @treturn boolean whether the redrawing area is empty + -- @function isClipEmpty + isClipEmpty = function (self) + return protolib.Graphics_isClipEmpty(self) + end; + + + --- Save state. + -- Saves the current state of the graphics target on a stack. + -- This does not save the actual graphic's contents but its current + -- colour, transform, origin, etc. + -- @function saveState + saveState = function (self) + protolib.Graphics_saveState(self) + end; + + + --- Restore state. + -- Restores a state of the graphics target from the stack. + -- Useful to cancel any previous uses + -- of @{addTransform}, @{setColour}, etc. + -- @function restoreState + restoreState = function (self) + protolib.Graphics_restoreState(self) + end; + + + --- Begin transparency layer. + -- Saves the current state and begins drawing on a temporary layer, + -- to be applied with the specified final transparency. + -- @function beginTransparencyLayer + beginTransparencyLayer = function (self, layerOpacity) + protolib.Graphics_beginTransparencyLayer(self, layerOpacity) + end; + + + --- End transparency layer. + -- Applies the transparency layer that was started with @{beginTransparencyLayer}. + -- @function endTransparencyLayer + endTransparencyLayer = function (self) + protolib.Graphics_endTransparencyLayer(self) + end; + + + --no + -- Set origin. tparam juce.Point newOrigin function setOrigin + + --- Set origin. + -- @param newOriginX + -- @param newOriginY + -- @function setOrigin + setOrigin = function (self, ...) + if select("#", ...) == 1 then + protolib.Graphics_setOrigin(self, ...) + else + protolib.Graphics_setOrigin2(self, ...) + end + end; + + + --- Add a transformation matrix. + -- The matrix will be chained onto the current one, and affect all + -- subsequent graphics operations. Use @{saveState} and @{restoreState} + -- to apply a temporary transform. + -- @tparam juce.AffineTransform transform + -- @function addTransform + addTransform = function (self, transform) + protolib.Graphics_addTransform(self, transform) + end; + + + --- Reset to default state. + -- @function resetToDefaultState + resetToDefaultState = function (self) + protolib.Graphics_resetToDefaultState(self) + end; + + + --- Is vector device. + -- @treturn boolean whether the target is a vector device. + -- @function isVectorDevice + isVectorDevice = function (self) + return protolib.Graphics_isVectorDevice(self) + end; + } +} + +--- Resampling qualities. +-- @table juce.Graphics.ResamplingQuality +Graphics.ResamplingQuality = +{ + low = 0; + medium = 1; + high = 2 +}; + +ffi.metatype("pGraphics", Graphics_mt); + +return Graphics \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/image.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/image.lua new file mode 100644 index 0000000..12c9c95 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/image.lua @@ -0,0 +1,74 @@ +--- Image. +-- Images can be loaded from a file, or created as temporary graphics targets. +-- +-- Is a pointer to a [JUCE Image](http://www.juce.com/api/classImage.html), +-- and wraps some [JUCE ImageFileFormat](http://www.juce.com/api/classImageFileFormat.html) +-- functionality. +-- @classmod juce.Image + +ffi.cdef [[ +pImage Image_new(); +pImage Image_new2(int pixelFormat, int imageWidth, int imageHeight, bool clearImage); +void Image_delete(pImage i); +bool Image_isValid(pImage i); + +pImage ImageFileFormat_loadFrom2(const char *filename); +]] + +local Image = setmetatable ({}, { + + --- Load an image from a file. + -- The path can be absolute or relative to the protoplug directory. + -- To check if the file was loaded successfully, use @{isValid}. + -- @param filename + -- @within Constructors + -- @constructor + -- @function Image + + --- Create a temporary in-memory image. + -- @tparam juce.Image.PixelFormat pixelFormat + -- @param imageWidth + -- @param imageHeight + -- @tparam boolean clearImage fill the image with black + -- @within Constructors + -- @constructor + -- @function Image + __call = function(self, ...) + if select("#", ...)==4 then + return ffi.gc( + protolib.Image_new2(...), + protolib.Image_delete + ) + else + return ffi.gc( + protolib.ImageFileFormat_loadFrom2(...), + protolib.Image_delete + ) + end + end; +}) + +local Image_mt = { + -- methods + __index = { + + --- Check Image validity. + -- @treturn boolean whether the image is valid and can be used. + -- @function isValid + isValid = function (self) + return protolib.Image_isValid(self) + end; + } +} +ffi.metatype("pImage", Image_mt); + +--- Pixel formats. +-- @table juce.Image.PixelFormat +Image.PixelFormat = { + UnknownFormat = 0; -- 0 + RGB = 1; -- 1 + ARGB = 2; -- 2 + SingleChannel = 3 -- 3 +} + +return Image \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/justification.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/justification.lua new file mode 100644 index 0000000..2e08f2e --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/justification.lua @@ -0,0 +1,26 @@ +--- Justification. +-- Is converted to a [JUCE Justification](http://www.juce.com/api/Justification.html) +-- @classmod juce.Justification + +--- Justification Constants. +-- @table juce.Justification +local r = { + left = 1; + right = 2; + horizontallyCentred = 4; + top = 8; + bottom = 16; + verticallyCentred = 32; + horizontallyJustified = 64; + centred = 36; + centredLeft = 33; + centredRight = 34; + centredTop = 12; + centredBottom = 20; + topLeft = 9; + topRight = 10; + bottomLeft = 17; + bottomRight = 18 +} + +return r \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/lagrangeinterpolator.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/lagrangeinterpolator.lua new file mode 100644 index 0000000..dca1557 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/lagrangeinterpolator.lua @@ -0,0 +1,41 @@ +--- Lagrange Interpolator. +-- Is converted to a [JUCE LagrangeInterpolator](http://www.juce.com/api/classLagrangeInterpolator.html) +-- @classmod juce.LagrangeInterpolator + +ffi.cdef [[ +LagrangeInterpolator LagrangeInterpolator_create(); +int LagrangeInterpolator_process(LagrangeInterpolator ex, + double speedRatio, + const float* inputSamples, + float* outputSamples, + int numOutputSamplesToProduce); +]] + +--- Constuctor. +-- @within Constructors +-- @constructor +-- @function LagrangeInterpolator +local LagrangeInterpolator = setmetatable({}, { + __call = function (self) + return protolib.LagrangeInterpolator_create() + end +}) + +local LagrangeInterpolator_mt = { + -- methods + __index = { + --- Interpolate. + -- @param speedRatio number of input samples per output sample (input/output) + -- @param inputSamples pointer to a cdata `float` array + -- @param outputSamples pointer to a cdata `float` array + -- @param numOutputSamplesToProduce + -- @treturn number number of input samples that were processed + -- @function process + process = function (self, speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce) + return protolib.LagrangeInterpolator_process(self, speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce) + end; + } +} +ffi.metatype("LagrangeInterpolator", LagrangeInterpolator_mt); + +return LagrangeInterpolator \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/line.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/line.lua new file mode 100644 index 0000000..20616f6 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/line.lua @@ -0,0 +1,50 @@ +--- Line. +-- Is converted to a [JUCE Line](http://www.juce.com/api/classLine.html) +-- @classmod juce.Line + +--- Constuctor +-- @param x1 +-- @param y1 +-- @param x2 +-- @param y2 +-- @within Constructors +-- @constructor +-- @function Line + +--- Constuctor +-- @param args +-- @param args.x1 +-- @param args.y1 +-- @param args.x2 +-- @param args.y2 +-- @within Constructors +-- @constructor +-- @function Line + +local Line = ffi.typeof("Line_float") + +local Line_mt = { + -- operator '==' + __eq = function(self, rhs) + return self.x1 == rhs.x1 and + self.y1 == rhs.y1 and + self.x2 == rhs.x2 and + self.y2 == rhs.y2 + end; +} +ffi.metatype(Line, Line_mt) + + +--- Point 1 X position +-- @simplefield x1 + +--- Point 1 Y position +-- @simplefield y1 + +--- Point 2 X position +-- @simplefield x2 + +--- Point 2 Y position +-- @simplefield y2 + +return Line \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/path.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/path.lua new file mode 100644 index 0000000..55124ff --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/path.lua @@ -0,0 +1,586 @@ +--- Path. +-- Is a pointer to a [JUCE Path](http://www.juce.com/api/classPath.html). +-- @classmod juce.Path + +local script = require "include/core/script" +local Point = require"include/protojuce/point" +local AffineTransform = require"include/protojuce/affinetransform" +local util = require"include/luautil" +util.requireCdef(script.protoplugDir.."/include/protojuce/cdef/path.h") + +--- Constuctor +-- @within Constructors +-- @constructor +-- @function Path + +local Path_mt = { + -- methods + __index = { + + --- Get bounds. + -- @treturn Rectangle_float rectangle containing the path + -- @function getBounds + getBounds = function (self) + return protolib.Path_getBounds(self) + end; + + --- Get bounds transformed. + -- @tparam juce.AffineTransform transform + -- @treturn Rectangle_float rectangle containing the transformed path + -- @function getBoundsTransformed + getBoundsTransformed = function (self, transform) + return protolib.Path_getBoundsTransformed (self, transform) + end; + + --- Contains. + -- @param pointX + -- @param pointY + -- @param[opt=1] tolerance + -- @treturn boolean whether the path contains the point + -- @see closeSubPath + -- @function contains + + --- Contains. + -- @tparam juce.Point point + -- @param[opt=1] tolerance + -- @treturn boolean whether the path contains the point + -- @see closeSubPath + -- @function contains + contains = function (self, ...) + local control = ... + tolerance = tolerance or 1 + if type(control)=="number" then + return protolib.Path_contains (self, ...) + else + return protolib.Path_contains2 (self, ...) + end + end; + + --- Intersects line. + -- @tparam juce.Line line + -- @param[opt=1] tolerance + -- @treturn boolean whether the path intersects the line + -- @function intersectsLine + intersectsLine = function (self, line, tolerance) + tolerance = tolerance or 1 + return protolib.Path_intersectsLine (self, line, tolerance) + end; + + --- Get clipped line. + -- @tparam juce.Line line + -- @tparam boolean keepSectionOutsidePath + -- @treturn juce.Line_float the line clipped by the path + -- @function getClippedLine + getClippedLine = function (self, line, keepSectionOutsidePath) + return protolib.Path_getClippedLine (self, line, keepSectionOutsidePath) + end; + + --- Get length. + -- @tparam[opt=juce.AffineTransform.identity] juce.AffineTransform transform + -- @return length of the path + -- @function getLength + getLength = function (self, transform) + transform = transform or AffineTransform.identity + return protolib.Path_getLength (self, transform) + end; + + --- Get point along path. + -- @param distanceFromStart + -- @tparam[opt=juce.AffineTransform.identity] juce.AffineTransform transform + -- @treturn Point_float the point on the path + -- @function getPointAlongPath + getPointAlongPath = function (self, distanceFromStart, transform) + transform = transform or AffineTransform.identity + return protolib.Path_getPointAlongPath (self, distanceFromStart, transform) + end; + + --- Get nearest point. + -- Get the nearest on-path point to an arbitrary point, and + -- the distance between the points + -- @tparam juce.Point targetPoint + -- @tparam[opt=juce.AffineTransform.identity] juce.AffineTransform transform + -- @return distance + -- @treturn juce.Point pointOnPath + -- @function getNearestPoint + getNearestPoint = function (self, targetPoint, + transform) + transform = transform or AffineTransform.identity + local pointOnPath = Point() + local distance = protolib.Path_getNearestPoint (self, targetPoint, + pointOnPath, + transform) + return distance, pointOnPath + end; + + --- Clear. + -- @function clear + clear = function (self) + protolib.Path_clear(self) + end; + + --- Start new sub path. + -- @param startX + -- @param startY + -- @function startNewSubPath + + --- Start new sub path. + -- @tparam juce.Point start + -- @function startNewSubPath + startNewSubPath = function (self, ...) + local control = ... + if type(control)=="number" then + protolib.Path_startNewSubPath (self, ...) + else + protolib.Path_startNewSubPath2 (self, ...) + end + end; + + --- Close sub path. + -- @function closeSubPath + closeSubPath = function (self) + protolib.Path_closeSubPath(self) + end; + + --- Line to. + -- @param endX + -- @param endY + -- @function lineTo + + --- Line to. + -- @tparam juce.Point endpoint + -- @function lineTo + lineTo = function (self, ...) + local control = ... + if type(control)=="number" then + protolib.Path_lineTo (self, ...) + else + protolib.Path_lineTo2 (self, ...) + end + end; + + --- Quadratic to. + -- @param controlPointX + -- @param controlPointY + -- @param endPointX + -- @param endPointY + -- @function quadraticTo + + --- Quadratic to2. + -- @tparam juce.Point controlPoint + -- @tparam juce.Point endPoint + -- @function quadraticTo2 + quadraticTo = function (self, ...) + local control = ... + if type(control)=="number" then + protolib.Path_quadraticTo (self, ...) + else + protolib.Path_quadraticTo2 (self, ...) + end + end; + + --- Cubic to. + -- @param controlPoint1X + -- @param controlPoint1Y + -- @param controlPoint2X + -- @param controlPoint2Y + -- @param endPointX + -- @param endPointY + -- @function cubicTo + + --- Cubic to. + -- @tparam juce.Point controlPoint1 + -- @tparam juce.Point controlPoint2 + -- @tparam juce.Point endPoint + -- @function cubicTo + cubicTo = function (self, ...) + local control = ... + if type(control)=="number" then + protolib.Path_cubicTo (self, ...) + else + protolib.Path_cubicTo2 (self, ...) + end + end; + + --- Get current position. + -- @treturn juce.Point the current path construction position + -- @function getCurrentPosition + getCurrentPosition = function (self) + return protolib.Path_getCurrentPosition(self) + end; + + --- Add rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @function addRectangle + + --- Add rectangle. + -- @tparam juce.Rectangle_float rectangle + -- @function addRectangle + addRectangle = function (self, ...) + local control = ... + if type(control)=="number" then + protolib.Path_addRectangle (self, ...) + else + protolib.Path_addRectangle2 (self, ...) + end + end; + + --- Add rounded rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param cornerSize + -- @function addRoundedRectangle + + --- Add rounded rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param cornerSizeX + -- @param cornerSizeY + -- @function addRoundedRectangle + + --- Add rounded rectangle. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param cornerSizeX + -- @param cornerSizeY + -- @tparam boolean curveTopLeft + -- @tparam boolean curveTopRight + -- @tparam boolean curveBottomLeft + -- @tparam boolean curveBottomRight + -- @function addRoundedRectangle + + --- Add rounded rectangle. + -- @tparam juce.Rectangle_float rectangle + -- @param cornerSizeX + -- @param cornerSizeY + -- @function addRoundedRectangle + + --- Add rounded rectangle. + -- @tparam juce.Rectangle_float rectangle + -- @param cornerSize + -- @function addRoundedRectangle + addRoundedRectangle = function (self, ...) + if select('#',...) == 5 then + protolib.Path_addRoundedRectangle2 (self, ...) + elseif select('#',...) == 6 then + protolib.Path_addRoundedRectangle3 (self, ...) + elseif select('#',...) == 10 then + protolib.Path_addRoundedRectangle4 (self, ...) + elseif select('#',...) == 3 then + protolib.Path_addRoundedRectangle5 (self, ...) + elseif select('#',...) == 2 then + protolib.Path_addRoundedRectangle6 (self, ...) + end + end; + + --- Add triangle. + -- @param x1 + -- @param y1 + -- @param x2 + -- @param y2 + -- @param x3 + -- @param y3 + -- @function addTriangle + addTriangle = function (self, x1, y1, + x2, y2, + x3, y3) + protolib.Path_addTriangle (self, x1, y1, + x2, y2, + x3, y3) + end; + + --- Add quadrilateral. + -- @param x1 + -- @param y1 + -- @param x2 + -- @param y2 + -- @param x3 + -- @param y3 + -- @param x4 + -- @param y4 + -- @function addQuadrilateral + addQuadrilateral = function (self, x1, y1, + x2, y2, + x3, y3, + x4, y4) + protolib.Path_addQuadrilateral (self, x1, y1, + x2, y2, + x3, y3, + x4, y4) + end; + + --- Add ellipse. + -- @param x + -- @param y + -- @param width + -- @param height + -- @function addEllipse + addEllipse = function (self, x, y, width, height) + protolib.Path_addEllipse (self, x, y, width, height) + end; + + --- Add arc. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param fromRadians the start angle, clockwise from the top + -- @param toRadians the end angle + -- @param[opt=false] startAsNewSubPath + -- @function addArc + addArc = function (self, x, y, width, height, + fromRadians, + toRadians, startAsNewSubPath) + startAsNewSubPath = startAsNewSubPath or false + protolib.Path_addArc (self, x, y, width, height, + fromRadians, + toRadians, startAsNewSubPath) + end; + + --- Add centred arc. + -- @param centreX + -- @param centreY + -- @param radiusX + -- @param radiusY + -- @param rotationOfEllipse the ellipse inclination + -- @param fromRadians the start angle, clockwise from the top + -- @param toRadians the end angle + -- @param[opt=false] startAsNewSubPath + -- @function addCentredArc + addCentredArc = function (self, centreX, centreY, + radiusX, radiusY, + rotationOfEllipse, + fromRadians, + toRadians, startAsNewSubPath) + startAsNewSubPath = startAsNewSubPath or false + protolib.Path_addCentredArc (self, centreX, centreY, + radiusX, radiusY, + rotationOfEllipse, + fromRadians, + toRadians, startAsNewSubPath) + end; + + --- Add pie segment. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param fromRadians the start angle, clockwise from the top + -- @param toRadians the end angle + -- @param[opt=0] innerCircleProportionalSize band proportion size, if specified + -- @function addPieSegment + addPieSegment = function (self, x, y, + width, height, + fromRadians, + toRadians, innerCircleProportionalSize) + innerCircleProportionalSize = innerCircleProportionalSize or 0 + protolib.Path_addPieSegment (self, x, y, + width, height, + fromRadians, + toRadians, innerCircleProportionalSize) + end; + + --- Add line segment. + -- @tparam juce.Line line + -- @param lineThickness + -- @function addLineSegment + addLineSegment = function (self, line, lineThickness) + protolib.Path_addLineSegment (self, line, lineThickness) + end; + + --- Add arrow. + -- @tparam juce.Line line + -- @param lineThickness + -- @param arrowheadWidth + -- @param arrowheadLength + -- @function addArrow + addArrow = function (self, line, + lineThickness, + arrowheadWidth, arrowheadLength) + protolib.Path_addArrow (self, line, + lineThickness, + arrowheadWidth, arrowheadLength) + end; + + --- Add polygon. + -- @tparam juce.Point centre + -- @param numberOfSides + -- @param radius + -- @param[opt=0] startAngle + -- @function addPolygon + addPolygon = function (self, centre, + numberOfSides, + radius, startAngle) + startAngle = startAngle or 0 + protolib.Path_addPolygon (self, centre, + numberOfSides, + radius, startAngle) + end; + + --- Add star. + -- @tparam juce.Point centre + -- @param numberOfPoints + -- @param innerRadius + -- @param outerRadius + -- @param[opt=0] startAngle + -- @function addStar + addStar = function (self, centre, + numberOfPoints, + innerRadius, + outerRadius, startAngle) + startAngle = startAngle or 0 + protolib.Path_addStar (self, centre, + numberOfPoints, + innerRadius, + outerRadius, startAngle) + end; + + --- Add bubble. + -- @param bodyArea + -- @param maximumArea + -- @param arrowTipPosition + -- @param cornerSize + -- @param arrowBaseWidth + -- @function addBubble + addBubble = function (self, bodyArea, + maximumArea, + arrowTipPosition, + cornerSize, arrowBaseWidth) + protolib.Path_addBubble (self, bodyArea, + maximumArea, + arrowTipPosition, + cornerSize, arrowBaseWidth) + end; + + --- Add path. + -- @param pathToAppend + -- @tparam[opt=juce.AffineTransform.identity] juce.AffineTransform transform + -- @function addPath + addPath = function (self, pathToAppend, transformToApply) + if transformToApply then + protolib.Path_addPath2 (self, pathToAppend, transformToApply) + else + protolib.Path_addPath (self, pathToAppend) + end + end; + + --- Apply transform. + -- @tparam juce.AffineTransform transform + -- @function applyTransform + applyTransform = function (self, transform) + protolib.Path_applyTransform (self, transform) + end; + + --- Scale to fit. + -- @param x + -- @param y + -- @param width + -- @param height + -- @param preserveProportions + -- @function scaleToFit + scaleToFit = function (self, x, y, width, height, preserveProportions) + protolib.Path_scaleToFit (self, x, y, width, height, preserveProportions) + end; + + --- Get transform to scale to fit. + -- @param x + -- @param y + -- @param width + -- @param height + -- @tparam boolean preserveProportions + -- @tparam[opt=Justification.centred] juce.Justification justification + -- @treturn juce.AffineTransform the required transform + -- @function getTransformToScaleToFit + + --- Get transform to scale to fit. + -- @tparam juce.Rectangle_float area + -- @tparam boolean preserveProportions + -- @tparam[opt=Justification.centred] juce.Justification justification + -- @treturn juce.AffineTransform the required transform + -- @function getTransformToScaleToFit + getTransformToScaleToFit = function (self, ...) + local control = ... + if type(control)=="number" then + return protolib.Path_getTransformToScaleToFit (self, ...) + else + return protolib.Path_getTransformToScaleToFit2 (self, ...) + end + end; + + --- Create path with rounded corners. + -- @param cornerRadius + -- @treturn juce.Path the rounded path + -- @function createPathWithRoundedCorners + createPathWithRoundedCorners = function (self, cornerRadius) + return protolib.Path_createPathWithRoundedCorners (self, cornerRadius) + end; + + --- Set using non zero winding. + -- @tparam boolean isNonZeroWinding + -- @function setUsingNonZeroWinding + setUsingNonZeroWinding = function (self, isNonZeroWinding) + protolib.Path_setUsingNonZeroWinding (self, isNonZeroWinding) + end; + + --- Is using non zero winding. + -- @treturn boolean whether the path is using non-zero winding + -- @function isUsingNonZeroWinding + isUsingNonZeroWinding = function (self) + return protolib.Path_isUsingNonZeroWinding(self) + end; + + toString = function (self, dest, bufSize) + protolib.Path_toString(self, dest, bufSize) + end; + + restoreFromString = function (self, src) + protolib.Path_restoreFromString (self, src) + end; + } +} + +ffi.metatype("pPath", Path_mt) + + +local Line = ffi.typeof("Line_float") + +local Path = { + --- Joint styles. + -- for use with @{juce.Graphics.strokePath} + -- @table juce.Path.JointStyle + JointStyle = + { + mitered = 0; + curved = 1; + beveled = 2 + }; + --- End cap styles. + -- for use with @{juce.Graphics.strokePath} + -- @table juce.Path.EndCapStyle + EndCapStyle = + { + butt = 0; + square = 1; + rounded = 2 + } +}; + +Path = setmetatable(Path,{ + -- constructor + __call = function () + return ffi.gc( + protolib.Path_new(), + protolib.Path_delete + ) + end; +}) + +return Path diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/point.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/point.lua new file mode 100644 index 0000000..bc38f21 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/point.lua @@ -0,0 +1,37 @@ +--- Point. +-- Is converted to a [JUCE Point](http://www.juce.com/api/classPoint.html) +-- @classmod juce.Point + +--- Constuctor +-- @param x +-- @param y +-- @within Constructors +-- @constructor +-- @function Point + +--- Constuctor +-- @param args +-- @param args.x +-- @param args.y +-- @within Constructors +-- @constructor +-- @function Point + +local Point = ffi.typeof("Point_float") + +local Point_mt = { + -- operator '==' + __eq = function(self, rhs) + return self.x == rhs.x and + self.y == rhs.y + end; +} +ffi.metatype(Point, Point_mt) + +--- Point X position +-- @simplefield x + +--- Point Y position +-- @simplefield y + +return Point \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/rectangle_float.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/rectangle_float.lua new file mode 100644 index 0000000..9d1f0d7 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/rectangle_float.lua @@ -0,0 +1,89 @@ +--- A floating-point (sub-pixel) rectangle. +-- Is converted to a [JUCE Rectangle](http://www.juce.com/api/classRectangle.html) +-- @classmod juce.Rectangle_float + +--- Constuctor with classical arguments. +-- @param x left position +-- @param y top position +-- @param w width +-- @param h height +-- @within Constructors +-- @constructor +-- @function Rectangle_float + +--- Constuctor with named arguments. +-- Every field is optional. +-- @tparam table args +-- @param args.x left position +-- @param args.y top position +-- @param args.w width +-- @param args.h height +-- @within Constructors +-- @constructor +-- @function Rectangle_float + +local Rectangle_float = ffi.typeof("Rectangle_float") + +local Rectangle_int = {} -- circular dependency technique + +local Rectangle_float_mt = { + -- operator '==' + __eq = function(self, rhs) + return self.x == rhs.x and + self.y == rhs.y and + self.w == rhs.w and + self.h == rhs.h + end; + -- methods + __index = { + + --- To int. + -- Convert to a pixel-aligned rectangle + -- @treturn juce.Rectangle_int + -- @function toInt + toInt = function (self) + Rectangle_int = Rectangle_float or require"include/protojuce/rectangle_int" + return Rectangle_int { + self.x, self.y, self.w, self.h + } + end; + + --- Contains. + -- @tparam juce.Point point + -- @treturn boolean whether the rectangle contains the point + -- @function contains + contains = function (self, p) + return p.x>=self.x and p.x<=(self.x+self.w) and + p.y>=self.y and p.y<=(self.y+self.h) + end; + + --- Get right. + -- @return the rectangle's right position on the X axis + -- @function getR + getR = function (self) + return self.x + self.w + end; + + --- Get bottom. + -- @return the rectangle's bottom position on the Y axis + -- @function getB + getB = function (self) + return self.y + self.h + end; + }; +} +ffi.metatype(Rectangle_float, Rectangle_float_mt) + +--- Left position +-- @simplefield x + +--- Top position +-- @simplefield y + +--- Width +-- @simplefield w + +--- Height +-- @simplefield h + +return Rectangle_float \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/rectangle_int.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/rectangle_int.lua new file mode 100644 index 0000000..58c91a0 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/rectangle_int.lua @@ -0,0 +1,89 @@ +--- An integer (pixel-aligned) rectangle. +-- Is converted to a [JUCE Rectangle](http://www.juce.com/api/classRectangle.html) +-- @classmod juce.Rectangle_int + +--- Constuctor with classical arguments. +-- @param x left position +-- @param y top position +-- @param w width +-- @param h height +-- @within Constructors +-- @constructor +-- @function Rectangle_int + +--- Constuctor with named arguments. +-- Every field is optional. +-- @tparam table args +-- @param args.x left position +-- @param args.y top position +-- @param args.w width +-- @param args.h height +-- @within Constructors +-- @constructor +-- @function Rectangle_int + +local Rectangle_int = ffi.typeof("Rectangle_int") + +local Rectangle_float = {} -- circular dependency technique + +local Rectangle_int_mt = { + -- operator '==' + __eq = function(self, rhs) + return self.x == rhs.x and + self.y == rhs.y and + self.w == rhs.w and + self.h == rhs.h + end; + -- methods + __index = { + + --- To float. + -- Convert to a sub-pixel rectangle + -- @treturn juce.Rectangle_float + -- @function toFloat + toFloat = function (self) + Rectangle_float = Rectangle_float or require"include/protojuce/rectangle_float" + return Rectangle_float { + self.x, self.y, self.w, self.h + } + end; + + --- Contains. + -- @tparam juce.Point point + -- @treturn boolean whether the rectangle contains the point + -- @function contains + contains = function (self, p) + return p.x>=self.x and p.x<=(self.x+self.w) and + p.y>=self.y and p.y<=(self.y+self.h) + end; + + --- Get right. + -- @return the rectangle's right position on the X axis + -- @function getR + getR = function (self) + return self.x + self.w + end; + + --- Get bottom. + -- @return the rectangle's bottom position on the Y axis + -- @function getB + getB = function (self) + return self.y + self.h + end; + }; +} +ffi.metatype(Rectangle_int, Rectangle_int_mt) + +--- Left position +-- @simplefield x + +--- Top position +-- @simplefield y + +--- Width +-- @simplefield w + +--- Height +-- @simplefield h + +return Rectangle_int \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protojuce/rectangleplacement.lua b/ports/protoplug/ProtoplugFiles/include/protojuce/rectangleplacement.lua new file mode 100644 index 0000000..a5457da --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protojuce/rectangleplacement.lua @@ -0,0 +1,22 @@ +--- Rectangle Placement. +-- Is converted to a [JUCE RectanglePlacement](http://www.juce.com/api/RectanglePlacement.html) +-- @classmod juce.RectanglePlacement + +--- Rectangle Placement Constants. +-- @table juce.RectanglePlacement +local r = { + xLeft = 1; + xRight = 2; + xMid = 4; + yTop = 8; + yBottom = 16; + yMid = 32; + stretchToFit = 64; + fillDestination = 128; + onlyReduceInSize = 256; + onlyIncreaseInSize = 512; + doNotResize = 768; + centred = 4 + 32 +} + +return r \ No newline at end of file diff --git a/ports/protoplug/ProtoplugFiles/include/protoplug.lua b/ports/protoplug/ProtoplugFiles/include/protoplug.lua new file mode 100644 index 0000000..95bec45 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/include/protoplug.lua @@ -0,0 +1,19 @@ +-- protoplug.lua +-- basic globals for every protoplug script + +-- luaJIT +ffi = require "ffi" +bit = require "bit" + +-- load protoplug as a dynamic library using ffi +protolib = ffi.load(protoplug_path) + +juce = require "include/protojuce" + +midi = require "include/core/midi" +script = require "include/core/script" +plugin = require "include/core/plugin" +gui = require "include/core/gui" +polyGen = require "include/core/polygen" +stereoFx = require "include/core/stereofx" + diff --git a/ports/protoplug/ProtoplugFiles/prefs.default.xml b/ports/protoplug/ProtoplugFiles/prefs.default.xml new file mode 100644 index 0000000..9cedce2 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/prefs.default.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/ProtoplugFiles/themes/SciTE black mod.xml b/ports/protoplug/ProtoplugFiles/themes/SciTE black mod.xml new file mode 100644 index 0000000..f107cef --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/themes/SciTE black mod.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/ProtoplugFiles/themes/juce default.xml b/ports/protoplug/ProtoplugFiles/themes/juce default.xml new file mode 100644 index 0000000..0efabf7 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/themes/juce default.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/ProtoplugFiles/themes/npp blackboard.xml b/ports/protoplug/ProtoplugFiles/themes/npp blackboard.xml new file mode 100644 index 0000000..bc34ed7 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/themes/npp blackboard.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/ProtoplugFiles/themes/npp default.xml b/ports/protoplug/ProtoplugFiles/themes/npp default.xml new file mode 100644 index 0000000..f028350 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/themes/npp default.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/ProtoplugFiles/themes/npp hello kitty.xml b/ports/protoplug/ProtoplugFiles/themes/npp hello kitty.xml new file mode 100644 index 0000000..5e83153 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/themes/npp hello kitty.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/ProtoplugFiles/themes/npp mono industrial.xml b/ports/protoplug/ProtoplugFiles/themes/npp mono industrial.xml new file mode 100644 index 0000000..57d00c7 --- /dev/null +++ b/ports/protoplug/ProtoplugFiles/themes/npp mono industrial.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ports/protoplug/Source/BinaryData.cpp b/ports/protoplug/Source/BinaryData.cpp new file mode 100644 index 0000000..60907ed --- /dev/null +++ b/ports/protoplug/Source/BinaryData.cpp @@ -0,0 +1,71 @@ +/* ==================================== JUCER_BINARY_RESOURCE ==================================== + + This is an auto-generated file: Any edits you make may be overwritten! + +*/ + +namespace BinaryData +{ + +//================== lua-16.png ================== +static const unsigned char temp_binary_data_0[] = +{ 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,97,0,0,1,24,73,68,65,84,56,141,149,147,61,78,3,49,16,133,223,216,102,181,252,72,81,138,40,74,131,4,71,200,17,16,53,125,202,228,14,72,217,2,25,87,4,137,75,80,114,11,10, +106,238,145,52,9,18,18,171,104,226,161,8,113,204,254,37,251,26,91,99,127,207,51,242,12,161,165,140,113,83,102,255,180,221,171,140,218,26,0,86,254,25,54,189,176,143,169,140,217,206,170,236,104,127,169,12,198,82,138,62,147,68,61,51,203,117,92,130,58,4, +143,199,87,16,121,196,102,99,135,163,209,229,27,0,36,201,201,93,167,147,14,153,237,140,170,234,138,181,88,220,163,215,59,7,0,204,231,223,24,12,94,126,68,220,89,200,204,24,55,173,131,1,4,24,0,250,253,11,136,224,52,102,84,83,221,0,48,153,188,150,246,49, +67,77,233,239,212,237,166,16,1,86,171,60,138,58,2,42,190,177,74,203,101,94,123,166,142,49,40,138,136,56,24,24,163,178,182,6,90,211,67,48,219,46,86,210,212,32,207,185,142,41,200,133,6,252,107,36,149,173,215,252,117,12,90,204,88,3,128,247,239,31,90,223, +192,123,185,61,4,23,103,162,52,141,81,91,203,238,188,105,152,126,1,241,29,109,224,248,198,121,57,0,0,0,0,73,69,78,68,174,66,96,130,0,0 }; + +const char* lua16_png = (const char*) temp_binary_data_0; + +//================== lua-32.png ================== +static const unsigned char temp_binary_data_1[] = +{ 137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0,0,115,122,122,244,0,0,5,54,73,68,65,84,88,133,189,150,107,108,83,101,24,199,255,239,123,78,47,235,122,177,237,202,50,24,142,49,32,97,42,48,8,226,5,89,100,16,65,72,70,204,8,32,137, +132,24,3,146,8,209,152,176,193,88,41,12,8,160,120,201,34,16,140,176,15,106,36,40,34,36,154,96,2,36,98,48,192,46,162,136,72,22,182,193,230,24,237,232,189,61,59,231,60,126,88,90,183,222,104,65,124,62,157,247,185,253,254,231,205,123,99,248,31,204,110,223, +109,242,251,163,47,9,2,115,136,34,107,245,251,235,47,196,98,236,81,195,117,186,237,243,36,73,254,130,8,142,56,148,241,31,172,86,117,153,199,227,242,241,71,9,183,217,26,199,72,146,252,205,112,56,0,16,169,11,124,62,254,9,0,60,82,1,129,128,178,138,8,166, +84,49,69,81,151,143,30,189,211,46,102,219,172,184,248,125,219,157,59,225,89,170,42,79,34,130,13,32,98,140,185,181,90,225,47,135,195,120,161,179,243,237,123,201,16,140,75,215,143,8,66,48,40,148,100,20,176,116,233,81,225,228,201,107,75,37,73,89,123,251, +182,111,54,17,132,132,54,144,101,25,93,93,30,89,20,157,103,52,26,225,64,56,172,124,11,184,84,0,96,12,29,233,122,51,166,202,38,147,120,51,237,34,212,235,93,207,75,18,29,80,85,122,50,147,200,68,227,156,181,232,116,108,109,56,236,188,88,80,208,88,228,118, +15,254,65,4,75,98,158,32,176,35,138,178,117,117,202,53,160,213,186,106,163,81,245,92,174,112,0,80,85,154,30,137,168,231,181,90,215,250,187,119,235,123,13,6,113,9,231,236,239,225,57,162,200,191,179,217,10,222,2,82,108,67,65,216,186,87,81,232,221,92,160, +99,198,152,177,106,213,84,148,150,90,209,209,49,128,230,230,54,244,244,248,145,151,39,238,8,135,183,212,23,21,29,52,184,221,253,85,68,170,221,96,208,180,123,189,117,173,177,218,17,2,180,218,109,27,36,73,249,48,23,120,85,85,41,142,31,95,14,147,73,23,247, +249,124,81,84,87,127,137,179,103,111,66,167,19,222,136,70,27,62,77,87,31,23,96,48,108,155,26,14,43,23,137,160,201,22,110,52,106,209,209,177,1,14,71,126,82,172,175,47,128,178,178,143,16,10,13,134,141,70,161,194,239,111,248,51,85,143,248,26,136,68,212, +143,115,129,3,192,252,249,101,41,225,0,80,88,104,68,85,213,120,16,33,47,16,80,62,72,215,131,15,253,201,142,74,85,165,57,185,192,1,160,160,192,144,49,110,183,15,197,137,176,208,98,217,53,35,173,128,72,68,126,61,87,56,0,180,182,246,102,140,183,181,253, +187,248,3,1,41,37,131,59,157,78,174,170,234,203,15,34,224,210,165,30,156,58,117,61,101,236,196,137,107,9,2,105,81,74,1,251,246,9,101,170,10,123,204,161,209,8,88,184,112,34,4,33,187,107,98,197,138,99,104,110,110,131,44,171,0,0,89,86,113,248,112,43,86, +174,252,122,68,158,162,208,227,5,5,251,138,18,235,153,193,176,125,65,40,36,127,31,115,88,173,121,240,120,54,194,100,218,137,64,64,202,74,196,80,157,30,99,199,90,208,213,229,197,189,123,145,148,57,122,189,248,66,36,178,229,167,225,62,49,18,33,115,214, +148,12,54,48,16,193,192,64,106,112,204,6,7,213,164,155,145,139,34,228,108,33,155,55,207,65,77,77,121,124,92,91,59,27,203,150,13,157,214,115,231,150,226,202,149,117,240,120,54,162,187,251,29,172,94,93,145,170,69,18,139,107,181,66,127,182,2,26,27,231,198, +183,22,0,236,218,53,47,190,21,155,154,22,193,233,60,3,155,109,55,106,106,190,194,158,61,243,147,234,117,186,100,150,104,54,179,171,193,32,136,232,225,158,103,21,21,251,161,40,132,113,227,30,195,196,137,118,232,245,35,111,122,198,152,108,177,56,174,135, +66,35,235,120,79,207,38,55,99,248,237,97,224,0,208,212,84,9,183,123,35,218,219,223,196,228,201,142,164,56,99,116,177,183,119,77,40,209,47,2,128,40,242,99,146,164,62,149,13,136,165,152,167,9,19,108,168,174,158,129,162,162,247,16,10,13,194,106,213,99,253, +250,89,35,65,34,63,38,165,216,84,34,0,152,205,194,33,183,91,174,35,226,250,88,192,229,122,17,146,164,196,19,143,30,29,154,36,34,160,162,162,8,45,45,107,208,223,31,4,0,248,253,18,116,58,17,149,149,37,112,187,195,56,125,250,53,136,34,71,73,137,5,157,157, +94,112,206,2,163,70,25,143,220,186,149,225,207,52,154,173,187,1,39,233,245,219,233,208,161,115,148,104,229,229,77,100,52,238,136,143,235,234,126,36,34,162,105,211,246,19,224,164,197,139,63,39,175,55,66,94,111,132,102,206,60,72,87,175,246,147,215,27,33, +192,73,90,173,171,33,237,140,198,62,10,11,247,230,247,247,7,91,84,149,38,101,208,153,179,113,206,126,29,63,222,250,244,141,27,27,162,25,5,0,64,126,254,182,39,194,97,229,188,170,38,191,225,30,196,24,99,119,77,38,237,179,62,223,166,27,105,5,14,31,4,131, +13,191,235,116,154,5,156,51,207,127,0,191,35,138,124,94,38,120,146,0,0,8,135,235,47,228,231,243,103,56,71,107,170,130,108,140,115,252,98,54,235,102,13,14,54,180,223,47,87,72,229,148,164,51,158,233,211,95,253,204,237,14,13,16,161,130,8,169,159,61,201, +224,94,65,224,181,138,82,190,46,26,93,59,144,77,205,125,79,191,146,18,167,190,175,79,120,69,150,105,9,145,250,156,162,96,116,172,142,49,16,231,172,155,49,252,44,138,252,120,113,177,229,68,186,197,246,192,2,18,109,202,148,189,249,221,221,17,27,99,26,42, +45,181,122,46,95,78,62,221,114,177,127,0,23,64,50,140,198,53,156,205,0,0,0,0,73,69,78,68,174,66,96,130,0,0 }; + +const char* lua32_png = (const char*) temp_binary_data_1; + + +const char* getNamedResource (const char*, int&) throw(); +const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw() +{ + unsigned int hash = 0; + if (resourceNameUTF8 != 0) + while (*resourceNameUTF8 != 0) + hash = 31 * hash + (unsigned int) *resourceNameUTF8++; + + switch (hash) + { + case 0x68c81707: numBytes = 337; return lua16_png; + case 0x6bf96a41: numBytes = 1391; return lua32_png; + default: break; + } + + numBytes = 0; + return 0; +} + +const char* namedResourceList[] = +{ + "lua16_png", + "lua32_png" +}; + +} diff --git a/ports/protoplug/Source/BinaryData.h b/ports/protoplug/Source/BinaryData.h new file mode 100644 index 0000000..f320a85 --- /dev/null +++ b/ports/protoplug/Source/BinaryData.h @@ -0,0 +1,29 @@ +/* ========================================================================================= + + This is an auto-generated file: Any edits you make may be overwritten! + +*/ + +#ifndef BINARYDATA_H_17170897_INCLUDED +#define BINARYDATA_H_17170897_INCLUDED + +namespace BinaryData +{ + extern const char* lua16_png; + const int lua16_pngSize = 337; + + extern const char* lua32_png; + const int lua32_pngSize = 1391; + + // Points to the start of a list of resource names. + extern const char* namedResourceList[]; + + // Number of elements in the namedResourceList array. + const int namedResourceListSize = 2; + + // If you provide the name of one of the binary resource variables above, this function will + // return the corresponding data and its size (or a null pointer if the name isn't found). + const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw(); +} + +#endif diff --git a/ports/protoplug/Source/JuceHeader.h b/ports/protoplug/Source/JuceHeader.h new file mode 100644 index 0000000..f5954a1 --- /dev/null +++ b/ports/protoplug/Source/JuceHeader.h @@ -0,0 +1,42 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + + This is the header file that your files should include in order to get all the + JUCE library headers. You should avoid including the JUCE headers directly in + your own source files, because that wouldn't pick up the correct configuration + options for your app. + +*/ + +#ifndef __APPHEADERFILE_RZMZHD__ +#define __APPHEADERFILE_RZMZHD__ + +#include "JucePluginMain.h" +#include "BinaryData.h" + +#if ! DONT_SET_USING_JUCE_NAMESPACE + // If your code uses a lot of JUCE classes, then this will obviously save you + // a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE. + using namespace juce; +#endif + +#if ! PROTOPLUGFX + #define _PROTOGEN +#endif + +#if ! JUCE_DONT_DECLARE_PROJECTINFO +namespace ProjectInfo +{ +#if PROTOPLUGFX + const char* const projectName = "protoplug_fx"; +#else + const char* const projectName = "protoplug_gen"; +#endif + const char* const versionString = "1.3.0"; + const int versionNumber = 0x10300; +} +#endif + +#endif // __APPHEADERFILE_RZMZHD__ diff --git a/ports/protoplug/Source/JucePluginCharacteristics.h b/ports/protoplug/Source/JucePluginCharacteristics.h new file mode 100644 index 0000000..ae5f146 --- /dev/null +++ b/ports/protoplug/Source/JucePluginCharacteristics.h @@ -0,0 +1,77 @@ +/* + + IMPORTANT! This file is auto-generated each time you save your + project - if you alter its contents, your changes may be overwritten! + + There's a section below where you can add your own custom code safely, and the + Introjucer will preserve the contents of that block, but the best way to change + any of these definitions is by using the Introjucer's project settings. + + Any commented-out settings will assume their default values. + +*/ + +#ifndef __JUCE_APPCONFIG_DVRNRZ__ +#define __JUCE_APPCONFIG_DVRNRZ__ + +//============================================================================== +// Audio plugin settings.. + +#if PROTOPLUGFX + #define JucePlugin_Name "Lua Protoplug Fx" + #define JucePlugin_Desc "Lua Protoplug Effect" + #define JucePlugin_PluginCode 'ppgf' +#else + #define JucePlugin_Name "Lua Protoplug Gen" + #define JucePlugin_Desc "Lua Protoplug Generator (Instrument)" + #define JucePlugin_PluginCode 'ppgg' +#endif + +#define JucePlugin_Manufacturer "pac" +#define JucePlugin_ManufacturerWebsite "" +#define JucePlugin_ManufacturerEmail "" +#define JucePlugin_ManufacturerCode '_PAC' +#define JucePlugin_MaxNumInputChannels 2 +#define JucePlugin_MaxNumOutputChannels 2 +#define JucePlugin_PreferredChannelConfigurations {2, 2} +#define JucePlugin_IsSynth PROTOPLUGFX +#define JucePlugin_WantsMidiInput 1 +#define JucePlugin_ProducesMidiOutput 1 +#define JucePlugin_SilenceInProducesSilenceOut 0 +#define JucePlugin_EditorRequiresKeyboardFocus 1 +#define JucePlugin_Version 1.3.0 +#define JucePlugin_VersionCode 0x10300 +#define JucePlugin_VersionString "1.3.0" +#define JucePlugin_VSTUniqueID JucePlugin_PluginCode + +#if PROTOPLUGFX + #define JucePlugin_VSTCategory kPlugCategEffect + #define JucePlugin_AUMainType kAudioUnitType_MusicEffect + #define JucePlugin_AUExportPrefix protoplug_fxAU + #define JucePlugin_AUExportPrefixQuoted "protoplug_fxAU" + #define JucePlugin_CFBundleIdentifier com.pac.protoplugfx + #define JucePlugin_RTASCategory ePlugInCategory_None + #define JucePlugin_AAXIdentifier com.yourcompany.protoplug_fx +#else + #define JucePlugin_VSTCategory kPlugCategSynth + #define JucePlugin_AUMainType kAudioUnitType_MusicDevice + #define JucePlugin_AUExportPrefix protoplug_genAU + #define JucePlugin_AUExportPrefixQuoted "protoplug_genAU" + #define JucePlugin_CFBundleIdentifier com.pac.protopluggen + #define JucePlugin_RTASCategory ePlugInCategory_SWGenerators + #define JucePlugin_AAXIdentifier com.yourcompany.protoplug_gen +#endif + +#define JucePlugin_AUSubType JucePlugin_PluginCode +#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode +#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode +#define JucePlugin_RTASProductId JucePlugin_PluginCode +#define JucePlugin_RTASDisableBypass 0 +#define JucePlugin_RTASDisableMultiMono 0 +#define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode +#define JucePlugin_AAXProductId JucePlugin_PluginCode +#define JucePlugin_AAXCategory AAX_ePlugInCategory_Dynamics +#define JucePlugin_AAXDisableBypass 0 +#define JucePlugin_AAXDisableMultiMono 0 + +#endif // __JUCE_APPCONFIG_DVRNRZ__ diff --git a/ports/protoplug/Source/LuaCodeTokeniser.cpp b/ports/protoplug/Source/LuaCodeTokeniser.cpp new file mode 100644 index 0000000..fb6f21a --- /dev/null +++ b/ports/protoplug/Source/LuaCodeTokeniser.cpp @@ -0,0 +1,281 @@ +#include "LuaCodeTokeniser.h" + +struct LuaTokeniserFunctions +{ + static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept + { + static const char* const keywords2Char[] = + { "if", "or", "in", "do", nullptr }; + + static const char* const keywords3Char[] = + { "and", "end", "for", "nil", "not", nullptr }; + + static const char* const keywords4Char[] = + { "then", "true", "else", nullptr }; + + static const char* const keywords5Char[] = + { "false", "local", "until", "while", "break", nullptr }; + + static const char* const keywords6Char[] = + { "repeat", "return", "elseif", nullptr}; + + static const char* const keywords7Char[] = + { "require", 0 }; + + static const char* const keywordsOther[] = + { "function", "@interface", "@end", "@synthesize", "@dynamic", "@public", + "@private", "@property", "@protected", "@class", nullptr }; + + const char* const* k; + + switch (tokenLength) + { + case 2: k = keywords2Char; break; + case 3: k = keywords3Char; break; + case 4: k = keywords4Char; break; + case 5: k = keywords5Char; break; + case 6: k = keywords6Char; break; + case 7: k = keywords7Char; break; + + default: + if (tokenLength < 2 || tokenLength > 16) + return false; + + k = keywordsOther; + break; + } + + for (int i = 0; k[i] != 0; ++i) + if (token.compare (CharPointer_ASCII (k[i])) == 0) + return true; + + return false; + } + + template + static bool skipQuotedString (Iterator& source) noexcept + { + const juce_wchar quote = source.nextChar(); + + for (;;) + { + const juce_wchar c = source.nextChar(); + const juce_wchar next = source.peekNextChar(); + + if (c == quote) + break; + + if (c == 0 || c == '\n') + return false; + + if (c == '\\' && next != '\r' && next != '\n') + source.skip(); + } + return true; + } + + template + static int parseIdentifier (Iterator& source) noexcept + { + int tokenLength = 0; + String::CharPointerType::CharType possibleIdentifier [100]; + String::CharPointerType possible (possibleIdentifier); + + while (CppTokeniserFunctions::isIdentifierBody (source.peekNextChar())) + { + const juce_wchar c = source.nextChar(); + + if (tokenLength < 20) + possible.write (c); + + ++tokenLength; + } + + if (tokenLength > 1 && tokenLength <= 16) + { + possible.writeNull(); + + if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength)) + return LuaTokeniser::tokenType_keyword; + } + + return LuaTokeniser::tokenType_identifier; + } + + template + static int readNextToken (Iterator& source) + { + source.skipWhitespace(); + + const juce_wchar firstChar = source.peekNextChar(); + + switch (firstChar) + { + case 0: + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '.': + { + int result = CppTokeniserFunctions::parseNumber (source); + + if (result == LuaTokeniser::tokenType_error) + { + source.skip(); + + if (firstChar == '.') + return LuaTokeniser::tokenType_punctuation; + } + + return result; + } + + case ',': + case ';': + case ':': + source.skip(); + return LuaTokeniser::tokenType_punctuation; + + case '(': case ')': + case '{': case '}': + case ']': + source.skip(); + return LuaTokeniser::tokenType_bracket; + + case '[': + { + source.skip(); + if (source.peekNextChar() == '[') + { + // skip to ]] or eof + source.nextChar(); + for (;;) + { + const juce_wchar c = source.nextChar(); + if ((c == ']' && source.peekNextChar() == ']')|| c == 0) + { + source.skip(); + break; + } + } + return LuaTokeniser::tokenType_string; + } + return LuaTokeniser::tokenType_bracket; + } + + case '"': + case '\'': + if (skipQuotedString (source)) + return LuaTokeniser::tokenType_string; + else + return LuaTokeniser::tokenType_error; + + case '+': + source.skip(); + CppTokeniserFunctions::skipIfNextCharMatches (source, '+', '='); + return LuaTokeniser::tokenType_operator; + + case '-': + { + source.skip(); + int result = CppTokeniserFunctions::parseNumber (source); + + if (source.peekNextChar() == '-') + { + source.skip(); + if (source.peekNextChar() == '[') + { + source.skip(); + if (source.peekNextChar() == '[') + { + // skip to ]] or eof + source.nextChar(); + for (;;) + { + const juce_wchar c = source.nextChar(); + if ((c == ']' && source.peekNextChar() == ']')|| c == 0) + { + source.skip(); + break; + } + } + return LuaTokeniser::tokenType_comment; + } + } + + source.skipToEndOfLine(); + return LuaTokeniser::tokenType_comment; + } + + if (result == LuaTokeniser::tokenType_error) + { + CppTokeniserFunctions::skipIfNextCharMatches (source, '-', '='); + return LuaTokeniser::tokenType_operator; + } + + return result; + } + + case '*': case '%': + case '=': case '!': + source.skip(); + CppTokeniserFunctions::skipIfNextCharMatches (source, '='); + return LuaTokeniser::tokenType_operator; + + case '?': + case '~': + source.skip(); + return LuaTokeniser::tokenType_operator; + + case '<': case '>': + case '|': case '&': case '^': + source.skip(); + CppTokeniserFunctions::skipIfNextCharMatches (source, firstChar); + CppTokeniserFunctions::skipIfNextCharMatches (source, '='); + return LuaTokeniser::tokenType_operator; + + default: + if (CppTokeniserFunctions::isIdentifierStart (firstChar)) + return parseIdentifier (source); + + source.skip(); + break; + } + + return LuaTokeniser::tokenType_error; + } +}; + +//============================================================================== +ProtoLuaTokeniser::ProtoLuaTokeniser() {} +ProtoLuaTokeniser::~ProtoLuaTokeniser() {} + +int ProtoLuaTokeniser::readNextToken (CodeDocument::Iterator& source) +{ + return LuaTokeniserFunctions::readNextToken (source); +} + +CodeEditorComponent::ColourScheme ProtoLuaTokeniser::getDefaultColourScheme() +{ + static const CodeEditorComponent::ColourScheme::TokenType types[] = + { + { "Error", Colour (0xffcc0000) }, + { "Comment", Colour (0xff3c3c3c) }, + { "Keyword", Colour (0xff0000cc) }, + { "Operator", Colour (0xff225500) }, + { "Identifier", Colour (0xff000000) }, + { "Integer", Colour (0xff880000) }, + { "Float", Colour (0xff885500) }, + { "String", Colour (0xff990099) }, + { "Bracket", Colour (0xff000055) }, + { "Punctuation", Colour (0xff004400) } + }; + + CodeEditorComponent::ColourScheme cs; + + for (unsigned int i = 0; i < sizeof (types) / sizeof (types[0]); ++i) // (NB: numElementsInArray doesn't work here in GCC4.2) + cs.set (types[i].name, types[i].colour); + + return cs; +} diff --git a/ports/protoplug/Source/LuaCodeTokeniser.h b/ports/protoplug/Source/LuaCodeTokeniser.h new file mode 100644 index 0000000..8aca449 --- /dev/null +++ b/ports/protoplug/Source/LuaCodeTokeniser.h @@ -0,0 +1,37 @@ +#pragma once + +// Lua code tokeniser from Ctrlr project +// http://ctrlr.org + +#include "JuceHeader.h" + +class ProtoLuaTokeniser : public CodeTokeniser +{ +public: + //============================================================================== + ProtoLuaTokeniser(); + ~ProtoLuaTokeniser(); + + //============================================================================== + int readNextToken (CodeDocument::Iterator&) override; + CodeEditorComponent::ColourScheme getDefaultColourScheme() override; + + /** The token values returned by this tokeniser. */ + enum TokenType + { + tokenType_error = 0, + tokenType_comment, + tokenType_keyword, + tokenType_operator, + tokenType_identifier, + tokenType_integer, + tokenType_float, + tokenType_string, + tokenType_bracket, + tokenType_punctuation + }; + +private: + //============================================================================== + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProtoLuaTokeniser) +}; diff --git a/ports/protoplug/Source/LuaLink.cpp b/ports/protoplug/Source/LuaLink.cpp new file mode 100644 index 0000000..7bf8b47 --- /dev/null +++ b/ports/protoplug/Source/LuaLink.cpp @@ -0,0 +1,525 @@ +#include "LuaLink.h" +#include "PluginProcessor.h" +#include "PluginEditor.h" +#include "ProtoplugDir.h" +#include + +// exports for scripts +extern "C" { +#include "ProtoplugExports.h" +} + +// could be avoided by namespacing every callback into a userdata (eg. theme api) +std::map globalStates; + +static int LuaWriteLine (protolua::lua_State *L) { + LuaLink *luli = globalStates[L]; + if (!luli) return 0; + luli->addToLog(luli->ls->tolstring(1, 0)); + return 0; +} + +static int LuaSetParam (protolua::lua_State *L) { + LuaLink *luli = globalStates[L]; + if (!luli) return 0; + luli->pfx->setParameterNotifyingHost((int)luli->ls->tonumber(1), (float)luli->ls->tonumber(2)); + return 0; +} + +LuaLink::LuaLink(LuaProtoplugJuceAudioProcessor *_pfx) +{ + ls = 0; + guiThreadRunning = workable = iLuaLoaded = 0; + pfx = _pfx; + customGui = 0; + + libFolder = ProtoplugDir::Instance()->getScriptsDir().getFullPathName(); + code = File(libFolder).getChildFile("default.lua").loadFileAsString(); + // unfortunately we can't know whether the host will call setStateInformation or not, + // so the default script is always compiled even if we're loading something else + compile(); +} + +LuaLink::~LuaLink() +{ +} + +void LuaLink::initProtoplugDir() { + libFolder = ProtoplugDir::Instance()->getScriptsDir().getFullPathName(); + if (code.isEmpty()) + code = File(libFolder).getChildFile("default.lua").loadFileAsString(); +} + +void LuaLink::addToLog(String buf, bool isInput /*= false*/) { + if (log.length()>4000) + log = log.substring(log.length()-3000); + Time t = Time::getCurrentTime(); + if (isInput) + log += String::formatted("\n%02i:%02i > ", t.getMinutes(), t.getSeconds()); + else + log += String::formatted("\n%02i:%02i - ", t.getMinutes(), t.getSeconds()); + log += buf; + ped = pfx->getProtoEditor(); + if (ped) + ped->msg_UpdateLog = true; +} + +void LuaLink::compile() { + // first, write the code to a temp file in case of crash + File kk = File::getCurrentWorkingDirectory().getChildFile("protoplug last compile.lua"); + if (kk.create().wasOk()) + kk.replaceWithText(code); + + // save to keep user's data across compilations + String sd = save(); + if (sd.isNotEmpty()) + saveData = sd; + + // wait for running functions to finish and prevent new ones from happening + workable = iLuaLoaded = 0; + cs.enter(); + cs.exit(); + + if (ls) { + preClose(); + globalStates.erase(ls->l); + delete ls; + ls=0; + } + + ls = new protolua::LuaState(ProtoplugDir::Instance()->getLibDir()); + if (ls->failed) { + addToLog(ls->errmsg); + delete ls; + ls=0; + return; + } + ls->openlibs(); + ls->pushcclosure(LuaWriteLine, 0); + ls->setglobal("print"); + ls->pushcclosure(LuaSetParam, 0); + ls->setglobal("plugin_setParameter"); + + // set globals + ls->pushlightuserdata((void *)&pfx->params); + ls->setglobal("plugin_params"); + ls->pushlightuserdata((void *)&customGui); + ls->setglobal("gui_component"); + ls->pushstring(File::getSpecialLocation(File::currentExecutableFile).getFullPathName().getCharPointer().getAddress()); + ls->setglobal("protoplug_path"); + ls->pushstring(ProtoplugDir::Instance()->getDir().getFullPathName().getCharPointer().getAddress()); + ls->setglobal("protoplug_dir"); + ls->pushnumber(1); + ls->setglobal("protoplug_version"); + ls->pushlightuserdata((AudioProcessor *)pfx); + ls->setglobal("plugin_effect"); + + // add plugin location to the include paths + String addPath = ProtoplugDir::Instance()->getDir().getFullPathName(); + ls->getglobal( "package" ); + ls->getfield(-1, "path" ); + String newpack, pack = ls->tolstring(-1,0 ); + newpack << addPath << "/?.lua;" << pack; + ls->pop(1 ); + ls->pushstring( newpack.getCharPointer().getAddress()); + ls->setfield(-2, "path" ); + ls->pop( 1 ); + + // compile + int error = ls->loadbuffer(code.getCharPointer().getAddress(), code.length(), "Lua Script"); + if (error) + { + addToLog(ls->tolstring(-1,0)); + return; + } + + // now callbacks might happen : associate the lua state to this plugin instance + globalStates[ls->l] = this; + addToLog("compile successful"); + + // run whole script + int result = ls->pcall(0, 0, 0); + if (result) { + addToLog(ls->tostring(-1)); + globalStates.erase(ls->l); + delete ls; // Cya, Lua + ls=0; + return; + } + + // call Init + ls->getglobal( "script_init"); + if (ls->isfunction(-1)){ + result = ls->pcall( 0, 0, 0); + if (result) { + addToLog(String("error calling script_init() : ")+ls->tostring(-1)); + globalStates.erase(ls->l); + delete ls; // Cya, Lua + ls=0; + return; + } + } else + ls->pop( 1); // pop nil + + // bask in the glory of success + workable = 1; + + if (saveData.isNotEmpty()) + load(saveData); + + return; +} + +bool LuaLink::runString(String toRun) { + if (!workable) + return false; + ls->loadstring(toRun.getCharPointer().getAddress()); + int result = ls->pcall(0, 0, 0); + if (result) { + addToLog(ls->tostring(-1)); + return false; + // the rest still works, right? + /*globalStates.erase(ls->l); + delete ls; // Cya, Lua + ls=0; + return;*/ + } + return true; +} + +void LuaLink::runStringInteractive(String toRun) { + if (!workable) + return; + addToLog(toRun, true); + if (!iLuaLoaded) { + if (runString("require 'include/iluaembed'")) + iLuaLoaded = true; + else + return; + } + callVoidOverride("ilua_runline" , LUA_TSTRING, toRun.getCharPointer().getAddress(), 0); +} + +void LuaLink::stackDump () { + if (!workable) + return; + String dump = "Lua State Stack Dump : "; + int i; + int top = ls->gettop(); + for (i = 1; i <= top; i++) { + int t = ls->type(i); + switch (t) { + case LUA_TSTRING: + dump <<"`"<tostring(i)<<"'"; + break; + case LUA_TBOOLEAN: + dump<<"bool"; + break; + case LUA_TNUMBER: + dump << ls->tonumber(i); + break; + default: + dump << ls->ltypename(t); + break; + } + dump << " "; // separator + } + dump << ""; + addToLog(dump); +} + +bool LuaLink::startOverride(const char *fname) +{ + if (!workable) + return false; + ls->getglobal( fname); + if (!ls->isfunction( -1)) { + ls->pop( 1); // pop nil or you will die + return false; + } + return true; +} + +int LuaLink::startVarargOverride(const char *fname, va_list _args) +{ + if (!startOverride(fname)) + return -1; + int numArgs = 0; + int type = 0; + while (type = va_arg(_args, int)) { + numArgs++; + switch (type) { + case LUA_TBOOLEAN: + ls->pushboolean(va_arg(_args, bool)); + break; + case LUA_TLIGHTUSERDATA: + ls->pushlightuserdata(va_arg(_args, void*)); + break; + case LUA_TNUMBER: + ls->pushnumber(va_arg(_args, double)); + break; + case LUA_TSTRING: + ls->pushstring(va_arg(_args, char*)); + break; + default: + juce_breakDebugger; + } + } + return numArgs; +} + +int LuaLink::safepcall(const char *fname, int nargs, int nresults, int errfunc) +{ + int result = ls->pcall(nargs, nresults, errfunc); + if (result) { + addToLog(String("error calling ")+fname+String("() : ")+ls->tostring(-1)); + workable = 0; + globalStates.erase(ls->l); + delete ls; // Cya, Lua + ls=0; + } + return result; +} + +bool LuaLink::callVoidOverride(const char *fname, ...) +{ + const GenericScopedLock lok(cs); + va_list args; + va_start(args, fname); + int numArgs = startVarargOverride(fname, args); + va_end(args); + if (numArgs<0) + return false; // state or function does not exist + safepcall (fname, numArgs, 0, 0); + return true; +} + +String LuaLink::callStringOverride(const char *fname, ...) +{ + const GenericScopedLock lok(cs); + va_list args; + va_start(args, fname); + int numArgs = startVarargOverride(fname, args); + va_end(args); + if (numArgs<0) + return String::empty; // state or function does not exist + if (safepcall (fname, numArgs, 1, 0)) + return String::empty; // function crashed + return safetostring(); +} + +bool LuaLink::callBoolOverride(const char *fname, ...) +{ + const GenericScopedLock lok(cs); + va_list args; + va_start(args, fname); + int numArgs = startVarargOverride(fname, args); + va_end(args); + if (numArgs<0) + return false; // state or function does not exist + if (safepcall (fname, numArgs, 1, 0)) + return false; // function crashed + return safetobool(); +} + +bool LuaLink::safetobool() +{ + if (!ls->isboolean(-1)) { + ls->settop(0); + return false; // there is no bool + } + bool ret = ls->toboolean(-1)!=0; + ls->settop(0); + return ret; +} + +String LuaLink::safetostring() +{ + if (!ls->isstring(-1)) { + ls->settop(0); + return String::empty; // there is no string + } + String ret = ls->tostring(-1); + ls->settop(0); + return ret; +} + +double LuaLink::getTailLengthSeconds() +{ + const GenericScopedLock lok(cs); + if (!workable) + return 0.0; + + ls->getglobal( "plugin_getTailLengthSeconds"); + if (!ls->isfunction(-1)) { + ls->pop( 1); // pop nil or you will die + return 0.0; + } + int result = ls->pcall( 0, 1, 0); + if (result) { + addToLog(String("error calling plugin_getTailLengthSeconds() : ")+ls->tostring(-1)); + workable = 0; + globalStates.erase(ls->l); + delete ls; // Cya, Lua + ls=0; + return 0.0; + } + if (!ls->isnumber(-1)) { + ls->pop( 1); + return 0.0; + } + double ret = ls->tonumber(-1); + ls->pop( 1); // pop returned value + return ret; +} + +void LuaLink::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages, AudioPlayHead* ph) +{ + bool res = callVoidOverride("plugin_processBlock" , LUA_TNUMBER, (double)buffer.getNumSamples(), + LUA_TLIGHTUSERDATA, buffer.getArrayOfChannels(), + LUA_TLIGHTUSERDATA, &midiMessages, + LUA_TLIGHTUSERDATA, ph, + LUA_TNUMBER, pfx->getSampleRate(), + 0); +#ifdef _PROTOGEN + if (!res) { + for (int channel = 0; channel < pfx->getNumOutputChannels(); ++channel) + { + buffer.clear (channel, 0, buffer.getNumSamples()); + } + } +#endif +} + +String LuaLink::getParameterName (int index) +{ return callStringOverride("plugin_getParameterName", LUA_TNUMBER, (double)index, 0); } + +String LuaLink::getParameterText (int index) +{ return callStringOverride("plugin_getParameterText", LUA_TNUMBER, (double)index, 0); } + +bool LuaLink::parameterText2Double (int index, String text, double &d) +{ + const GenericScopedLock lok(cs); + if (startOverride("plugin_parameterText2Double")) { + ls->pushnumber(index); + ls->pushstring(text.getCharPointer().getAddress()); + safepcall ("plugin_parameterText2Double", 2, 1, 0); + if (!ls->isnumber(-1)) { + ls->settop(0); + return false; // there is no number + } + double ret = ls->tonumber(-1); + ls->settop(0); + d = ret; + return true; + } else return false; // there is no function +} + +void LuaLink::paramChanged (int index) +{ callVoidOverride("plugin_paramChanged" , LUA_TNUMBER, (double)index, 0); } + +String LuaLink::save () +{ return callStringOverride("script_saveData", 0); } + +void LuaLink::load(String loadData) +{ callVoidOverride("script_loadData" , LUA_TSTRING, loadData.getCharPointer().getAddress(), 0); } + +void LuaLink::preClose () +{ callVoidOverride("script_preClose", 0); } + +void LuaLink::paint (Graphics& g) +{ + if (!callVoidOverride("gui_paint" , LUA_TLIGHTUSERDATA, &g, 0)) + { + g.fillAll(); + g.setColour(Colours::grey); + g.drawText("Override gui.paint to paint a gui here !", g.getClipBounds(), Justification::centred, false); + } +} + +void LuaLink::resized () +{ callVoidOverride("gui_resized", 0); } + + +void LuaLink::mouseOverride (const char *fname, const MouseEvent& event) +{ + const GenericScopedLock lok(cs); + if (startOverride(fname)) { + exMouseEvent exEvent = MouseEvent2Struct(event); + ls->pushlightuserdata(&exEvent); + /* pass by value experimental version - allows Lua to manage the data, + * but not in the spirit of LuaJIT (i think) and probably slower + exMouseEvent *em = (exMouseEvent *)ls->newuserdata(sizeof(exMouseEvent)); + em->initFrom(event);*/ + safepcall (fname, 1, 0, 0); + } +} + +void LuaLink::mouseMove (const MouseEvent& event) +{ mouseOverride ("gui_mouseMove", event); } + +void LuaLink::mouseEnter (const MouseEvent& event) +{ mouseOverride ("gui_mouseEnter", event); } + +void LuaLink::mouseExit (const MouseEvent& event) +{ mouseOverride ("gui_mouseExit", event); } + +void LuaLink::mouseDown (const MouseEvent& event) +{ mouseOverride ("gui_mouseDown", event); } + +void LuaLink::mouseDrag (const MouseEvent& event) +{ mouseOverride ("gui_mouseDrag", event); } + +void LuaLink::mouseUp (const MouseEvent& event) +{ mouseOverride ("gui_mouseUp", event); } + +void LuaLink::mouseDoubleClick (const MouseEvent& event) +{ mouseOverride ("gui_mouseDoubleClick", event); } + +void LuaLink::mouseWheelMove (const MouseEvent& event, const MouseWheelDetails& wheel) +{ + const GenericScopedLock lok(cs); + if (startOverride("gui_mouseWheelMove")) { + exMouseEvent exEvent = MouseEvent2Struct(event); + ls->pushlightuserdata(&exEvent); + exMouseWheelDetails exWheel = MouseWheelDetails2Struct(wheel); + ls->pushlightuserdata(&exWheel); + // pass by value version (see above) + //((exMouseEvent *)ls->newuserdata(sizeof(exMouseEvent)))->init(event); + //((exMouseWheelDetails*)ls->newuserdata(sizeof(exMouseWheelDetails)))->init(wheel); + safepcall ("gui_mouseWheelMove", 2, 0, 0); + } +} + +bool LuaLink::keyPressed (const KeyPress &key, Component *originatingComponent) +{ + const GenericScopedLock lok(cs); + if (startOverride("gui_keyPressed")) { + exKeyPress exKey = KeyPress2Struct(key); + ls->pushlightuserdata(&exKey); + ls->pushlightuserdata(originatingComponent); + safepcall ("gui_keyPressed", 2, 0, 0); + return safetobool(); + } else return false; +} + +bool LuaLink::keyStateChanged (bool isKeyDown, Component *originatingComponent) +{ + const GenericScopedLock lok(cs); + if (startOverride("gui_keyStateChanged")) { + ls->pushboolean(isKeyDown); + ls->pushlightuserdata(originatingComponent); + safepcall ("gui_keyStateChanged", 2, 1, 0); + return safetobool(); + } else return false; +} + +void LuaLink::modifierKeysChanged (const ModifierKeys &modifiers) +{ callVoidOverride("gui_modifierKeysChanged", LUA_TNUMBER, (double)modifiers.getRawFlags(), 0); } + +void LuaLink::focusGained (Component::FocusChangeType cause) +{ callVoidOverride("gui_focusGained", LUA_TNUMBER, (double)cause, 0); } + +void LuaLink::focusLost (Component::FocusChangeType cause) +{ callVoidOverride("gui_focusLost", LUA_TNUMBER, (double)cause, 0); } + diff --git a/ports/protoplug/Source/LuaLink.h b/ports/protoplug/Source/LuaLink.h new file mode 100644 index 0000000..a04957b --- /dev/null +++ b/ports/protoplug/Source/LuaLink.h @@ -0,0 +1,76 @@ +#pragma once + +#include "JuceHeader.h" +#include "LuaState.h" + +class LuaProtoplugJuceAudioProcessor; +class ProtoWindow; + +class LuaLink +{ +public: + LuaLink(LuaProtoplugJuceAudioProcessor *pfx); + ~LuaLink(); + + void addToLog(String buf, bool isInput = false); + void compile(); + void stackDump(); + bool runString(String toRun); + void runStringInteractive(String toRun); + + // Audio plugin overrides : + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages, AudioPlayHead* ph); + String getParameterName (int index); + String getParameterText (int index); + bool parameterText2Double (int index, String text, double &d); + void paramChanged(int index); + double getTailLengthSeconds(); + String save(); + void load(String loadData); + void preClose(); + void initProtoplugDir(); + + // Custom GUI component overrides : + void paint (Graphics& g); + void resized (); + + void mouseMove (const MouseEvent& event); + void mouseEnter (const MouseEvent& event); + void mouseExit (const MouseEvent& event); + void mouseDown (const MouseEvent& event); + void mouseDrag (const MouseEvent& event); + void mouseUp (const MouseEvent& event); + void mouseDoubleClick (const MouseEvent& event); + void mouseWheelMove (const MouseEvent& event, const MouseWheelDetails& wheel); + bool keyPressed (const KeyPress &key, Component *originatingComponent); + bool keyStateChanged (bool isKeyDown, Component *originatingComponent); + void modifierKeysChanged (const ModifierKeys &modifiers); + void focusGained (Component::FocusChangeType cause); + void focusLost (Component::FocusChangeType cause); + + String code, libFolder, log, saveData; + protolua::LuaState *ls; + Component *customGui; + LuaProtoplugJuceAudioProcessor *pfx; + +private: + bool startOverride(const char *fname); + int startVarargOverride(const char *fname, va_list _args); + int safepcall(const char *fname, int nargs, int nresults, int errfunc); + + /** Calls a lua function if it has been defined, ignoring the return value + + add any parameters to be sent to the function, preceded by their type (as + defined in luastate.h) Last argument must be 0. + */ + bool callVoidOverride(const char *fname, ...); + String callStringOverride(const char *fname, ...); + bool callBoolOverride(const char *fname, ...); + bool safetobool(); + String safetostring(); + void mouseOverride (const char *fname, const MouseEvent& event); + + ProtoWindow *ped; + CriticalSection cs; + bool guiThreadRunning, workable, iLuaLoaded; +}; diff --git a/ports/protoplug/Source/LuaState.cpp b/ports/protoplug/Source/LuaState.cpp new file mode 100644 index 0000000..4064883 --- /dev/null +++ b/ports/protoplug/Source/LuaState.cpp @@ -0,0 +1,200 @@ +#include "LuaState.h" + +namespace protolua +{ + +DynamicLibrary * LuaState::dll = 0; +ptr_luaL_newstate LuaState::luaL_newstate = 0; +ptr_luaL_openlibs LuaState::luaL_openlibs = 0; +ptr_luaL_loadbuffer LuaState::luaL_loadbuffer = 0; +ptr_luaL_loadstring LuaState::luaL_loadstring = 0; +ptr_lua_tolstring LuaState::lua_tolstring = 0; +ptr_lua_tonumber LuaState::lua_tonumber = 0; +ptr_lua_toboolean LuaState::lua_toboolean = 0; +ptr_lua_pushcclosure LuaState::lua_pushcclosure = 0; +ptr_lua_close LuaState::lua_close = 0; +ptr_lua_gettop LuaState::lua_gettop = 0; +ptr_lua_settop LuaState::lua_settop = 0; +ptr_lua_pcall LuaState::lua_pcall = 0; +ptr_lua_getfield LuaState::lua_getfield = 0; +ptr_lua_pushlightuserdata LuaState::lua_pushlightuserdata = 0; +ptr_lua_pushstring LuaState::lua_pushstring = 0; +ptr_lua_pushnumber LuaState::lua_pushnumber = 0; +ptr_lua_pushboolean LuaState::lua_pushboolean = 0; +ptr_lua_type LuaState::lua_type = 0; +ptr_lua_setfield LuaState::lua_setfield = 0; +ptr_lua_isstring LuaState::lua_isstring = 0; +ptr_lua_isnumber LuaState::lua_isnumber = 0; +ptr_lua_typename LuaState::lua_typename = 0; +ptr_lua_newuserdata LuaState::lua_newuserdata = 0; +#if REQUIRE_JIT +ptr_luajit_setmode LuaState::luajit_setmode = 0; +#endif + +LuaState::LuaState(File defaultDir) +{ + l = 0; +#if JUCE_WINDOWS + String libName = "lua51.dll"; + String libName2 = "luajit.dll"; +#else + String libName = "libluajit-5.1.so"; + String libName2 = "libluajit-5.1.so.2"; +#endif + String defaultPath = defaultDir.getChildFile(libName).getFullPathName(); + if (!dll) { + dll = new DynamicLibrary(); + if (!dll->open(defaultPath)) + if (!dll->open(libName2)) + dll->open(libName); + // why + luaL_newstate = ptr_luaL_newstate (dll->getFunction("luaL_newstate")); + luaL_openlibs = ptr_luaL_openlibs (dll->getFunction("luaL_openlibs")); + luaL_loadbuffer = ptr_luaL_loadbuffer (dll->getFunction("luaL_loadbuffer")); + luaL_loadstring = ptr_luaL_loadstring (dll->getFunction("luaL_loadstring")); + lua_tolstring = ptr_lua_tolstring (dll->getFunction("lua_tolstring")); + lua_tonumber = ptr_lua_tonumber (dll->getFunction("lua_tonumber")); + lua_toboolean = ptr_lua_toboolean (dll->getFunction("lua_toboolean")); + lua_pushcclosure = ptr_lua_pushcclosure (dll->getFunction("lua_pushcclosure")); + lua_close = ptr_lua_close (dll->getFunction("lua_close")); + lua_gettop = ptr_lua_gettop (dll->getFunction("lua_gettop")); + lua_settop = ptr_lua_settop (dll->getFunction("lua_settop")); + lua_pcall = ptr_lua_pcall (dll->getFunction("lua_pcall")); + lua_getfield = ptr_lua_getfield (dll->getFunction("lua_getfield")); + lua_pushlightuserdata = ptr_lua_pushlightuserdata (dll->getFunction("lua_pushlightuserdata")); + lua_pushstring = ptr_lua_pushstring (dll->getFunction("lua_pushstring")); + lua_pushnumber = ptr_lua_pushnumber (dll->getFunction("lua_pushnumber")); + lua_pushboolean = ptr_lua_pushboolean (dll->getFunction("lua_pushboolean")); + lua_type = ptr_lua_type (dll->getFunction("lua_type")); + lua_setfield = ptr_lua_setfield (dll->getFunction("lua_setfield")); + lua_isstring = ptr_lua_isstring (dll->getFunction("lua_isstring")); + lua_isnumber = ptr_lua_isnumber (dll->getFunction("lua_isnumber")); + lua_typename = ptr_lua_typename (dll->getFunction("lua_typename")); + lua_newuserdata = ptr_lua_newuserdata (dll->getFunction("lua_newuserdata")); +#if REQUIRE_JIT + luajit_setmode = ptr_luajit_setmode (dll->getFunction("luaJIT_setmode")); +#endif + } + void *kk[23] = { + // cast required for some compilers + (void*)luaL_newstate, + (void*)luaL_openlibs, + (void*)luaL_loadbuffer, + (void*)luaL_loadstring, + (void*)lua_tolstring, + (void*)lua_tonumber, + (void*)lua_toboolean, + (void*)lua_pushcclosure, + (void*)lua_close, + (void*)lua_gettop, + (void*)lua_settop, + (void*)lua_pcall, + (void*)lua_getfield, + (void*)lua_pushlightuserdata, + (void*)lua_pushstring, + (void*)lua_pushnumber, + (void*)lua_pushboolean, + (void*)lua_type, + (void*)lua_setfield, + (void*)lua_isstring, + (void*)lua_isnumber, + (void*)lua_typename, + (void*)lua_newuserdata}; + for (int i=0; i<23; i++) + if (kk[i]==0) { + failed = 1; + errmsg = "Error: Could not load " + libName + + ". Tried " + defaultPath + " and system path."; + return; + } +#if REQUIRE_JIT + // in windows the luajit dll has the same name as plain lua, so do a sanity check + if (!luajit_setmode) { + failed = 1; + errmsg = "Error: linked with wrong " + libName + ". Library is Lua, but LuaJIT is required. " + + "Please add the luajit library in the system path or at " + defaultPath; + return; + } +#endif + failed = 0; + l = (*luaL_newstate)(); +} + +LuaState::~LuaState() { + if (l) // so, does your font suck ? + close(); +} + +void LuaState::openlibs() +{ (*luaL_openlibs)(l);} + +int LuaState::loadbuffer(const char *buff, size_t sz, const char *name) +{ return (*luaL_loadbuffer)(l, buff, sz, name);} + +int LuaState::loadstring(const char *buff) +{ return (*luaL_loadstring)(l, buff);} + +const char * LuaState::tolstring(int idx, size_t *len) +{ return (*lua_tolstring)(l, idx, len);} + +lua_Number LuaState::tonumber(int idx) +{ return (*lua_tonumber)(l, idx);} + +int LuaState::toboolean(int idx) +{ return (*lua_toboolean)(l, idx);} + +void LuaState::pushcclosure(lua_CFunction fn, int n) +{ (*lua_pushcclosure)(l, fn, n);} + +void LuaState::close() +{ (*lua_close)(l);} + +int LuaState::gettop() +{ return (*lua_gettop)(l);} + +void LuaState::settop(int idx) +{ (*lua_settop)(l, idx);} + +int LuaState::pcall(int nargs, int nresults, int errfunc) +{ return (*lua_pcall)(l, nargs, nresults, errfunc);} + +void LuaState::getfield(int idx, const char *k) +{ (*lua_getfield)(l, idx, k);} + +void LuaState::pushlightuserdata(void *p) +{ (*lua_pushlightuserdata)(l, p);} + +void LuaState::pushstring(const char *s) +{ (*lua_pushstring)(l, s);} + +void LuaState::pushnumber(lua_Number n) +{ (*lua_pushnumber)(l, n);} + +void LuaState::pushboolean(int b) +{ (*lua_pushboolean)(l, b);} + +int LuaState::type(int idx) +{ return (*lua_type)(l, idx);} + +void LuaState::setfield(int idx, const char *k) +{ (*lua_setfield)(l, idx, k);} + +int LuaState::isstring(int idx) +{ return (*lua_isstring)(l, idx);} + +int LuaState::isnumber(int idx) +{ return (*lua_isnumber)(l, idx);} + +const char * LuaState::ltypename(int t) +{ return (*lua_typename)(l, t);} + +void * LuaState::newuserdata(size_t sz) +{ return (*lua_newuserdata)(l, sz);} + +#if REQUIRE_JIT +int LuaState::jit_setmode(int idx, int mode) +{ return (*luajit_setmode)(l, idx, mode);} +#endif + + +} // namespace protolua diff --git a/ports/protoplug/Source/LuaState.h b/ports/protoplug/Source/LuaState.h new file mode 100644 index 0000000..cf86a87 --- /dev/null +++ b/ports/protoplug/Source/LuaState.h @@ -0,0 +1,142 @@ +#pragma once + +#include "JuceHeader.h" +#define REQUIRE_JIT 1 + +// lua types +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 +#define LUA_GLOBALSINDEX (-10002) + + +namespace protolua +{ +// from the lua headers : +typedef struct { } lua_State; +typedef double lua_Number; +typedef int (*lua_CFunction) (lua_State *L); + +// some function pointer types : +typedef lua_State* (*ptr_luaL_newstate) (); +typedef void (*ptr_luaL_openlibs) (lua_State *L); +typedef int (*ptr_luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, const char *name); +typedef int (*ptr_luaL_loadstring) (lua_State *L, const char *s); +typedef const char* (*ptr_lua_tolstring) (lua_State *L, int idx, size_t *len); +typedef lua_Number (*ptr_lua_tonumber) (lua_State *L, int idx); +typedef int (*ptr_lua_toboolean) (lua_State *L, int idx); +typedef void (*ptr_lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +typedef void (*ptr_lua_close) (lua_State *L); +typedef int (*ptr_lua_gettop) (lua_State *L); +typedef void (*ptr_lua_settop) (lua_State *L, int idx); +typedef int (*ptr_lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +typedef void (*ptr_lua_getfield) (lua_State *L, int idx, const char *k); +typedef void (*ptr_lua_pushlightuserdata)(lua_State *L, void *p); +typedef void (*ptr_lua_pushstring) (lua_State *L, const char *s); +typedef void (*ptr_lua_pushnumber) (lua_State *L, lua_Number n); +typedef void (*ptr_lua_pushboolean) (lua_State *L, int b); +typedef int (*ptr_lua_type) (lua_State *L, int idx); +typedef void (*ptr_lua_setfield) (lua_State *L, int idx, const char *k); +typedef int (*ptr_lua_isstring) (lua_State *L, int idx); +typedef int (*ptr_lua_isnumber) (lua_State *L, int idx); +typedef const char* (*ptr_lua_typename) (lua_State *L, int t); +typedef void * (*ptr_lua_newuserdata) (lua_State *L, size_t sz); +#if REQUIRE_JIT +typedef int (*ptr_luajit_setmode) (lua_State *L, int idx, int mode); +#endif + + +// the purpose of this abominable class is to load a lua/luajit dynamic library +// located at a chosen path at runtime and resolve its symbols, while remaining cross platform +// and giving a clear message if the library is missing. +// i don't really care about encapsulating lua in a c++ class but it happened as collateral damage +class LuaState +{ +public: + LuaState(File defaultDir); + ~LuaState(); + void openlibs(); + int loadbuffer(const char *buff, size_t sz, const char *name); + int loadstring(const char *s); + const char * tolstring(int idx, size_t *len); + lua_Number tonumber(int idx); + int toboolean(int idx); + void pushcclosure(lua_CFunction fn, int n); + void close(); + int gettop(); + void settop(int idx); + int pcall(int nargs, int nresults, int errfunc); + void getfield(int idx, const char *k); + void pushlightuserdata(void *p); + void pushstring(const char *s); + void pushnumber(lua_Number n); + void pushboolean(int b); + int type(int idx); + void setfield(int idx, const char *k); + int isstring (int idx); + int isnumber(int idx); + const char * ltypename(int t); + void * newuserdata(size_t sz); +#if REQUIRE_JIT + int jit_setmode(int idx, int mode); +#endif + + void setglobal(const char * n) { + setfield(LUA_GLOBALSINDEX, n); + } + void getglobal(const char * n) { + getfield(LUA_GLOBALSINDEX, n); + } + void pop(int n) { + settop(-(n)-1); + } + const char * tostring(int idx) { + return tolstring(idx, 0); + } + bool isfunction(int idx) { + return lua_type(l, idx) == LUA_TFUNCTION; + } + bool isboolean(int idx) { + return lua_type(l, idx) == LUA_TBOOLEAN; + } + + lua_State *l; + bool failed; + String errmsg; + + static DynamicLibrary *dll; + static ptr_luaL_newstate luaL_newstate; + static ptr_luaL_openlibs luaL_openlibs; + static ptr_luaL_loadbuffer luaL_loadbuffer; + static ptr_luaL_loadstring luaL_loadstring; + static ptr_lua_tolstring lua_tolstring; + static ptr_lua_tonumber lua_tonumber; + static ptr_lua_toboolean lua_toboolean; + static ptr_lua_pushcclosure lua_pushcclosure; + static ptr_lua_close lua_close; + static ptr_lua_gettop lua_gettop; + static ptr_lua_settop lua_settop; + static ptr_lua_pcall lua_pcall; + static ptr_lua_getfield lua_getfield; + static ptr_lua_pushlightuserdata lua_pushlightuserdata; + static ptr_lua_pushstring lua_pushstring; + static ptr_lua_pushnumber lua_pushnumber; + static ptr_lua_pushboolean lua_pushboolean; + static ptr_lua_type lua_type; + static ptr_lua_setfield lua_setfield; + static ptr_lua_isstring lua_isstring; + static ptr_lua_isnumber lua_isnumber; + static ptr_lua_typename lua_typename; + static ptr_lua_newuserdata lua_newuserdata; +#if REQUIRE_JIT + static ptr_luajit_setmode luajit_setmode; +#endif +}; + +} diff --git a/ports/protoplug/Source/PluginEditor.cpp b/ports/protoplug/Source/PluginEditor.cpp new file mode 100644 index 0000000..27caaea --- /dev/null +++ b/ports/protoplug/Source/PluginEditor.cpp @@ -0,0 +1,193 @@ +/* + ============================================================================== + + This file was auto-generated by the Introjucer! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" +#include "guiclasses/ProtoPopout.h" +#include "ProtoplugDir.h" + + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4355) // 'this' used in base member initializer list +#endif +//============================================================================== +LuaProtoplugJuceAudioProcessorEditor::LuaProtoplugJuceAudioProcessorEditor (LuaProtoplugJuceAudioProcessor* ownerFilter) + : AudioProcessorEditor (ownerFilter), + content(this, ownerFilter), + yank("bring to front"), + popin("pop back in"), + locateFiles("locate directory...") +{ + poppedWin = 0; + processor = ownerFilter; + ownerFilter->setProtoEditor(&content); + addChildComponent(&yank); + addChildComponent(&popin); + addChildComponent(&locateFiles); + yank.addListener(this); + popin.addListener(this); + locateFiles.addListener(this); + //yank.setLookAndFeel(&laf); + //popin.setLookAndFeel(&laf); + yank.setBounds(20, 50, 150, 30); + yank.setCentrePosition(140, 60); + popin.setBounds(20, 95, 150, 30); + popin.setCentrePosition(140, 102); + locateFiles.setBounds(45, 95, 150, 30); + locateFiles.setCentrePosition(190, 95); + + if (!ProtoplugDir::Instance()->found) { + setSize (380, 130); + locateFiles.setVisible(true); + } else if (processor->popout) { + content.initProtoplugDir(); + content.setSize(ownerFilter->lastUIWidth, + ownerFilter->lastUIHeight); + popOut(); + } else { + content.initProtoplugDir(); + addAndMakeVisible(&content); + content.takeFocus(); + setSize (ownerFilter->lastUIWidth, + ownerFilter->lastUIHeight); + } +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +LuaProtoplugJuceAudioProcessorEditor::~LuaProtoplugJuceAudioProcessorEditor() +{ + if (poppedWin!=0) { + processor->lastPopoutX = poppedWin->getX(); + processor->lastPopoutY = poppedWin->getY(); + } + content.saveCode(); +} + +void LuaProtoplugJuceAudioProcessorEditor::paint (Graphics& g) +{ + g.fillAll (Colours::white); + if ( ! ProtoplugDir::Instance()->found) + { + g.setColour (Colours::black); + g.setFont (15.0f); + g.drawFittedText ( + "ProtoplugFiles not found! Please locate the \"ProtoplugFiles\" directory " + " (which should contain \"generators\", \"effects\", \"themes\"...)", + 10, 0, 360, 80, + Justification::centred, 3); + } + else if (poppedWin) + { + g.setColour (Colours::black); + g.setFont (15.0f); + g.drawFittedText ("interface popped out", + 0, 0, 280, 50, + Justification::centred, 1); + } +} + +void LuaProtoplugJuceAudioProcessorEditor::resized() +{ + if (poppedWin==0) + content.setBounds(0, 0, getWidth(), getHeight()); +} + +void LuaProtoplugJuceAudioProcessorEditor::buttonClicked(Button *b) +{ + if (b==&yank && poppedWin) + poppedWin->toFront(true); + else if (b==&popin && poppedWin) + popIn(); + else if (b==&locateFiles) { + FileChooser fileOpen( + "Where did you put my ProtoplugFiles directory:", + File::getSpecialLocation(File::currentApplicationFile).getParentDirectory()); + if (fileOpen.browseForDirectory()) + { + File chosen = fileOpen.getResult(); + String missing; + if (ProtoplugDir::Instance()->checkDir(chosen, missing)) { + ProtoplugDir::Instance()->setDir(chosen); + if (ProtoplugDir::Instance()->getDirTextFile().create().wasOk()) + ProtoplugDir::Instance()->getDirTextFile().replaceWithText(chosen.getFullPathName()); + setSize (670, 455); + processor->luli->initProtoplugDir(); + locateFiles.setVisible(false); + addAndMakeVisible(&content); + content.takeFocus(); + content.initProtoplugDir(); + } else { + AlertWindow::showNativeDialogBox("Protoplug", "Wrong directory: \"" + missing + + "\" was not found in the given directory.", false); + } + } + + } +} + +void LuaProtoplugJuceAudioProcessorEditor::popOut() +{ + poppedWin = new ProtoPopout(this, processor->getName(), Colours::white, DocumentWindow::allButtons, true); + poppedWin->setAlwaysOnTop(processor->alwaysontop); + poppedWin->setResizable(true, false); + poppedWin->setUsingNativeTitleBar(true); + poppedWin->setContentNonOwned(&content, true); + processor->popout = true; + poppedWin->setContentComponentSize(processor->lastUIWidth, processor->lastUIHeight); + poppedWin->setTopLeftPosition(processor->lastPopoutX, processor->lastPopoutY); + content.setPoppedOut(true); + poppedWin->setVisible(true); + setSize (280, 130); + yank.setVisible(true); + content.takeFocus(); + popin.setVisible(true); +} + +void LuaProtoplugJuceAudioProcessorEditor::popIn() +{ + processor->lastUIWidth = 670; + processor->lastUIHeight = 455; + if (poppedWin!=0) { + processor->lastPopoutX = poppedWin->getX(); + processor->lastPopoutY = poppedWin->getY(); + } + processor->popout = false; + int w=processor->lastUIWidth, h=processor->lastUIHeight; + addAndMakeVisible(&content); + content.setPoppedOut(false); + setSize (w,h); + content.setSize (w,h); + poppedWin = 0; + yank.setVisible(false); + content.takeFocus(); + popin.setVisible(false); + //content.resized(); +} + +void LuaProtoplugJuceAudioProcessorEditor::handleCommandMessage(int com) +{ + if (com==MSG_POPOUT && !processor->popout) + { + popOut(); + } + else if (com==MSG_POPOUT && processor->popout) + { + popIn(); + } + else if (com==MSG_ALWAYSONTOP) + { + processor->alwaysontop = !processor->alwaysontop; + if (poppedWin!=0) + poppedWin->setAlwaysOnTop(processor->alwaysontop); + } +} diff --git a/ports/protoplug/Source/PluginEditor.h b/ports/protoplug/Source/PluginEditor.h new file mode 100644 index 0000000..69a57f1 --- /dev/null +++ b/ports/protoplug/Source/PluginEditor.h @@ -0,0 +1,30 @@ +#pragma once + +#include "JuceHeader.h" +#include "PluginProcessor.h" +#include "guiclasses/ProtoWindow.h" + +class LuaProtoplugJuceAudioProcessorEditor : public AudioProcessorEditor, + public Button::Listener +{ +public: + LuaProtoplugJuceAudioProcessorEditor (LuaProtoplugJuceAudioProcessor* ownerFilter); + ~LuaProtoplugJuceAudioProcessorEditor(); + + void paint (Graphics& g); + void resized(); + void handleCommandMessage(int com); + void buttonClicked(Button *); + + void popOut(); + void popIn(); + LuaProtoplugJuceAudioProcessor *processor; + +private: + ProtoWindow content; // the actual gui is in there + ScopedPointer poppedWin; + TextButton yank; + TextButton popin; + TextButton locateFiles; +}; + diff --git a/ports/protoplug/Source/PluginProcessor.cpp b/ports/protoplug/Source/PluginProcessor.cpp new file mode 100644 index 0000000..fea1678 --- /dev/null +++ b/ports/protoplug/Source/PluginProcessor.cpp @@ -0,0 +1,185 @@ +/* + ============================================================================== + + This file was auto-generated! + + It contains the basic startup code for a Juce application. + + ============================================================================== +*/ + +#include "PluginProcessor.h" +#include "PluginEditor.h" +#include "ProtoplugDir.h" + + +//============================================================================== +LuaProtoplugJuceAudioProcessor::LuaProtoplugJuceAudioProcessor() +{ + lastUIWidth = 670; + lastUIHeight = 455; + lastUISplit = 455-46; + lastUIPanel = 0; + lastPopoutX = lastPopoutY = 60; + lastUIFontSize = -1; + popout = alwaysontop = liveMode = false; + for (int i=0; i= NPARAMS) + return 0.f; + return (float)params[index]; +} + +void LuaProtoplugJuceAudioProcessor::setParameter (int index, float newValue) +{ + if (index >= NPARAMS) + return; + params[index] = (double) newValue; + luli->paramChanged(index); + if (getActiveEditor()) + lastOpenedEditor->msg_ParamsChanged = true; +} + +const String LuaProtoplugJuceAudioProcessor::getParameterName (int index) +{ + if (index >= NPARAMS) + return String::empty; + return luli->getParameterName(index); +} + +const String LuaProtoplugJuceAudioProcessor::getParameterText (int index) +{ + if (index >= NPARAMS) + return String::empty; + String s = luli->getParameterText(index); + if (s.isEmpty()) + s = String(params[index], 4); + return s; +} + +bool LuaProtoplugJuceAudioProcessor::parameterText2Double (int index, String text, double &d) +{ + if (index >= NPARAMS) + return false; + return luli->parameterText2Double(index, text, d); +} + +double LuaProtoplugJuceAudioProcessor::getTailLengthSeconds() const +{ + return luli->getTailLengthSeconds(); +} + +//============================================================================== + +void LuaProtoplugJuceAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) +{ + luli->processBlock(buffer, midiMessages, getPlayHead()); + //midiMessages.data; +} + +AudioProcessorEditor* LuaProtoplugJuceAudioProcessor::createEditor() +{ + return new LuaProtoplugJuceAudioProcessorEditor (this); +} + +//============================================================================== +void LuaProtoplugJuceAudioProcessor::getStateInformation (MemoryBlock& destData) +{ + // if code editor is open, flush its code to luli buffer + if (getActiveEditor()) + lastOpenedEditor->saveCode(); + + // if lua save() is overridden, call it and store the script's custom data + luli->saveData = luli->save(); + + int sz_script = luli->code.length()*2; + int sz_user = luli->saveData.length()*2; + int sz_total = 3*4 + 8*NPARAMS + sz_script + sz_user + 8; + + if (chunk) + delete[] chunk; + chunk = new char[sz_total]; + + int *pi = (int*)chunk; + *pi++ = NPARAMS; // store number of parameters + double *pd = (double*) pi; + for (int i=0; icode.getCharPointer()); // store code + pc += sz_script; + pi = (int*)pc; + *pi++ = sz_user; // store size of lua saveable string + pc = (char*)pi; + strcpy(pc, luli->saveData.getCharPointer()); // store lua saveable string + + destData.append(chunk, sz_total); + return; +} + +void LuaProtoplugJuceAudioProcessor::setStateInformation (const void* data, int /*sizeInBytes*/) +{ + int *pi = (int*)data; + int numparams = *pi++; // get number of parameters + double *pd = (double*) pi; + for (int i=0; icode = pc; // get code + luli->saveData = String::empty; + if (ProtoplugDir::Instance()->found) + luli->compile(); + else + luli->addToLog("could not compile script because the ProtoplugFiles directory is missing or incomplete"); + + pc += sz_script; + pi = (int*)pc; + int sz_user = *pi++; // get size of lua saveable string + pc = (char*)pi; + if (sz_user>0) { + luli->saveData = pc; // get lua saveable string + luli->load(luli->saveData); + } +} + +//============================================================================== +// This creates new instances of the plugin.. +AudioProcessor* JUCE_CALLTYPE createPluginFilter() +{ + return new LuaProtoplugJuceAudioProcessor(); +} + + +ProtoWindow *LuaProtoplugJuceAudioProcessor::getProtoEditor() +{ + if (getActiveEditor()) + return lastOpenedEditor; + else + return 0; +} + +void LuaProtoplugJuceAudioProcessor::setProtoEditor(ProtoWindow *_ed) +{ + lastOpenedEditor = _ed; +} \ No newline at end of file diff --git a/ports/protoplug/Source/PluginProcessor.h b/ports/protoplug/Source/PluginProcessor.h new file mode 100644 index 0000000..c7fefdb --- /dev/null +++ b/ports/protoplug/Source/PluginProcessor.h @@ -0,0 +1,65 @@ +#pragma once +#include "JuceHeader.h" +#include "LuaLink.h" + + +#define NPARAMS 127 +class ProtoWindow; +class LuaProtoplugJuceAudioProcessor; +class ProtoPopout; + +class LuaProtoplugJuceAudioProcessor : public AudioProcessor +{ +public: + LuaProtoplugJuceAudioProcessor(); + ~LuaProtoplugJuceAudioProcessor(); + + // overrides + void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + AudioProcessorEditor* createEditor(); + float getParameter (int index); + void setParameter (int index, float newValue); + const String getParameterName (int index); + const String getParameterText (int index); + double getTailLengthSeconds() const; + void getStateInformation (MemoryBlock& destData); + void setStateInformation (const void* data, int sizeInBytes); + + // some inlined overrides + const String getInputChannelName (int channelIndex) const { return String (channelIndex + 1); } + const String getOutputChannelName (int channelIndex) const { return String (channelIndex + 1); } + float getParameterDefaultValue (int /*parameterIndex*/) { return 0.5; } + bool isInputChannelStereoPair (int /*index*/) const { return true; } + bool isOutputChannelStereoPair (int /*index*/) const { return true; } + bool acceptsMidi() const { return true; } + bool producesMidi() const { return true; } + bool silenceInProducesSilenceOut() const { return false; } + const String getName() const { return JucePlugin_Name; } + int getNumParameters() { return NPARAMS; } + bool hasEditor() const { return true; } + // leave 1 as per JuceVSTWrapper constructor requirement: + int getNumPrograms() { return 1; } + int getCurrentProgram() { return 1; } + void setCurrentProgram (int /*index*/) { } + const String getProgramName (int /*index*/) { return String::empty; } + void changeProgramName (int /*index*/, const String& /*newName*/) { } + void prepareToPlay (double /*sampleRate*/, int /*samplesPerBlock*/) { } + void releaseResources() { } + + // some added methods + ProtoWindow *getProtoEditor(); + void setProtoEditor(ProtoWindow * _ed); + bool parameterText2Double (int index, String text, double &d); + + int lastUIWidth, lastUIHeight, lastUISplit, lastUIPanel; + int lastPopoutX, lastPopoutY; + float lastUIFontSize; + bool popout, alwaysontop, liveMode; + LuaLink *luli; + double params[NPARAMS]; + +private: + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LuaProtoplugJuceAudioProcessor) + ProtoWindow *lastOpenedEditor; + char *chunk; +}; diff --git a/ports/protoplug/Source/ProtoplugDir.cpp b/ports/protoplug/Source/ProtoplugDir.cpp new file mode 100644 index 0000000..ed70b71 --- /dev/null +++ b/ports/protoplug/Source/ProtoplugDir.cpp @@ -0,0 +1,96 @@ +#include "ProtoplugDir.h" + +ProtoplugDir* ProtoplugDir::pInstance = 0; + +// private contructor called once +ProtoplugDir::ProtoplugDir() +{ + found = true; + #if JUCE_WINDOWS + dir = File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("ProtoplugFiles"); + #endif + #if JUCE_MAC + dir = File::getSpecialLocation(File::currentApplicationFile).getSiblingFile("ProtoplugFiles"); + //if (ret.getFullPathName().endsWith("/Contents/MacOS")) // assume OSX bundle format + //pluginLocation = pluginLocation.getSiblingFile("../../../"); + #endif + #if JUCE_LINUX + dir = File("/usr/share/ProtoplugFiles"); + #endif + if (dir.exists()) + return; + + // compatibility with old version + dir = dir.getSiblingFile("protoplug"); + if (dir.exists()) + return; + + dir = File::getSpecialLocation(File::userHomeDirectory).getSiblingFile("ProtoplugFiles"); + if (dir.exists()) + return; + + File appDataDir = File::getSpecialLocation(File::userApplicationDataDirectory).getChildFile("Protoplug"); + if (!appDataDir.exists()) + appDataDir.createDirectory(); + dirTextFile = appDataDir.getChildFile("ProtoplugFiles.txt"); + String protoPath = dirTextFile.loadFileAsString(); + if (protoPath.isNotEmpty() && File::isAbsolutePath(protoPath)) + dir = File(protoPath); + if (!dir.exists()) + // ProtoplugFiles not found + found = false; +} + +bool ProtoplugDir::checkDir(File _dir, String &missing) +{ + bool valid = true; + StringArray requiredFiles; + requiredFiles.add("effects"); + requiredFiles.add("generators"); + requiredFiles.add("include"); + requiredFiles.add("effects/default.lua"); + requiredFiles.add("generators/default.lua"); + for (int i = 0; i < requiredFiles.size(); ++i) + { + if (!_dir.getChildFile(requiredFiles[i]).exists()) { + valid = false; + missing = requiredFiles[i]; + break; + } + } + return valid; +} + +void ProtoplugDir::setDir(File _dir) +{ + found = true; + dir = _dir; +} + +File ProtoplugDir::getDir() +{ + return dir; +} + +File ProtoplugDir::getDirTextFile() +{ + return dirTextFile; +} + +File ProtoplugDir::getScriptsDir() +{ + return getDir().getChildFile(SCRIPTS_DIR); +} + +File ProtoplugDir::getLibDir() +{ + return getDir().getChildFile("lib"); +} + +ProtoplugDir* ProtoplugDir::Instance() +{ + if (!pInstance) + pInstance = new ProtoplugDir; + + return pInstance; +} diff --git a/ports/protoplug/Source/ProtoplugDir.h b/ports/protoplug/Source/ProtoplugDir.h new file mode 100644 index 0000000..a312c9d --- /dev/null +++ b/ports/protoplug/Source/ProtoplugDir.h @@ -0,0 +1,34 @@ +#pragma once + +#include "JuceHeader.h" + +#ifdef _PROTOGEN +#define SCRIPTS_DIR "generators" +#else +#define SCRIPTS_DIR "effects" +#endif + +class ProtoplugDir +{ +public: + static ProtoplugDir* Instance(); + File getDir(); + void setDir(File _dir); + bool checkDir(File dir, String &missing); + + File getScriptsDir(); + File getLibDir(); + File getDirTextFile(); + bool found; + + +private: + File dir; + File dirTextFile; + + // i still consider singletons an anti-pattern, but here you go... + ProtoplugDir(); + ProtoplugDir(ProtoplugDir const&); + ProtoplugDir& operator=(ProtoplugDir const&); + static ProtoplugDir* pInstance; +}; diff --git a/ports/protoplug/Source/ProtoplugExports.h b/ports/protoplug/Source/ProtoplugExports.h new file mode 100644 index 0000000..af7337d --- /dev/null +++ b/ports/protoplug/Source/ProtoplugExports.h @@ -0,0 +1,78 @@ + +#pragma once + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4190) // C function returns C-incompatible UDT. +#endif + +#include "exports/typedefs.h" + +#include "exports/pAudioFormatReader.h" +#include "exports/pColourGradient.h" +#include "exports/pComponent.h" +#include "exports/pFillType.h" +#include "exports/pFont.h" +#include "exports/pGraphics.h" +#include "exports/pImage.h" +#include "exports/pImageFileFormat.h" +#include "exports/pLagrangeInterpolator.h" +#include "exports/pMidiBuffer.h" +#include "exports/pPath.h" + + +PROTO_API bool AudioPlayHead_getCurrentPosition(pAudioPlayHead self, AudioPlayHead::CurrentPositionInfo& result) +{ return self.a->getCurrentPosition(result); } + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +/* +the protojuce api looks somewhat consistent on the outside, but on the inside +it's not so pretty. I didn't use any of the c++ to Lua autowrapping libraries, +instead i rolled my own wrappers and used LuaJIT's FFI. This may or may not +have been the easier route, either way the end product is a little faster. + +In a nutshell : +1. The required C++ juce functionality is wrapped into a C API and exported by + protoplug. This is done by the headers in the "Exports" folder. + +2. This API is then imported into Lua using LuaJIT's FFI feature. + +3. The "protojuce" lua module then takes this (somewhat messy) C API and + re-wraps it into a nicer lua API. + +JUCE's c++ classes are handled in different ways : + +classes that need to be managed by JUCE : + export constuctor/destructor (always ffi.gc) + ColourGradient + FillType + Path + RectangleList + Image + Font + do not export constructor/destructor + Component + Graphics +classes that convert to structs and need not export anything: + Rectangle<> + MouseEvent + Time + Point<> + MouseWheelDetails + Colour + AffineTransform + PathStrokeType + Line<> +classes that convert to something else : + String (to const char*) + ModifierKeys (to int) + Justification (to int) + RectanglePlacement (to int) +classes that are opaque pointers and only referred to : + MouseInputSource +*/ + + diff --git a/ports/protoplug/Source/exports/pAudioFormatReader.h b/ports/protoplug/Source/exports/pAudioFormatReader.h new file mode 100644 index 0000000..c10f99a --- /dev/null +++ b/ports/protoplug/Source/exports/pAudioFormatReader.h @@ -0,0 +1,43 @@ +/* + ============================================================================== + + pAudioFormatReader.h + Created: 5 Jul 2014 12:53:12am + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" +#include "../ProtoplugDir.h" + +PROTO_API pAudioFormatReader AudioFormatReader_new(const char *filename) +{ + File f = ProtoplugDir::Instance()->getDir().getChildFile(filename); + if (f == File::nonexistent) + f = File(filename); + AudioFormatManager afm; + afm.registerBasicFormats(); + pAudioFormatReader a = {afm.createReaderFor(f)}; + if (a.a) { + a.sampleRate = a.a->sampleRate; + a.bitsPerSample = a.a->bitsPerSample; + a.lengthInSamples = a.a->lengthInSamples; + a.numChannels = a.a->numChannels; + a.usesFloatingPointData = a.a->usesFloatingPointData; + } + return a; +} + +PROTO_API bool AudioFormatReader_read (pAudioFormatReader a, + int *const * destSamples, + int numDestChannels, + int64 startSampleInSource, + int numSamplesToRead, + bool fillLeftoverChannelsWithCopies) +{ return a.a->read(destSamples, numDestChannels, startSampleInSource, numSamplesToRead, fillLeftoverChannelsWithCopies); } + +PROTO_API void AudioFormatReader_delete(pAudioFormatReader a) +{ if (a.a) delete a.a; } diff --git a/ports/protoplug/Source/exports/pColourGradient.h b/ports/protoplug/Source/exports/pColourGradient.h new file mode 100644 index 0000000..5bd2857 --- /dev/null +++ b/ports/protoplug/Source/exports/pColourGradient.h @@ -0,0 +1,63 @@ +/* + ============================================================================== + + exColourGradient.h + Created: 25 Feb 2014 6:06:46pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + +PROTO_API pColourGradient ColourGradient_new (exColour c1, float x1, float y1, exColour c2, float x2, float y2, bool isRadial) +{ + pColourGradient c = {new ColourGradient(Colour(c1.c), x1, y1, Colour(c2.c), x2, y2, isRadial)}; + return c; +} + +PROTO_API void ColourGradient_delete (pColourGradient c) +{ + delete c.c; +} + +PROTO_API int ColourGradient_addColour (pColourGradient self, double proportionAlongGradient, + exColour colour) +{ + return self.c->addColour (proportionAlongGradient, Colour(colour.c)); +} + +PROTO_API void ColourGradient_removeColour (pColourGradient self, int index) +{ + self.c->removeColour (index); +} + +PROTO_API void ColourGradient_multiplyOpacity (pColourGradient self, float multiplier) + +{ + self.c->multiplyOpacity (multiplier); +} + +PROTO_API int ColourGradient_getNumColours(pColourGradient self) +{ + return self.c->getNumColours(); +} + +PROTO_API exColour ColourGradient_getColour (pColourGradient self, int index) +{ + exColour c = {self.c->getColour (index).getARGB()}; + return c; +} + +PROTO_API void ColourGradient_setColour (pColourGradient self, int index, exColour newColour) +{ + self.c->setColour (index, Colour(newColour.c)); +} + +PROTO_API exColour ColourGradient_getColourAtPosition (pColourGradient self, double position) +{ + exColour c = {self.c->getColourAtPosition (position).getARGB()}; + return c; +} \ No newline at end of file diff --git a/ports/protoplug/Source/exports/pComponent.h b/ports/protoplug/Source/exports/pComponent.h new file mode 100644 index 0000000..96fae32 --- /dev/null +++ b/ports/protoplug/Source/exports/pComponent.h @@ -0,0 +1,57 @@ +/* + ============================================================================== + + exComponent.h + Created: 25 Feb 2014 6:03:51pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + + + +PROTO_API void Component_repaint(pComponent self) +{ + self.c->repaint(); + /* this doesn't even catch segfaults :( + bool caught = false; + try { + self.c->repaint(); + } catch (...) { + caught = true; + } + if (caught) { + juce::AlertWindow( + "protoplug error", + "An exception occured in a protoplug script. The script is probably passing a null pointer to an ffi function ! " + +String("\r\nThe host program might crash because of this."), + AlertWindow::AlertIconType::QuestionIcon); + }*/ +} + + +PROTO_API void Component_repaint2(pComponent self, int x, int y, int width, int height) +{ + self.c->repaint(x, y, width, height); +} + + +PROTO_API void Component_repaint3(pComponent self, exRectangle_int area) +{ + self.c->repaint(area.toJuceRect()); +} + + +PROTO_API pImage Component_createComponentSnapshot (pComponent self, + exRectangle_int areaToGrab, + bool clipImageToComponentBounds = true, + float scaleFactor = 1.0f) +{ + pImage i = { new Image() }; + *i.i = self.c->createComponentSnapshot(areaToGrab.toJuceRect(), clipImageToComponentBounds, scaleFactor); + return i; +} \ No newline at end of file diff --git a/ports/protoplug/Source/exports/pFillType.h b/ports/protoplug/Source/exports/pFillType.h new file mode 100644 index 0000000..d57f69f --- /dev/null +++ b/ports/protoplug/Source/exports/pFillType.h @@ -0,0 +1,35 @@ +/* + ============================================================================== + + exFillType.h + Created: 25 Feb 2014 6:08:09pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + +PROTO_API pFillType FillType_new(exColour c) +{ + pFillType f = { new FillType(Colour(c.c)) }; + return f; +} + +PROTO_API pFillType FillType_new2(pColourGradient c) +{ + pFillType f = { new FillType(*c.c) }; + return f; +} + +PROTO_API void FillType_delete(pFillType f) +{ + delete f.f; +} + +PROTO_API void FillType_setOpacity (pFillType f, float newOpacity) +{ + f.f->setOpacity(newOpacity); +} \ No newline at end of file diff --git a/ports/protoplug/Source/exports/pFont.h b/ports/protoplug/Source/exports/pFont.h new file mode 100644 index 0000000..1c11122 --- /dev/null +++ b/ports/protoplug/Source/exports/pFont.h @@ -0,0 +1,28 @@ +/* + ============================================================================== + + exFont.h + Created: 25 Feb 2014 7:37:37pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + +PROTO_API pFont Font_new(const char *typefaceName, float fontHeight, int styleFlags, bool hinted) +{ + String stypefaceName = typefaceName; + if (hinted) + stypefaceName += "_hinted_"; + pFont f = { new Font(stypefaceName, fontHeight, styleFlags) }; + return f; +} + +PROTO_API void Font_delete(pFont f) +{ + delete f.f; +} + diff --git a/ports/protoplug/Source/exports/pGraphics.h b/ports/protoplug/Source/exports/pGraphics.h new file mode 100644 index 0000000..0c860ed --- /dev/null +++ b/ports/protoplug/Source/exports/pGraphics.h @@ -0,0 +1,352 @@ +/* + ============================================================================== + + exGraphics.h + Created: 25 Feb 2014 6:10:20pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + + + +PROTO_API pGraphics Graphics_new(pImage imageToDrawOnto) +{ + pGraphics g = { new Graphics(*imageToDrawOnto.i) }; + return g; +} + +PROTO_API void Graphics_delete(pGraphics g) +{ delete g.g; } + + +PROTO_API void Graphics_setColour(pGraphics self, exColour newColour) +{ self.g->setColour(Colour(newColour.c)); } + + +PROTO_API void Graphics_setOpacity(pGraphics self, float newOpacity) +{ self.g->setOpacity(newOpacity); } + + +PROTO_API void Graphics_setGradientFill(pGraphics self, const pColourGradient gradient) +{ self.g->setGradientFill(*gradient.c); } + + +PROTO_API void Graphics_setTiledImageFill(pGraphics self, const pImage imageToUse, + int anchorX, int anchorY, + float opacity) +{ self.g->setTiledImageFill(*imageToUse.i, anchorX, anchorY, opacity); } + + +PROTO_API void Graphics_setFillType(pGraphics self, const pFillType newFill) +{ self.g->setFillType(*newFill.f); } + + +PROTO_API void Graphics_setFont(pGraphics self, const pFont newFont) +{ self.g->setFont(*newFont.f); } + + +PROTO_API void Graphics_setFont2(pGraphics self, float newFontHeight) +{ self.g->setFont(newFontHeight); } + + +PROTO_API pFont Graphics_getCurrentFont(pGraphics self) +{ + pFont f = {new Font(self.g->getCurrentFont())}; + return f; +} + + +PROTO_API void Graphics_drawSingleLineText(pGraphics self, char * text, + int startX, int baselineY, + int justification) +{ self.g->drawSingleLineText(text, startX, baselineY, Justification(justification)); } + + +PROTO_API void Graphics_drawMultiLineText(pGraphics self, char * text, + int startX, int baselineY, + int maximumLineWidth) +{ self.g->drawMultiLineText(text, startX, baselineY, maximumLineWidth); } + + +PROTO_API void Graphics_drawText(pGraphics self, char * text, + int x, int y, int width, int height, + int justificationType, + bool useEllipsesIfTooBig) +{ self.g->drawText(text, x, y, width, height, Justification(justificationType), useEllipsesIfTooBig); } + + +PROTO_API void Graphics_drawText2(pGraphics self, char * text, + exRectangle_int area, + int justificationType, + bool useEllipsesIfTooBig) +{ self.g->drawText(text, area.toJuceRect(), Justification(justificationType), useEllipsesIfTooBig); } + + +PROTO_API void Graphics_drawFittedText(pGraphics self, char * text, + int x, int y, int width, int height, + int justificationFlags, + int maximumNumberOfLines, + float minimumHorizontalScale = 0.7f) +{ + self.g->drawFittedText(text, x, y, width, height, Justification(justificationFlags), + maximumNumberOfLines, minimumHorizontalScale); +} + + +PROTO_API void Graphics_drawFittedText2(pGraphics self, char * text, + exRectangle_int area, + int justificationFlags, + int maximumNumberOfLines, + float minimumHorizontalScale = 0.7f) +{ + self.g->drawFittedText(text, area.toJuceRect(), Justification(justificationFlags), + maximumNumberOfLines, minimumHorizontalScale); +} + + +PROTO_API void Graphics_fillAll(pGraphics self) +{ self.g->fillAll(); } + + +PROTO_API void Graphics_fillAll2(pGraphics self, exColour colourToUse) +{ self.g->fillAll(Colour(colourToUse.c)); } + + +PROTO_API void Graphics_fillRect(pGraphics self, exRectangle_int rectangle) +{ self.g->fillRect(rectangle.toJuceRect()); } + + +PROTO_API void Graphics_fillRect2(pGraphics self, exRectangle_float rectangle) +{ self.g->fillRect(rectangle.toJuceRect()); } + + +PROTO_API void Graphics_fillRect3(pGraphics self, int x, int y, int width, int height) +{ self.g->fillRect(x, y, width, height); } + + +PROTO_API void Graphics_fillRect4(pGraphics self, float x, float y, float width, float height) +{ self.g->fillRect(x, y, width, height); } + +/* +PROTO_API void Graphics_fillRectList(pGraphics self, const RectangleList& rectangles) +{ self.g->fillRectList(rectangles); }*/ + + +PROTO_API void Graphics_fillRoundedRectangle(pGraphics self, float x, float y, float width, float height, + float cornerSize) +{ self.g->fillRoundedRectangle(x, y, width, height, cornerSize); } + + +PROTO_API void Graphics_fillRoundedRectangle2(pGraphics self, exRectangle_float rectangle, + float cornerSize) +{ self.g->fillRoundedRectangle(rectangle.toJuceRect(), cornerSize); } + + +PROTO_API void Graphics_fillCheckerBoard(pGraphics self, exRectangle_int area, + int checkWidth, int checkHeight, + exColour colour1, exColour colour2) +{ self.g->fillCheckerBoard(area.toJuceRect(), checkWidth, checkHeight, Colour(colour1.c), Colour(colour2.c)); } + + +PROTO_API void Graphics_drawRect(pGraphics self, int x, int y, int width, int height, int lineThickness = 1) +{ self.g->drawRect(x, y, width, height, lineThickness); } + + +PROTO_API void Graphics_drawRect2(pGraphics self, float x, float y, float width, float height, float lineThickness = 1.0f) +{ self.g->drawRect(x, y, width, height, lineThickness); } + + +PROTO_API void Graphics_drawRect3(pGraphics self, exRectangle_int rectangle, int lineThickness = 1) +{ self.g->drawRect(rectangle.toJuceRect(), lineThickness); } + + +PROTO_API void Graphics_drawRect4(pGraphics self, exRectangle_float rectangle, float lineThickness = 1.0f) +{ self.g->drawRect(rectangle.toJuceRect(), lineThickness); } + + +PROTO_API void Graphics_drawRoundedRectangle(pGraphics self, float x, float y, float width, float height, + float cornerSize, float lineThickness) +{ self.g->drawRoundedRectangle(x, y, width, height, cornerSize, lineThickness); } + + +PROTO_API void Graphics_drawRoundedRectangle2(pGraphics self, exRectangle_float rectangle, + float cornerSize, float lineThickness) +{ self.g->drawRoundedRectangle(rectangle.toJuceRect(), cornerSize, lineThickness); } + + +PROTO_API void Graphics_setPixel(pGraphics self, int x, int y) +{ self.g->setPixel(x, y); } + + +PROTO_API void Graphics_fillEllipse(pGraphics self, float x, float y, float width, float height) +{ self.g->fillEllipse(x, y, width, height); } + + +PROTO_API void Graphics_fillEllipse2(pGraphics self, exRectangle_float area) +{ self.g->fillEllipse(area.toJuceRect()); } + + +PROTO_API void Graphics_drawEllipse(pGraphics self, float x, float y, float width, float height, + float lineThickness) +{ self.g->drawEllipse(x, y, width, height, lineThickness); } + + +PROTO_API void Graphics_drawLine(pGraphics self, float startX, float startY, float endX, float endY) +{ self.g->drawLine(startX, startY, endX, endY); } + + +PROTO_API void Graphics_drawLine2(pGraphics self, float startX, float startY, float endX, float endY, float lineThickness) +{ self.g->drawLine(startX, startY, endX, endY, lineThickness); } + + +PROTO_API void Graphics_drawLine3(pGraphics self, exLine_float line) +{ self.g->drawLine(line.toJuceLine()); } + + +PROTO_API void Graphics_drawLine4(pGraphics self, exLine_float line, float lineThickness) +{ self.g->drawLine(line.toJuceLine(), lineThickness); } + + +PROTO_API void Graphics_drawDashedLine(pGraphics self, exLine_float line, + const float* dashLengths, int numDashLengths, + float lineThickness = 1.0f, + int dashIndexToStartFrom = 0) +{ self.g->drawDashedLine(line.toJuceLine(), dashLengths, numDashLengths, lineThickness, dashIndexToStartFrom); } + + +PROTO_API void Graphics_drawVerticalLine(pGraphics self, int x, float top, float bottom) +{ self.g->drawVerticalLine(x, top, bottom); } + + +PROTO_API void Graphics_drawHorizontalLine(pGraphics self, int y, float left, float right) +{ self.g->drawHorizontalLine(y, left, right); } + + +PROTO_API void Graphics_fillPath(pGraphics self, pPath path, + exAffineTransform transform) +{ self.g->fillPath(*path.p, transform.toJuceAff()); } + + +PROTO_API void Graphics_strokePath(pGraphics self, pPath path, + exPathStrokeType strokeType, + exAffineTransform transform) +{ self.g->strokePath(*path.p, strokeType.toJuceType(), transform.toJuceAff()); } + + +PROTO_API void Graphics_drawArrow(pGraphics self, exLine_float line, + float lineThickness, + float arrowheadWidth, + float arrowheadLength) +{ self.g->drawArrow(line.toJuceLine(), lineThickness, arrowheadWidth, arrowheadLength); } + + +PROTO_API void Graphics_setImageResamplingQuality(pGraphics self, const int newQuality) +{ self.g->setImageResamplingQuality((Graphics::ResamplingQuality)newQuality); } + + +PROTO_API void Graphics_drawImageAt(pGraphics self, pImage imageToDraw, int topLeftX, int topLeftY, + bool fillAlphaChannelWithCurrentBrush = false) +{ self.g->drawImageAt(*imageToDraw.i, topLeftX, topLeftY, fillAlphaChannelWithCurrentBrush); } + + +PROTO_API void Graphics_drawImage(pGraphics self, pImage imageToDraw, + int destX, int destY, int destWidth, int destHeight, + int sourceX, int sourceY, int sourceWidth, int sourceHeight, + bool fillAlphaChannelWithCurrentBrush = false) +{ self.g->drawImage(*imageToDraw.i, destX, destY, destWidth, destHeight, sourceX, sourceY, sourceWidth, sourceHeight, fillAlphaChannelWithCurrentBrush); } + + +PROTO_API void Graphics_drawImageTransformed(pGraphics self, pImage imageToDraw, + exAffineTransform transform, + bool fillAlphaChannelWithCurrentBrush = false) +{ self.g->drawImageTransformed(*imageToDraw.i, transform.toJuceAff(), fillAlphaChannelWithCurrentBrush); } + + +PROTO_API void Graphics_drawImageWithin(pGraphics self, pImage imageToDraw, + int destX, int destY, int destWidth, int destHeight, + int placementWithinTarget, + bool fillAlphaChannelWithCurrentBrush = false) +{ + self.g->drawImageWithin(*imageToDraw.i, destX, destY, destWidth, destHeight, + RectanglePlacement(placementWithinTarget), fillAlphaChannelWithCurrentBrush); } + + +PROTO_API exRectangle_int Graphics_getClipBounds(pGraphics self) +{ return exRectangle_int(self.g->getClipBounds()); } + + +PROTO_API bool Graphics_clipRegionIntersects(pGraphics self, exRectangle_int area) +{ return self.g->clipRegionIntersects(area.toJuceRect()); } + + +PROTO_API bool Graphics_reduceClipRegion(pGraphics self, int x, int y, int width, int height) +{ return self.g->reduceClipRegion(x, y, width, height); } + + +PROTO_API bool Graphics_reduceClipRegion2(pGraphics self, exRectangle_int area) +{ return self.g->reduceClipRegion(area.toJuceRect()); } + +/* +PROTO_API bool Graphics_reduceClipRegion3(pGraphics self, const RectangleList& clipRegion) +{ return self.g->reduceClipRegion(clipRegion); }*/ + + +PROTO_API bool Graphics_reduceClipRegion4(pGraphics self, pPath path, exAffineTransform transform) +{ return self.g->reduceClipRegion(*path.p, transform.toJuceAff()); } + + +PROTO_API bool Graphics_reduceClipRegion5(pGraphics self, pImage image, exAffineTransform transform) +{ return self.g->reduceClipRegion(*image.i, transform.toJuceAff()); } + + +PROTO_API void Graphics_excludeClipRegion(pGraphics self, exRectangle_int rectangleToExclude) +{ self.g->excludeClipRegion(rectangleToExclude.toJuceRect()); } + + +PROTO_API bool Graphics_isClipEmpty(pGraphics self) +{ return self.g->isClipEmpty(); } + + +PROTO_API void Graphics_saveState(pGraphics self) +{ self.g->saveState(); } + + +PROTO_API void Graphics_restoreState(pGraphics self) +{ self.g->restoreState(); } + + +PROTO_API void Graphics_beginTransparencyLayer(pGraphics self, float layerOpacity) +{ self.g->beginTransparencyLayer(layerOpacity); } + + +PROTO_API void Graphics_endTransparencyLayer(pGraphics self) +{ self.g->endTransparencyLayer(); } + + +PROTO_API void Graphics_setOrigin(pGraphics self, exPoint_int newOrigin) +{ self.g->setOrigin(newOrigin.toJucePoint()); } + + +PROTO_API void Graphics_setOrigin2(pGraphics self, int newOriginX, int newOriginY) +{ self.g->setOrigin(newOriginX, newOriginY); } + + +PROTO_API void Graphics_addTransform(pGraphics self, exAffineTransform transform) +{ self.g->addTransform(transform.toJuceAff()); } + + +PROTO_API void Graphics_resetToDefaultState(pGraphics self) +{ self.g->resetToDefaultState(); } + + +PROTO_API bool Graphics_isVectorDevice(pGraphics self) +{ return self.g->isVectorDevice(); } + +/* +PROTO_API LowLevelGraphicsContext& Graphics_getInternalContext(pGraphics self) +{ return self.g->getInternalContext(); }*/ diff --git a/ports/protoplug/Source/exports/pImage.h b/ports/protoplug/Source/exports/pImage.h new file mode 100644 index 0000000..a4e89bc --- /dev/null +++ b/ports/protoplug/Source/exports/pImage.h @@ -0,0 +1,36 @@ +/* + ============================================================================== + + pImage.h + Created: 15 Mar 2014 5:17:51pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + +PROTO_API pImage Image_new() +{ + pImage i = { new Image() }; + return i; +} + +PROTO_API pImage Image_new2(int pixelFormat, int imageWidth, int imageHeight, bool clearImage) +{ + pImage i = { new Image((Image::PixelFormat)pixelFormat, imageWidth, imageHeight, clearImage) }; + return i; +} + +PROTO_API void Image_delete(pImage i) +{ delete i.i; } + +PROTO_API bool Image_isValid(pImage i) +{ + if (i.i) + return i.i->isValid(); + else + return false; +} \ No newline at end of file diff --git a/ports/protoplug/Source/exports/pImageFileFormat.h b/ports/protoplug/Source/exports/pImageFileFormat.h new file mode 100644 index 0000000..0776ded --- /dev/null +++ b/ports/protoplug/Source/exports/pImageFileFormat.h @@ -0,0 +1,23 @@ +/* + ============================================================================== + + pImageFileFormat.h + Created: 23 Mar 2014 7:29:52pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" +#include "../ProtoplugDir.h" + +PROTO_API pImage ImageFileFormat_loadFrom2(const char *filename) +{ + pImage i = { new Image() }; + File f = ProtoplugDir::Instance()->getDir().getChildFile(filename); + if (f != File::nonexistent) + *i.i = ImageFileFormat::loadFrom(f); + return i; +} \ No newline at end of file diff --git a/ports/protoplug/Source/exports/pLagrangeInterpolator.h b/ports/protoplug/Source/exports/pLagrangeInterpolator.h new file mode 100644 index 0000000..4b925c8 --- /dev/null +++ b/ports/protoplug/Source/exports/pLagrangeInterpolator.h @@ -0,0 +1,31 @@ +/* + ============================================================================== + + pLagrangeInterpolator.h + Created: 6 Jul 2014 3:12:08am + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" +#include "../LuaState.h" + +PROTO_API exLagrangeInterpolator LagrangeInterpolator_create() +{ + LagrangeInterpolator li; + exLagrangeInterpolator ret(*(exLagrangeInterpolator*)(&li)); // look away children + return ret; +} + +PROTO_API int LagrangeInterpolator_process(exLagrangeInterpolator ex, + double speedRatio, + const float* inputSamples, + float* outputSamples, + int numOutputSamplesToProduce) +{ + LagrangeInterpolator *li = (LagrangeInterpolator*)(&ex); + return li->process(speedRatio, inputSamples, outputSamples, numOutputSamplesToProduce); +} diff --git a/ports/protoplug/Source/exports/pMidiBuffer.h b/ports/protoplug/Source/exports/pMidiBuffer.h new file mode 100644 index 0000000..306bb28 --- /dev/null +++ b/ports/protoplug/Source/exports/pMidiBuffer.h @@ -0,0 +1,29 @@ +/* + ============================================================================== + + pMidiBuffer.h + Created: 24 Mar 2014 5:41:49pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + + +PROTO_API uint8 *MidiBuffer_getDataPointer(pMidiBuffer mb) +{ + return mb.m->data.getRawDataPointer(); +} + +PROTO_API int MidiBuffer_getDataSize(pMidiBuffer mb) +{ + return mb.m->data.size(); +} + +PROTO_API void MidiBuffer_resizeData(pMidiBuffer mb, int size) +{ + return mb.m->data.resize(size); +} diff --git a/ports/protoplug/Source/exports/pPath.h b/ports/protoplug/Source/exports/pPath.h new file mode 100644 index 0000000..8f49cef --- /dev/null +++ b/ports/protoplug/Source/exports/pPath.h @@ -0,0 +1,396 @@ +/* + ============================================================================== + + exPath.h + Created: 25 Feb 2014 7:37:52pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "typedefs.h" + + +PROTO_API pPath Path_new() +{ + pPath p = {new Path()}; + return p; +} + +PROTO_API void Path_delete(pPath p) +{ + delete p.p; +} + + +PROTO_API exRectangle_float Path_getBounds(pPath self) +{ + return exRectangle_float(self.p->getBounds()); +} + +PROTO_API exRectangle_float Path_getBoundsTransformed (pPath self, exAffineTransform transform) +{ + return exRectangle_float(self.p->getBoundsTransformed (transform.toJuceAff())); +} + +PROTO_API bool Path_contains (pPath self, float x, float y, + float tolerance = 1.0f) +{ + return self.p->contains (x, y, + tolerance); +} + +PROTO_API bool Path_contains2 (pPath self, exPoint_float point, + float tolerance = 1.0f) +{ + return self.p->contains (point.toJucePoint(), + tolerance); +} + +PROTO_API bool Path_intersectsLine (pPath self, exLine_float line, + float tolerance = 1.0f) +{ + return self.p->intersectsLine (line.toJuceLine(), + tolerance); +} + +PROTO_API exLine_float Path_getClippedLine (pPath self, exLine_float line, bool keepSectionOutsidePath) +{ + return exLine_float(self.p->getClippedLine (line.toJuceLine(), keepSectionOutsidePath)); +} + +PROTO_API float Path_getLength (pPath self, exAffineTransform transform) +{ + return self.p->getLength (transform.toJuceAff()); +} + +PROTO_API exPoint_float Path_getPointAlongPath (pPath self, float distanceFromStart, + exAffineTransform transform) +{ + return exPoint_float(self.p->getPointAlongPath (distanceFromStart, + transform.toJuceAff())); +} + +PROTO_API float Path_getNearestPoint (pPath self, exPoint_float targetPoint, + exPoint_float &pointOnPath, + exAffineTransform transform) +{ + Point p; + float f = self.p->getNearestPoint (targetPoint.toJucePoint(), p, + transform.toJuceAff()); + pointOnPath.x = p.x; + pointOnPath.y = p.y; + return f; +} + +PROTO_API void Path_clear(pPath self) +{ + self.p->clear(); +} + +PROTO_API void Path_startNewSubPath (pPath self, float startX, float startY) +{ + self.p->startNewSubPath (startX, startY); +} + +PROTO_API void Path_startNewSubPath2 (pPath self, exPoint_float start) +{ + self.p->startNewSubPath (start.toJucePoint()); +} + +PROTO_API void Path_closeSubPath(pPath self) +{ + self.p->closeSubPath(); +} + +PROTO_API void Path_lineTo (pPath self, float endX, float endY) +{ + self.p->lineTo (endX, endY); +} + +PROTO_API void Path_lineTo2 (pPath self, exPoint_float end) +{ + self.p->lineTo (end.toJucePoint()); +} + +PROTO_API void Path_quadraticTo (pPath self, float controlPointX, + float controlPointY, + float endPointX, + float endPointY) +{ + self.p->quadraticTo (controlPointX, + controlPointY, + endPointX, + endPointY); +} + +PROTO_API void Path_quadraticTo2 (pPath self, exPoint_float controlPoint, + exPoint_float endPoint) +{ + self.p->quadraticTo (controlPoint.toJucePoint(), + endPoint.toJucePoint()); +} + +PROTO_API void Path_cubicTo (pPath self, float controlPoint1X, + float controlPoint1Y, + float controlPoint2X, + float controlPoint2Y, + float endPointX, + float endPointY) +{ + self.p->cubicTo (controlPoint1X, + controlPoint1Y, + controlPoint2X, + controlPoint2Y, + endPointX, + endPointY); +} + +PROTO_API void Path_cubicTo2 (pPath self, exPoint_float controlPoint1, + exPoint_float controlPoint2, + exPoint_float endPoint) +{ + self.p->cubicTo (controlPoint1.toJucePoint(), + controlPoint2.toJucePoint(), + endPoint.toJucePoint()); +} + +PROTO_API exPoint_float Path_getCurrentPosition(pPath self) +{ + return exPoint_float(self.p->getCurrentPosition()); +} + +PROTO_API void Path_addRectangle (pPath self, float x, float y, float width, float height) +{ + self.p->addRectangle (x, y, width, height); +} + +PROTO_API void Path_addRectangle2 (pPath self, exRectangle_float rectangle) +{ + self.p->addRectangle (rectangle.toJuceRect()); +} + +PROTO_API void Path_addRoundedRectangle2 (pPath self, float x, float y, float width, float height, + float cornerSize) +{ + self.p->addRoundedRectangle (x, y, width, height, + cornerSize); +} + +PROTO_API void Path_addRoundedRectangle3 (pPath self, float x, float y, float width, float height, + float cornerSizeX, + float cornerSizeY) +{ + self.p->addRoundedRectangle (x, y, width, height, + cornerSizeX, + cornerSizeY); +} + +PROTO_API void Path_addRoundedRectangle4 (pPath self, float x, float y, float width, float height, + float cornerSizeX, float cornerSizeY, + bool curveTopLeft, bool curveTopRight, + bool curveBottomLeft, bool curveBottomRight) +{ + self.p->addRoundedRectangle (x, y, width, height, + cornerSizeX, cornerSizeY, + curveTopLeft, curveTopRight, + curveBottomLeft, curveBottomRight); +} + +PROTO_API void Path_addRoundedRectangle5 (pPath self, exRectangle_float rectangle, float cornerSizeX, float cornerSizeY) +{ + self.p->addRoundedRectangle (rectangle.toJuceRect(), cornerSizeX, cornerSizeY); +} + +PROTO_API void Path_addRoundedRectangle6 (pPath self, exRectangle_float rectangle, float cornerSize) +{ + self.p->addRoundedRectangle (rectangle.toJuceRect(), cornerSize); +} + +PROTO_API void Path_addTriangle (pPath self, float x1, float y1, + float x2, float y2, + float x3, float y3) +{ + self.p->addTriangle (x1, y1, + x2, y2, + x3, y3); +} + +PROTO_API void Path_addQuadrilateral (pPath self, float x1, float y1, + float x2, float y2, + float x3, float y3, + float x4, float y4) +{ + self.p->addQuadrilateral (x1, y1, + x2, y2, + x3, y3, + x4, y4); +} + +PROTO_API void Path_addEllipse (pPath self, float x, float y, float width, float height) +{ + self.p->addEllipse (x, y, width, height); +} + +PROTO_API void Path_addArc (pPath self, float x, float y, float width, float height, + float fromRadians, + float toRadians, + bool startAsNewSubPath = false) +{ + self.p->addArc (x, y, width, height, + fromRadians, + toRadians, + startAsNewSubPath); +} + +PROTO_API void Path_addCentredArc (pPath self, float centreX, float centreY, + float radiusX, float radiusY, + float rotationOfEllipse, + float fromRadians, + float toRadians, + bool startAsNewSubPath = false) +{ + self.p->addCentredArc (centreX, centreY, + radiusX, radiusY, + rotationOfEllipse, + fromRadians, + toRadians, + startAsNewSubPath); +} + +PROTO_API void Path_addPieSegment (pPath self, float x, float y, + float width, float height, + float fromRadians, + float toRadians, + float innerCircleProportionalSize) +{ + self.p->addPieSegment (x, y, + width, height, + fromRadians, + toRadians, + innerCircleProportionalSize); +} + +PROTO_API void Path_addLineSegment (pPath self, exLine_float line, float lineThickness) +{ + self.p->addLineSegment (line.toJuceLine(), lineThickness); +} + +PROTO_API void Path_addArrow (pPath self, exLine_float line, + float lineThickness, + float arrowheadWidth, + float arrowheadLength) +{ + self.p->addArrow (line.toJuceLine(), + lineThickness, + arrowheadWidth, + arrowheadLength); +} + +PROTO_API void Path_addPolygon (pPath self, exPoint_float centre, + int numberOfSides, + float radius, + float startAngle = 0.0f) +{ + self.p->addPolygon (centre.toJucePoint(), + numberOfSides, + radius, + startAngle); +} + +PROTO_API void Path_addStar (pPath self, exPoint_float centre, + int numberOfPoints, + float innerRadius, + float outerRadius, + float startAngle = 0.0f) +{ + self.p->addStar (centre.toJucePoint(), + numberOfPoints, + innerRadius, + outerRadius, + startAngle); +} + +PROTO_API void Path_addBubble (pPath self, exRectangle_float bodyArea, + exRectangle_float maximumArea, + exPoint_float arrowTipPosition, + const float cornerSize, + const float arrowBaseWidth) +{ + self.p->addBubble (bodyArea.toJuceRect(), + maximumArea.toJuceRect(), + arrowTipPosition.toJucePoint(), + cornerSize, + arrowBaseWidth); +} + +PROTO_API void Path_addPath (pPath self, pPath pathToAppend) +{ + self.p->addPath (*pathToAppend.p); +} + +PROTO_API void Path_addPath2 (pPath self, pPath pathToAppend, + exAffineTransform transformToApply) +{ + self.p->addPath (*pathToAppend.p, + transformToApply.toJuceAff()); +} + +PROTO_API void Path_applyTransform (pPath self, exAffineTransform transform) +{ + self.p->applyTransform (transform.toJuceAff()); +} + +PROTO_API void Path_scaleToFit (pPath self, float x, float y, float width, float height, + bool preserveProportions) +{ + self.p->scaleToFit (x, y, width, height, + preserveProportions); +} + +PROTO_API exAffineTransform Path_getTransformToScaleToFit (pPath self, float x, float y, float width, float height, + bool preserveProportions, + int justificationType) +{ + return exAffineTransform(self.p->getTransformToScaleToFit (x, y, width, height, + preserveProportions, + justificationType)); +} + +PROTO_API exAffineTransform Path_getTransformToScaleToFit2 (pPath self, exRectangle_float area, + bool preserveProportions, + int justificationType) +{ + return exAffineTransform(self.p->getTransformToScaleToFit (area.toJuceRect(), + preserveProportions, + justificationType)); +} + +PROTO_API pPath Path_createPathWithRoundedCorners (pPath self, float cornerRadius) +{ + pPath p = {new Path()}; + *p.p = self.p->createPathWithRoundedCorners (cornerRadius); + return p; +} + +PROTO_API void Path_setUsingNonZeroWinding (pPath self, bool isNonZeroWinding) +{ + self.p->setUsingNonZeroWinding (isNonZeroWinding); +} + +PROTO_API bool Path_isUsingNonZeroWinding(pPath self) +{ + return self.p->isUsingNonZeroWinding(); +} + +PROTO_API void Path_toString(pPath self, char* dest, int bufSize) +{ + self.p->toString().copyToUTF8(dest, bufSize); +} + +PROTO_API void Path_restoreFromString (pPath self, const char *src) +{ + self.p->restoreFromString (StringRef(src)); +} \ No newline at end of file diff --git a/ports/protoplug/Source/exports/typedefs.h b/ports/protoplug/Source/exports/typedefs.h new file mode 100644 index 0000000..c4232ac --- /dev/null +++ b/ports/protoplug/Source/exports/typedefs.h @@ -0,0 +1,253 @@ +/* + ============================================================================== + + typedefs.h + Created: 7 Mar 2014 5:57:09pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "JuceHeader.h" + + +// adapted from juce_StandardHeader.h +#if JUCE_MSVC + #define PROTO_API __declspec (dllexport) + #pragma warning (disable: 4251) + #ifdef __INTEL_COMPILER + #pragma warning (disable: 1125) // (virtual override warning) + #endif +#else + #define PROTO_API __attribute__ ((visibility("default"))) +#endif + +// pointer-structs : +// this is equivalent passing the pointers directly +// and can be handled as such by the importing program +// it's necessary for proper extern C + +struct pGraphics +{ Graphics *g; }; + +struct pFillType +{ FillType *f; }; + +struct pColourGradient +{ ColourGradient *c; }; + +struct pImage +{ Image *i; }; + +struct pAudioFormatReader +{ + AudioFormatReader *a; + double sampleRate; + unsigned int bitsPerSample; + int64 lengthInSamples; + unsigned int numChannels; + bool usesFloatingPointData; +}; + +struct pFont +{ Font *f; }; + +struct pPath +{ Path *p; }; + +struct pComponent +{ + Component *c; + pComponent(Component *_c) : c(_c) { } +}; + +struct pMidiBuffer +{ MidiBuffer *m; }; + +struct pAudioPlayHead +{ AudioPlayHead *a; }; + + + + +struct exLagrangeInterpolator +{ + float lastInputSamples[5]; + double subSamplePos; +}; + +struct exPoint_int +{ + int x, y; + exPoint_int (const Point &p) :x(p.x), y(p.y) { } + const Point toJucePoint() { return Point(x,y); } +}; + +struct exPoint_float +{ + float x, y; + exPoint_float (const Point &p) :x(p.x), y(p.y) { } + Point toJucePoint() { return Point(x,y); } +}; + +struct exLine_int +{ + int startx, starty; + int endx, endy; + const Line toJuceLine() + { + return Line(startx, starty, endx, endy); + } +}; + +struct exLine_float +{ + float startx, starty; + float endx, endy; + const Line toJuceLine() + { + return Line(startx, starty, endx, endy); + } + exLine_float(Line in) + :startx(in.getStart().getX()), starty(in.getStart().getY()), + endx(in.getEnd().getX()), endy(in.getEnd().getY()) + {} +}; + +struct exRectangle_int +{ + int x, y, w, h; + const Rectangle toJuceRect() + { return Rectangle(x, y, w, h); } + exRectangle_int(const Rectangle &in) + :x(in.getX()), y(in.getY()), w(in.getWidth()), h(in.getHeight()) + { } +}; + +struct exRectangle_float +{ + float x, y, w, h; + const Rectangle toJuceRect() + { return Rectangle(x, y, w, h); } + exRectangle_float(const Rectangle &in) + :x(in.getX()), y(in.getY()), w(in.getWidth()), h(in.getHeight()) + { } +}; + +struct exColour +{ + uint32 c; +}; + +struct exKeyPress +{ + int keyCode; + int mods; + juce_wchar textCharacter; +}; + +exKeyPress KeyPress2Struct(const KeyPress& _k) +{ + exKeyPress k = { + _k.getKeyCode(), + _k.getModifiers().getRawFlags(), + _k.getTextCharacter() + }; + return k; +} + +struct exAffineTransform +{ + float mat00, mat01, mat02; + float mat10, mat11, mat12; + const AffineTransform toJuceAff() + { + return AffineTransform( + mat00, mat01, mat02, + mat10, mat11, mat12); + } + exAffineTransform (AffineTransform in) + : mat00(in.mat00), mat01(in.mat01), mat02(in.mat02), + mat10(in.mat10), mat11(in.mat11), mat12(in.mat12) + {} +}; + +struct exPathStrokeType +{ + float thickness; + int jointStyle; + int endStyle; + const PathStrokeType toJuceType() + { + return PathStrokeType(thickness, + (juce::PathStrokeType::JointStyle)jointStyle, + (juce::PathStrokeType::EndCapStyle)endStyle); + } +}; + +struct exTime +{ + int64 millisSinceEpoch; + exTime (const Time &t) : millisSinceEpoch(t.toMilliseconds()) { } +}; + +// warning in VS because of VS bug 488660 "Improper issuance of C4610" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4510) +#pragma warning(disable:4610) +#endif +struct exMouseEvent +{ + int x, y; + int mods; + pComponent eventComponent; + pComponent originalComponent; + exTime eventTime; + exTime mouseDownTime; + exPoint_int mouseDownPos; + uint8 numberOfClicks, wasMovedSinceMouseDown; +}; +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +exMouseEvent MouseEvent2Struct (const MouseEvent &_e) +{ + exMouseEvent e = + { + _e.x, + _e.y, + _e.mods.getRawFlags(), + _e.eventComponent, + _e.originalComponent, + _e.eventTime, + _e.mouseDownTime, + _e.getMouseDownPosition(), + (uint8)_e.getNumberOfClicks(), + _e.getDistanceFromDragStart()!=0 + }; + return e; +} + +struct exMouseWheelDetails +{ + float deltaX; + float deltaY; + bool isReversed; + bool isSmooth; +}; + +exMouseWheelDetails MouseWheelDetails2Struct (const MouseWheelDetails& _d) +{ + exMouseWheelDetails d = + { + _d.deltaX, + _d.deltaY, + _d.isReversed, + _d.isSmooth + }; + return d; +} diff --git a/ports/protoplug/Source/guiclasses/AboutBox.h b/ports/protoplug/Source/guiclasses/AboutBox.h new file mode 100644 index 0000000..f36231e --- /dev/null +++ b/ports/protoplug/Source/guiclasses/AboutBox.h @@ -0,0 +1,78 @@ + +#pragma once + +#include "JuceHeader.h" +#include "../LuaState.h" +#include "../PluginProcessor.h" +#include "../vflib/FreeTypeAmalgam.h" + +class AboutBox +{ +public: + static void launch(LuaProtoplugJuceAudioProcessor *processor, Component *colours) + { + protolua::LuaState ls(ProtoplugDir::Instance()->getLibDir()); + if (!ls.failed) { + ls.openlibs(); + const char versionScript[] = "return (_VERSION..'\\n'..jit.version)"; + ls.loadbuffer(versionScript, strlen(versionScript), "vs"); + ls.pcall(0, 1, 0); + } + String arch; + arch << + #ifdef JUCE_64BIT + "64-bit " + #else + "32-bit " + #endif + #ifdef JUCE_PPC + << "PPC" + #endif + #ifdef JUCE_ARM + << "ARM" + #endif + #ifdef JUCE_INTEL + << "Intel" + #endif + ; + String plugType; + if (processor->wrapperType == AudioProcessor::wrapperType_AudioUnit) + plugType = "AU"; + else if (processor->wrapperType == AudioProcessor::wrapperType_VST) + plugType = "VST"; + else + plugType = "error"; + String m; + m << "Protoplug " << JucePlugin_VersionString << newLine + << "Author: Pierre Cusa" << newLine + << "Homepage: http://osar.fr/protoplug" << newLine + << "Build date: " << __DATE__ << newLine + << "Architecture: " << arch << newLine + << "Plugin type: " << plugType << newLine << newLine + << "Version info:" << newLine + << "JUCE " << JUCE_MAJOR_VERSION << "." << JUCE_MINOR_VERSION << "." << JUCE_BUILDNUMBER << newLine + << (ls.failed ? "LuaJIT not found" : ls.tostring(-1)) << newLine + << "Freetype " << FREETYPE_MAJOR << "." << FREETYPE_MINOR << "." << FREETYPE_PATCH; + TextEditor *aboutBox = new TextEditor(); + aboutBox->setColour(TextEditor::backgroundColourId, colours->findColour(CodeEditorComponent::backgroundColourId)); + aboutBox->setColour(TextEditor::textColourId, colours->findColour(CodeEditorComponent::defaultTextColourId)); + aboutBox->setColour(TextEditor::highlightedTextColourId, colours->findColour(CodeEditorComponent::defaultTextColourId)); + aboutBox->setColour(TextEditor::highlightColourId, colours->findColour(CodeEditorComponent::highlightColourId)); + aboutBox->setMultiLine (true); + aboutBox->setReadOnly (true); + aboutBox->setScrollbarsShown (true); + aboutBox->setCaretVisible (false); + aboutBox->setPopupMenuEnabled (true); + aboutBox->setText(m); + DialogWindow::LaunchOptions options; + options.content.setOwned (aboutBox); + + options.dialogTitle = "About Protoplug"; + options.escapeKeyTriggersCloseButton = true; + options.useNativeTitleBar = false; + options.resizable = true; + + DialogWindow* dw = options.launchAsync(); + dw->centreWithSize (300, 300); + } +}; diff --git a/ports/protoplug/Source/guiclasses/BottomPane.cpp b/ports/protoplug/Source/guiclasses/BottomPane.cpp new file mode 100644 index 0000000..d5596ea --- /dev/null +++ b/ports/protoplug/Source/guiclasses/BottomPane.cpp @@ -0,0 +1,86 @@ +#include "BottomPane.h" +#include "ProtoWindow.h" + + +//============================================================================== +BottomPane::BottomPane (ProtoWindow *_protoWin): + compileButton("Compile", "It's not pink, it's like, ah... lightish red") +{ + protoWin = _protoWin; + + // Log area + addAndMakeVisible (&log); + log.setMultiLine(true); + log.setReadOnly(true); + log.setCaretVisible(false); + log.setFont(Font(Font::getDefaultMonospacedFontName(), 12, 0)); + log.setColour(TextEditor::backgroundColourId, Colour(0xffe0e0e0)); + + // Compile button + addChildComponent(&compileButton); + compileButton.setColour(TextButton::buttonColourId, Colour(0xffff8d8d)); + tooltip.setLookAndFeel(&protoWin->newFeel); + compileButton.addListener(this); + + // Input area + addChildComponent(&input); + input.setFont(Font(Font::getDefaultMonospacedFontName(), 12, 0)); + input.setColour(TextEditor::backgroundColourId, Colours::transparentWhite); + input.setIndents(16, 4); + input.addListener(this); + + // Prompt label + addAndMakeVisible (&prompt); + prompt.setTarget(&input); + prompt.setFont(Font(Font::getDefaultMonospacedFontName(), 14, Font::bold)); + prompt.setColour(Label::textColourId, Colours::red); + prompt.setText(">", dontSendNotification); +} + +void BottomPane::resized() +{ + if (getHeight()>35) { + input.setVisible(true); + prompt.setVisible(true); + input.setBounds(0, getHeight()-22, getWidth()-103, 22); + prompt.setBounds(0, getHeight()-22, 20, 22); + log.setBounds(0, 0, getWidth()-16, getHeight()-22); + } else { + input.setVisible(false); + prompt.setVisible(false); + log.setBounds(0, 0, getWidth()-16, getHeight()); + } + compileButton.setBounds (getWidth()-100, getHeight()-22, 80, 22); +} + +void BottomPane::buttonClicked (Button *b) +{ + if (b==&compileButton) + protoWin->compile(); +} + +void BottomPane::setCompileVisible(bool hue) +{ + compileButton.setVisible(hue); +} + +void BottomPane::scrollLog() +{ + log.moveCaretToEndOfLine(false); + log.moveCaretToStartOfLine(false); +} + +void BottomPane::updateLog() +{ + log.clear(); + log.setText(protoWin->processor->luli->log); + log.moveCaretToEnd(); + log.moveCaretToEndOfLine(false); + log.moveCaretToStartOfLine(false); +} + +void BottomPane::textEditorReturnKeyPressed (TextEditor &t) +{ + protoWin->processor->luli->runStringInteractive(input.getText()); + input.clear(); +} \ No newline at end of file diff --git a/ports/protoplug/Source/guiclasses/BottomPane.h b/ports/protoplug/Source/guiclasses/BottomPane.h new file mode 100644 index 0000000..a71511a --- /dev/null +++ b/ports/protoplug/Source/guiclasses/BottomPane.h @@ -0,0 +1,51 @@ +#pragma once + +#include "JuceHeader.h" +#include "../LuaCodeTokeniser.h" +#include "HintedFeel.h" +#include "DarkSplitter.h" +#include "ParameterPanel.h" +#include "CustomGuiPanel.h" +#include "LuaEditor.h" +#include "Dockable.h" +#include "ProtoTabButton.h" +#include + +class ProtoWindow; + +// isn't this what labels are supposed to be? +class LabelOfOtherComponent : public Label, public MouseListener +{ +public: + LabelOfOtherComponent() { tgt = 0; } + void setTarget(Component *_tgt) { tgt = _tgt; } + void mouseUp (const MouseEvent &event) { if (tgt) tgt->grabKeyboardFocus(); } +private: + Component *tgt; +}; + +class BottomPane : public Component, + public Button::Listener, + public TextEditor::Listener +{ +public: + BottomPane (ProtoWindow *protoWin); + + void resized(); + void buttonClicked (Button *b); + void textEditorReturnKeyPressed (TextEditor &t); + void setCompileVisible(bool hue); + void updateLog(); + void scrollLog(); + +private: + ProtoWindow *protoWin; + + TextEditor log; + TextButton compileButton; + LabelOfOtherComponent prompt; + TooltipWindow tooltip; // is this used? + + TextEditor input; + //TextButton runButton; // meh, at this point your hand is over the enter key +}; \ No newline at end of file diff --git a/ports/protoplug/Source/guiclasses/CustomGuiPanel.cpp b/ports/protoplug/Source/guiclasses/CustomGuiPanel.cpp new file mode 100644 index 0000000..427804f --- /dev/null +++ b/ports/protoplug/Source/guiclasses/CustomGuiPanel.cpp @@ -0,0 +1,36 @@ +#include "CustomGuiPanel.h" + +void CustomGuiPanel::paint (Graphics& g) +{ luli->paint(g); } + +void CustomGuiPanel::resized () +{ luli->resized(); } + +void CustomGuiPanel::mouseMove (const MouseEvent& event) +{ luli->mouseMove(event); } +void CustomGuiPanel::mouseEnter (const MouseEvent& event) +{ luli->mouseEnter(event); } +void CustomGuiPanel::mouseExit (const MouseEvent& event) +{ luli->mouseExit(event); } +void CustomGuiPanel::mouseDown (const MouseEvent& event) +{ luli->mouseDown(event); } +void CustomGuiPanel::mouseDrag (const MouseEvent& event) +{ luli->mouseDrag(event); } +void CustomGuiPanel::mouseUp (const MouseEvent& event) +{ luli->mouseUp(event); } +void CustomGuiPanel::mouseDoubleClick (const MouseEvent& event) +{ luli->mouseDoubleClick(event); } +void CustomGuiPanel::mouseWheelMove (const MouseEvent& event, const MouseWheelDetails& wheel) +{ luli->mouseWheelMove(event, wheel); } + +bool CustomGuiPanel::keyPressed (const KeyPress &key, Component *originatingComponent) +{ return luli->keyPressed(key, originatingComponent); } +bool CustomGuiPanel::keyStateChanged (bool isKeyDown, Component *originatingComponent) +{ return luli->keyStateChanged(isKeyDown, originatingComponent); } + +void CustomGuiPanel::modifierKeysChanged (const ModifierKeys &modifiers) +{ luli->modifierKeysChanged(modifiers); } +void CustomGuiPanel::focusGained (FocusChangeType cause) +{ luli->focusGained(cause); } +void CustomGuiPanel::focusLost (FocusChangeType cause) +{ luli->focusLost(cause); } \ No newline at end of file diff --git a/ports/protoplug/Source/guiclasses/CustomGuiPanel.h b/ports/protoplug/Source/guiclasses/CustomGuiPanel.h new file mode 100644 index 0000000..89da132 --- /dev/null +++ b/ports/protoplug/Source/guiclasses/CustomGuiPanel.h @@ -0,0 +1,34 @@ +#pragma once + +#include "JuceHeader.h" +#include "../LuaLink.h" + +class CustomGuiPanel : public Component, public KeyListener +{ +public: + CustomGuiPanel (LuaLink *_luli) + { + luli = _luli; + luli->customGui = this; + } + void paint (Graphics& g); + void resized (); + + void mouseMove (const MouseEvent& event); + void mouseEnter (const MouseEvent& event); + void mouseExit (const MouseEvent& event); + void mouseDown (const MouseEvent& event); + void mouseDrag (const MouseEvent& event); + void mouseUp (const MouseEvent& event); + void mouseDoubleClick (const MouseEvent& event); + void mouseWheelMove (const MouseEvent& event, const MouseWheelDetails& wheel); + + bool keyPressed (const KeyPress &key, Component *originatingComponent); + bool keyStateChanged (bool isKeyDown, Component *originatingComponent); + void modifierKeysChanged (const ModifierKeys &modifiers); + void focusGained (FocusChangeType cause); + void focusLost (FocusChangeType cause); + +private: + LuaLink *luli; +}; diff --git a/ports/protoplug/Source/guiclasses/DarkSplitter.h b/ports/protoplug/Source/guiclasses/DarkSplitter.h new file mode 100644 index 0000000..2910f42 --- /dev/null +++ b/ports/protoplug/Source/guiclasses/DarkSplitter.h @@ -0,0 +1,31 @@ +#pragma once + +#include "JuceHeader.h" + + +class DarkSplitter : public StretchableLayoutResizerBar +{ +public: + DarkSplitter (StretchableLayoutManager* layout, const int index, const bool vertical) + : StretchableLayoutResizerBar (layout, index, vertical) + { } + void paint (Graphics& g) + { + float alpha = 0.5f; + if (isMouseOver() || isMouseButtonDown()) + { + g.fillAll (Colour (0x190000ff)); + alpha = 1.0f; + } else + g.fillAll (Colour (0x101010ff)); + + const float cx = getWidth() * 0.5f; + const float cy = getHeight() * 0.5f; + const float cr = jmin (getWidth(), getHeight()) * 0.4f; + + g.setGradientFill (ColourGradient (Colours::white.withAlpha (alpha), cx + cr * 0.1f, cy + cr, + Colours::black.withAlpha (alpha), cx, cy - cr * 4.0f, + true)); + g.fillEllipse (cx - cr, cy - cr, cr * 2.0f, cr * 2.0f); + } +}; diff --git a/ports/protoplug/Source/guiclasses/Dockable.cpp b/ports/protoplug/Source/guiclasses/Dockable.cpp new file mode 100644 index 0000000..4879376 --- /dev/null +++ b/ports/protoplug/Source/guiclasses/Dockable.cpp @@ -0,0 +1,17 @@ +/* + ============================================================================== + + Dockable.cpp + Created: 13 Apr 2014 4:37:52pm + Author: pac + + ============================================================================== +*/ + +#include "Dockable.h" + + + +void DockablePopout::closeButtonPressed() +{ dad->postCommandMessage(1); } + diff --git a/ports/protoplug/Source/guiclasses/Dockable.h b/ports/protoplug/Source/guiclasses/Dockable.h new file mode 100644 index 0000000..3182bce --- /dev/null +++ b/ports/protoplug/Source/guiclasses/Dockable.h @@ -0,0 +1,121 @@ +/* + ============================================================================== + + Dockable.h + Created: 13 Apr 2014 3:42:04pm + Author: pac + + ============================================================================== +*/ + +#pragma once + +#include "JuceHeader.h" +#include "../PluginProcessor.h" + +class Dockable; + +class DockablePopout : public DocumentWindow +{ +public: + DockablePopout ( Dockable *_dad, + const String& name, + Colour backgroundColour, + int requiredButtons, + bool addToDesktop = true) + :DocumentWindow(name, backgroundColour, requiredButtons, addToDesktop) + { dad = _dad; } + + void closeButtonPressed(); +private: + Dockable *dad; +}; + + +class Dockable : public Component +{ +public: + Dockable(Component *_content, String _name, LuaProtoplugJuceAudioProcessor* _processor) + { + content = _content; + name = _name; + processor = _processor; + addAndMakeVisible(content); + } + + void paint (Graphics& g) + { + g.fillAll (Colours::white); + if (docwin==0) return; + g.fillAll(); + g.setColour(Colours::grey); + g.drawText(name + " window popped out !", g.getClipBounds(), Justification::centred, false); + } + + void resized() + { + if (docwin==0) + content->setBounds(0, 0, getWidth(), getHeight()); + } + + void handleCommandMessage(int com) + { + if (com==1 && docwin==0) + popOut(); + else if (com==1 && docwin!=0) + popIn(); + } + + void popOut() + { + docwin = new DockablePopout(this, name, Colours::white, DocumentWindow::allButtons, true); + docwin->setAlwaysOnTop(processor->alwaysontop); + docwin->setResizable(true, false); + docwin->setUsingNativeTitleBar(true); + docwin->setContentNonOwned(content, true); + //processor->popout = true; + //docwin->setContentComponentSize(processor->lastUIWidth, processor->lastUIHeight); + docwin->setTopLeftPosition(processor->lastPopoutX, processor->lastPopoutY); + //content.setPoppedOut(true); + docwin->setVisible(true); + //setSize (280, 130); + //yank.setVisible(true); + //popin.setVisible(true); + //content.takeFocus(); + resized(); + } + + void popIn() + { + //processor->popout = false; + //int w=processor->lastUIWidth, h=processor->lastUIHeight; + addAndMakeVisible(content); + //content.setPoppedOut(false); + //setSize (w,h); + content->setSize (getWidth(), getHeight()); + docwin = 0; + //yank.setVisible(false); + //content.takeFocus(); + //popin.setVisible(false); + resized(); + } + void setAlwaysOnTop(bool aot) + { + if (docwin==0) return; + docwin->setAlwaysOnTop(aot); + } + bool isPoppedOut() + { + return (docwin!=0); + } + void bringWindowToFront() + { + if (docwin==0) return; + docwin->toFront(true); + } +private: + Component *content; + ScopedPointer docwin; + String name; + LuaProtoplugJuceAudioProcessor *processor; +}; diff --git a/ports/protoplug/Source/guiclasses/HintedFeel.cpp b/ports/protoplug/Source/guiclasses/HintedFeel.cpp new file mode 100644 index 0000000..80b64cf --- /dev/null +++ b/ports/protoplug/Source/guiclasses/HintedFeel.cpp @@ -0,0 +1,100 @@ +#include "HintedFeel.h" + +#if JUCE_WINDOWS +#include "juce_core/native/juce_BasicNativeHeaders.h" + +// adapted from Wouter Huysentruit's example +bool GetFontDataFromSystem(String faceName_in, std::vector& data_out) +{ + bool result = false; + HDC hdc = CreateCompatibleDC(NULL); + if (hdc == NULL) + return result; + // give random height, we just want a pointer to the font file's data + HFONT hFont = CreateFont(12,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, + CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,faceName_in.toWideCharPointer()); + if (hFont == NULL) { + DeleteDC(hdc); + return result; + } + SelectObject(hdc, hFont); + const size_t size = GetFontData(hdc, 0, 0, NULL, 0); + if (size > 0) + { + char* buffer = new char[size]; + if (GetFontData(hdc, 0, 0, buffer, size) == size) + { + data_out.resize(size); + memcpy(&data_out[0], buffer, size); + result = true; + } + delete[] buffer; + } + DeleteObject(hFont); + DeleteDC(hdc); + return result; +} + +#else + +bool GetFontDataFromSystem(String faceName_in, std::vector& data_out) +{ + // some day over the + return false; +} + +#endif + +bool GetFontData(const String faceName_in, std::vector& data_out) +{ + for (unsigned int i = 0; i < sizeof (protoFonts) / sizeof (protoFonts[0]); ++i) + if (faceName_in==protoFonts[i].name) + { + data_out.resize(protoFonts[i].size); + memcpy(&data_out[0], protoFonts[i].data, protoFonts[i].size); + return true; + } + return GetFontDataFromSystem(faceName_in, data_out); +} + +FontDataMap HintedFeel::faces = FontDataMap(); + +Typeface::Ptr HintedFeel::getTypefaceForFont (Font const& font) +{ + Typeface::Ptr tf; + String faceName (font.getTypefaceName()); + + if (faceName.endsWith("_hinted_")) + { + faceName = faceName.dropLastCharacters(8); + // add typeface if not yet added + if (faces.count(faceName)==0) { + // for now each font is kept once in memory until program exit + std::vector *data = new std::vector; + faces[faceName] = data; + if (GetFontData(faceName, *data)) + FreeTypeFaces::addFaceFromMemory(9.f, 18.f,true,&((*data)[0]),data->size()); + } + // use freetype if font reading hasn't failed + if (faces[faceName]->size()>0) + { + Font f (font); + f.setTypefaceName (faceName); + tf = FreeTypeFaces::createTypefaceForFont (f); + } + } + // use JUCE rendering if not _hinted_ or freetype failed + if (!tf) { + Font f (font); + f.setTypefaceName (faceName); + tf = LookAndFeel::getTypefaceForFont (f); + } + + return tf; +} + +HintedFeel::~HintedFeel() +{ + // possibly use a static ReferenceCountedObjectPtr ? + // the current implementation may be more efficient +} \ No newline at end of file diff --git a/ports/protoplug/Source/guiclasses/HintedFeel.h b/ports/protoplug/Source/guiclasses/HintedFeel.h new file mode 100644 index 0000000..eec6fbc --- /dev/null +++ b/ports/protoplug/Source/guiclasses/HintedFeel.h @@ -0,0 +1,63 @@ +#pragma once + +#include "../vflib/vf_FreeTypeFaces.h" +#include "../vflib/BinaryDejaVu.h" +#include "../vflib/BinarySourceCodePro.h" +#include +#include + +struct BuiltInFont +{ + const char* name; + int size; + const char* data; +}; +const BuiltInFont protoFonts[] = +{ + { "DejaVu Sans Mono", + BinaryDejaVu::dejavusansmono_ttfSize, + BinaryDejaVu::dejavusansmono_ttf }, + { "Source Code Pro", + BinarySourceCodePro::sourcecodeproregular_ttfSize, + BinarySourceCodePro::sourcecodeproregular_ttf } +}; + +typedef std::map*> FontDataMap; + +class HintedFeel : public LookAndFeel_V3 +{ +public: + HintedFeel() { } + ~HintedFeel(); + Typeface::Ptr getTypefaceForFont (Font const& font); + static FontDataMap faces; + + Font getPopupMenuFont() + { + return Font (15.0f); + } + bool areScrollbarButtonsVisible () {return true;} + void drawTooltip (Graphics& g, const String& text, int width, int height) + { + // this is just a non-bold version of the parent + g.fillAll (findColour (TooltipWindow::backgroundColourId)); + #if ! JUCE_MAC + g.setColour (findColour (TooltipWindow::outlineColourId)); + g.drawRect (0, 0, width, height, 1); + #endif + AttributedString s; + s.setJustification (Justification::centred); + s.append (text, Font (13.0f), findColour (TooltipWindow::textColourId)); + TextLayout tl; + tl.createLayoutWithBalancedLineLengths (s, (float) 400); + tl.draw (g, juce::Rectangle ((float) width, (float) height)); + } + + void getIdealPopupMenuItemSize (const String& text, bool isSeparator, + int standardMenuItemHeight, int& idealWidth, int& idealHeight) + { + LookAndFeel_V2::getIdealPopupMenuItemSize(text, isSeparator, standardMenuItemHeight, idealWidth, idealHeight); + idealHeight += 4; + } +}; + diff --git a/ports/protoplug/Source/guiclasses/LuaEditor.h b/ports/protoplug/Source/guiclasses/LuaEditor.h new file mode 100644 index 0000000..58b2098 --- /dev/null +++ b/ports/protoplug/Source/guiclasses/LuaEditor.h @@ -0,0 +1,78 @@ +#pragma once + +#include "JuceHeader.h" +#include "../PluginProcessor.h" + +class LuaEditor : public CodeEditorComponent, public CodeDocument::Listener +{ +public: + LuaEditor(CodeDocument &doc, CodeTokeniser *tok) : + CodeEditorComponent(doc, tok) + { + somethingChanged = false; + getDocument().addListener(this); + } + void setFontSize(float sz) + { + if (sz<2) sz = 2; + setFont(getFont().withHeight(sz)); + } + void mouseWheelMove(const MouseEvent &e,const MouseWheelDetails &wheel) + { + if (wheel.deltaY != 0 && ModifierKeys::getCurrentModifiers() == ModifierKeys(ModifierKeys::commandModifier)) + setFontSize(getFont().getHeight()+(wheel.deltaY>0?1.f:-1.f)); + else + CodeEditorComponent::mouseWheelMove(e, wheel); + } + void handleTabKey() + { + if (isHighlightActive()) + { + if (ModifierKeys::getCurrentModifiers() == ModifierKeys::noModifiers) + { indentSelection(); return; } + else if (ModifierKeys::getCurrentModifiers() == ModifierKeys::shiftModifier) + { unindentSelection(); return; } + } + insertTabAtCaret(); + } + void handleReturnKey() + { + String line = getDocument().getLine(getCaretPos().getLineNumber()); + String padding = line.initialSectionContainingOnly(" \t"); + insertTextAtCaret (getDocument().getNewLineCharacters()+padding); + } + void findNext(String searchTerm, bool direction, bool wrap = false) + { + if (searchTerm.isEmpty()) + return; + int searchFrom; + if (wrap) + searchFrom = direction ? 0 : getDocument().getAllContent().length(); + else { + Range range = getHighlightedRegion(); + if (range.isEmpty()) + searchFrom = getCaretPos().getPosition() + (direction ? 1 : 0); + else + searchFrom = direction ? range.getEnd() : range.getStart(); + } + int result; + if (direction) + result = getDocument().getAllContent().indexOf(searchFrom, searchTerm); + else + result = getDocument().getAllContent().substring(0,searchFrom).lastIndexOf(searchTerm); + if (result != -1) { + setHighlightedRegion(Range(result, result+searchTerm.length())); + return; + } else { + if (wrap) + return; + else + findNext(searchTerm, direction, true); + } + } + void codeDocumentTextInserted(const String &newText, int insertIndex) + { somethingChanged = true; } + void codeDocumentTextDeleted(int startIndex, int endIndex) + { somethingChanged = true; } + bool somethingChanged; +}; diff --git a/ports/protoplug/Source/guiclasses/ParameterPanel.h b/ports/protoplug/Source/guiclasses/ParameterPanel.h new file mode 100644 index 0000000..c29becf --- /dev/null +++ b/ports/protoplug/Source/guiclasses/ParameterPanel.h @@ -0,0 +1,126 @@ +#pragma once + +#include "JuceHeader.h" +#include "../PluginProcessor.h" + +class ParamSlider : public Slider +{ +public: + ParamSlider(LuaProtoplugJuceAudioProcessor *_pfx, int _index) + { + pfx = _pfx; + index = _index; + //Slider::setTextBoxIsEditable(false); + } + String getTextFromValue (double /*value must be set in pfx*/) + { + return pfx->getParameterText(index); + } + double getValueFromText (const String &text) + { + double d; + if (pfx->parameterText2Double(index, text, d)) + return d; + return Slider::getValueFromText(text); + } +private: + int index; + LuaProtoplugJuceAudioProcessor *pfx; +}; + +class ParamPanelContent : public Component +{ +public: + void paint (Graphics& g) { g.fillAll (Colour(0xffffffff)); } +}; + +class ParameterPanel : public Viewport, public Slider::Listener +{ +public: + ParameterPanel (LuaProtoplugJuceAudioProcessor* _processor) + { + processor = _processor; + content = new ParamPanelContent(); + content->setBounds(0, 0, 220, NPARAMS*36+36); + for (int i=0; isetEditable (false, false, false); + labels[i]->setBounds(10, i*36, 100, 22); + content->addAndMakeVisible(labels[i]); + sliders[i] = new ParamSlider(processor, i); + sliders[i]->setSliderStyle (Slider::LinearBar); + sliders[i]->setBounds(110, i*36, getWidth()-130, 22); + sliders[i]->setRange(0, 1.0); + sliders[i]->setValue(processor->params[i], dontSendNotification); + sliders[i]->updateText(); + sliders[i]->addListener(this); + content->addAndMakeVisible(sliders[i]); + } + updateNames(); + setViewedComponent (content); + } + + void resized() + { + content->setSize(std::max(getWidth()-getLookAndFeel().getDefaultScrollbarWidth(),320), NPARAMS*36+36); + for (int i=0; isetSize(std::max(getWidth()-130,200), 22); + } + // work around shit + setViewPosition(getViewPosition().x, getViewPosition().y+1); + setViewPosition(getViewPosition().x, getViewPosition().y-1); + } + + void sliderDragStarted (Slider* sliderThatWasMoved) + { + for (int i=0; ibeginParameterChangeGesture(i); + break; + } + } + void sliderDragEnded (Slider* sliderThatWasMoved) + { + for (int i=0; iendParameterChangeGesture(i); + break; + } + } + void sliderValueChanged (Slider* sliderThatWasMoved) + { + for (int i=0; isetParameterNotifyingHost(i, (float)sliderThatWasMoved->getValue()); + sliders[i]->updateText(); + break; + } + } + void updateNames() + { + for (int i=0; iluli->getParameterName(i); + if (s==String::empty) { + s = "nameless"; + labels[i]->setColour(Label::textColourId, Colours::grey); + } else + labels[i]->setColour(Label::textColourId, Colours::black); + labels[i]->setText(String::formatted("%d. ",i) + s, dontSendNotification); + } + } + void paramsChanged() + { + for (int i=0; isetValue(processor->params[i], dontSendNotification); + sliders[i]->updateText(); + } + } + void paint (Graphics& g) { g.fillAll (Colour(0xffffffff)); } + +private: + ScopedPointer content; + ScopedPointer sliders[NPARAMS]; + ScopedPointer