|
|
@@ -50,13 +50,13 @@ struct SynthGrid |
|
|
|
{
|
|
|
|
gridFillArray.clear();
|
|
|
|
|
|
|
|
for (int i = 0; i < numRows; ++i)
|
|
|
|
for (auto i = 0; i < numRows; ++i)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < numColumns; ++j)
|
|
|
|
for (auto j = 0; j < numColumns; ++j)
|
|
|
|
{
|
|
|
|
DrumPadGridProgram::GridFill fill;
|
|
|
|
|
|
|
|
int padNum = (i * 5) + j;
|
|
|
|
auto padNum = (i * 5) + j;
|
|
|
|
|
|
|
|
fill.colour = notes.contains (padNum) ? baseGridColour
|
|
|
|
: tonics.contains (padNum) ? Colours::white
|
|
|
@@ -69,8 +69,8 @@ struct SynthGrid |
|
|
|
|
|
|
|
int getNoteNumberForPad (int x, int y) const
|
|
|
|
{
|
|
|
|
int xIndex = x / 3;
|
|
|
|
int yIndex = y / 3;
|
|
|
|
auto xIndex = x / 3;
|
|
|
|
auto yIndex = y / 3;
|
|
|
|
|
|
|
|
return 60 + ((4 - yIndex) * 5) + xIndex;
|
|
|
|
}
|
|
|
@@ -185,55 +185,61 @@ private: |
|
|
|
{
|
|
|
|
if (currentMode == waveformSelectionMode && touch.isTouchStart && allowTouch)
|
|
|
|
{
|
|
|
|
// Change the displayed waveshape to the next one
|
|
|
|
++waveshapeMode;
|
|
|
|
if (auto* waveshapeProgram = getWaveshapeProgram())
|
|
|
|
{
|
|
|
|
// Change the displayed waveshape to the next one
|
|
|
|
++waveshapeMode;
|
|
|
|
|
|
|
|
if (waveshapeMode > 3)
|
|
|
|
waveshapeMode = 0;
|
|
|
|
if (waveshapeMode > 3)
|
|
|
|
waveshapeMode = 0;
|
|
|
|
|
|
|
|
waveshapeProgram->setWaveshapeType (static_cast<uint8> (waveshapeMode));
|
|
|
|
waveshapeProgram->setWaveshapeType (static_cast<uint8> (waveshapeMode));
|
|
|
|
|
|
|
|
allowTouch = false;
|
|
|
|
startTimer (250);
|
|
|
|
allowTouch = false;
|
|
|
|
startTimer (250);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (currentMode == playMode)
|
|
|
|
{
|
|
|
|
// Translate X and Y touch events to LED indexes
|
|
|
|
int xLed = roundToInt (touch.startX * scaleX);
|
|
|
|
int yLed = roundToInt (touch.startY * scaleY);
|
|
|
|
if (auto* gridProgram = getGridProgram())
|
|
|
|
{
|
|
|
|
// Translate X and Y touch events to LED indexes
|
|
|
|
auto xLed = roundToInt (touch.startX * scaleX);
|
|
|
|
auto yLed = roundToInt (touch.startY * scaleY);
|
|
|
|
|
|
|
|
// Limit the number of touches per second
|
|
|
|
constexpr int maxNumTouchMessagesPerSecond = 100;
|
|
|
|
auto now = Time::getCurrentTime();
|
|
|
|
clearOldTouchTimes (now);
|
|
|
|
// Limit the number of touches per second
|
|
|
|
constexpr auto maxNumTouchMessagesPerSecond = 100;
|
|
|
|
auto now = Time::getCurrentTime();
|
|
|
|
clearOldTouchTimes (now);
|
|
|
|
|
|
|
|
int midiChannel = waveshapeMode + 1;
|
|
|
|
auto midiChannel = waveshapeMode + 1;
|
|
|
|
|
|
|
|
// Send the touch event to the DrumPadGridProgram and Audio class
|
|
|
|
if (touch.isTouchStart)
|
|
|
|
{
|
|
|
|
gridProgram->startTouch (touch.startX, touch.startY);
|
|
|
|
audio.noteOn (midiChannel, layout.getNoteNumberForPad (xLed, yLed), touch.z);
|
|
|
|
}
|
|
|
|
else if (touch.isTouchEnd)
|
|
|
|
{
|
|
|
|
gridProgram->endTouch (touch.startX, touch.startY);
|
|
|
|
audio.noteOff (midiChannel, layout.getNoteNumberForPad (xLed, yLed), 1.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (touchMessageTimesInLastSecond.size() > maxNumTouchMessagesPerSecond / 3)
|
|
|
|
return;
|
|
|
|
// Send the touch event to the DrumPadGridProgram and Audio class
|
|
|
|
if (touch.isTouchStart)
|
|
|
|
{
|
|
|
|
gridProgram->startTouch (touch.startX, touch.startY);
|
|
|
|
audio.noteOn (midiChannel, layout.getNoteNumberForPad (xLed, yLed), touch.z);
|
|
|
|
}
|
|
|
|
else if (touch.isTouchEnd)
|
|
|
|
{
|
|
|
|
gridProgram->endTouch (touch.startX, touch.startY);
|
|
|
|
audio.noteOff (midiChannel, layout.getNoteNumberForPad (xLed, yLed), 1.0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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) / activeBlock->getWidth());
|
|
|
|
audio.pressureChange (midiChannel, touch.z);
|
|
|
|
}
|
|
|
|
// Send pitch change and pressure values to the Audio class
|
|
|
|
audio.pitchChange (midiChannel, (touch.x - touch.startX) / activeBlock->getWidth());
|
|
|
|
audio.pressureChange (midiChannel, touch.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
touchMessageTimesInLastSecond.add (now);
|
|
|
|
touchMessageTimesInLastSecond.add (now);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
@@ -267,7 +273,7 @@ private: |
|
|
|
/** Clears the old touch times */
|
|
|
|
void clearOldTouchTimes (const Time now)
|
|
|
|
{
|
|
|
|
for (int i = touchMessageTimesInLastSecond.size(); --i >= 0;)
|
|
|
|
for (auto i = touchMessageTimesInLastSecond.size(); --i >= 0;)
|
|
|
|
if (touchMessageTimesInLastSecond.getReference(i) < now - juce::RelativeTime::seconds (0.33))
|
|
|
|
touchMessageTimesInLastSecond.remove (i);
|
|
|
|
}
|
|
|
@@ -289,23 +295,20 @@ private: |
|
|
|
{
|
|
|
|
if (currentMode == waveformSelectionMode)
|
|
|
|
{
|
|
|
|
// Create a new WaveshapeProgram for the LEDGrid
|
|
|
|
waveshapeProgram = new WaveshapeProgram (block);
|
|
|
|
|
|
|
|
// Set the LEDGrid program
|
|
|
|
block.setProgram (waveshapeProgram);
|
|
|
|
block.setProgram (new WaveshapeProgram (block));
|
|
|
|
|
|
|
|
// Initialise the program
|
|
|
|
waveshapeProgram->setWaveshapeType (static_cast<uint8> (waveshapeMode));
|
|
|
|
waveshapeProgram->generateWaveshapes();
|
|
|
|
if (auto* waveshapeProgram = getWaveshapeProgram())
|
|
|
|
{
|
|
|
|
waveshapeProgram->setWaveshapeType (static_cast<uint8> (waveshapeMode));
|
|
|
|
waveshapeProgram->generateWaveshapes();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (currentMode == playMode)
|
|
|
|
{
|
|
|
|
// Create a new DrumPadGridProgram for the LEDGrid
|
|
|
|
gridProgram = new DrumPadGridProgram (block);
|
|
|
|
|
|
|
|
// Set the LEDGrid program
|
|
|
|
auto error = block.setProgram (gridProgram);
|
|
|
|
auto error = block.setProgram (new DrumPadGridProgram (block));
|
|
|
|
|
|
|
|
if (error.failed())
|
|
|
|
{
|
|
|
@@ -314,15 +317,32 @@ private: |
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the grid layout
|
|
|
|
gridProgram->setGridFills (layout.numColumns,
|
|
|
|
layout.numRows,
|
|
|
|
layout.gridFillArray);
|
|
|
|
if (auto* gridProgram = getGridProgram())
|
|
|
|
gridProgram->setGridFills (layout.numColumns, layout.numRows, layout.gridFillArray);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Stops touch events from triggering multiple waveshape mode changes */
|
|
|
|
void timerCallback() override { allowTouch = true; }
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
DrumPadGridProgram* getGridProgram()
|
|
|
|
{
|
|
|
|
if (activeBlock != nullptr)
|
|
|
|
return dynamic_cast<DrumPadGridProgram*> (activeBlock->getProgram());
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
WaveshapeProgram* getWaveshapeProgram()
|
|
|
|
{
|
|
|
|
if (activeBlock != nullptr)
|
|
|
|
return dynamic_cast<WaveshapeProgram*> (activeBlock->getProgram());
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
enum BlocksSynthMode
|
|
|
|
{
|
|
|
|
waveformSelectionMode = 0,
|
|
|
@@ -334,9 +354,6 @@ private: |
|
|
|
//==============================================================================
|
|
|
|
Audio audio;
|
|
|
|
|
|
|
|
DrumPadGridProgram* gridProgram = nullptr;
|
|
|
|
WaveshapeProgram* waveshapeProgram = nullptr;
|
|
|
|
|
|
|
|
SynthGrid layout { 5, 5 };
|
|
|
|
PhysicalTopologySource topologySource;
|
|
|
|
Block::Ptr activeBlock;
|
|
|
|