Skip to content

Commit

Permalink
simplified AlignedBuf, corrected Dexed-theme, code cleanup related to…
Browse files Browse the repository at this point in the history
… MidiMonitor
  • Loading branch information
FulopNandor committed Jul 13, 2024
1 parent c1ddf06 commit a9b9277
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 38 deletions.
44 changes: 38 additions & 6 deletions Documentation/DexedTheme.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
Dexed Theme
===========
Last update: 10 July 2024


Dexed UI can be themed if you want a different colour combination or background images.

You need need to create a file named "DexedTheme.xml" and it must be placed in the same directory where "Dexed.xml" is created. On Windows, this is C:\Users\\<your user name>\AppData\Roaming\DigitalSuburban" and on Mac it is "~/Library/Application Support/DigitalSuburban"
You need need to create a file named "DexedTheme.xml" and it must be placed in the same directory where "Dexed.xml" is created. On Windows, this is "C:\Users\&lt;your user name&gt;\AppData\Roaming\DigitalSuburban\Dexed" and on Mac it is "~/Library/Application Support/DigitalSuburban" (or maybe "~/Library/Application Support/DigitalSuburban/Dexed" ? FIXME!), and in Linux it is "~/.local/share/DigitalSuburban/Dexed".

Colour id are analogous to JUCE color ID; see [DXLookNFeel() class](../Source/DXLookNFeel.cpp) for a complete list a defined colours id. Colour value is the hexa decimal values (from 0 to 0xFF) for ALPHA RED BLUE GREEN.
For ALPHA, 0x00 is completely transparent, 0xFF is opaque.

Known colour keys; simply override those you want different.

Expand All @@ -28,18 +31,47 @@ PopupMenu::backgroundColourId
PopupMenu::textColourId
PopupMenu::highlightedTextColourId
PopupMenu::highlightedBackgroundColourId
TreeView::backgroundColourId
DirectoryContentsDisplayComponent::highlightColourId
DirectoryContentsDisplayComponent::textColourId
ScrollBar::thumbColourId
Dexed::backgroundId
Dexed::fillColourId
```

Image id are the file name defined in [ui folder](../Resources/ui). If it cannot find the file, the image will no longer be rendered. The image path is relative to the path where "DexedTheme.xml" is defined.
Note that sizes in pixels and structures of the images should be same as original ones, because the layout of GUI based on these hardcoded fix sizes. Recently, the following image ids could be specified:

Knob_68x68.png
Switch_96x52.png
SwitchLighted_48x26.png
Switch_64x64.png
ButtonUnlabeled_50x30.png
Slider_52x52.png
Scaling_36_26.png
Light_28x28.png
LFO_36_26.png
OperatorEditor_574x436.png
GlobalEditor_1728x288.png


Example configuration
---------------------
Example ``DexedTheme.xml`` configuration
----------------------------------------

```xml
<dexedTheme>
<colour id="TextEditor::textColourId" value="0xFFFF33FF"/>
<image id="Knob_34x34.png" path="myTheme/Knob_34x34.png"/>
<colour id="PopupMenu::backgroundColourId" value="0xff0000ff"/>
<colour id="PopupMenu::textColourId" value="0xffffffff"/>
<colour id="PopupMenu::highlightedTextColourId" value="0xffffff00"/>
<colour id="PopupMenu::highlightedBackgroundColourId" value="0xff00ffff"/>
<colour id="ScrollBar::thumbColourId" value="0xFFC0C0C0"/>
<image id="Light_28x28.png" path="myTheme/GreenLight_28x28.png"/>
</dexedTheme>
```
```

As the result:
- the colors of the background of popup menus, the text of normal menu items, and the text and background of highlighted menu items are changed to opaque blue, white, yellow, and cyan,
- the color of thumbnail of scrollbars is changed to opaque lightgray,
- the color of bright LEDs are changed to green from red (if there is a folder named ``myTheme`` within the subdirectory where your ``Dexed.xml`` and ``DexedTheme.xml`` files are located, and there is the file ``GreenLight_28x28.png`` containing the image of a red LED inside that ``myTheme`` subdirectory).

Note that ``DexedTheme.xml``are loaded only once during the initialization when Dexed (either the Standalone or the plugin version) is launched.
Binary file added Documentation/GreenLight_28x28.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
84 changes: 66 additions & 18 deletions Source/DXLookNFeel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/

#include <inttypes.h>
#include <stdint.h>

#include "DXLookNFeel.h"
#include "DXComponents.h"
Expand All @@ -29,8 +32,12 @@ Image findImage(String path) {
Image img;
if ( path.length() <= 3 )
return img;
File imgFile(path);
//File imgFile(path); // it might cause an assertion in juce_File.cpp
File imgFile = File::getCurrentWorkingDirectory().getChildFile(path);
img = ImageCache::getFromFile(imgFile);
if (img.isNull()) {
TRACE("img.isNull() == true, path=%s", path.toRawUTF8());
}
return img;
}

Expand All @@ -40,6 +47,8 @@ DXLookNFeel::DXLookNFeel() {
DexedAudioProcessor::dexedAppDir.setAsCurrentWorkingDirectory();
ctrlBackground = Colour(20,18,18);

// WARNING! If you modify the colour IDs here, please actualize the file ''DexedTheme.md''
// in the subdirectory ``~/dexed/Documentation/``
REG_COLOUR(TextButton::buttonColourId,Colour(0xFF0FC00F));
REG_COLOUR(TextButton::textColourOnId, Colours::white);
REG_COLOUR(TextButton::textColourOffId, Colours::white);
Expand All @@ -62,6 +71,11 @@ DXLookNFeel::DXLookNFeel() {
REG_COLOUR(DirectoryContentsDisplayComponent::highlightColourId, fillColour);
REG_COLOUR(DirectoryContentsDisplayComponent::textColourId, Colours::white);

// Register ``Scrollbar::thumbColourId`` to allow its redefinion in ``DexedTheme.xml``.
REG_COLOUR(ScrollBar::thumbColourId, background.darker());

// WARNING! If you modify the images here, please actualize the file ''DexedTheme.md''
// in the subdirectory ``~/dexed/Documentation/``
imageKnob = ImageCache::getFromMemory(BinaryData::Knob_68x68_png, BinaryData::Knob_68x68_pngSize); // 2x
imageSwitch = ImageCache::getFromMemory(BinaryData::Switch_96x52_png, BinaryData::Switch_96x52_pngSize); // 2x
imageSwitchLighted = ImageCache::getFromMemory(BinaryData::SwitchLighted_48x26_png, BinaryData::SwitchLighted_48x26_pngSize);
Expand All @@ -74,14 +88,28 @@ DXLookNFeel::DXLookNFeel() {
imageOperator = ImageCache::getFromMemory(BinaryData::OperatorEditor_574x436_png, BinaryData::OperatorEditor_574x436_pngSize); // 2x
imageGlobal = ImageCache::getFromMemory (BinaryData::GlobalEditor_1728x288_png, BinaryData::GlobalEditor_1728x288_pngSize); // 2x

//---
// load and parse the file ``DexedTheme.xml``
//---

File dexedTheme = DexedAudioProcessor::dexedAppDir.getChildFile("DexedTheme.xml");

if ( ! dexedTheme.existsAsFile() )
if ( ! dexedTheme.existsAsFile() ) {
TRACE("no DexedTheme.xml found at %s", dexedTheme.getFullPathName().toRawUTF8());
return;
}

std::unique_ptr<XmlElement> root = XmlDocument::parse(dexedTheme);
if ( root == NULL )
{
TRACE("DXLookNFeel(): ERROR: XmlDocument::parse(): failed");
return;
}

//---
// get custom colors from ``DexedTheme.xml``
// specified by the ``colour id`` / ``value`` pairs
//---

forEachXmlChildElementWithTagName(*root, colour, "colour") {
String name = colour->getStringAttribute("id", "");
Expand All @@ -90,71 +118,91 @@ DXLookNFeel::DXLookNFeel() {
String value = colour->getStringAttribute("value", "");
if ( value == "" )
continue;
if ( value.length() < 8 )
if ( value.length() < 8 ) {
TRACE("ERROR: illegal value=\"%s\" at color id=\"%s\"; skipped", value.toRawUTF8(), name.toRawUTF8());
continue;
int conv = strtol(value.toRawUTF8(), NULL, 16);
}
//int conv = strtol(value.toRawUTF8(), NULL, 16); // as alpha (MSB) could be above 0x7F, hence ``strtol()`` is inappropiate to convert values exceeding ``0x7FFFFFFF``
char* endptr = NULL;
uint64_t conv = strtoull(value.toRawUTF8(), &endptr, 16);
TRACE("color id=\"%s\" value=\"%s\": conv=0x%" PRIx64 "", name.toRawUTF8(), value.toRawUTF8(), conv);
if (endptr != nullptr && *endptr != '\0') {
TRACE("ERROR: illegal char #%d in value=\"%s\" at color id=\"%s\"; skipped", (int)(*endptr), value.toRawUTF8(), name.toRawUTF8());
continue;
}
if (conv > 0xFFFFFFFFULL) {
TRACE("ERROR: value 0x%" PRIx64 " exceeded the limit at color id=\"%s\"; skipped", conv, name.toRawUTF8());
continue;
}
if ( colourMap.contains(name) ) {
setColour(colourMap[name], Colour(conv));
setColour(colourMap[name], Colour((uint32_t)conv));
} else {
if ( name == "Dexed::backgroundId" ) {
background = Colour(conv);
background = Colour((uint32_t)conv);
continue;
}
if ( name == "Dexed::fillColourId" ) {
fillColour = Colour(conv);
else if ( name == "Dexed::fillColourId" ) {
fillColour = Colour((uint32_t)conv);
continue;
}
TRACE("ERROR: color id=\"%s\" not found in colourMap; skipped.", name.toRawUTF8());
}
}

// TODO: THIS IS DEAD CODE. NOBODY IS USING THIS.
//---
// get custom images from ``DexedTheme.xml``
// specified by the ``image id`` / ``path`` pairs
//---

forEachXmlChildElementWithTagName(*root, image, "image") {
String name = image->getStringAttribute("id", "");
String path = image->getStringAttribute("path", "");
if ( name == "Knob_34x34.png" ) {
//TRACE("image id=\'%s\' path=\'%s\'", name.toRawUTF8(), path.toRawUTF8());
if ( name == /*"Knob_34x34.png"*/"Knob_68x68.png" ) { // 2x
imageKnob = findImage(path);
continue;
}
if ( name == "Switch_48x26.png" ) {
if ( name == /*"Switch_48x26.png"*/ "Switch_96x52.png" ) { // 2x
imageSwitch = findImage(path);
continue;
}
if ( name == "SwitchLighted_48x26.png" ) {
imageSwitchLighted = findImage(path);
continue;
}
if ( name == "Switch_32x64.png" ) {
if ( name == /*"Switch_32x64.png"*/ "Switch_64x64.png" ) { // 2x
imageSwitchOperator = findImage(path);
continue;
}
if ( name == "ButtonUnlabeled_50x30.png" ) {
imageButton = findImage(path);
continue;
}
if ( name == "Slider_26x26.png" ) {
if ( name == /*"Slider_26x26.png"*/ "Slider_52x52.png" ) { // 2x
imageSlider = findImage(path);
continue;
}
if ( name == "Scaling_36_26.png" ) {
imageScaling = findImage(path);
continue;
}
if ( name == "Light_14x14.png" ) {
if ( name == /*"Light_14x14.png"*/ "Light_28x28.png" ) { // 2x
imageLight = findImage(path);
continue;
}
if ( name == "LFO_36_26.png" ) {
imageLFO = findImage(path);
continue;
}
if ( name == "OperatorEditor_287x218.png" ) {
if ( name == /*"OperatorEditor_287x218.png"*/ "OperatorEditor_574x436_png" ) { // 2x
imageOperator = findImage(path);
continue;
}
if ( name == "GlobalEditor_864x144.png" ) {
if ( name == /*"GlobalEditor_864x144.png"*/ "GlobalEditor_1728x288_png" ) { // 2x
imageGlobal = findImage(path);
continue;
}
TRACE("ERROR: unknown image id=\"%s\"; skipped", name.toRawUTF8());
}
}

Expand All @@ -173,7 +221,8 @@ void DXLookNFeel::drawRotarySlider( Graphics &g, int x, int y, int width, int he
const int nFrames = imageKnob.getHeight()/imageKnob.getWidth(); // number of frames for vertical film strip
const int frameIdx = (int)ceil(fractRotation * ((double)nFrames-1.0) ); // current index from 0 --> nFrames-1

const float radius = jmin (width / 2.0f, height / 2.0f) ;
//const float radius = jmin (width / 2.0f, height / 2.0f) ;
const float radius = jmin(width * 0.5f, height * 0.5f);
const float centreX = x + width * 0.5f;
const float centreY = y + height * 0.5f;
const float rx = centreX - radius - 1.0f;
Expand Down Expand Up @@ -254,4 +303,3 @@ Colour DXLookNFeel::fillColour = Colour(77,159,151);
Colour DXLookNFeel::lightBackground = Colour(78,72,63);
Colour DXLookNFeel::background = Colour(60,50,47);
Colour DXLookNFeel::roundBackground = Colour(58,52,48);

38 changes: 27 additions & 11 deletions Source/GlobalEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,25 @@
* Ugly but useful midi monitor to know if you are really sending/receiving something from the DX7
* If the midi is not configured this component wont show up
*
*/
#ifdef IMPLEMENT_MidiMonitor
class MidiMonitor : public Component {
SysexComm *midi;
Image light;
int imageHeight;
int imageHeight2;
int imageWidth;

SharedResourcePointer<DXLookNFeel> lookAndFeel;
public:
MidiMonitor(SysexComm *sysexComm) {
midi = sysexComm;
light = DXLookNFeel::getLookAndFeel()->imageLight;
light = lookAndFeel->imageLight;
imageHeight = light.getHeight();
imageHeight2 = imageHeight / 2;
imageWidth = light.getWidth();

TRACE("WARNING! This functionality is a candidate for deprecation/obsolescence!");
}

void paint(Graphics &g) {
Expand All @@ -47,24 +58,25 @@ class MidiMonitor : public Component {
g.setColour(Colours::white);

if ( midi->isInputActive() ) {
g.drawSingleLineText("DX7 IN", 17,14);
g.drawImage(light, 0, 3, 14, 14, 0, midi->inActivity ? 14 : 0, 14, 14);
g.drawSingleLineText("DX7 IN", 24, 18);
g.drawImage(light, 0, 0, imageWidth, imageHeight2, 0, midi->inActivity ? imageHeight2 : 0, imageWidth, imageHeight2);
midi->inActivity = false;
}

if ( midi->isOutputActive() ) {
g.drawSingleLineText("DX7 OUT", 17, 28);
g.drawImage(light, 0, 17, 14, 14, 0, midi->outActivity ? 14 : 0, 14, 14);
g.drawSingleLineText("DX7 OUT", 24, 36);
g.drawImage(light, 0, 18, imageWidth, imageHeight2, 0, midi->outActivity ? imageHeight2 : 0, imageWidth, imageHeight2);
midi->outActivity = false;
}
}
};*/
};
#endif //IMPLEMENT_MidiMonitor

class AboutBox : public DialogWindow {
public:
Image logo_png;
std::unique_ptr<juce::HyperlinkButton> dexed; // changed to std::unique_ptr from juce::ScopedPointer
std::unique_ptr<juce::HyperlinkButton> surge; // changed to std__unique_ptr from juce::ScopedPointer
std::unique_ptr<juce::HyperlinkButton> surge; // changed to std::unique_ptr from juce::ScopedPointer

AboutBox(Component *parent) : DialogWindow("About", Colour(0xFF000000), true),
dexed(std::make_unique<juce::HyperlinkButton>("https://asb2m10.github.io/dexed/", URL("https://asb2m10.github.io/dexed/"))),
Expand Down Expand Up @@ -706,9 +718,11 @@ void GlobalEditor::bind(DexedAudioProcessorEditor *edit) {

editor = edit;

//midiMonitor = new MidiMonitor(&(processor->sysexComm));
//addAndMakeVisible(midiMonitor);
//midiMonitor->setBounds(155, 21, 80, 45);
#ifdef IMPLEMENT_MidiMonitor
midiMonitor = std::make_unique<MidiMonitor>(&(processor->sysexComm));
addAndMakeVisible(*midiMonitor);
midiMonitor->setBounds(110, 10, 80, 45); //midiMonitor->setBounds(155, 21, 80, 45);
#endif //IMPLEMENT_MidiMonitor

repaint();
}
Expand All @@ -734,7 +748,9 @@ void GlobalEditor::updatePitchPos(int pos) {
void GlobalEditor::updateVu(float f) {
vuOutput->v = f;
vuOutput->repaint();
//midiMonitor->repaint();
#ifdef IMPLEMENT_MidiMonitor
midiMonitor->repaint();
#endif //IMPLEMENT_MidiMonitor
}

void GlobalEditor::setMonoState(bool state) {
Expand Down
9 changes: 8 additions & 1 deletion Source/GlobalEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#include "DXComponents.h"
#include "AlgoDisplay.h"

#ifdef IMPLEMENT_MidiMonitor
#include "SysexComm.h"
#endif // IMPLEMENT_MidiMonitor

class DexedAudioProcessorEditor;
//[/Headers]

Expand Down Expand Up @@ -59,7 +63,10 @@ class GlobalEditor : public Component,

void setMonoState(bool state);
ProgramSelector *programs;
//std::unique_ptr<Component> midiMonitor;

#ifdef IMPLEMENT_MidiMonitor
std::unique_ptr<Component> midiMonitor;
#endif //IMPLEMENT_MidiMonitor

void mouseDown(const MouseEvent& e) override;
//[/UserMethods]
Expand Down
5 changes: 5 additions & 0 deletions Source/PluginFx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,12 @@ inline float PluginFx::NR(float sample, float g) {
}

void PluginFx::process(float *work, int sampleSize) {

// very basic DC filter
// see descriptions at: https://www.musicdsp.org/en/latest/Filters/135-dc-filter.html
// https://www.degruyter.com/document/doi/10.1515/freq-2020-0177/html?lang=en
// https://www.dsprelated.com/showarticle/58.php

float t_fd = work[0];
work[0] = work[0] - dc_id + dc_r * dc_od;
dc_id = t_fd;
Expand Down
4 changes: 3 additions & 1 deletion Source/PluginProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,9 @@ void DexedAudioProcessor::handleIncomingMidiMessage(MidiInput* source, const Mid
if ( message.isActiveSense() )
return;

sysexComm.inActivity = true;
#ifdef IMPLEMENT_MidiMonitor
sysexComm.inActivity = true; // indicate for MidiMonitor, that a MIDI messages (other than Active Sense) received
#endif //IMPLEMENT_MidiMonitor

const uint8 *buf = message.getRawData();
int sz = message.getRawDataSize();
Expand Down
Loading

0 comments on commit a9b9277

Please sign in to comment.