mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-25 02:04:23 +00:00
BLOCKS example apps: some cleanup, enabled DUMP_TOPOLOGY flag
This commit is contained in:
parent
7bb0fe4077
commit
de84462f2d
9 changed files with 172 additions and 169 deletions
|
|
@ -17,7 +17,7 @@
|
|||
//==============================================================================
|
||||
// [BEGIN_USER_CODE_SECTION]
|
||||
|
||||
// (You can add your own code in this section, and the Projucer will not overwrite it)
|
||||
#define DUMP_TOPOLOGY 1
|
||||
|
||||
// [END_USER_CODE_SECTION]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "../JuceLibraryCode/JuceHeader.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A struct that handles the setup and layout of the DrumPadGridProgram
|
||||
*/
|
||||
|
|
@ -70,28 +71,31 @@ struct ColourGrid
|
|||
|
||||
//==============================================================================
|
||||
int numColumns, numRows;
|
||||
float width, height;
|
||||
|
||||
Array<DrumPadGridProgram::GridFill> gridFillArray;
|
||||
Array<Colour> colourArray = { Colours::white, Colours::red, Colours::green, Colours::blue, Colours::hotpink,
|
||||
Colours::orange, Colours::magenta, Colours::cyan, Colours::black };
|
||||
|
||||
Array<Colour> colourArray = { Colours::white, Colours::red, Colours::green,
|
||||
Colours::blue, Colours::hotpink, Colours::orange,
|
||||
Colours::magenta, Colours::cyan, Colours::black };
|
||||
|
||||
Colour currentColour = Colours::hotpink;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourGrid)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
The main component
|
||||
*/
|
||||
class MainComponent : public Component,
|
||||
public TopologySource::Listener,
|
||||
private TouchSurface::Listener,
|
||||
private ControlButton::Listener,
|
||||
private Timer
|
||||
public TopologySource::Listener,
|
||||
private TouchSurface::Listener,
|
||||
private ControlButton::Listener,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
MainComponent() : layout (3, 3)
|
||||
MainComponent()
|
||||
{
|
||||
setSize (600, 400);
|
||||
|
||||
|
|
@ -110,7 +114,8 @@ public:
|
|||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (Colours::lightgrey);
|
||||
g.drawText ("Connect a Lightpad Block to draw.", getLocalBounds(), Justification::centred, false);
|
||||
g.drawText ("Connect a Lightpad Block to draw.",
|
||||
getLocalBounds(), Justification::centred, false);
|
||||
}
|
||||
|
||||
void resized() override {}
|
||||
|
|
@ -176,7 +181,7 @@ private:
|
|||
}
|
||||
|
||||
/** Overridden from ControlButton::Listener. Called when a button on the Lightpad is pressed */
|
||||
void buttonPressed (ControlButton&, Block::Timestamp) override {};
|
||||
void buttonPressed (ControlButton&, Block::Timestamp) override {}
|
||||
|
||||
/** Overridden from ControlButton::Listener. Called when a button on the Lightpad is released */
|
||||
void buttonReleased (ControlButton&, Block::Timestamp) override
|
||||
|
|
@ -257,7 +262,9 @@ private:
|
|||
grid->setProgram (colourPaletteProgram);
|
||||
|
||||
// Setup the grid layout
|
||||
colourPaletteProgram->setGridFills (layout.numColumns, layout.numRows, layout.gridFillArray);
|
||||
colourPaletteProgram->setGridFills (layout.numColumns,
|
||||
layout.numRows,
|
||||
layout.gridFillArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,20 +272,12 @@ private:
|
|||
void drawLEDs (uint32 x0, uint32 y0, float z, Colour drawColour)
|
||||
{
|
||||
// Check if the activeLeds array already contains an ActiveLED object for this LED
|
||||
int index = -1;
|
||||
for (int i = 0; i < activeLeds.size(); ++i)
|
||||
{
|
||||
if (activeLeds.getReference(i).occupies (x0, y0))
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto index = getLEDAt (x0, y0);
|
||||
|
||||
// If the colour is black then just set the LED to black and return
|
||||
if (drawColour == Colours::black)
|
||||
{
|
||||
if (index != -1)
|
||||
if (index >= 0)
|
||||
{
|
||||
canvasProgram->setLED (x0, y0, Colours::black);
|
||||
activeLeds.remove (index);
|
||||
|
|
@ -289,7 +288,7 @@ private:
|
|||
|
||||
// If there is no ActiveLED obejct for this LED then create one,
|
||||
// add it to the array, set the LED on the Block and return
|
||||
if (index == -1)
|
||||
if (index < 0)
|
||||
{
|
||||
ActiveLED led;
|
||||
led.x = x0;
|
||||
|
|
@ -333,37 +332,42 @@ private:
|
|||
*/
|
||||
struct ActiveLED
|
||||
{
|
||||
uint32 x;
|
||||
uint32 y;
|
||||
uint32 x, y;
|
||||
Colour colour;
|
||||
float brightness;
|
||||
|
||||
/** Returns true if this LED occupies the given co-ordiantes */
|
||||
/** Returns true if this LED occupies the given co-ordinates */
|
||||
bool occupies (uint32 xPos, uint32 yPos) const
|
||||
{
|
||||
if (xPos == x && yPos == y)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return xPos == x && yPos == y;
|
||||
}
|
||||
};
|
||||
|
||||
Array<ActiveLED> activeLeds;
|
||||
|
||||
/**
|
||||
enum for the two modes
|
||||
*/
|
||||
int getLEDAt (uint32 x, uint32 y) const
|
||||
{
|
||||
for (int i = 0; i < activeLeds.size(); ++i)
|
||||
if (activeLeds.getReference(i).occupies (x, y))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
enum DisplayMode
|
||||
{
|
||||
colourPalette = 0,
|
||||
canvas
|
||||
};
|
||||
|
||||
DisplayMode currentMode = colourPalette;
|
||||
|
||||
//==============================================================================
|
||||
BitmapLEDProgram* canvasProgram;
|
||||
DrumPadGridProgram* colourPaletteProgram;
|
||||
BitmapLEDProgram* canvasProgram = nullptr;
|
||||
DrumPadGridProgram* colourPaletteProgram = nullptr;
|
||||
|
||||
ColourGrid layout;
|
||||
ColourGrid layout { 3, 3 };
|
||||
PhysicalTopologySource topologySource;
|
||||
Block::Ptr activeBlock;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
//==============================================================================
|
||||
// [BEGIN_USER_CODE_SECTION]
|
||||
|
||||
// (You can add your own code in this section, and the Projucer will not overwrite it)
|
||||
#define DUMP_TOPOLOGY 1
|
||||
|
||||
// [END_USER_CODE_SECTION]
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ class BlockComponent : public Component,
|
|||
private Timer
|
||||
{
|
||||
public:
|
||||
/** Constructor */
|
||||
BlockComponent (Block::Ptr blockToUse)
|
||||
: block (blockToUse)
|
||||
{
|
||||
|
|
@ -38,7 +37,6 @@ public:
|
|||
startTimerHz (25);
|
||||
}
|
||||
|
||||
/** Destructor */
|
||||
~BlockComponent()
|
||||
{
|
||||
// Remove any listeners
|
||||
|
|
@ -53,19 +51,16 @@ public:
|
|||
void updateStatsAndTooltip()
|
||||
{
|
||||
// Get the battery level of this Block and inform any subclasses
|
||||
const float batteryLevel = block->getBatteryLevel();
|
||||
auto batteryLevel = block->getBatteryLevel();
|
||||
handleBatteryLevelUpdate (batteryLevel);
|
||||
|
||||
// Format the tooltip string
|
||||
const String ttString = "Name = " + block->getDeviceDescription() + "\n"
|
||||
+ "UID = " + String (block->uid) + "\n"
|
||||
+ "Serial number = " + block->serialNumber + "\n"
|
||||
+ "Battery level = " + String ((int) (batteryLevel * 100)) + "%"
|
||||
+ (block->isBatteryCharging() ? "++" : "--");
|
||||
|
||||
// Update the tooltip string if it has changed
|
||||
if (ttString != getTooltip())
|
||||
setTooltip (ttString);
|
||||
// Update the tooltip
|
||||
setTooltip ("Name = " + block->getDeviceDescription() + "\n"
|
||||
+ "UID = " + String (block->uid) + "\n"
|
||||
+ "Serial number = " + block->serialNumber + "\n"
|
||||
+ "Battery level = " + String ((int) (batteryLevel * 100)) + "%"
|
||||
+ (block->isBatteryCharging() ? "++"
|
||||
: "--"));
|
||||
}
|
||||
|
||||
/** Subclasses should override this to paint the Block object on the screen */
|
||||
|
|
@ -88,31 +83,35 @@ public:
|
|||
|
||||
//==============================================================================
|
||||
/** Returns an integer index corresponding to a physical position on the hardware
|
||||
for each type of Control Block. */
|
||||
for each type of Control Block. */
|
||||
static int controlButtonFunctionToIndex (ControlButton::ButtonFunction f)
|
||||
{
|
||||
static std::initializer_list<ControlButton::ButtonFunction> map[] =
|
||||
{{ControlButton::mode, ControlButton::button0},
|
||||
{ControlButton::volume, ControlButton::button1},
|
||||
{ControlButton::scale, ControlButton::button2, ControlButton::click},
|
||||
{ControlButton::chord, ControlButton::button3, ControlButton::snap},
|
||||
{ControlButton::arp,ControlButton:: button4, ControlButton::back},
|
||||
{ControlButton::sustain, ControlButton::button5, ControlButton::playOrPause},
|
||||
{ControlButton::octave, ControlButton::button6, ControlButton::record},
|
||||
{ControlButton::love, ControlButton::button7, ControlButton::learn},
|
||||
{ControlButton::up},
|
||||
{ControlButton::down}};
|
||||
using CB = ControlButton;
|
||||
|
||||
for (size_t i = 0; i < (sizeof (map) / sizeof (map[0])); ++i)
|
||||
if (std::find (map[i].begin(), map[i].end(), f) != map[i].end())
|
||||
return static_cast<int> (i);
|
||||
static Array<ControlButton::ButtonFunction> map[] =
|
||||
{
|
||||
{ CB::mode, CB::button0 },
|
||||
{ CB::volume, CB::button1 },
|
||||
{ CB::scale, CB::button2, CB::click },
|
||||
{ CB::chord, CB::button3, CB::snap },
|
||||
{ CB::arp, CB::button4, CB::back },
|
||||
{ CB::sustain, CB::button5, CB::playOrPause },
|
||||
{ CB::octave, CB::button6, CB::record },
|
||||
{ CB::love, CB::button7, CB::learn },
|
||||
{ CB::up },
|
||||
{ CB::down }
|
||||
};
|
||||
|
||||
for (int i = 0; i < numElementsInArray (map); ++i)
|
||||
if (map[i].contains (f))
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private:
|
||||
/** Used to call repaint() periodically */
|
||||
void timerCallback() override { repaint(); }
|
||||
void timerCallback() override { repaint(); }
|
||||
|
||||
/** Overridden from TouchSurface::Listener */
|
||||
void touchChanged (TouchSurface&, const TouchSurface::Touch& t) override { handleTouchChange (t); }
|
||||
|
|
@ -123,14 +122,14 @@ private:
|
|||
/** Overridden from ControlButton::Listener */
|
||||
void buttonReleased (ControlButton& b, Block::Timestamp t) override { handleButtonReleased (b.getType(), t); }
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BlockComponent)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Class that renders a Lightpad on the screen
|
||||
*/
|
||||
class LightpadComponent : public BlockComponent
|
||||
class LightpadComponent : public BlockComponent
|
||||
{
|
||||
public:
|
||||
LightpadComponent (Block::Ptr blockToUse)
|
||||
|
|
@ -154,23 +153,25 @@ public:
|
|||
g.fillAll (Colours::black);
|
||||
|
||||
// size ration between physical and on-screen blocks
|
||||
const Point<float> ratio (r.getWidth() / block->getWidth(),
|
||||
r.getHeight() / block->getHeight());
|
||||
const float maxCircleSize = block->getWidth() / 3.0f;
|
||||
Point<float> ratio (r.getWidth() / block->getWidth(),
|
||||
r.getHeight() / block->getHeight());
|
||||
|
||||
float maxCircleSize = block->getWidth() / 3.0f;
|
||||
|
||||
// iterate over the list of current touches and draw them on the onscreen Block
|
||||
for (auto touch : touches)
|
||||
{
|
||||
const float circleSize = touch.touch.z * maxCircleSize;
|
||||
const Point<float> touchPosition = Point<float> (touch.touch.x, touch.touch.y);
|
||||
float circleSize = touch.touch.z * maxCircleSize;
|
||||
|
||||
const Colour c = colourArray[touch.touch.index];
|
||||
const Rectangle<float> blob =
|
||||
(Rectangle<float> (circleSize, circleSize).withCentre (touchPosition)) * ratio;
|
||||
Point<float> touchPosition (touch.touch.x,
|
||||
touch.touch.y);
|
||||
|
||||
const ColourGradient cg = ColourGradient (colourArray[touch.touch.index], blob.getCentreX(), blob.getCentreY(),
|
||||
Colours::transparentBlack, blob.getRight(), blob.getBottom(),
|
||||
true);
|
||||
auto blob = Rectangle<float> (circleSize, circleSize)
|
||||
.withCentre (touchPosition) * ratio;
|
||||
|
||||
ColourGradient cg (colourArray[touch.touch.index], blob.getCentreX(), blob.getCentreY(),
|
||||
Colours::transparentBlack, blob.getRight(), blob.getBottom(),
|
||||
true);
|
||||
|
||||
g.setGradientFill (cg);
|
||||
g.fillEllipse (blob);
|
||||
|
|
@ -181,21 +182,26 @@ public:
|
|||
|
||||
private:
|
||||
/** An Array of colours to use for touches */
|
||||
Array<Colour> colourArray = { Colours::red, Colours::blue, Colours::green,
|
||||
Colours::yellow, Colours::white, Colours::hotpink,
|
||||
Array<Colour> colourArray = { Colours::red,
|
||||
Colours::blue,
|
||||
Colours::green,
|
||||
Colours::yellow,
|
||||
Colours::white,
|
||||
Colours::hotpink,
|
||||
Colours::mediumpurple };
|
||||
|
||||
/** A list of current Touch events */
|
||||
TouchList<TouchSurface::Touch> touches;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LightpadComponent)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Class that renders a Control Block on the screen
|
||||
*/
|
||||
class ControlBlockComponent : public BlockComponent
|
||||
class ControlBlockComponent : public BlockComponent
|
||||
{
|
||||
public:
|
||||
ControlBlockComponent (Block::Ptr blockToUse)
|
||||
|
|
@ -205,13 +211,12 @@ public:
|
|||
addAndMakeVisible (roundedRectangleButton);
|
||||
|
||||
// Display the battery level on the LEDRow
|
||||
int numLedsToTurnOn = static_cast<int> (static_cast<float> (numLeds) * block->getBatteryLevel());
|
||||
auto numLedsToTurnOn = static_cast<int> (numLeds * block->getBatteryLevel());
|
||||
|
||||
// add LEDs
|
||||
LEDComponent* ledComponent;
|
||||
for (int i = 0; i < numLeds; ++i)
|
||||
{
|
||||
ledComponent = new LEDComponent();
|
||||
auto ledComponent = new LEDComponent();
|
||||
ledComponent->setOnState (i < numLedsToTurnOn);
|
||||
|
||||
addAndMakeVisible (leds.add (ledComponent));
|
||||
|
|
@ -238,9 +243,9 @@ public:
|
|||
auto buttonRow1 = row.removeFromTop (rowHeight * 2).withSizeKeepingCentre (r.getWidth(), buttonWidth);
|
||||
auto buttonRow2 = row.removeFromTop (rowHeight * 2).withSizeKeepingCentre (r.getWidth(), buttonWidth);
|
||||
|
||||
for (int i = 0; i < numLeds; ++i)
|
||||
for (auto* led : leds)
|
||||
{
|
||||
leds.getUnchecked (i)->setBounds (ledRow.removeFromLeft (ledWidth).reduced (2));
|
||||
led->setBounds (ledRow.removeFromLeft (ledWidth).reduced (2));
|
||||
ledRow.removeFromLeft (5);
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +266,7 @@ public:
|
|||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
const auto r = getLocalBounds().toFloat();
|
||||
auto r = getLocalBounds().toFloat();
|
||||
|
||||
// Fill a black rectangle for the Control Block
|
||||
g.setColour (Colours::black);
|
||||
|
|
@ -281,7 +286,7 @@ public:
|
|||
void handleBatteryLevelUpdate (float batteryLevel) override
|
||||
{
|
||||
// Update the number of LEDs that are on to represent the battery level
|
||||
int numLedsOn = static_cast<int> (static_cast<float> (numLeds) * batteryLevel);
|
||||
int numLedsOn = static_cast<int> (numLeds * batteryLevel);
|
||||
|
||||
if (numLedsOn != previousNumLedsOn)
|
||||
for (int i = 0; i < numLeds; ++i)
|
||||
|
|
@ -292,22 +297,22 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
/**
|
||||
Base class that renders a Control Block button
|
||||
*/
|
||||
struct ControlBlockSubComponent : public Component,
|
||||
public TooltipClient
|
||||
struct ControlBlockSubComponent : public Component,
|
||||
public TooltipClient
|
||||
{
|
||||
ControlBlockSubComponent (Colour componentColourToUse)
|
||||
: componentColour (componentColourToUse),
|
||||
onState (false)
|
||||
: componentColour (componentColourToUse)
|
||||
{}
|
||||
|
||||
/** Subclasses should override this to paint the button on the screen */
|
||||
virtual void paint (Graphics&) override = 0;
|
||||
|
||||
/** Sets the colour of the button */
|
||||
void setColour (Colour c) { componentColour = c; }
|
||||
void setColour (Colour c) { componentColour = c; }
|
||||
|
||||
/** Sets the on state of the button */
|
||||
void setOnState (bool isOn)
|
||||
|
|
@ -320,15 +325,15 @@ private:
|
|||
String getTooltip() override
|
||||
{
|
||||
for (Component* comp = this; comp != nullptr; comp = comp->getParentComponent())
|
||||
if (SettableTooltipClient* sttc = dynamic_cast<SettableTooltipClient*> (comp))
|
||||
if (auto* sttc = dynamic_cast<SettableTooltipClient*> (comp))
|
||||
return sttc->getTooltip();
|
||||
|
||||
return String();
|
||||
return {};
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Colour componentColour;
|
||||
bool onState;
|
||||
bool onState = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ControlBlockSubComponent)
|
||||
|
|
@ -372,8 +377,7 @@ private:
|
|||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
const auto r = getLocalBounds().toFloat();
|
||||
|
||||
auto r = getLocalBounds().toFloat();
|
||||
|
||||
g.setColour (componentColour.withAlpha (0.2f));
|
||||
g.fillRoundedRectangle (r.toFloat(), 20.0f);
|
||||
|
|
@ -382,11 +386,11 @@ private:
|
|||
// is a button pressed?
|
||||
if (doubleButtonOnState[0] || doubleButtonOnState[1])
|
||||
{
|
||||
const float semiButtonWidth = r.getWidth() / 2.0f;
|
||||
const auto semiButtonBounds = r.withWidth (semiButtonWidth)
|
||||
.withX (doubleButtonOnState[1] ? semiButtonWidth : 0)
|
||||
.reduced (5.0f, 2.0f);
|
||||
auto semiButtonWidth = r.getWidth() / 2.0f;
|
||||
|
||||
auto semiButtonBounds = r.withWidth (semiButtonWidth)
|
||||
.withX (doubleButtonOnState[1] ? semiButtonWidth : 0)
|
||||
.reduced (5.0f, 2.0f);
|
||||
|
||||
g.fillEllipse (semiButtonBounds);
|
||||
}
|
||||
|
|
@ -399,7 +403,7 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
bool doubleButtonOnState[2] = {false, false};
|
||||
bool doubleButtonOnState[2] = { false, false };
|
||||
};
|
||||
|
||||
/** Displays a button press or release interaction for a button at a given index */
|
||||
|
|
|
|||
|
|
@ -46,10 +46,10 @@ public:
|
|||
}
|
||||
|
||||
// Work out the maximum diplay area for each Block
|
||||
const Rectangle<int> bounds = getLocalBounds().reduced (20);
|
||||
auto bounds = getLocalBounds().reduced (20);
|
||||
|
||||
auto squareRoot = sqrt (numBlockComponents);
|
||||
int gridSize = (int)squareRoot;
|
||||
auto squareRoot = std::sqrt (numBlockComponents);
|
||||
int gridSize = (int) squareRoot;
|
||||
|
||||
if (squareRoot - gridSize > 0)
|
||||
gridSize++;
|
||||
|
|
@ -64,7 +64,7 @@ public:
|
|||
for (auto block : blockComponents)
|
||||
{
|
||||
Rectangle<int> blockBounds;
|
||||
const Block::Type type = block->block->getType();
|
||||
auto type = block->block->getType();
|
||||
|
||||
// Can fit 2 ControlBlockComponents in the space of one LightpadBlockComponent
|
||||
if (type == Block::liveBlock || type == Block::loopBlock)
|
||||
|
|
@ -105,11 +105,11 @@ public:
|
|||
blockComponents.clear();
|
||||
|
||||
// Get the array of currently connected Block objects from the PhysicalTopologySource
|
||||
Block::Array blocksArray = topologySource.getCurrentTopology().blocks;
|
||||
auto blocksArray = topologySource.getCurrentTopology().blocks;
|
||||
|
||||
// Create a BlockComponent object for each Block object
|
||||
for (auto& block : blocksArray)
|
||||
if (BlockComponent* blockComponent = createBlockComponent (block))
|
||||
if (auto* blockComponent = createBlockComponent (block))
|
||||
addAndMakeVisible (blockComponents.add (blockComponent));
|
||||
|
||||
// Update the display
|
||||
|
|
@ -120,16 +120,16 @@ private:
|
|||
/** Creates a BlockComponent object for a new Block and adds it to the content component */
|
||||
BlockComponent* createBlockComponent (Block::Ptr newBlock)
|
||||
{
|
||||
const Block::Type type = newBlock->getType();
|
||||
auto type = newBlock->getType();
|
||||
|
||||
if (type == Block::lightPadBlock)
|
||||
return new LightpadComponent (newBlock);
|
||||
|
||||
if (type == Block::loopBlock || type == Block::liveBlock)
|
||||
return new ControlBlockComponent (newBlock);
|
||||
|
||||
// should only be connecting a Lightpad or Control Block!
|
||||
jassertfalse;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
//==============================================================================
|
||||
// [BEGIN_USER_CODE_SECTION]
|
||||
|
||||
// (You can add your own code in this section, and the Projucer will not overwrite it)
|
||||
#define DUMP_TOPOLOGY 1
|
||||
|
||||
// [END_USER_CODE_SECTION]
|
||||
|
||||
|
|
|
|||
|
|
@ -27,9 +27,8 @@ public:
|
|||
void shutdown() override { mainWindow = nullptr; }
|
||||
|
||||
//==============================================================================
|
||||
class MainWindow : public DocumentWindow
|
||||
struct MainWindow : public DocumentWindow
|
||||
{
|
||||
public:
|
||||
MainWindow (String name) : DocumentWindow (name,
|
||||
Colours::lightgrey,
|
||||
DocumentWindow::allButtons)
|
||||
|
|
@ -47,10 +46,8 @@ public:
|
|||
JUCEApplication::getInstance()->systemRequestedQuit();
|
||||
}
|
||||
|
||||
private:
|
||||
TooltipWindow tooltipWindow;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "../JuceLibraryCode/JuceHeader.h"
|
||||
#include "Audio.h"
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A struct that handles the setup and layout of the DrumPadGridProgram
|
||||
*/
|
||||
|
|
@ -41,7 +42,7 @@ struct SynthGrid
|
|||
}
|
||||
}
|
||||
|
||||
int getNoteNumberForPad (int x, int y)
|
||||
int getNoteNumberForPad (int x, int y) const
|
||||
{
|
||||
int xIndex = x / 3;
|
||||
int yIndex = y / 3;
|
||||
|
|
@ -64,6 +65,7 @@ struct SynthGrid
|
|||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SynthGrid)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
The main component
|
||||
*/
|
||||
|
|
@ -74,7 +76,7 @@ class MainComponent : public Component,
|
|||
private Timer
|
||||
{
|
||||
public:
|
||||
MainComponent() : layout (5, 5)
|
||||
MainComponent()
|
||||
{
|
||||
setSize (600, 400);
|
||||
|
||||
|
|
@ -93,7 +95,8 @@ public:
|
|||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (Colours::lightgrey);
|
||||
g.drawText ("Connect a Lightpad Block to play.", getLocalBounds(), Justification::centred, false);
|
||||
g.drawText ("Connect a Lightpad Block to play.",
|
||||
getLocalBounds(), Justification::centred, false);
|
||||
}
|
||||
|
||||
void resized() override {}
|
||||
|
|
@ -106,7 +109,7 @@ public:
|
|||
detachActiveBlock();
|
||||
|
||||
// Get the array of currently connected Block objects from the PhysicalTopologySource
|
||||
Block::Array blocks = topologySource.getCurrentTopology().blocks;
|
||||
auto blocks = topologySource.getCurrentTopology().blocks;
|
||||
|
||||
// Iterate over the array of Block objects
|
||||
for (auto b : blocks)
|
||||
|
|
@ -180,10 +183,11 @@ private:
|
|||
if (touchMessageTimesInLastSecond.size() > maxNumTouchMessagesPerSecond / 3)
|
||||
return;
|
||||
|
||||
gridProgram->sendTouch (touch.x, touch.y, touch.z, layout.touchColour);
|
||||
gridProgram->sendTouch (touch.x, touch.y, touch.z,
|
||||
layout.touchColour);
|
||||
|
||||
// Send pitch change and pressure values to the Audio class
|
||||
audio.pitchChange (midiChannel, (touch.x - touch.startX) / static_cast<float> (activeBlock->getWidth()));
|
||||
audio.pitchChange (midiChannel, (touch.x - touch.startX) / activeBlock->getWidth());
|
||||
audio.pressureChange (midiChannel, touch.z);
|
||||
}
|
||||
|
||||
|
|
@ -215,26 +219,18 @@ private:
|
|||
// Clear all LEDs
|
||||
for (uint32 x = 0; x < 15; ++x)
|
||||
for (uint32 y = 0; y < 15; ++y)
|
||||
bitmapProgram->setLED (x, y, Colours::black);
|
||||
setLED (x, y, Colours::black);
|
||||
|
||||
// Determine which array to use based on waveshapeMode
|
||||
int* waveshapeY = nullptr;
|
||||
|
||||
switch (waveshapeMode)
|
||||
{
|
||||
case 0:
|
||||
waveshapeY = sineWaveY;
|
||||
break;
|
||||
case 1:
|
||||
waveshapeY = squareWaveY;
|
||||
break;
|
||||
case 2:
|
||||
waveshapeY = sawWaveY;
|
||||
break;
|
||||
case 3:
|
||||
waveshapeY = triangleWaveY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 0: waveshapeY = sineWaveY; break;
|
||||
case 1: waveshapeY = squareWaveY; break;
|
||||
case 2: waveshapeY = sawWaveY; break;
|
||||
case 3: waveshapeY = triangleWaveY; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// For each X co-ordinate
|
||||
|
|
@ -306,7 +302,9 @@ private:
|
|||
grid->setProgram (gridProgram);
|
||||
|
||||
// Setup the grid layout
|
||||
gridProgram->setGridFills (layout.numColumns, layout.numRows, layout.gridFillArray);
|
||||
gridProgram->setGridFills (layout.numColumns,
|
||||
layout.numRows,
|
||||
layout.gridFillArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -341,6 +339,7 @@ private:
|
|||
|
||||
// Saw wave output, set flags for when vertical line should be drawn
|
||||
sawWaveY[x] = 14 - ((x / 2) % 15);
|
||||
|
||||
if (sawWaveY[x] == 0 && sawWaveY[x - 1] != -1)
|
||||
sawWaveY[x] = -1;
|
||||
|
||||
|
|
@ -361,42 +360,47 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
/** Simple wrapper function to set a LED colour */
|
||||
void setLED (uint32 x, uint32 y, Colour colour)
|
||||
{
|
||||
if (bitmapProgram != nullptr)
|
||||
bitmapProgram->setLED (x, y, colour);
|
||||
}
|
||||
|
||||
/** Draws a 'circle' on the Lightpad around an origin co-ordinate */
|
||||
void drawLEDCircle (uint32 x0, uint32 y0)
|
||||
{
|
||||
bitmapProgram->setLED (x0, y0, waveshapeColour);
|
||||
setLED (x0, y0, waveshapeColour);
|
||||
|
||||
const uint32 minLedIndex = 0;
|
||||
const uint32 maxLedIndex = 14;
|
||||
|
||||
bitmapProgram->setLED (jmin (x0 + 1, maxLedIndex), y0, waveshapeColour.withBrightness (0.4f));
|
||||
bitmapProgram->setLED (jmax (x0 - 1, minLedIndex), y0, waveshapeColour.withBrightness (0.4f));
|
||||
bitmapProgram->setLED (x0, jmin (y0 + 1, maxLedIndex), waveshapeColour.withBrightness (0.4f));
|
||||
bitmapProgram->setLED (x0, jmax (y0 - 1, minLedIndex), waveshapeColour.withBrightness (0.4f));
|
||||
setLED (jmin (x0 + 1, maxLedIndex), y0, waveshapeColour.withBrightness (0.4f));
|
||||
setLED (jmax (x0 - 1, minLedIndex), y0, waveshapeColour.withBrightness (0.4f));
|
||||
setLED (x0, jmin (y0 + 1, maxLedIndex), waveshapeColour.withBrightness (0.4f));
|
||||
setLED (x0, jmax (y0 - 1, minLedIndex), waveshapeColour.withBrightness (0.4f));
|
||||
|
||||
bitmapProgram->setLED (jmin (x0 + 1, maxLedIndex), jmin (y0 + 1, maxLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
bitmapProgram->setLED (jmin (x0 + 1, maxLedIndex), jmax (y0 - 1, minLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
bitmapProgram->setLED (jmax (x0 - 1, minLedIndex), jmin (y0 + 1, maxLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
bitmapProgram->setLED (jmax (x0 - 1, minLedIndex), jmax (y0 - 1, minLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
setLED (jmin (x0 + 1, maxLedIndex), jmin (y0 + 1, maxLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
setLED (jmin (x0 + 1, maxLedIndex), jmax (y0 - 1, minLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
setLED (jmax (x0 - 1, minLedIndex), jmin (y0 + 1, maxLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
setLED (jmax (x0 - 1, minLedIndex), jmax (y0 - 1, minLedIndex), waveshapeColour.withBrightness (0.1f));
|
||||
}
|
||||
|
||||
/**
|
||||
enum for the two modes
|
||||
*/
|
||||
enum BlocksSynthMode
|
||||
{
|
||||
waveformSelectionMode = 0,
|
||||
playMode
|
||||
};
|
||||
|
||||
BlocksSynthMode currentMode = playMode;
|
||||
|
||||
//==============================================================================
|
||||
Audio audio;
|
||||
|
||||
DrumPadGridProgram* gridProgram;
|
||||
BitmapLEDProgram* bitmapProgram;
|
||||
DrumPadGridProgram* gridProgram = nullptr;
|
||||
BitmapLEDProgram* bitmapProgram = nullptr;
|
||||
|
||||
SynthGrid layout;
|
||||
SynthGrid layout { 5, 5 };
|
||||
PhysicalTopologySource topologySource;
|
||||
Block::Ptr activeBlock;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
/**
|
||||
Base class for oscillators
|
||||
*/
|
||||
class Oscillator : public SynthesiserVoice
|
||||
class Oscillator : public SynthesiserVoice
|
||||
{
|
||||
public:
|
||||
Oscillator()
|
||||
|
|
@ -16,10 +16,6 @@ public:
|
|||
phaseIncrement.reset (getSampleRate(), 0.1);
|
||||
}
|
||||
|
||||
virtual ~Oscillator()
|
||||
{
|
||||
}
|
||||
|
||||
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int) override
|
||||
{
|
||||
frequency = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
|
||||
|
|
@ -57,7 +53,7 @@ public:
|
|||
|
||||
void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples) override
|
||||
{
|
||||
while(--numSamples >= 0)
|
||||
while (--numSamples >= 0)
|
||||
{
|
||||
double output = getSample() * amplitude.getNextValue();
|
||||
|
||||
|
|
@ -82,22 +78,20 @@ public:
|
|||
}
|
||||
|
||||
/** Subclasses should override this to say whether they can play the given sound */
|
||||
virtual bool canPlaySound (SynthesiserSound* sound) override = 0;
|
||||
virtual bool canPlaySound (SynthesiserSound*) override = 0;
|
||||
|
||||
/** Subclasses should override this to render a waveshape */
|
||||
virtual double renderWaveShape (const double currentPhase) = 0;
|
||||
virtual double renderWaveShape (double currentPhase) = 0;
|
||||
|
||||
private:
|
||||
LinearSmoothedValue<double> amplitude;
|
||||
LinearSmoothedValue<double> phaseIncrement;
|
||||
LinearSmoothedValue<double> amplitude, phaseIncrement;
|
||||
|
||||
double frequency;
|
||||
double frequency = 0;
|
||||
double phasePos = 0.0f;
|
||||
double sampleRate = 44100.0;
|
||||
|
||||
int initialNote;
|
||||
double maxFreq;
|
||||
double minFreq;
|
||||
int initialNote = 0;
|
||||
double maxFreq = 0, minFreq = 0;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oscillator)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue