Browse Source

Add simple file handling example, WIP

Signed-off-by: falkTX <falktx@falktx.com>
pull/232/head
falkTX 2 years ago
parent
commit
28fc6635bc
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
6 changed files with 783 additions and 0 deletions
  1. +47
    -0
      examples/FileHandling/DistrhoPluginInfo.h
  2. +257
    -0
      examples/FileHandling/FileHandlingPlugin.cpp
  3. +269
    -0
      examples/FileHandling/FileHandlingUI.cpp
  4. +46
    -0
      examples/FileHandling/Makefile
  5. +104
    -0
      examples/FileHandling/NanoButton.cpp
  6. +60
    -0
      examples/FileHandling/NanoButton.hpp

+ 47
- 0
examples/FileHandling/DistrhoPluginInfo.h View File

@@ -0,0 +1,47 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_PLUGIN_INFO_H_INCLUDED
#define DISTRHO_PLUGIN_INFO_H_INCLUDED

#define DISTRHO_PLUGIN_BRAND "DISTRHO"
#define DISTRHO_PLUGIN_NAME "FileHandling"
#define DISTRHO_PLUGIN_URI "http://distrho.sf.net/examples/FileHandling"

#define DISTRHO_PLUGIN_HAS_UI 1
#define DISTRHO_PLUGIN_IS_RT_SAFE 1
#define DISTRHO_PLUGIN_NUM_INPUTS 1
#define DISTRHO_PLUGIN_NUM_OUTPUTS 1
#define DISTRHO_PLUGIN_WANT_STATE 1
#define DISTRHO_PLUGIN_WANT_STATEFILES 1
#define DISTRHO_UI_USER_RESIZABLE 1
#define DISTRHO_UI_USE_NANOVG 1

enum Parameters {
kParameterFileSize1 = 0,
kParameterFileSize2,
kParameterFileSize3,
kParameterCount
};

enum States {
kStateFile1 = 0,
kStateFile2,
kStateFile3,
kStateCount
};

#endif // DISTRHO_PLUGIN_INFO_H_INCLUDED

+ 257
- 0
examples/FileHandling/FileHandlingPlugin.cpp View File

@@ -0,0 +1,257 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "DistrhoPlugin.hpp"

START_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------------------------------------------

/**
Plugin to demonstrate File handling within DPF.
*/
class FileHandlingExamplePlugin : public Plugin
{
public:
FileHandlingExamplePlugin()
: Plugin(kParameterCount, 0, kStateCount)
{
std::memset(fParameters, 0, sizeof(fParameters));
}

protected:
/* --------------------------------------------------------------------------------------------------------
* Information */

/**
Get the plugin label.
This label is a short restricted name consisting of only _, a-z, A-Z and 0-9 characters.
*/
const char* getLabel() const override
{
return "FileHandling";
}

/**
Get an extensive comment/description about the plugin.
*/
const char* getDescription() const override
{
return "Plugin to demonstrate File handling.";
}

/**
Get the plugin author/maker.
*/
const char* getMaker() const override
{
return "DISTRHO";
}

/**
Get the plugin homepage.
*/
const char* getHomePage() const override
{
return "https://github.com/DISTRHO/DPF";
}

/**
Get the plugin license name (a single line of text).
For commercial plugins this should return some short copyright information.
*/
const char* getLicense() const override
{
return "ISC";
}

/**
Get the plugin version, in hexadecimal.
*/
uint32_t getVersion() const override
{
return d_version(0, 0, 0);
}

/**
Get the plugin unique Id.
This value is used by LADSPA, DSSI and VST plugin formats.
*/
int64_t getUniqueId() const override
{
return d_cconst('d', 'F', 'i', 'H');
}

/* --------------------------------------------------------------------------------------------------------
* Init */

/**
Initialize the parameter @a index.
This function will be called once, shortly after the plugin is created.
*/
void initParameter(uint32_t index, Parameter& param) override
{
param.hints = kParameterIsOutput|kParameterIsInteger;

switch (index)
{
case kParameterFileSize1:
param.name = "Size #1";
param.symbol = "size1";
break;
case kParameterFileSize2:
param.name = "Size #2";
param.symbol = "size2";
break;
case kParameterFileSize3:
param.name = "Size #3";
param.symbol = "size3";
break;
}
}

/**
Set the state key and default value of @a index.@n
This function will be called once, shortly after the plugin is created.@n
Must be implemented by your plugin class only if DISTRHO_PLUGIN_WANT_STATE is enabled.
*/
void initState(uint32_t index, String& stateKey, String& defaultStateValue) override
{
switch (index)
{
case kStateFile1:
stateKey = "file1";
break;
case kStateFile2:
stateKey = "file2";
break;
case kStateFile3:
stateKey = "file3";
break;
}

defaultStateValue = "";
}

/**
TODO API under construction
*/
bool isStateFile(uint32_t index) override
{
switch (index)
{
case kStateFile1:
case kStateFile2:
case kStateFile3:
return true;
}

return false;
}

/* --------------------------------------------------------------------------------------------------------
* Internal data */

/**
Get the current value of a parameter.
The host may call this function from any context, including realtime processing.
We have no parameters in this plugin example, so we do nothing with the function.
*/
float getParameterValue(uint32_t index) const override
{
return fParameters[index];
}

/**
Change a parameter value.@n
The host may call this function from any context, including realtime processing.

This function will only be called for parameter inputs.
Since we have no parameters inputs in this example, so we do nothing with the function.
*/
void setParameterValue(uint32_t, float) override {}

/**
Change an internal state @a key to @a value.
*/
void setState(const char* key, const char* value) override
{
d_stdout("DSP setState %s %s", key, value);
int fileId = -1;

/**/ if (std::strcmp(key, "file1") == 0)
fileId = 0;
else if (std::strcmp(key, "file2") == 0)
fileId = 1;
else if (std::strcmp(key, "file3") == 0)
fileId = 2;

if (fileId == -1)
return;

if (FILE* const fh = fopen(value, "r"))
{
fseek(fh, 0, SEEK_END);

// filesize
const long int size = ftell(fh);
d_stdout("size of %s is %li", value, size);
fParameters[kParameterFileSize1 + fileId] = static_cast<float>(size) / 1000.0f;

fclose(fh);
}
}

/* --------------------------------------------------------------------------------------------------------
* Audio/MIDI Processing */

/**
Run/process function for plugins without MIDI input.
@note Some parameters might be null if there are no audio inputs or outputs.
*/
void run(const float** inputs, float** outputs, uint32_t frames) override
{
/**
This plugin doesn't do audio, it just demonstrates file handling usage.
So here we directly copy inputs over outputs, leaving the audio untouched.
We need to be careful in case the host re-uses the same buffer for both ins and outs.
*/
if (outputs[0] != inputs[0])
std::memcpy(outputs[0], inputs[0], sizeof(float)*frames);
}

// -------------------------------------------------------------------------------------------------------

private:
float fParameters[kParameterCount];

/**
Set our plugin class as non-copyable and add a leak detector just in case.
*/
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileHandlingExamplePlugin)
};

/* ------------------------------------------------------------------------------------------------------------
* Plugin entry point, called by DPF to create a new plugin instance. */

Plugin* createPlugin()
{
return new FileHandlingExamplePlugin();
}

// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

+ 269
- 0
examples/FileHandling/FileHandlingUI.cpp View File

@@ -0,0 +1,269 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include "DistrhoUI.hpp"

#include "extra/String.hpp"

#include "DistrhoPluginInfo.h"
#include "NanoButton.hpp"

START_NAMESPACE_DISTRHO

const char* kStateKeys[kStateCount] = {
"file1",
"file2",
"file3",
};

// -----------------------------------------------------------------------------------------------------------

static void setupButton(Button& btn, int y)
{
btn.setAbsolutePos(5, y);
btn.setLabel("Open...");
btn.setSize(100, 30);
}

class FileHandlingExampleUI : public UI,
public Button::Callback
{
public:
static const uint kInitialWidth = 600;
static const uint kInitialHeight = 350;

FileHandlingExampleUI()
: UI(kInitialWidth, kInitialHeight),
fButton1(this, this),
fButton2(this, this),
fButton3(this, this),
fScale(1.0f)
{
std::memset(fParameters, 0, sizeof(fParameters));
std::memset(fStrBuf, 0, sizeof(fStrBuf));

setupButton(fButton1, 5);
setupButton(fButton2, 105);
setupButton(fButton3, 205);

#ifdef DGL_NO_SHARED_RESOURCES
createFontFromFile("sans", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
#else
loadSharedResources();
#endif

setGeometryConstraints(kInitialWidth, kInitialHeight, true);
}

protected:
/* --------------------------------------------------------------------------------------------------------
* DSP/Plugin Callbacks */

/**
A parameter has changed on the plugin side.@n
This is called by the host to inform the UI about parameter changes.
*/
void parameterChanged(uint32_t index, float value) override
{
fParameters[index] = value;
repaint();
}

/**
A state has changed on the plugin side.@n
This is called by the host to inform the UI about state changes.
*/
void stateChanged(const char* key, const char* value) override
{
States stateId = kStateCount;

/**/ if (std::strcmp(key, "file1") == 0)
stateId = kStateFile1;
else if (std::strcmp(key, "file2") == 0)
stateId = kStateFile2;
else if (std::strcmp(key, "file3") == 0)
stateId = kStateFile3;

if (stateId == kStateCount)
return;

fState[stateId] = value;
repaint();
}

/* --------------------------------------------------------------------------------------------------------
* Widget Callbacks */

/**
The NanoVG drawing function.
*/
void onNanoDisplay() override
{
const float lineHeight = 20 * fScale;
float y;

fontSize(15.0f * fScale);
textLineHeight(lineHeight);

// ---------------------------------------------------------------------------------------
// File 1

y = 45.0f * fScale;

if (fState[kStateFile1].isNotEmpty())
{
drawLeft(0.0f, y, "Name:");
drawRight(0.0f, y, fState[kStateFile1]);
y += lineHeight;

drawLeft(0.0f, y, "Size:");
drawRight(0.0f, y, getTextBufFileSize(fParameters[kParameterFileSize1]));
y += lineHeight;
}
else
{
drawLeft(0.0f, y, "No file loaded");
}

// ---------------------------------------------------------------------------------------
// File 2

y = 145.0f * fScale;

if (fState[kStateFile2].isNotEmpty())
{
drawLeft(0.0f, y, "Name:");
drawRight(0.0f, y, fState[kStateFile2]);
y += lineHeight;

drawLeft(0.0f, y, "Size:");
drawRight(0.0f, y, getTextBufFileSize(fParameters[kParameterFileSize2]));
y += lineHeight;
}
else
{
drawLeft(0.0f, y, "No file loaded");
}

// ---------------------------------------------------------------------------------------
// File 3

y = 245.0f * fScale;

if (fState[kStateFile3].isNotEmpty())
{
drawLeft(0.0f, y, "Name:");
drawRight(0.0f, y, fState[kStateFile3]);
y += lineHeight;

drawLeft(0.0f, y, "Size:");
drawRight(0.0f, y, getTextBufFileSize(fParameters[kParameterFileSize3]));
y += lineHeight;
}
else
{
drawLeft(0.0f, y, "No file loaded");
}
}

void onResize(const ResizeEvent& ev) override
{
fScale = static_cast<float>(ev.size.getHeight())/kInitialHeight;

UI::onResize(ev);
}

void buttonClicked(Button* const button, bool) override
{
States stateId = kStateCount;

/**/ if (button == &fButton1)
stateId = kStateFile1;
else if (button == &fButton2)
stateId = kStateFile2;
else if (button == &fButton3)
stateId = kStateFile3;

if (stateId == kStateCount)
return;

requestStateFile(kStateKeys[stateId]);
}

// -------------------------------------------------------------------------------------------------------

private:
// Parameters
float fParameters[kParameterCount];

// State (files)
String fState[kStateCount];
Button fButton1, fButton2, fButton3;

// UI stuff
float fScale;

// temp buf for text
char fStrBuf[0xff];

// helpers for putting text into fStrBuf and returning it
const char* getTextBufFileSize(const float value)
{
/**/ if (value > 1024*1024)
std::snprintf(fStrBuf, 0xfe, "%.2f GiB", value/(1024*1024));
else if (value > 1024)
std::snprintf(fStrBuf, 0xfe, "%.2f MiB", value/1024);
else
std::snprintf(fStrBuf, 0xfe, "%.2f KiB", value);
return fStrBuf;
}

// helpers for drawing text
void drawLeft(const float x, const float y, const char* const text)
{
beginPath();
fillColor(200, 200, 200);
textAlign(ALIGN_RIGHT|ALIGN_TOP);
textBox(x, y, 100 * fScale, text);
closePath();
}

void drawRight(const float x, const float y, const char* const text)
{
beginPath();
fillColor(255, 255, 255);
textAlign(ALIGN_LEFT|ALIGN_TOP);
textBox(x + (105 * fScale), y, (kInitialWidth - x) * fScale, text);
closePath();
}

/**
Set our UI class as non-copyable and add a leak detector just in case.
*/
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FileHandlingExampleUI)
};

/* ------------------------------------------------------------------------------------------------------------
* UI entry point, called by DPF to create a new UI instance. */

UI* createUI()
{
return new FileHandlingExampleUI();
}

// -----------------------------------------------------------------------------------------------------------

END_NAMESPACE_DISTRHO

+ 46
- 0
examples/FileHandling/Makefile View File

@@ -0,0 +1,46 @@
#!/usr/bin/make -f
# Makefile for DISTRHO Plugins #
# ---------------------------- #
# Created by falkTX
#

# --------------------------------------------------------------
# Project name, used for binaries

NAME = d_files

# --------------------------------------------------------------
# Files to build

FILES_DSP = \
FileHandlingPlugin.cpp

FILES_UI = \
FileHandlingUI.cpp \
NanoButton.cpp

# --------------------------------------------------------------
# Do some magic

include ../../Makefile.plugins.mk

# --------------------------------------------------------------
# Enable all possible plugin types

ifeq ($(HAVE_JACK),true)
ifeq ($(HAVE_OPENGL),true)
TARGETS += jack
endif
endif

ifeq ($(HAVE_OPENGL),true)
TARGETS += lv2_sep
else
TARGETS += lv2_dsp
endif

TARGETS += vst

all: $(TARGETS)

# --------------------------------------------------------------

+ 104
- 0
examples/FileHandling/NanoButton.cpp View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2018-2019 Rob van den Berg <rghvdberg at gmail dot org>
*
* This file is part of CharacterCompressor
*
* Nnjas2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CharacterCompressor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CharacterCompressor. If not, see <https://www.gnu.org/licenses/>.
*/

#include "NanoButton.hpp"
#include "Window.hpp"

START_NAMESPACE_DISTRHO

Button::Button(Widget *parent, Callback *cb)
: NanoWidget(parent),
fCallback(cb),
buttonActive(false)
{
loadSharedResources();
fNanoFont = findFont(NANOVG_DEJAVU_SANS_TTF);
labelColor = Color(255, 255, 255);
backgroundColor = Color(32,32,32);
Label = "button";
}

void Button::onNanoDisplay()
{
auto w = getWidth();
auto h = getHeight();
auto margin = 1.0f;

// Background
beginPath();
fillColor(backgroundColor);
strokeColor(borderColor);
rect(margin, margin, w - 2 * margin, h-2*margin);
fill();
stroke();
closePath();

//Label
beginPath();
fontFaceId(fNanoFont);
fontSize(14);
fillColor(labelColor);
Rectangle<float> bounds;
textBounds(0, 0, Label.c_str(), NULL, bounds);
// float tw = bounds.getWidth();
// float th = bounds.getHeight();
float tx = w / 2.0f ;
float ty = h / 2.0f;
textAlign(ALIGN_CENTER | ALIGN_MIDDLE);

fillColor(255, 255, 255, 255);
text(tx, ty, Label.c_str(), NULL);
closePath();
}

void Button::setLabel(std::string label)
{
Label = label;
}

void Button::setLabelColor(const Color color)
{
labelColor = color;
borderColor = color;
}
void Button::setBackgroundColor(const Color color)
{
backgroundColor = color;
}

bool Button::onMouse(const MouseEvent &ev)
{
if (ev.press & contains(ev.pos))
{
buttonActive = true;
setLabelColor(labelColor);
fCallback->buttonClicked(this, true);
return true;
}
else if (buttonActive)
{
buttonActive = false;
//setLabelColor(Color(128,128,128));
return true;
}

return false;
}

END_NAMESPACE_DISTRHO

+ 60
- 0
examples/FileHandling/NanoButton.hpp View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2018-2019 Rob van den Berg <rghvdberg at gmail dot org>
*
* This file is part of CharacterCompressor
*
* Nnjas2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CharacterCompressor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CharacterCompressor. If not, see <https://www.gnu.org/licenses/>.
*/

#ifndef BUTTON_HPP_INCLUDED
#define BUTTON_HPP_INCLUDED

#include "Widget.hpp"
#include "NanoVG.hpp"

#include <string>

START_NAMESPACE_DISTRHO

class Button : public NanoWidget
{
public:
class Callback
{
public:
virtual ~Callback() {}
virtual void buttonClicked(Button *button, bool value) = 0;
};
explicit Button(Widget *parent, Callback *cb);

void setLabel(std::string label);
void setLabelColor(Color color);
void setBackgroundColor(Color color);

protected:
void onNanoDisplay() override;
bool onMouse(const MouseEvent &ev) override;

private:
std::string Label;
Color labelColor,backgroundColor,borderColor;
Callback *const fCallback;
bool buttonActive;
FontId fNanoFont;
DISTRHO_LEAK_DETECTOR(Button)
};

END_NAMESPACE_DISTRHO

#endif

Loading…
Cancel
Save