+2
-2
@@ -1,13 +1,13 @@
|
|||||||
cmake_minimum_required(VERSION 3.16.0)
|
cmake_minimum_required(VERSION 3.16.0)
|
||||||
project(pipedal
|
project(pipedal
|
||||||
VERSION 1.5.93
|
VERSION 1.5.94
|
||||||
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi"
|
||||||
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
HOMEPAGE_URL "https://rerdavies.github.io/pipedal"
|
||||||
)
|
)
|
||||||
|
|
||||||
execute_process( COMMAND dpkg --print-architecture COMMAND tr -d '\n' OUTPUT_VARIABLE DEBIAN_ARCHITECTURE )
|
execute_process( COMMAND dpkg --print-architecture COMMAND tr -d '\n' OUTPUT_VARIABLE DEBIAN_ARCHITECTURE )
|
||||||
|
|
||||||
set (DISPLAY_VERSION "PiPedal v1.5.93-Experimental")
|
set (DISPLAY_VERSION "PiPedal v1.5.94-Experimental")
|
||||||
set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
|
set (PACKAGE_ARCHITECTURE ${DEBIAN_ARCHITECTURE})
|
||||||
set (CMAKE_INSTALL_PREFIX "/usr/")
|
set (CMAKE_INSTALL_PREFIX "/usr/")
|
||||||
|
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
<img src="https://img.shields.io/github/downloads/rerdavies/pipedal/total?color=%23808080&link=https%3A%2F%2Frerdavies.github.io%2Fpipedal%2Fdownload.html"/>
|
<img src="https://img.shields.io/github/downloads/rerdavies/pipedal/total?color=%23808080&link=https%3A%2F%2Frerdavies.github.io%2Fpipedal%2Fdownload.html"/>
|
||||||
|
|
||||||
|
|
||||||
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.5.93</a>
|
Download: <a href='https://rerdavies.github.io/pipedal/download.html'>v1.5.94</a>
|
||||||
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
|
Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal).
|
||||||
Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).
|
Documentation: [https://rerdavies.github.io/pipedal/Documentation.html](https://rerdavies.github.io/pipedal/Documentation.html).
|
||||||
|
|
||||||
#### NEW version 1.5.93 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. TooB NAM calibration, manipulation of i/r files in Toob Convolution Reverb, new Parametric EQ and 3 Band EQ plugins, and MORE!
|
#### NEW version 1.5.94 Release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. TooB NAM calibration, manipulation of i/r files in Toob Convolution Reverb, new Parametric EQ and 3 Band EQ plugins, and MORE!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -13,18 +13,18 @@ page_icon: img/Install4.jpg
|
|||||||
|
|
||||||
Download the most recent Debian (.deb) package for your platform:
|
Download the most recent Debian (.deb) package for your platform:
|
||||||
|
|
||||||
- [Raspberry Pi OS bookworm (aarch64) v1.5.93](https://github.com/rerdavies/pipedal/releases/download/v1.5.93/pipedal_1.5.93_arm64.deb)
|
- [Raspberry Pi OS bookworm (aarch64) v1.5.94](https://github.com/rerdavies/pipedal/releases/download/v1.5.94/pipedal_1.5.94_arm64.deb)
|
||||||
- [Ubuntu 24.04 through 25.04 (aarch64) v1.5.93](https://github.com/rerdavies/pipedal/releases/download/v1.5.93/pipedal_1.5.93_arm64.deb)
|
- [Ubuntu 24.04 through 25.04 (aarch64) v1.5.94](https://github.com/rerdavies/pipedal/releases/download/v1.5.94/pipedal_1.5.94_arm64.deb)
|
||||||
- [Ubuntu 24.04 through 25.04 (amd64) v1.5.93](https://github.com/rerdavies/pipedal/releases/download/v1.5.93/pipedal_1.5.93_amd64.deb)
|
- [Ubuntu 24.04 through 25.04 (amd64) v1.5.94](https://github.com/rerdavies/pipedal/releases/download/v1.5.94/pipedal_1.5.94_amd64.deb)
|
||||||
|
|
||||||
|
|
||||||
Version 1.5.93 has been tested on Raspberry Pi OS bookworm, Ubuntu 24.04 (amd64), Ubuntu 24.10 (aarch64), and Ubuntu 25.04 (aarch64). Download the appropriate package for your platform, and install using the following procedure:
|
Version 1.5.94 has been tested on Raspberry Pi OS bookworm, Ubuntu 24.04 (amd64), Ubuntu 24.10 (aarch64), and Ubuntu 25.04 (aarch64). Download the appropriate package for your platform, and install using the following procedure:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt upgrade
|
sudo apt upgrade
|
||||||
cd ~/Downloads
|
cd ~/Downloads
|
||||||
sudo apt-get install ./pipedal_1.5.93_arm64.deb
|
sudo apt-get install ./pipedal_1.5.94_arm64.deb
|
||||||
```
|
```
|
||||||
You MUST use `apt-get`. `apt` will not install downloaded packages; and `dpkg -i` will not install dependencies.
|
You MUST use `apt-get`. `apt` will not install downloaded packages; and `dpkg -i` will not install dependencies.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# Release Notes
|
# Release Notes
|
||||||
|
|
||||||
|
## PiPedal 1.5.94 Beta
|
||||||
|
|
||||||
|
A minor release that allows use of plugins with audio sidechains.
|
||||||
|
|
||||||
|
### Features in this release
|
||||||
|
|
||||||
|
- **Sidechains**. You can now load plugins that have sidechain inputs. This allows you to use compressor and gate plugins, particularly, that often have sidechains, but also enables a broad class of dynamics processing plugins that would not be loadable in previous versions of PiPedal. Plugins that have sidechain inputs will show a dropdown control in their control view which allows you to select the source of the sidechain input. The source plugin for the sidechain must appear earlier in the signal chain.
|
||||||
|
|
||||||
|
Although sidechain processing is occasionally useful in guitar effect pedalboards, the more important part of this feature is that it allows you to load plugins that were rejected by previous versions of PiPedal because they had optional sidechain inputs.
|
||||||
|
|
||||||
|
|
||||||
## PiPedal 1.5.93 Release
|
## PiPedal 1.5.93 Release
|
||||||
|
|
||||||
### Major Features in This Build
|
### Major Features in This Build
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ Here is a brief list of other particularly recommended plugin collections.
|
|||||||
| Collection | To Install | Description |
|
| Collection | To Install | Description |
|
||||||
|---------------------------------|---------------------------------------|------------------|
|
|---------------------------------|---------------------------------------|------------------|
|
||||||
| [Guitarix](https://guitarix.org) ★★★☆☆ | `sudo apt install guitarix-lv2` | A large collection of guitar amplifiers and effects. Prior to the advent of neural network amplifier emulations, Guitarix was the go-to source for open-source amp modeling.|
|
| [Guitarix](https://guitarix.org) ★★★☆☆ | `sudo apt install guitarix-lv2` | A large collection of guitar amplifiers and effects. Prior to the advent of neural network amplifier emulations, Guitarix was the go-to source for open-source amp modeling.|
|
||||||
| [GxPlugins](https://github.com/brummer10/GxPlugins.lv2) ★★★★★ | `sudo apt install gxplugins` | Additional amps and effects from the the principle developer of Guitarix, many of which are significantly superior to the original Guitarix plugins. Most of these plugins
|
| [GxPlugins](https://github.com/brummer10/GxPlugins.lv2) ★★★★★ | On Raspberry Pi Os: `sudo apt install gxplugins`, on amd64/x64 donwload from [Github](https://github.com/brummer10/GxPlugins.lv2/releases) | Additional amps and effects from the the principle developer of Guitarix, many of which are significantly superior to the original Guitarix plugins. Most of these plugins
|
||||||
use circuit simulation to directly model actual original circuits. The results are uniformly excellent.|
|
use circuit simulation to directly model actual original circuits. The results are uniformly excellent.|
|
||||||
| [DPF Plugins](https://github.com/DISTRHO/DPF-Plugins) ★★★★★ | `sudo apt install dpf-plugins-lv2` | Useful and interesting guitar effect plugins. Bit crusher, pitch shift, reverbs, 3-band EQ and more. |
|
| [DPF Plugins](https://github.com/DISTRHO/DPF-Plugins) ★★★★★ | `sudo apt install dpf-plugins-lv2` | Useful and interesting guitar effect plugins. Bit crusher, pitch shift, reverbs, 3-band EQ and more. |
|
||||||
| [MDA Plugins](http://drobilla.net/software/mda-lv2.html) ★★★★☆ | `sudo apt install mda-lv2` | 36 high-quality plugs |
|
| [MDA Plugins](http://drobilla.net/software/mda-lv2.html) ★★★★☆ | `sudo apt install mda-lv2` | 36 high-quality plugs |
|
||||||
|
|||||||
+4
-4
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
Download the most recent Debian (.deb) package for your platform:
|
Download the most recent Debian (.deb) package for your platform:
|
||||||
|
|
||||||
- [Raspberry Pi OS bookworm (aarch64) v1.5.93 Beta](https://github.com/rerdavies/pipedal/releases/download/v1.5.93/pipedal_1.5.93_arm64.deb)
|
- [Raspberry Pi OS bookworm (aarch64) v1.5.94 Beta](https://github.com/rerdavies/pipedal/releases/download/v1.5.94/pipedal_1.5.94_arm64.deb)
|
||||||
- [Ubuntu 24.x, 25.04 (aarch64) v1.5.93 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.5.93/pipedal_1.5.93_arm64.deb)
|
- [Ubuntu 24.x, 25.04 (aarch64) v1.5.94 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.5.94/pipedal_1.5.94_arm64.deb)
|
||||||
- [Ubuntu 24.x, 25.04 (amd64) v1.5.93 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.5.93/pipedal_1.5.93_amd64.deb)
|
- [Ubuntu 24.x, 25.04 (amd64) v1.5.94 Alpha](https://github.com/rerdavies/pipedal/releases/download/v1.5.94/pipedal_1.5.94_amd64.deb)
|
||||||
|
|
||||||
|
|
||||||
Install the package by running
|
Install the package by running
|
||||||
@@ -14,7 +14,7 @@ Install the package by running
|
|||||||
```
|
```
|
||||||
sudo apt update
|
sudo apt update
|
||||||
cd ~/Downloads
|
cd ~/Downloads
|
||||||
sudo apt-get install ./pipedal_1.5.93_arm64.deb
|
sudo apt-get install ./pipedal_1.5.94_arm64.deb
|
||||||
```
|
```
|
||||||
You MUST use `apt-get` to install the package. `apt install` will NOT install the package correctly. The message about missing permissions given by `apt-get` is
|
You MUST use `apt-get` to install the package. `apt install` will NOT install the package correctly. The message about missing permissions given by `apt-get` is
|
||||||
expected, and can be safely ignored.
|
expected, and can be safely ignored.
|
||||||
|
|||||||
+1
-1
Submodule modules/libzip updated: 92035140df...fb59b49dff
@@ -54,7 +54,9 @@ namespace pipedal {
|
|||||||
|
|
||||||
virtual int GetNumberOfInputAudioBuffers() const = 0; // may be different if plugin has zero inputs.
|
virtual int GetNumberOfInputAudioBuffers() const = 0; // may be different if plugin has zero inputs.
|
||||||
virtual int GetNumberOfOutputAudioBuffers() const = 0; // may be different if plugin has zero inputs.
|
virtual int GetNumberOfOutputAudioBuffers() const = 0; // may be different if plugin has zero inputs.
|
||||||
|
virtual int GetNumberOfSidechainAudioBuffers() const { return 0; }
|
||||||
virtual float *GetAudioInputBuffer(int index) const = 0;
|
virtual float *GetAudioInputBuffer(int index) const = 0;
|
||||||
|
virtual float *GetAudioSidechainBuffer(int index) const { throw std::runtime_error("Not implemented"); }
|
||||||
virtual float *GetAudioOutputBuffer(int index) const = 0;
|
virtual float *GetAudioOutputBuffer(int index) const = 0;
|
||||||
virtual void ResetAtomBuffers() = 0;
|
virtual void ResetAtomBuffers() = 0;
|
||||||
|
|
||||||
@@ -65,6 +67,7 @@ namespace pipedal {
|
|||||||
|
|
||||||
virtual void SetAudioInputBuffer(int index, float *buffer) = 0;
|
virtual void SetAudioInputBuffer(int index, float *buffer) = 0;
|
||||||
virtual void SetAudioOutputBuffer(int index, float*buffer) = 0;
|
virtual void SetAudioOutputBuffer(int index, float*buffer) = 0;
|
||||||
|
virtual void SetAudioSidechainBuffer(int index, float *buffer) { throw std::runtime_error("Not implemented");}
|
||||||
|
|
||||||
virtual void Activate() = 0;
|
virtual void Activate() = 0;
|
||||||
|
|
||||||
|
|||||||
+78
-5
@@ -384,7 +384,12 @@ void Lv2Effect::PreparePortIndices()
|
|||||||
{
|
{
|
||||||
if (port->is_input())
|
if (port->is_input())
|
||||||
{
|
{
|
||||||
this->inputAudioPortIndices.push_back(portIndex);
|
if (port->is_sidechain())
|
||||||
|
{
|
||||||
|
this->inputSidechainPortIndices.push_back(portIndex);
|
||||||
|
} else {
|
||||||
|
this->inputAudioPortIndices.push_back(portIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -432,6 +437,7 @@ void Lv2Effect::PreparePortIndices()
|
|||||||
this->maxInputControlPort = maxInputControlPort;
|
this->maxInputControlPort = maxInputControlPort;
|
||||||
|
|
||||||
inputAudioBuffers.resize(inputAudioPortIndices.size());
|
inputAudioBuffers.resize(inputAudioPortIndices.size());
|
||||||
|
inputSidechainBuffers.resize(inputSidechainPortIndices.size());
|
||||||
outputAudioBuffers.resize(outputAudioPortIndices.size());
|
outputAudioBuffers.resize(outputAudioPortIndices.size());
|
||||||
inputAtomBuffers.resize(inputAtomPortIndices.size());
|
inputAtomBuffers.resize(inputAtomPortIndices.size());
|
||||||
outputAtomBuffers.resize(outputAtomPortIndices.size());
|
outputAtomBuffers.resize(outputAtomPortIndices.size());
|
||||||
@@ -439,9 +445,7 @@ void Lv2Effect::PreparePortIndices()
|
|||||||
if (RequiresBufferStaging())
|
if (RequiresBufferStaging())
|
||||||
{
|
{
|
||||||
EnableBufferStaging(
|
EnableBufferStaging(
|
||||||
GetStagedBufferSize(),
|
GetStagedBufferSize());
|
||||||
this->GetNumberOfInputAudioBuffers(),
|
|
||||||
this->GetNumberOfOutputAudioBuffers());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,6 +477,7 @@ void Lv2Effect::PrepareNoInputEffect(int numberOfInputs, size_t maxBufferSize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Lv2Effect::SetAudioInputBuffer(int index, float *buffer)
|
void Lv2Effect::SetAudioInputBuffer(int index, float *buffer)
|
||||||
{
|
{
|
||||||
this->inputAudioBuffers.at(index) = buffer;
|
this->inputAudioBuffers.at(index) = buffer;
|
||||||
@@ -512,6 +517,32 @@ void Lv2Effect::SetAudioInputBuffer(int index, float *buffer)
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void Lv2Effect::SetAudioSidechainBuffer(int index, float *buffer)
|
||||||
|
{
|
||||||
|
this->inputSidechainBuffers.at(index) = buffer;
|
||||||
|
|
||||||
|
if (borrowedEffect)
|
||||||
|
{
|
||||||
|
// Already running on the realtime thread,
|
||||||
|
// so don't update the audio ports until the effect gets placed on the realtime thread.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stagingBufferSize != 0)
|
||||||
|
{
|
||||||
|
int pluginIndex = this->inputSidechainPortIndices.at(index);
|
||||||
|
if (index >= sidechainStagingBufferPointers.size())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid input staging buffer index.");
|
||||||
|
}
|
||||||
|
lilv_instance_connect_port(this->pInstance, pluginIndex, sidechainStagingBufferPointers.at(index));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pluginIndex = this->inputSidechainPortIndices.at(index);
|
||||||
|
lilv_instance_connect_port(this->pInstance, pluginIndex, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Lv2Effect::SetAudioInputBuffer(float *left)
|
void Lv2Effect::SetAudioInputBuffer(float *left)
|
||||||
{
|
{
|
||||||
@@ -664,6 +695,14 @@ void Lv2Effect::UpdateAudioPorts()
|
|||||||
lilv_instance_connect_port(pInstance, portIndex, outputStagingBufferPointers.at(i));
|
lilv_instance_connect_port(pInstance, portIndex, outputStagingBufferPointers.at(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < this->inputSidechainPortIndices.size(); ++i)
|
||||||
|
{
|
||||||
|
int portIndex = this->inputSidechainPortIndices.at(i);
|
||||||
|
if (sidechainStagingBufferPointers.at(i) != nullptr)
|
||||||
|
{
|
||||||
|
lilv_instance_connect_port(pInstance, portIndex, sidechainStagingBufferPointers.at(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
for (size_t i = 0; i < this->inputAtomPortIndices.size(); ++i)
|
for (size_t i = 0; i < this->inputAtomPortIndices.size(); ++i)
|
||||||
{
|
{
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
@@ -710,6 +749,15 @@ void Lv2Effect::UpdateAudioPorts()
|
|||||||
lilv_instance_connect_port(pInstance, portIndex, GetAudioOutputBuffer(i));
|
lilv_instance_connect_port(pInstance, portIndex, GetAudioOutputBuffer(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < this->inputSidechainPortIndices.size(); ++i)
|
||||||
|
{
|
||||||
|
int portIndex = this->inputSidechainPortIndices.at(i);
|
||||||
|
if (GetAudioSidechainBuffer(i) != nullptr)
|
||||||
|
{
|
||||||
|
lilv_instance_connect_port(pInstance, portIndex, GetAudioSidechainBuffer(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < this->inputAtomPortIndices.size(); ++i)
|
for (size_t i = 0; i < this->inputAtomPortIndices.size(); ++i)
|
||||||
{
|
{
|
||||||
auto atomInputBuffer = this->GetAtomInputBuffer(i);
|
auto atomInputBuffer = this->GetAtomInputBuffer(i);
|
||||||
@@ -877,6 +925,16 @@ size_t Lv2Effect::stageToInput(size_t inputSampleOffset, size_t samples)
|
|||||||
pOutput[i] = pInput[i];
|
pOutput[i] = pInput[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (size_t nSidechain = 0; nSidechain < this->inputSidechainBuffers.size(); ++nSidechain)
|
||||||
|
{
|
||||||
|
float *restrict pInput = this->inputSidechainBuffers[nSidechain] + inputSampleOffset;
|
||||||
|
float *restrict pOutput = this->sidechainStagingBufferPointers.at(nSidechain) + this->stagingInputIx;
|
||||||
|
for (size_t i = 0; i < thisTime; ++i)
|
||||||
|
{
|
||||||
|
pOutput[i] = pInput[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
this->stagingInputIx += thisTime;
|
this->stagingInputIx += thisTime;
|
||||||
inputSampleOffset += thisTime;
|
inputSampleOffset += thisTime;
|
||||||
|
|
||||||
@@ -1487,8 +1545,11 @@ void Lv2Effect::SetPathPatchProperty(const std::string &propertyUri, const std::
|
|||||||
mainThreadPathProperties[propertyUri] = jsonAtom;
|
mainThreadPathProperties[propertyUri] = jsonAtom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Lv2Effect::EnableBufferStaging(size_t bufferSize, size_t nInputs, size_t nOutputs)
|
void Lv2Effect::EnableBufferStaging(size_t bufferSize )
|
||||||
{
|
{
|
||||||
|
size_t nInputs = this->GetNumberOfInputAudioBuffers();
|
||||||
|
size_t nSidechainInputs = this->GetNumberOfSidechainAudioBuffers();
|
||||||
|
size_t nOutputs = this->GetNumberOfOutputAudioBuffers();
|
||||||
|
|
||||||
stagingBufferSize = bufferSize;
|
stagingBufferSize = bufferSize;
|
||||||
stagingOutputIx = bufferSize;
|
stagingOutputIx = bufferSize;
|
||||||
@@ -1520,6 +1581,12 @@ void Lv2Effect::EnableBufferStaging(size_t bufferSize, size_t nInputs, size_t nO
|
|||||||
inputStagingBuffers[i][bufferSize] = 99.9f; // guard entry
|
inputStagingBuffers[i][bufferSize] = 99.9f; // guard entry
|
||||||
inputStagingBufferPointers.at(i) = inputStagingBuffers.at(i).data();
|
inputStagingBufferPointers.at(i) = inputStagingBuffers.at(i).data();
|
||||||
}
|
}
|
||||||
|
for (size_t i = 0; i < nSidechainInputs; ++i)
|
||||||
|
{
|
||||||
|
sidechainStagingBuffers.at(i).resize(bufferSize + 1);
|
||||||
|
sidechainStagingBuffers[i][bufferSize] = 99.9f; // guard entry
|
||||||
|
sidechainStagingBufferPointers.at(i) = sidechainStagingBuffers.at(i).data();
|
||||||
|
}
|
||||||
for (size_t i = 0; i < nOutputs; ++i)
|
for (size_t i = 0; i < nOutputs; ++i)
|
||||||
{
|
{
|
||||||
outputStagingBuffers.at(i).resize(bufferSize + 1);
|
outputStagingBuffers.at(i).resize(bufferSize + 1);
|
||||||
@@ -1571,6 +1638,12 @@ float *Lv2Effect::GetAudioInputBuffer(int index) const
|
|||||||
throw std::range_error("Lv2Effect::GetAudioInputBuffer");
|
throw std::range_error("Lv2Effect::GetAudioInputBuffer");
|
||||||
return this->inputAudioBuffers.at(index);
|
return this->inputAudioBuffers.at(index);
|
||||||
}
|
}
|
||||||
|
float *Lv2Effect::GetAudioSidechainBuffer(int index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= this->inputSidechainBuffers.size())
|
||||||
|
throw std::range_error("Lv2Effect::GetAudioSidechainBuffer");
|
||||||
|
return this->inputSidechainBuffers.at(index);
|
||||||
|
}
|
||||||
|
|
||||||
float *Lv2Effect::GetAudioOutputBuffer(int index) const
|
float *Lv2Effect::GetAudioOutputBuffer(int index) const
|
||||||
{
|
{
|
||||||
|
|||||||
+20
-11
@@ -81,6 +81,8 @@ namespace pipedal
|
|||||||
std::vector<int> inputAudioPortIndices;
|
std::vector<int> inputAudioPortIndices;
|
||||||
std::vector<int> outputAudioPortIndices;
|
std::vector<int> outputAudioPortIndices;
|
||||||
|
|
||||||
|
std::vector<int> inputSidechainPortIndices;
|
||||||
|
|
||||||
std::vector<int> inputAtomPortIndices;
|
std::vector<int> inputAtomPortIndices;
|
||||||
std::vector<int> outputAtomPortIndices;
|
std::vector<int> outputAtomPortIndices;
|
||||||
|
|
||||||
@@ -90,6 +92,7 @@ namespace pipedal
|
|||||||
std::vector<int> midiInputIndices;
|
std::vector<int> midiInputIndices;
|
||||||
|
|
||||||
std::vector<float *> inputAudioBuffers;
|
std::vector<float *> inputAudioBuffers;
|
||||||
|
std::vector<float *> inputSidechainBuffers;
|
||||||
std::vector<float *> outputAudioBuffers;
|
std::vector<float *> outputAudioBuffers;
|
||||||
|
|
||||||
std::vector<char *> inputAtomBuffers;
|
std::vector<char *> inputAtomBuffers;
|
||||||
@@ -212,7 +215,7 @@ namespace pipedal
|
|||||||
|
|
||||||
bool borrowedEffect = false;
|
bool borrowedEffect = false;
|
||||||
bool activated = false;
|
bool activated = false;
|
||||||
void EnableBufferStaging(size_t bufferSize, size_t nInputs, size_t nOutputs);
|
void EnableBufferStaging(size_t bufferSize);
|
||||||
void CheckStagingBufferSentries();
|
void CheckStagingBufferSentries();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -262,8 +265,10 @@ namespace pipedal
|
|||||||
size_t stagingInputIx = 0;
|
size_t stagingInputIx = 0;
|
||||||
size_t stagingOutputIx = 0;
|
size_t stagingOutputIx = 0;
|
||||||
std::vector<std::vector<float>> inputStagingBuffers;
|
std::vector<std::vector<float>> inputStagingBuffers;
|
||||||
|
std::vector<std::vector<float>> sidechainStagingBuffers;
|
||||||
std::vector<std::vector<float>> outputStagingBuffers;
|
std::vector<std::vector<float>> outputStagingBuffers;
|
||||||
std::vector<float*> inputStagingBufferPointers;
|
std::vector<float*> inputStagingBufferPointers;
|
||||||
|
std::vector<float*> sidechainStagingBufferPointers;
|
||||||
std::vector<float*> outputStagingBufferPointers;
|
std::vector<float*> outputStagingBufferPointers;
|
||||||
|
|
||||||
std::vector<uint8_t> stagedInputAtomBuffer;
|
std::vector<uint8_t> stagedInputAtomBuffer;
|
||||||
@@ -297,22 +302,26 @@ namespace pipedal
|
|||||||
|
|
||||||
virtual void ResetAtomBuffers();
|
virtual void ResetAtomBuffers();
|
||||||
virtual uint64_t GetInstanceId() const { return instanceId; }
|
virtual uint64_t GetInstanceId() const { return instanceId; }
|
||||||
virtual int GetNumberOfInputAudioPorts() const { return inputAudioPortIndices.size(); }
|
virtual int GetNumberOfInputAudioPorts() const override { return inputAudioPortIndices.size(); }
|
||||||
virtual int GetNumberOfOutputAudioPorts() const { return outputAudioPortIndices.size(); }
|
virtual int GetNumberOfOutputAudioPorts() const override { return outputAudioPortIndices.size(); }
|
||||||
|
|
||||||
virtual int GetNumberOfInputAtomPorts() const { return inputAtomPortIndices.size(); }
|
virtual int GetNumberOfInputAtomPorts() const { return inputAtomPortIndices.size(); }
|
||||||
|
|
||||||
virtual int GetNumberOfOutputAtomPorts() const { return outputAtomPortIndices.size(); }
|
virtual int GetNumberOfOutputAtomPorts() const { return outputAtomPortIndices.size(); }
|
||||||
virtual int GetNumberOfMidiInputPorts() const { return inputMidiPortIndices.size(); }
|
virtual int GetNumberOfMidiInputPorts() const { return inputMidiPortIndices.size(); }
|
||||||
virtual int GetNumberOfMidiOutputPorts() const { return outputMidiPortIndices.size(); }
|
virtual int GetNumberOfMidiOutputPorts() const { return outputMidiPortIndices.size(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual int GetNumberOfInputAudioBuffers() const { return this->inputAudioBuffers.size(); }
|
virtual int GetNumberOfInputAudioBuffers() const override { return this->inputAudioBuffers.size(); }
|
||||||
virtual int GetNumberOfOutputAudioBuffers() const {return this->outputAudioBuffers.size(); }
|
virtual int GetNumberOfSidechainAudioBuffers() const override { return this->inputSidechainBuffers.size(); }
|
||||||
|
virtual int GetNumberOfOutputAudioBuffers() const override {return this->outputAudioBuffers.size(); }
|
||||||
|
|
||||||
virtual void SetAudioInputBuffer(int index, float *buffer);
|
virtual void SetAudioInputBuffer(int index, float *buffer) override;
|
||||||
virtual float *GetAudioInputBuffer(int index) const;
|
virtual float *GetAudioInputBuffer(int index) const override;
|
||||||
|
|
||||||
|
virtual void SetAudioSidechainBuffer(int index, float *buffer) override;
|
||||||
|
virtual float *GetAudioSidechainBuffer(int index) const override;
|
||||||
|
|
||||||
|
|
||||||
virtual void SetAudioInputBuffer(float *buffer);
|
virtual void SetAudioInputBuffer(float *buffer);
|
||||||
|
|||||||
+54
-1
@@ -176,6 +176,60 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
|
|||||||
auto bufferR = inputBuffers[1];
|
auto bufferR = inputBuffers[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Connect sidechain buffers.
|
||||||
|
|
||||||
|
if (pLv2Effect->GetNumberOfSidechainAudioBuffers() != 0)
|
||||||
|
{
|
||||||
|
if (item.sideChainInputId() == -2) // -2 means "use pedalboard inputs".
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < pLv2Effect->GetNumberOfSidechainAudioBuffers(); ++i)
|
||||||
|
{
|
||||||
|
if (i < this->pedalboardInputBuffers.size())
|
||||||
|
{
|
||||||
|
pLv2Effect->SetAudioSidechainBuffer(i, this->pedalboardInputBuffers[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// just use the first output buffer for all sidechain inputs.
|
||||||
|
pLv2Effect->SetAudioSidechainBuffer(i, this->pedalboardInputBuffers[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item.sideChainInputId() != -1) {
|
||||||
|
IEffect *pSideChainInput = GetEffect(item.sideChainInputId());
|
||||||
|
|
||||||
|
if (pSideChainInput)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < pLv2Effect->GetNumberOfSidechainAudioBuffers(); ++i)
|
||||||
|
{
|
||||||
|
if (i < pSideChainInput->GetNumberOfOutputAudioBuffers())
|
||||||
|
{
|
||||||
|
pLv2Effect->SetAudioSidechainBuffer(i, pSideChainInput->GetAudioOutputBuffer(i));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// just use the first output buffer for all sidechain inputs.
|
||||||
|
pLv2Effect->SetAudioSidechainBuffer(i, pSideChainInput->GetAudioOutputBuffer(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Internal error: Sidechain input IEffect not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No sidechain input. Feed zero buffer to all sidechain audio ports..
|
||||||
|
for (size_t i = 0; i < pLv2Effect->GetNumberOfSidechainAudioBuffers(); ++i)
|
||||||
|
{
|
||||||
|
|
||||||
|
// just use one buffer for all plugins
|
||||||
|
if (!this->pedalboardSidechainBuffer)
|
||||||
|
{
|
||||||
|
this->pedalboardSidechainBuffer = CreateNewAudioBuffer();
|
||||||
|
}
|
||||||
|
pLv2Effect->SetAudioSidechainBuffer(i, this->pedalboardSidechainBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check to see whether we need buffer staging.
|
// check to see whether we need buffer staging.
|
||||||
bool requiresBufferStaging = false;
|
bool requiresBufferStaging = false;
|
||||||
@@ -194,7 +248,6 @@ std::vector<float *> Lv2Pedalboard::PrepareItems(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!requiresBufferStaging)
|
if (!requiresBufferStaging)
|
||||||
{
|
{
|
||||||
this->processActions.push_back(
|
this->processActions.push_back(
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ namespace pipedal
|
|||||||
BufferPool bufferPool;
|
BufferPool bufferPool;
|
||||||
std::vector<float *> pedalboardInputBuffers;
|
std::vector<float *> pedalboardInputBuffers;
|
||||||
std::vector<float *> pedalboardOutputBuffers;
|
std::vector<float *> pedalboardOutputBuffers;
|
||||||
|
float *pedalboardSidechainBuffer = nullptr;
|
||||||
|
|
||||||
std::vector<std::shared_ptr<IEffect>> effects;
|
std::vector<std::shared_ptr<IEffect>> effects;
|
||||||
std::vector<IEffect *> realtimeEffects;
|
std::vector<IEffect *> realtimeEffects;
|
||||||
|
|||||||
@@ -534,6 +534,7 @@ JSON_MAP_BEGIN(PedalboardItem)
|
|||||||
JSON_MAP_REFERENCE(PedalboardItem,title)
|
JSON_MAP_REFERENCE(PedalboardItem,title)
|
||||||
JSON_MAP_REFERENCE(PedalboardItem,useModUi)
|
JSON_MAP_REFERENCE(PedalboardItem,useModUi)
|
||||||
JSON_MAP_REFERENCE(PedalboardItem,iconColor)
|
JSON_MAP_REFERENCE(PedalboardItem,iconColor)
|
||||||
|
JSON_MAP_REFERENCE(PedalboardItem,sideChainInputId)
|
||||||
JSON_MAP_END()
|
JSON_MAP_END()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ public:
|
|||||||
std::string title_;
|
std::string title_;
|
||||||
bool useModUi_ = false;
|
bool useModUi_ = false;
|
||||||
std::string iconColor_;
|
std::string iconColor_;
|
||||||
|
int64_t sideChainInputId_ = -1;
|
||||||
|
|
||||||
// non persistent state.
|
// non persistent state.
|
||||||
PropertyMap patchProperties;
|
PropertyMap patchProperties;
|
||||||
@@ -138,6 +139,7 @@ public:
|
|||||||
GETTER_SETTER_REF(title)
|
GETTER_SETTER_REF(title)
|
||||||
GETTER_SETTER_REF(iconColor)
|
GETTER_SETTER_REF(iconColor)
|
||||||
GETTER_SETTER(useModUi)
|
GETTER_SETTER(useModUi)
|
||||||
|
GETTER_SETTER(sideChainInputId)
|
||||||
|
|
||||||
Lv2PluginState&lv2State() { return lv2State_; } // non-const version.
|
Lv2PluginState&lv2State() { return lv2State_; } // non-const version.
|
||||||
GETTER_SETTER_REF(lilvPresetUri)
|
GETTER_SETTER_REF(lilvPresetUri)
|
||||||
|
|||||||
@@ -2428,7 +2428,7 @@ void PiPedalModel::OnNotifyPathPatchPropertyReceived(
|
|||||||
auto i = pedalboardItem->pathProperties_.find(pathPatchPropertyUri);
|
auto i = pedalboardItem->pathProperties_.find(pathPatchPropertyUri);
|
||||||
if (i != pedalboardItem->pathProperties_.end())
|
if (i != pedalboardItem->pathProperties_.end())
|
||||||
{
|
{
|
||||||
std::string abstractAtomString = storage.ToAbstractPathJson(atomString);
|
std::string abstractAtomString = storage.ToAbstractPathFromJson(atomString);
|
||||||
pedalboardItem->pathProperties_[pathPatchPropertyUri] = abstractAtomString;
|
pedalboardItem->pathProperties_[pathPatchPropertyUri] = abstractAtomString;
|
||||||
|
|
||||||
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
std::vector<IPiPedalModelSubscriber::ptr> t{subscribers.begin(), subscribers.end()};
|
||||||
|
|||||||
+111
-7
@@ -121,6 +121,7 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
|
|||||||
enumeration_property_uri = lilv_new_uri(pWorld, LV2_CORE__enumeration);
|
enumeration_property_uri = lilv_new_uri(pWorld, LV2_CORE__enumeration);
|
||||||
core__toggled = lilv_new_uri(pWorld, LV2_CORE__toggled);
|
core__toggled = lilv_new_uri(pWorld, LV2_CORE__toggled);
|
||||||
core__connectionOptional = lilv_new_uri(pWorld, LV2_CORE__connectionOptional);
|
core__connectionOptional = lilv_new_uri(pWorld, LV2_CORE__connectionOptional);
|
||||||
|
core__isSideChain = lilv_new_uri(pWorld, LV2_CORE_PREFIX "isSideChain"); // missing in lv2.h
|
||||||
portprops__not_on_gui_property_uri = lilv_new_uri(pWorld, LV2_PORT_PROPS__notOnGUI);
|
portprops__not_on_gui_property_uri = lilv_new_uri(pWorld, LV2_PORT_PROPS__notOnGUI);
|
||||||
portprops__trigger = lilv_new_uri(pWorld, LV2_PORT_PROPS__trigger);
|
portprops__trigger = lilv_new_uri(pWorld, LV2_PORT_PROPS__trigger);
|
||||||
midi__event = lilv_new_uri(pWorld, LV2_MIDI__MidiEvent);
|
midi__event = lilv_new_uri(pWorld, LV2_MIDI__MidiEvent);
|
||||||
@@ -134,6 +135,7 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
|
|||||||
|
|
||||||
atom__bufferType = lilv_new_uri(pWorld, LV2_ATOM__bufferType);
|
atom__bufferType = lilv_new_uri(pWorld, LV2_ATOM__bufferType);
|
||||||
atom__Path = lilv_new_uri(pWorld, LV2_ATOM__Path);
|
atom__Path = lilv_new_uri(pWorld, LV2_ATOM__Path);
|
||||||
|
atom__String = lilv_new_uri(pWorld, LV2_ATOM__String);
|
||||||
presets__preset = lilv_new_uri(pWorld, LV2_PRESETS__Preset);
|
presets__preset = lilv_new_uri(pWorld, LV2_PRESETS__Preset);
|
||||||
state__state = lilv_new_uri(pWorld, LV2_STATE__state);
|
state__state = lilv_new_uri(pWorld, LV2_STATE__state);
|
||||||
rdfs__label = lilv_new_uri(pWorld, LILV_NS_RDFS "label");
|
rdfs__label = lilv_new_uri(pWorld, LILV_NS_RDFS "label");
|
||||||
@@ -214,6 +216,7 @@ void PluginHost::LilvUris::Initialize(LilvWorld *pWorld)
|
|||||||
buf_size__maxBlockLength = lilv_new_uri(pWorld, LV2_BUF_SIZE__maxBlockLength);
|
buf_size__maxBlockLength = lilv_new_uri(pWorld, LV2_BUF_SIZE__maxBlockLength);
|
||||||
buf_size__fixedBlockLength = lilv_new_uri(pWorld, LV2_BUF_SIZE__fixedBlockLength);
|
buf_size__fixedBlockLength = lilv_new_uri(pWorld, LV2_BUF_SIZE__fixedBlockLength);
|
||||||
buf_size__coarseBlockLength = lilv_new_uri(pWorld, LV2_BUF_SIZE__coarseBlockLength);
|
buf_size__coarseBlockLength = lilv_new_uri(pWorld, LV2_BUF_SIZE__coarseBlockLength);
|
||||||
|
port_groups__sideChainOf = lilv_new_uri(pWorld, LV2_PORT_GROUPS__sideChainOf);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -794,7 +797,12 @@ Lv2PluginInfo::FindWritablePathProperties(PluginHost *lv2Host, const LilvPlugin
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsupportedPatchProperty = true;
|
if (lilv_world_ask(pWorld, propertyUri, lv2Host->lilvUris->rdfs__range, lv2Host->lilvUris->atom__String))
|
||||||
|
{
|
||||||
|
|
||||||
|
} else {
|
||||||
|
unsupportedPatchProperty = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -945,6 +953,60 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP
|
|||||||
|
|
||||||
|
|
||||||
std::sort(ports_.begin(), ports_.end(), ports_sort_compare);
|
std::sort(ports_.begin(), ports_.end(), ports_sort_compare);
|
||||||
|
|
||||||
|
|
||||||
|
// Check the portgroup for audio inputs to see if they are sidechains.
|
||||||
|
std::string last_sidechain_title;
|
||||||
|
for (auto&port: this->ports_)
|
||||||
|
{
|
||||||
|
if (port->is_audio_port() && port->is_input()) {
|
||||||
|
if (!port->port_group().empty())
|
||||||
|
{
|
||||||
|
for (auto &pg: this->port_groups_)
|
||||||
|
{
|
||||||
|
if (pg->uri() == port->port_group())
|
||||||
|
{
|
||||||
|
if (!pg->sideChainOf().empty())
|
||||||
|
{
|
||||||
|
port->is_sidechain(true);
|
||||||
|
audio_sidechain_title_ = pg->name();
|
||||||
|
if (last_sidechain_title.empty()) {
|
||||||
|
last_sidechain_title = pg->name();
|
||||||
|
}
|
||||||
|
else if (last_sidechain_title != pg->name()) {
|
||||||
|
// multiple sidechain titles!
|
||||||
|
isValid = false;
|
||||||
|
Lv2Log::debug("Plugin %s (%s) has multiple sidechain titles (%s and %s).",
|
||||||
|
this->name_.c_str(),
|
||||||
|
this->uri_.c_str(),
|
||||||
|
last_sidechain_title.c_str(),
|
||||||
|
pg->name().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (port->is_sidechain()) {
|
||||||
|
// port is marked as sidechain, but has no port group.
|
||||||
|
if (last_sidechain_title.empty())
|
||||||
|
{
|
||||||
|
last_sidechain_title = port->name();
|
||||||
|
this->audio_sidechain_title_ = port->name();
|
||||||
|
}
|
||||||
|
else if (last_sidechain_title != port->name()) {
|
||||||
|
isValid = false;
|
||||||
|
Lv2Log::debug("Plugin %s (%s) has multiple sidechain ports, but no portgroup. (%s)",
|
||||||
|
this->name_.c_str(),
|
||||||
|
this->uri_.c_str(),
|
||||||
|
port->name().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch patch properties.
|
// Fetch patch properties.
|
||||||
{
|
{
|
||||||
AutoLilvNodes patchWritables = lilv_world_find_nodes(pWorld, plugUri, lv2Host->lilvUris->patch__writable, nullptr);
|
AutoLilvNodes patchWritables = lilv_world_find_nodes(pWorld, plugUri, lv2Host->lilvUris->patch__writable, nullptr);
|
||||||
@@ -1034,17 +1096,28 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP
|
|||||||
}
|
}
|
||||||
|
|
||||||
int nInputs = 0;
|
int nInputs = 0;
|
||||||
|
int nSideChains = 0;
|
||||||
for (size_t i = 0; i < ports_.size(); ++i)
|
for (size_t i = 0; i < ports_.size(); ++i)
|
||||||
{
|
{
|
||||||
auto port = ports_[i];
|
auto port = ports_[i];
|
||||||
if (port->is_audio_port() && port->is_input())
|
if (port->is_audio_port() && port->is_input())
|
||||||
{
|
{
|
||||||
if (nInputs >= 2 && !port->connection_optional())
|
if (!port->is_sidechain()) {
|
||||||
{
|
if (nInputs >= 2)
|
||||||
isValid = false;
|
{
|
||||||
break;
|
isValid = false;
|
||||||
|
Lv2Log::debug("Plugin %s (%s) has more than 2 audio inputs.", this->name_.c_str(), this->uri_.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++nInputs;
|
||||||
|
} else {
|
||||||
|
if (nSideChains >= 2) {
|
||||||
|
Lv2Log::debug("Plugin %s (%s) has more than 2 audio sidechain inputs.", this->name_.c_str(), this->uri_.c_str());
|
||||||
|
isValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++nSideChains;
|
||||||
}
|
}
|
||||||
++nInputs;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int nOutputs = 0;
|
int nOutputs = 0;
|
||||||
@@ -1199,6 +1272,7 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP
|
|||||||
this->not_on_gui_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__not_on_gui_property_uri);
|
this->not_on_gui_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__not_on_gui_property_uri);
|
||||||
this->connection_optional_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__connectionOptional);
|
this->connection_optional_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__connectionOptional);
|
||||||
this->trigger_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__trigger);
|
this->trigger_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__trigger);
|
||||||
|
this->is_sidechain_ = lilv_port_has_property(plugin,pPort,host->lilvUris->core__isSideChain);
|
||||||
|
|
||||||
AutoLilvNode port_ledColor = lilv_port_get(plugin, pPort, host->lilvUris->pipedalUI__ledColor);
|
AutoLilvNode port_ledColor = lilv_port_get(plugin, pPort, host->lilvUris->pipedalUI__ledColor);
|
||||||
if (port_ledColor)
|
if (port_ledColor)
|
||||||
@@ -1402,7 +1476,12 @@ Lv2PluginUiInfo::Lv2PluginUiInfo(PluginHost *pHost, const Lv2PluginInfo *plugin)
|
|||||||
}
|
}
|
||||||
else if (port->is_audio_port())
|
else if (port->is_audio_port())
|
||||||
{
|
{
|
||||||
++audio_inputs_;
|
if (port->is_sidechain()) {
|
||||||
|
// sidechain outputs don't count.
|
||||||
|
++audio_side_chain_inputs_;
|
||||||
|
} else {
|
||||||
|
++audio_inputs_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (port->is_output())
|
else if (port->is_output())
|
||||||
@@ -1918,12 +1997,29 @@ Lv2PortGroup::Lv2PortGroup(PluginHost *lv2Host, const std::string &groupUri)
|
|||||||
{
|
{
|
||||||
LilvWorld *pWorld = lv2Host->pWorld;
|
LilvWorld *pWorld = lv2Host->pWorld;
|
||||||
|
|
||||||
|
// Enumerate all Lilv nodes for groupUri that have an 'a' predicate
|
||||||
|
|
||||||
this->uri_ = groupUri;
|
this->uri_ = groupUri;
|
||||||
AutoLilvNode uri = lilv_new_uri(pWorld, groupUri.c_str());
|
AutoLilvNode uri = lilv_new_uri(pWorld, groupUri.c_str());
|
||||||
|
|
||||||
|
|
||||||
|
AutoLilvNode aPredicate = lilv_new_uri(pWorld, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type");
|
||||||
|
|
||||||
|
AutoLilvNodes types = lilv_world_find_nodes(pWorld, uri, aPredicate, nullptr);
|
||||||
|
LILV_FOREACH(nodes, iNode, types)
|
||||||
|
{
|
||||||
|
AutoLilvNode typeNode = lilv_nodes_get(types, iNode);
|
||||||
|
std::string typeUri = nodeAsString(typeNode);
|
||||||
|
this->isA_.push_back(std::move(typeUri));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
AutoLilvNode symbolNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->lv2core__symbol, nullptr);
|
AutoLilvNode symbolNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->lv2core__symbol, nullptr);
|
||||||
symbol_ = nodeAsString(symbolNode);
|
symbol_ = nodeAsString(symbolNode);
|
||||||
AutoLilvNode nameNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->lv2core__name, nullptr);
|
AutoLilvNode nameNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->lv2core__name, nullptr);
|
||||||
name_ = nodeAsString(nameNode);
|
name_ = nodeAsString(nameNode);
|
||||||
|
AutoLilvNode sideChainOfNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->port_groups__sideChainOf, nullptr);
|
||||||
|
sideChainOf_ = nodeAsString(sideChainOfNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Lv2PluginInfo::isSplit() const
|
bool Lv2PluginInfo::isSplit() const
|
||||||
@@ -2187,6 +2283,7 @@ json_map::storage_type<Lv2PortInfo> Lv2PortInfo::jmap{
|
|||||||
|
|
||||||
json_map::reference("is_input", &Lv2PortInfo::is_input_),
|
json_map::reference("is_input", &Lv2PortInfo::is_input_),
|
||||||
json_map::reference("is_output", &Lv2PortInfo::is_output_),
|
json_map::reference("is_output", &Lv2PortInfo::is_output_),
|
||||||
|
json_map::reference("is_sidechain", &Lv2PortInfo::is_sidechain_),
|
||||||
|
|
||||||
json_map::reference("is_control_port", &Lv2PortInfo::is_control_port_),
|
json_map::reference("is_control_port", &Lv2PortInfo::is_control_port_),
|
||||||
json_map::reference("is_audio_port", &Lv2PortInfo::is_audio_port_),
|
json_map::reference("is_audio_port", &Lv2PortInfo::is_audio_port_),
|
||||||
@@ -2226,7 +2323,11 @@ json_map::storage_type<Lv2PortInfo> Lv2PortInfo::jmap{
|
|||||||
|
|
||||||
|
|
||||||
json_map::storage_type<Lv2PortGroup> Lv2PortGroup::jmap{{
|
json_map::storage_type<Lv2PortGroup> Lv2PortGroup::jmap{{
|
||||||
|
MAP_REF(Lv2PortGroup, isA),
|
||||||
MAP_REF(Lv2PortGroup, uri),
|
MAP_REF(Lv2PortGroup, uri),
|
||||||
|
MAP_REF(Lv2PortGroup, name),
|
||||||
|
MAP_REF(Lv2PortGroup, symbol),
|
||||||
|
MAP_REF(Lv2PortGroup, sideChainOf),
|
||||||
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -2281,6 +2382,7 @@ json_map::storage_type<Lv2PluginUiPort> Lv2PluginUiPort::jmap{{
|
|||||||
json_map::reference("name", &Lv2PluginUiPort::name_),
|
json_map::reference("name", &Lv2PluginUiPort::name_),
|
||||||
MAP_REF(Lv2PluginUiPort, index),
|
MAP_REF(Lv2PluginUiPort, index),
|
||||||
MAP_REF(Lv2PluginUiPort, is_input),
|
MAP_REF(Lv2PluginUiPort, is_input),
|
||||||
|
MAP_REF(Lv2PluginUiPort, is_sidechain),
|
||||||
MAP_REF(Lv2PluginUiPort, min_value),
|
MAP_REF(Lv2PluginUiPort, min_value),
|
||||||
MAP_REF(Lv2PluginUiPort, max_value),
|
MAP_REF(Lv2PluginUiPort, max_value),
|
||||||
MAP_REF(Lv2PluginUiPort, default_value),
|
MAP_REF(Lv2PluginUiPort, default_value),
|
||||||
@@ -2324,7 +2426,9 @@ json_map::storage_type<Lv2PluginUiInfo>
|
|||||||
json_map::reference("author_name", &Lv2PluginUiInfo::author_name_),
|
json_map::reference("author_name", &Lv2PluginUiInfo::author_name_),
|
||||||
json_map::reference("author_homepage", &Lv2PluginUiInfo::author_homepage_),
|
json_map::reference("author_homepage", &Lv2PluginUiInfo::author_homepage_),
|
||||||
json_map::reference("audio_inputs", &Lv2PluginUiInfo::audio_inputs_),
|
json_map::reference("audio_inputs", &Lv2PluginUiInfo::audio_inputs_),
|
||||||
|
json_map::reference("audio_side_chain_inputs", &Lv2PluginUiInfo::audio_side_chain_inputs_),
|
||||||
json_map::reference("audio_outputs", &Lv2PluginUiInfo::audio_outputs_),
|
json_map::reference("audio_outputs", &Lv2PluginUiInfo::audio_outputs_),
|
||||||
|
json_map::reference("audio_side_chain_title", &Lv2PluginUiInfo::audio_side_chain_title_),
|
||||||
json_map::reference("description", &Lv2PluginUiInfo::description_),
|
json_map::reference("description", &Lv2PluginUiInfo::description_),
|
||||||
json_map::reference("has_midi_input", &Lv2PluginUiInfo::has_midi_input_),
|
json_map::reference("has_midi_input", &Lv2PluginUiInfo::has_midi_input_),
|
||||||
json_map::reference("has_midi_output", &Lv2PluginUiInfo::has_midi_output_),
|
json_map::reference("has_midi_output", &Lv2PluginUiInfo::has_midi_output_),
|
||||||
|
|||||||
+61
-49
@@ -33,7 +33,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include "ModGui.hpp"
|
#include "ModGui.hpp"
|
||||||
|
|
||||||
//#include "lv2.h"
|
// #include "lv2.h"
|
||||||
#include "Units.hpp"
|
#include "Units.hpp"
|
||||||
#include "PluginPreset.hpp"
|
#include "PluginPreset.hpp"
|
||||||
|
|
||||||
@@ -206,6 +206,7 @@ namespace pipedal
|
|||||||
|
|
||||||
bool is_control_port_ = false;
|
bool is_control_port_ = false;
|
||||||
bool is_audio_port_ = false;
|
bool is_audio_port_ = false;
|
||||||
|
bool is_sidechain_ = false;
|
||||||
bool is_atom_port_ = false;
|
bool is_atom_port_ = false;
|
||||||
bool is_cv_port_ = false;
|
bool is_cv_port_ = false;
|
||||||
bool connection_optional_ = false;
|
bool connection_optional_ = false;
|
||||||
@@ -287,6 +288,7 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET_SCALAR(is_output);
|
LV2_PROPERTY_GETSET_SCALAR(is_output);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(is_control_port);
|
LV2_PROPERTY_GETSET_SCALAR(is_control_port);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(is_audio_port);
|
LV2_PROPERTY_GETSET_SCALAR(is_audio_port);
|
||||||
|
LV2_PROPERTY_GETSET_SCALAR(is_sidechain);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(is_atom_port);
|
LV2_PROPERTY_GETSET_SCALAR(is_atom_port);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(connection_optional);
|
LV2_PROPERTY_GETSET_SCALAR(connection_optional);
|
||||||
LV2_PROPERTY_GETSET_SCALAR(is_cv_port);
|
LV2_PROPERTY_GETSET_SCALAR(is_cv_port);
|
||||||
@@ -321,7 +323,6 @@ namespace pipedal
|
|||||||
return Lv2BufferType::Unknown;
|
return Lv2BufferType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Lv2PortInfo() {}
|
Lv2PortInfo() {}
|
||||||
~Lv2PortInfo() = default;
|
~Lv2PortInfo() = default;
|
||||||
@@ -330,7 +331,8 @@ namespace pipedal
|
|||||||
static json_map::storage_type<Lv2PortInfo> jmap;
|
static json_map::storage_type<Lv2PortInfo> jmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Lv2PatchPropertyInfo {
|
class Lv2PatchPropertyInfo
|
||||||
|
{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string uri_;
|
std::string uri_;
|
||||||
@@ -343,9 +345,10 @@ namespace pipedal
|
|||||||
std::string shortName_;
|
std::string shortName_;
|
||||||
std::vector<std::string> fileTypes_;
|
std::vector<std::string> fileTypes_;
|
||||||
std::vector<std::string> supportedExtensions_;
|
std::vector<std::string> supportedExtensions_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Lv2PatchPropertyInfo() {}
|
Lv2PatchPropertyInfo() {}
|
||||||
Lv2PatchPropertyInfo(PluginHost *pluginHost, const LilvNode *propertyUri);
|
Lv2PatchPropertyInfo(PluginHost *pluginHost, const LilvNode *propertyUri);
|
||||||
|
|
||||||
LV2_PROPERTY_GETSET(uri);
|
LV2_PROPERTY_GETSET(uri);
|
||||||
LV2_PROPERTY_GETSET(writable);
|
LV2_PROPERTY_GETSET(writable);
|
||||||
@@ -359,21 +362,24 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET(supportedExtensions);
|
LV2_PROPERTY_GETSET(supportedExtensions);
|
||||||
|
|
||||||
DECLARE_JSON_MAP(Lv2PatchPropertyInfo);
|
DECLARE_JSON_MAP(Lv2PatchPropertyInfo);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Lv2PortGroup
|
class Lv2PortGroup
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
std::vector<std::string> isA_;
|
||||||
std::string uri_;
|
std::string uri_;
|
||||||
std::string symbol_;
|
std::string symbol_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
std::string sideChainOf_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
LV2_PROPERTY_GETSET(isA);
|
||||||
LV2_PROPERTY_GETSET(uri);
|
LV2_PROPERTY_GETSET(uri);
|
||||||
LV2_PROPERTY_GETSET(symbol);
|
LV2_PROPERTY_GETSET(symbol);
|
||||||
LV2_PROPERTY_GETSET(name);
|
LV2_PROPERTY_GETSET(name);
|
||||||
|
LV2_PROPERTY_GETSET(sideChainOf);
|
||||||
|
|
||||||
Lv2PortGroup() {}
|
Lv2PortGroup() {}
|
||||||
Lv2PortGroup(PluginHost *lv2Host, const std::string &groupUri);
|
Lv2PortGroup(PluginHost *lv2Host, const std::string &groupUri);
|
||||||
|
|
||||||
@@ -389,10 +395,11 @@ namespace pipedal
|
|||||||
using ptr = std::shared_ptr<Lv2PluginInfo>;
|
using ptr = std::shared_ptr<Lv2PluginInfo>;
|
||||||
Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvPlugin *);
|
Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvPlugin *);
|
||||||
Lv2PluginInfo() {}
|
Lv2PluginInfo() {}
|
||||||
bool isSplit() const ;
|
bool isSplit() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct FindWritablePathPropertiesResult {
|
struct FindWritablePathPropertiesResult
|
||||||
|
{
|
||||||
std::shared_ptr<PiPedalUI> pipedalUi;
|
std::shared_ptr<PiPedalUI> pipedalUi;
|
||||||
bool hasUnsupportedPatchProperties = false;
|
bool hasUnsupportedPatchProperties = false;
|
||||||
};
|
};
|
||||||
@@ -406,7 +413,7 @@ namespace pipedal
|
|||||||
std::string name_;
|
std::string name_;
|
||||||
std::string plugin_class_;
|
std::string plugin_class_;
|
||||||
std::string brand_;
|
std::string brand_;
|
||||||
std::string label_;
|
std::string label_;
|
||||||
std::vector<std::string> supported_features_;
|
std::vector<std::string> supported_features_;
|
||||||
std::vector<std::string> required_features_;
|
std::vector<std::string> required_features_;
|
||||||
std::vector<std::string> optional_features_;
|
std::vector<std::string> optional_features_;
|
||||||
@@ -420,9 +427,9 @@ namespace pipedal
|
|||||||
std::vector<std::shared_ptr<Lv2PortInfo>> ports_;
|
std::vector<std::shared_ptr<Lv2PortInfo>> ports_;
|
||||||
std::vector<std::shared_ptr<Lv2PortGroup>> port_groups_;
|
std::vector<std::shared_ptr<Lv2PortGroup>> port_groups_;
|
||||||
std::vector<Lv2PatchPropertyInfo> patchProperties_;
|
std::vector<Lv2PatchPropertyInfo> patchProperties_;
|
||||||
|
std::string audio_sidechain_title_;
|
||||||
bool hasDefaultState_;
|
bool hasDefaultState_;
|
||||||
|
|
||||||
bool is_valid_ = false;
|
bool is_valid_ = false;
|
||||||
PiPedalUI::ptr piPedalUI_;
|
PiPedalUI::ptr piPedalUI_;
|
||||||
ModGui::ptr modGui_;
|
ModGui::ptr modGui_;
|
||||||
@@ -463,6 +470,7 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET(minBlockLength)
|
LV2_PROPERTY_GETSET(minBlockLength)
|
||||||
LV2_PROPERTY_GETSET(maxBlockLength)
|
LV2_PROPERTY_GETSET(maxBlockLength)
|
||||||
LV2_PROPERTY_GETSET(powerOf2BlockLength)
|
LV2_PROPERTY_GETSET(powerOf2BlockLength)
|
||||||
|
LV2_PROPERTY_GETSET(audio_sidechain_title)
|
||||||
|
|
||||||
bool WantsWorkerThread() const;
|
bool WantsWorkerThread() const;
|
||||||
|
|
||||||
@@ -529,9 +537,11 @@ namespace pipedal
|
|||||||
class Lv2PluginUiPortGroup
|
class Lv2PluginUiPortGroup
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
std::vector<std::string> isA_;
|
||||||
std::string uri_;
|
std::string uri_;
|
||||||
std::string symbol_;
|
std::string symbol_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
std::string sideChainOf_;
|
||||||
|
|
||||||
std::string parent_group_;
|
std::string parent_group_;
|
||||||
int32_t program_list_id_ = -1; // used by VST3.
|
int32_t program_list_id_ = -1; // used by VST3.
|
||||||
@@ -546,9 +556,7 @@ namespace pipedal
|
|||||||
public:
|
public:
|
||||||
Lv2PluginUiPortGroup() {}
|
Lv2PluginUiPortGroup() {}
|
||||||
Lv2PluginUiPortGroup(Lv2PortGroup *pPortGroup)
|
Lv2PluginUiPortGroup(Lv2PortGroup *pPortGroup)
|
||||||
: symbol_(pPortGroup->symbol())
|
: isA_(pPortGroup->isA()), symbol_(pPortGroup->symbol()), name_(pPortGroup->name()), uri_(pPortGroup->uri()), sideChainOf_(pPortGroup->sideChainOf())
|
||||||
, name_(pPortGroup->name())
|
|
||||||
, uri_(pPortGroup->uri())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Lv2PluginUiPortGroup(
|
Lv2PluginUiPortGroup(
|
||||||
@@ -570,14 +578,18 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
Lv2PluginUiPort(const Lv2PluginInfo *pPlugin, const Lv2PortInfo *pPort)
|
Lv2PluginUiPort(const Lv2PluginInfo *pPlugin, const Lv2PortInfo *pPort)
|
||||||
: symbol_(pPort->symbol()), index_(pPort->index()),
|
: symbol_(pPort->symbol()), index_(pPort->index()),
|
||||||
is_input_(pPort->is_input()), name_(pPort->name()), min_value_(pPort->min_value()), max_value_(pPort->max_value()),
|
is_input_(pPort->is_input()),
|
||||||
|
is_sidechain_(pPort->is_sidechain()),
|
||||||
|
name_(pPort->name()),
|
||||||
|
min_value_(pPort->min_value()),
|
||||||
|
max_value_(pPort->max_value()),
|
||||||
default_value_(pPort->default_value()), range_steps_(pPort->range_steps()), display_priority_(pPort->display_priority()),
|
default_value_(pPort->default_value()), range_steps_(pPort->range_steps()), display_priority_(pPort->display_priority()),
|
||||||
is_logarithmic_(pPort->is_logarithmic()),
|
is_logarithmic_(pPort->is_logarithmic()),
|
||||||
integer_property_(pPort->integer_property()),
|
integer_property_(pPort->integer_property()),
|
||||||
mod_momentaryOffByDefault_(pPort->mod_momentaryOffByDefault()),
|
mod_momentaryOffByDefault_(pPort->mod_momentaryOffByDefault()),
|
||||||
mod_momentaryOnByDefault_(pPort->mod_momentaryOnByDefault()),
|
mod_momentaryOnByDefault_(pPort->mod_momentaryOnByDefault()),
|
||||||
pipedal_graphicEq_(pPort->pipedal_graphicEq()),
|
pipedal_graphicEq_(pPort->pipedal_graphicEq()),
|
||||||
|
|
||||||
enumeration_property_(pPort->enumeration_property()),
|
enumeration_property_(pPort->enumeration_property()),
|
||||||
toggled_property_(pPort->toggled_property()), not_on_gui_(pPort->not_on_gui()), scale_points_(pPort->scale_points()),
|
toggled_property_(pPort->toggled_property()), not_on_gui_(pPort->not_on_gui()), scale_points_(pPort->scale_points()),
|
||||||
trigger_property_(pPort->trigger_property()),
|
trigger_property_(pPort->trigger_property()),
|
||||||
@@ -606,7 +618,7 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is_bypass_ =
|
is_bypass_ =
|
||||||
pPort->is_bypass() ||
|
pPort->is_bypass() ||
|
||||||
name_ == "bypass" || name_ == "Bypass" || symbol_ == "bypass" || symbol_ == "Bypass";
|
name_ == "bypass" || name_ == "Bypass" || symbol_ == "bypass" || symbol_ == "Bypass";
|
||||||
}
|
}
|
||||||
@@ -616,6 +628,7 @@ namespace pipedal
|
|||||||
int index_;
|
int index_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
bool is_input_ = true;
|
bool is_input_ = true;
|
||||||
|
bool is_sidechain_ = false;
|
||||||
float min_value_ = 0, max_value_ = 1, default_value_ = 0;
|
float min_value_ = 0, max_value_ = 1, default_value_ = 0;
|
||||||
bool is_logarithmic_ = false;
|
bool is_logarithmic_ = false;
|
||||||
int display_priority_ = -1;
|
int display_priority_ = -1;
|
||||||
@@ -682,7 +695,8 @@ namespace pipedal
|
|||||||
std::string uri_;
|
std::string uri_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
uint32_t minorVersion_ = 0;
|
uint32_t minorVersion_ = 0;
|
||||||
uint32_t microVersion_ = 0;;
|
uint32_t microVersion_ = 0;
|
||||||
|
;
|
||||||
std::string brand_;
|
std::string brand_;
|
||||||
std::string label_;
|
std::string label_;
|
||||||
std::string author_name_;
|
std::string author_name_;
|
||||||
@@ -690,12 +704,17 @@ namespace pipedal
|
|||||||
PluginType plugin_type_;
|
PluginType plugin_type_;
|
||||||
std::string plugin_display_type_;
|
std::string plugin_display_type_;
|
||||||
int audio_inputs_ = 0;
|
int audio_inputs_ = 0;
|
||||||
|
int audio_side_chain_inputs_ = 0;
|
||||||
int audio_outputs_ = 0;
|
int audio_outputs_ = 0;
|
||||||
|
std::string audio_side_chain_title_;
|
||||||
int has_midi_input_ = false;
|
int has_midi_input_ = false;
|
||||||
int has_midi_output_ = false;
|
int has_midi_output_ = false;
|
||||||
std::string description_;
|
std::string description_;
|
||||||
bool is_vst3_ = false;
|
bool is_vst3_ = false;
|
||||||
|
|
||||||
|
int64_t side_chain_input_id = -1;
|
||||||
|
|
||||||
|
|
||||||
std::vector<Lv2PluginUiPort> controls_;
|
std::vector<Lv2PluginUiPort> controls_;
|
||||||
std::vector<Lv2PluginUiPortGroup> port_groups_;
|
std::vector<Lv2PluginUiPortGroup> port_groups_;
|
||||||
std::vector<UiFileProperty::ptr> fileProperties_;
|
std::vector<UiFileProperty::ptr> fileProperties_;
|
||||||
@@ -704,7 +723,6 @@ namespace pipedal
|
|||||||
ModGui::ptr modGui_;
|
ModGui::ptr modGui_;
|
||||||
std::vector<Lv2PatchPropertyInfo> patchProperties_;
|
std::vector<Lv2PatchPropertyInfo> patchProperties_;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LV2_PROPERTY_GETSET(uri)
|
LV2_PROPERTY_GETSET(uri)
|
||||||
LV2_PROPERTY_GETSET(name)
|
LV2_PROPERTY_GETSET(name)
|
||||||
@@ -718,6 +736,7 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET(plugin_display_type)
|
LV2_PROPERTY_GETSET(plugin_display_type)
|
||||||
LV2_PROPERTY_GETSET_SCALAR(audio_inputs)
|
LV2_PROPERTY_GETSET_SCALAR(audio_inputs)
|
||||||
LV2_PROPERTY_GETSET_SCALAR(audio_outputs)
|
LV2_PROPERTY_GETSET_SCALAR(audio_outputs)
|
||||||
|
LV2_PROPERTY_GETSET(audio_side_chain_title)
|
||||||
LV2_PROPERTY_GETSET_SCALAR(has_midi_input)
|
LV2_PROPERTY_GETSET_SCALAR(has_midi_input)
|
||||||
LV2_PROPERTY_GETSET_SCALAR(has_midi_output)
|
LV2_PROPERTY_GETSET_SCALAR(has_midi_output)
|
||||||
LV2_PROPERTY_GETSET_SCALAR(description)
|
LV2_PROPERTY_GETSET_SCALAR(description)
|
||||||
@@ -729,6 +748,7 @@ namespace pipedal
|
|||||||
LV2_PROPERTY_GETSET(uiPortNotifications)
|
LV2_PROPERTY_GETSET(uiPortNotifications)
|
||||||
LV2_PROPERTY_GETSET(modGui)
|
LV2_PROPERTY_GETSET(modGui)
|
||||||
LV2_PROPERTY_GETSET(patchProperties)
|
LV2_PROPERTY_GETSET(patchProperties)
|
||||||
|
LV2_PROPERTY_GETSET_SCALAR(audio_side_chain_inputs)
|
||||||
|
|
||||||
static json_map::storage_type<Lv2PluginUiInfo> jmap;
|
static json_map::storage_type<Lv2PluginUiInfo> jmap;
|
||||||
};
|
};
|
||||||
@@ -772,6 +792,7 @@ namespace pipedal
|
|||||||
AutoLilvNode enumeration_property_uri;
|
AutoLilvNode enumeration_property_uri;
|
||||||
AutoLilvNode core__toggled;
|
AutoLilvNode core__toggled;
|
||||||
AutoLilvNode core__connectionOptional;
|
AutoLilvNode core__connectionOptional;
|
||||||
|
AutoLilvNode core__isSideChain;
|
||||||
AutoLilvNode portprops__not_on_gui_property_uri;
|
AutoLilvNode portprops__not_on_gui_property_uri;
|
||||||
AutoLilvNode portprops__trigger;
|
AutoLilvNode portprops__trigger;
|
||||||
AutoLilvNode midi__event;
|
AutoLilvNode midi__event;
|
||||||
@@ -782,9 +803,9 @@ namespace pipedal
|
|||||||
AutoLilvNode invada_units__unit; // typo in invada plugins.
|
AutoLilvNode invada_units__unit; // typo in invada plugins.
|
||||||
AutoLilvNode invada_portprops__logarithmic; // typo in invada plugins.
|
AutoLilvNode invada_portprops__logarithmic; // typo in invada plugins.
|
||||||
|
|
||||||
|
|
||||||
AutoLilvNode atom__bufferType;
|
AutoLilvNode atom__bufferType;
|
||||||
AutoLilvNode atom__Path;
|
AutoLilvNode atom__Path;
|
||||||
|
AutoLilvNode atom__String;
|
||||||
AutoLilvNode presets__preset;
|
AutoLilvNode presets__preset;
|
||||||
AutoLilvNode state__state;
|
AutoLilvNode state__state;
|
||||||
AutoLilvNode rdfs__label;
|
AutoLilvNode rdfs__label;
|
||||||
@@ -816,7 +837,6 @@ namespace pipedal
|
|||||||
AutoLilvNode pipedalUI__width;
|
AutoLilvNode pipedalUI__width;
|
||||||
AutoLilvNode pipedalUI__graphicEq;
|
AutoLilvNode pipedalUI__graphicEq;
|
||||||
|
|
||||||
|
|
||||||
AutoLilvNode pipedalUI__outputPorts;
|
AutoLilvNode pipedalUI__outputPorts;
|
||||||
AutoLilvNode pipedalUI__text;
|
AutoLilvNode pipedalUI__text;
|
||||||
|
|
||||||
@@ -846,7 +866,6 @@ namespace pipedal
|
|||||||
AutoLilvNode patch__readable;
|
AutoLilvNode patch__readable;
|
||||||
AutoLilvNode pipedal_patch__readable;
|
AutoLilvNode pipedal_patch__readable;
|
||||||
|
|
||||||
|
|
||||||
AutoLilvNode mod__brand;
|
AutoLilvNode mod__brand;
|
||||||
AutoLilvNode mod__label;
|
AutoLilvNode mod__label;
|
||||||
AutoLilvNode mod__preferMomentaryOffByDefault;
|
AutoLilvNode mod__preferMomentaryOffByDefault;
|
||||||
@@ -861,11 +880,9 @@ namespace pipedal
|
|||||||
AutoLilvNode buf_size__maxBlockLength;
|
AutoLilvNode buf_size__maxBlockLength;
|
||||||
AutoLilvNode buf_size__fixedBlockLength;
|
AutoLilvNode buf_size__fixedBlockLength;
|
||||||
AutoLilvNode buf_size__coarseBlockLength;
|
AutoLilvNode buf_size__coarseBlockLength;
|
||||||
|
AutoLilvNode port_groups__sideChainOf;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
LilvUris* lilvUris = nullptr;
|
LilvUris *lilvUris = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool vst3Enabled = true;
|
bool vst3Enabled = true;
|
||||||
@@ -896,7 +913,7 @@ namespace pipedal
|
|||||||
void free_world();
|
void free_world();
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Lv2PluginInfo>> plugins_;
|
std::vector<std::shared_ptr<Lv2PluginInfo>> plugins_;
|
||||||
std::map<std::string,std::shared_ptr<Lv2PluginInfo>> pluginsByUri;
|
std::map<std::string, std::shared_ptr<Lv2PluginInfo>> pluginsByUri;
|
||||||
std::vector<Lv2PluginUiInfo> ui_plugins_;
|
std::vector<Lv2PluginUiInfo> ui_plugins_;
|
||||||
|
|
||||||
std::map<std::string, std::shared_ptr<Lv2PluginClass>> classesMap;
|
std::map<std::string, std::shared_ptr<Lv2PluginClass>> classesMap;
|
||||||
@@ -947,22 +964,19 @@ namespace pipedal
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual MapFeature &GetMapFeature() override { return this->mapFeature; }
|
virtual MapFeature &GetMapFeature() override { return this->mapFeature; }
|
||||||
void CheckForResourceInitialization(const std::string& pluginUri,const std::filesystem::path& pluginUploadDirectory);
|
void CheckForResourceInitialization(const std::string &pluginUri, const std::filesystem::path &pluginUploadDirectory);
|
||||||
|
|
||||||
|
std::string MapResourcePath(const std::string &uri, const std::string &relativePath);
|
||||||
|
|
||||||
std::string MapResourcePath(const std::string&uri, const std::string&relativePath);
|
|
||||||
|
|
||||||
void ReloadPlugins();
|
void ReloadPlugins();
|
||||||
|
|
||||||
// equivalent to LV2 MapPath AbstractPath features.
|
// equivalent to LV2 MapPath AbstractPath features.
|
||||||
std::string MapPath(const std::string &abstractPath);
|
std::string MapPath(const std::string &abstractPath);
|
||||||
std::string AbstractPath(const std::string&path);
|
std::string AbstractPath(const std::string &path);
|
||||||
json_variant MapPath(const json_variant&json);
|
json_variant MapPath(const json_variant &json);
|
||||||
json_variant AbstractPath(const json_variant&json);
|
json_variant AbstractPath(const json_variant &json);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
std::set<std::string> pluginsThatHaveBeenCheckedForResources;
|
std::set<std::string> pluginsThatHaveBeenCheckedForResources;
|
||||||
|
|
||||||
void CheckForResourceInitization(const std::string pluginUri);
|
void CheckForResourceInitization(const std::string pluginUri);
|
||||||
@@ -973,12 +987,11 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
static void PortValueCallback(const char *symbol, void *user_data, const void *value, uint32_t size, uint32_t type);
|
static void PortValueCallback(const char *symbol, void *user_data, const void *value, uint32_t size, uint32_t type);
|
||||||
static void StateRestoreCallback(
|
static void StateRestoreCallback(
|
||||||
const char* port_symbol,
|
const char *port_symbol,
|
||||||
void* user_data,
|
void *user_data,
|
||||||
const void* value,
|
const void *value,
|
||||||
uint32_t size,
|
uint32_t size,
|
||||||
uint32_t type);
|
uint32_t type);
|
||||||
|
|
||||||
|
|
||||||
virtual IEffect *CreateEffect(PedalboardItem &pedalboardItem);
|
virtual IEffect *CreateEffect(PedalboardItem &pedalboardItem);
|
||||||
void LoadPluginClassesFromLilv();
|
void LoadPluginClassesFromLilv();
|
||||||
@@ -995,9 +1008,9 @@ namespace pipedal
|
|||||||
|
|
||||||
IHost *asIHost() { return this; }
|
IHost *asIHost() { return this; }
|
||||||
|
|
||||||
virtual Lv2Pedalboard *CreateLv2Pedalboard(Pedalboard &pedalboard,Lv2PedalboardErrorList &errorList);
|
virtual Lv2Pedalboard *CreateLv2Pedalboard(Pedalboard &pedalboard, Lv2PedalboardErrorList &errorList);
|
||||||
|
|
||||||
virtual Lv2Pedalboard *UpdateLv2PedalboardStructure(Pedalboard &pedalboard,Lv2Pedalboard *existingPedalboard,Lv2PedalboardErrorList &errorList);
|
virtual Lv2Pedalboard *UpdateLv2PedalboardStructure(Pedalboard &pedalboard, Lv2Pedalboard *existingPedalboard, Lv2PedalboardErrorList &errorList);
|
||||||
|
|
||||||
void setSampleRate(double sampleRate)
|
void setSampleRate(double sampleRate)
|
||||||
{
|
{
|
||||||
@@ -1010,9 +1023,8 @@ namespace pipedal
|
|||||||
|
|
||||||
class Urids;
|
class Urids;
|
||||||
|
|
||||||
Urids *urids = nullptr;
|
Urids *urids = nullptr;
|
||||||
ModGuiUris* mod_gui_uris = nullptr;
|
ModGuiUris *mod_gui_uris = nullptr;
|
||||||
|
|
||||||
|
|
||||||
void OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings);
|
void OnConfigurationChanged(const JackConfiguration &configuration, const JackChannelSelection &settings);
|
||||||
|
|
||||||
@@ -1021,7 +1033,7 @@ namespace pipedal
|
|||||||
|
|
||||||
std::shared_ptr<Lv2PluginClass> GetLv2PluginClass() const;
|
std::shared_ptr<Lv2PluginClass> GetLv2PluginClass() const;
|
||||||
|
|
||||||
const std::vector<std::shared_ptr<Lv2PluginInfo>>& GetPlugins() const { return plugins_; }
|
const std::vector<std::shared_ptr<Lv2PluginInfo>> &GetPlugins() const { return plugins_; }
|
||||||
const std::vector<Lv2PluginUiInfo> &GetUiPlugins() const { return ui_plugins_; }
|
const std::vector<Lv2PluginUiInfo> &GetUiPlugins() const { return ui_plugins_; }
|
||||||
|
|
||||||
virtual std::shared_ptr<Lv2PluginInfo> GetPluginInfo(const std::string &uri) const;
|
virtual std::shared_ptr<Lv2PluginInfo> GetPluginInfo(const std::string &uri) const;
|
||||||
|
|||||||
+14
-2
@@ -1717,7 +1717,7 @@ void Storage::ToAbstractPaths(PluginPreset &pluginPreset)
|
|||||||
std::map<std::string, std::string> newPathProperties;
|
std::map<std::string, std::string> newPathProperties;
|
||||||
for (const auto &pair : pluginPreset.pathProperties_)
|
for (const auto &pair : pluginPreset.pathProperties_)
|
||||||
{
|
{
|
||||||
newPathProperties[pair.first] = this->ToAbstractPathJson(pair.second);
|
newPathProperties[pair.first] = this->ToAbstractPathFromJson(pair.second);
|
||||||
}
|
}
|
||||||
pluginPreset.pathProperties_ = newPathProperties;
|
pluginPreset.pathProperties_ = newPathProperties;
|
||||||
}
|
}
|
||||||
@@ -2999,7 +2999,19 @@ std::string Storage::GetTone3000Auth() const
|
|||||||
return tone3000Auth;
|
return tone3000Auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Storage::ToAbstractPathJson(const std::string &pathJson)
|
std::filesystem::path Storage::FromAbstractPathString(const std::string &stringPath)
|
||||||
|
{
|
||||||
|
if (stringPath.empty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
fs::path path { stringPath};
|
||||||
|
if (path.is_absolute()) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return GetPluginUploadDirectory() / path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Storage::ToAbstractPathFromJson(const std::string &pathJson)
|
||||||
{
|
{
|
||||||
json_variant v = json_variant::parse(pathJson);
|
json_variant v = json_variant::parse(pathJson);
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -129,8 +129,9 @@ public:
|
|||||||
|
|
||||||
const std::filesystem::path &GetPluginUploadDirectory() const;
|
const std::filesystem::path &GetPluginUploadDirectory() const;
|
||||||
|
|
||||||
std::string ToAbstractPathJson(const std::string &jsonAtomPath);
|
std::string ToAbstractPathFromJson(const std::string &jsonAtomPath);
|
||||||
std::string FromAbstractPathJson(const std::string &jsonAtomPath);
|
std::string FromAbstractPathJson(const std::string &jsonAtomPath);
|
||||||
|
std::filesystem::path FromAbstractPathString(const std::string &stringPath);
|
||||||
|
|
||||||
|
|
||||||
//std::vector<std::string> GetPedalboards();
|
//std::vector<std::string> GetPedalboards();
|
||||||
|
|||||||
@@ -520,7 +520,7 @@ public:
|
|||||||
|
|
||||||
res.set(HttpField::content_type, "application/json");
|
res.set(HttpField::content_type, "application/json");
|
||||||
res.set(HttpField::cache_control, "no-cache");
|
res.set(HttpField::cache_control, "no-cache");
|
||||||
fs::path path = model->GetStorage().FromAbstractPathJson(request_uri.query("path"));
|
fs::path path = model->GetStorage().FromAbstractPathString(request_uri.query("path"));
|
||||||
|
|
||||||
if (!fs::exists(path) || !this->model->IsInUploadsDirectory(path) || HasDotDot(path))
|
if (!fs::exists(path) || !this->model->IsInUploadsDirectory(path) || HasDotDot(path))
|
||||||
{
|
{
|
||||||
|
|||||||
+147
-123
@@ -24,17 +24,40 @@ import { withStyles } from "tss-react/mui";
|
|||||||
import { createStyles } from './WithStyles';
|
import { createStyles } from './WithStyles';
|
||||||
import FullscreenIcon from '@mui/icons-material/Fullscreen';
|
import FullscreenIcon from '@mui/icons-material/Fullscreen';
|
||||||
import IconButtonEx from './IconButtonEx';
|
import IconButtonEx from './IconButtonEx';
|
||||||
import { isDarkMode } from './DarkMode';
|
|
||||||
import Backdrop from '@mui/material/Backdrop';
|
import Backdrop from '@mui/material/Backdrop';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
|
|
||||||
import Rect from './Rect';
|
import Rect from './Rect';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
|
||||||
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel';
|
||||||
|
|
||||||
const styles = (theme: Theme) => createStyles({
|
const styles = (theme: Theme) => createStyles({
|
||||||
pgraph: {
|
pgraph: css({
|
||||||
paddingBottom: 16
|
paddingBottom: 16
|
||||||
}
|
}),
|
||||||
|
backdrop: css({
|
||||||
|
zIndex: 1101,
|
||||||
|
overflow: "clip",
|
||||||
|
background: theme.palette.background.default,
|
||||||
|
|
||||||
|
}),
|
||||||
|
noToolbar: css({
|
||||||
|
display: "none"
|
||||||
|
}),
|
||||||
|
topToolBar: css({
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: 1101,
|
||||||
|
top: 0,
|
||||||
|
display: "flex", flexFlow: "row nowrap", justifyContent: "start", columnGap: 8,
|
||||||
|
}),
|
||||||
|
rightToolbar: css({
|
||||||
|
position: "absolute",
|
||||||
|
zIndex: 1101,
|
||||||
|
top: 24,
|
||||||
|
display: "flex", flexFlow: "column nowrap", rowGap: 8
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -42,6 +65,7 @@ export interface AutoZoomProps extends WithStyles<typeof styles> {
|
|||||||
leftPad: number,
|
leftPad: number,
|
||||||
rightPad: number,
|
rightPad: number,
|
||||||
children?: React.ReactNode,
|
children?: React.ReactNode,
|
||||||
|
toolbarChildren?: React.ReactNode[],
|
||||||
contentReady: boolean,
|
contentReady: boolean,
|
||||||
showZoomed: boolean,
|
showZoomed: boolean,
|
||||||
setShowZoomed: (value: boolean) => void;
|
setShowZoomed: (value: boolean) => void;
|
||||||
@@ -53,6 +77,15 @@ export interface AutoZoomState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// non-react zoom state.
|
||||||
|
class UnzoomedLayout {
|
||||||
|
horizontalToolbar = false;
|
||||||
|
effectiveClientRect: Rect = new Rect();
|
||||||
|
showToolbar = false;
|
||||||
|
zoom: number = 1;
|
||||||
|
showZoomButton = false;
|
||||||
|
contentRect: Rect = new Rect();
|
||||||
|
}
|
||||||
|
|
||||||
const AutoZoom = withStyles(
|
const AutoZoom = withStyles(
|
||||||
class extends ResizeResponsiveComponent<AutoZoomProps, AutoZoomState> {
|
class extends ResizeResponsiveComponent<AutoZoomProps, AutoZoomState> {
|
||||||
@@ -97,38 +130,43 @@ const AutoZoom = withStyles(
|
|||||||
if (this.normalRef) {
|
if (this.normalRef) {
|
||||||
this.updateZoom(this.normalRef);
|
this.updateZoom(this.normalRef);
|
||||||
}
|
}
|
||||||
if (this.maximizedRef) {
|
|
||||||
this.updateMaximizedZoom();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resizeObserver: ResizeObserver | null = null;
|
resizeObserver: ResizeObserver | null = null;
|
||||||
|
|
||||||
|
|
||||||
calculateZoomedClientRect(
|
calculateUnzoomedLayout(
|
||||||
clientRect: Rect,
|
clientRect: Rect,
|
||||||
contentWidth: number,
|
contentWidth: number,
|
||||||
contentHeight: number,
|
contentHeight: number,
|
||||||
buttonPadding: number
|
buttonPadding: number
|
||||||
): Rect {
|
): UnzoomedLayout {
|
||||||
|
|
||||||
|
let result = new UnzoomedLayout();
|
||||||
|
|
||||||
console.log("Zoom: " + clientRect.toString() + " content: " + contentWidth + "x" + contentHeight + " buttonPadding: " + buttonPadding);
|
|
||||||
let rightButtonZoom = Math.min((clientRect.width - buttonPadding) / contentWidth, clientRect.height / contentHeight);
|
let rightButtonZoom = Math.min((clientRect.width - buttonPadding) / contentWidth, clientRect.height / contentHeight);
|
||||||
let topButtonZoom = Math.min((clientRect.width - buttonPadding) / contentWidth, (clientRect.height - buttonPadding) / contentHeight);
|
let topButtonZoom = Math.min((clientRect.width - buttonPadding) / contentWidth, (clientRect.height - buttonPadding) / contentHeight);
|
||||||
|
|
||||||
let effectiveClientRect = clientRect.copy();
|
let effectiveClientRect = clientRect.copy();
|
||||||
if (rightButtonZoom > topButtonZoom) {
|
if (rightButtonZoom > topButtonZoom) {
|
||||||
|
result.horizontalToolbar = false;
|
||||||
effectiveClientRect.width -= buttonPadding;
|
effectiveClientRect.width -= buttonPadding;
|
||||||
} else {
|
} else {
|
||||||
|
result.horizontalToolbar = true;
|
||||||
effectiveClientRect.y += buttonPadding;
|
effectiveClientRect.y += buttonPadding;
|
||||||
effectiveClientRect.height -= buttonPadding;
|
effectiveClientRect.height -= buttonPadding;
|
||||||
}
|
}
|
||||||
|
result.effectiveClientRect = effectiveClientRect;
|
||||||
|
|
||||||
let zoom = Math.min(effectiveClientRect.width / contentWidth, effectiveClientRect.height / contentHeight);
|
let zoom = Math.min(effectiveClientRect.width / contentWidth, effectiveClientRect.height / contentHeight);
|
||||||
if (zoom > 1) {
|
if (zoom > 1) {
|
||||||
zoom = 1;
|
zoom = 1;
|
||||||
}
|
}
|
||||||
|
result.zoom = zoom;
|
||||||
|
result.showZoomButton = zoom !== 1;
|
||||||
|
result.showToolbar = result.showZoomButton || !!this.props.toolbarChildren;
|
||||||
|
|
||||||
let leftPad = (effectiveClientRect.width - contentWidth * zoom) / 2;
|
let leftPad = (effectiveClientRect.width - contentWidth * zoom) / 2;
|
||||||
if (leftPad < 0) {
|
if (leftPad < 0) {
|
||||||
leftPad = 0;
|
leftPad = 0;
|
||||||
@@ -137,7 +175,8 @@ const AutoZoom = withStyles(
|
|||||||
if (topPad < 0) {
|
if (topPad < 0) {
|
||||||
topPad = 0;
|
topPad = 0;
|
||||||
}
|
}
|
||||||
return new Rect(effectiveClientRect.x + leftPad, effectiveClientRect.y + topPad, contentWidth * zoom, contentHeight * zoom);
|
result.contentRect = new Rect(effectiveClientRect.x + leftPad, effectiveClientRect.y + topPad, contentWidth * zoom, contentHeight * zoom);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateZoom(ref: HTMLDivElement) {
|
updateZoom(ref: HTMLDivElement) {
|
||||||
@@ -145,59 +184,58 @@ const AutoZoom = withStyles(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let content = ref.firstElementChild as HTMLElement | null;
|
let content = ref.firstElementChild as HTMLElement | null;
|
||||||
|
const classes = withStyles.getClasses(this.props);
|
||||||
|
|
||||||
if (content) {
|
if (content) {
|
||||||
const { leftPad, rightPad } = this.props;
|
const { leftPad, rightPad } = this.props;
|
||||||
let bounds = new Rect(leftPad, 0, ref.clientWidth - leftPad - rightPad, ref.clientHeight - 8);
|
let bounds = new Rect(leftPad, 0, ref.clientWidth - leftPad - rightPad, ref.clientHeight - 8);
|
||||||
let zoomedClientRect = this.calculateZoomedClientRect(
|
let layout = this.calculateUnzoomedLayout(
|
||||||
bounds, content.clientWidth, content.clientHeight, 48);
|
bounds, content.clientWidth, content.clientHeight, 48);
|
||||||
|
|
||||||
|
let contentRect = layout.contentRect;
|
||||||
|
|
||||||
content.style.left = "0px";
|
content.style.left = "0px";
|
||||||
content.style.top = "0px";
|
content.style.top = "0px";
|
||||||
content.style.transformOrigin = "0 0"; // top-left corner
|
content.style.transformOrigin = "0 0"; // top-left corner
|
||||||
content.style.transform =
|
content.style.transform =
|
||||||
`translate(${zoomedClientRect.x}px, ${zoomedClientRect.y}px) scale(${zoomedClientRect.width / content.clientWidth}, ${zoomedClientRect.height / content.clientHeight})`;
|
`translate(${contentRect.x}px, ${contentRect.y}px) scale(${layout.zoom}, ${layout.zoom})`;
|
||||||
|
|
||||||
if (this.zoomButton) {
|
if (this.zoomToolbar) {
|
||||||
this.zoomButton.style.display = zoomedClientRect.width < content.clientWidth ? "block" : "none";
|
if (!layout.showToolbar) {
|
||||||
let rightSizeSpace = ref.clientWidth - zoomedClientRect.right;
|
|
||||||
if (rightSizeSpace - rightPad >= 48) {
|
this.zoomToolbar.className = classes.noToolbar;
|
||||||
this.zoomButton.style.top = `${zoomedClientRect.y + 24}px`;
|
} else if (layout.horizontalToolbar) {
|
||||||
this.zoomButton.style.left = `${zoomedClientRect.right + 4}px`;
|
this.zoomToolbar.className = classes.topToolBar;
|
||||||
|
this.zoomToolbar.style.left = `${contentRect.x +16}px`
|
||||||
|
this.zoomToolbar.style.top = `${contentRect.y - 48}px`;
|
||||||
|
this.zoomToolbar.style.width = `${contentRect.width}px`;
|
||||||
} else {
|
} else {
|
||||||
this.zoomButton.style.top = `${zoomedClientRect.y - 48}px`;
|
this.zoomToolbar.className = classes.rightToolbar;
|
||||||
this.zoomButton.style.left = `${zoomedClientRect.right - 64 - 12}px`;
|
this.zoomToolbar.style.left = "";
|
||||||
|
this.zoomToolbar.style.top = `${contentRect.y}px`;
|
||||||
|
this.zoomToolbar.style.left = `${contentRect.right + 4}px`;
|
||||||
|
this.zoomToolbar.style.width = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.zoomButton) {
|
||||||
|
this.zoomButton.style.display = layout.showZoomButton ? "block" : "none";
|
||||||
|
}
|
||||||
|
|
||||||
// save the position of the Mod UI in page coordinates for later zooming.
|
// save the position of the Mod UI in page coordinates for later zooming.
|
||||||
this.zoomStartRect = zoomedClientRect.copy();
|
this.zoomStartRect = layout.contentRect.copy();
|
||||||
let refBounds = ref.getBoundingClientRect();
|
let refBounds = ref.getBoundingClientRect();
|
||||||
this.zoomStartRect.x += refBounds.left;
|
this.zoomStartRect.x += refBounds.left;
|
||||||
this.zoomStartRect.y += refBounds.top;
|
this.zoomStartRect.y += refBounds.top;
|
||||||
|
} else {
|
||||||
|
if (this.zoomToolbar) {
|
||||||
|
this.zoomToolbar.className = classes.noToolbar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMaximizedZoom() {
|
updateMaximizedZoom() {
|
||||||
let ref = this.maximizedRef;
|
if (this.normalRef) {
|
||||||
if (!this.mounted || !ref) {
|
this.updateZoom(this.normalRef);
|
||||||
return;
|
|
||||||
}
|
|
||||||
let content = ref.firstElementChild as HTMLElement | null;
|
|
||||||
|
|
||||||
if (content) {
|
|
||||||
let leftPad = 16; let rightPad = 16;
|
|
||||||
let topPad = 16, bottomPad = 16;
|
|
||||||
let bounds: Rect;
|
|
||||||
bounds = new Rect(leftPad, topPad, ref.clientWidth - leftPad - rightPad, ref.clientHeight - topPad - bottomPad);
|
|
||||||
|
|
||||||
let zoomedClientRect = this.calculateZoomedClientRect(
|
|
||||||
bounds, content.clientWidth, content.clientHeight, 48);
|
|
||||||
content.style.left = "0px";
|
|
||||||
content.style.top = "0px";
|
|
||||||
content.style.transformOrigin = "0 0"; // top-left corner
|
|
||||||
content.style.transform = `translate(${zoomedClientRect.x}px, ${zoomedClientRect.y}px) scale(${zoomedClientRect.width / content.clientWidth}, ${zoomedClientRect.height / content.clientHeight})`;
|
|
||||||
//console.log("Zoomed to: ", zoomedClientRect.toString());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,20 +272,20 @@ const AutoZoom = withStyles(
|
|||||||
}
|
}
|
||||||
this.maximizedAnimateFrameHandle = window.requestAnimationFrame(() => {
|
this.maximizedAnimateFrameHandle = window.requestAnimationFrame(() => {
|
||||||
this.maximizedAnimateFrameHandle = null;
|
this.maximizedAnimateFrameHandle = null;
|
||||||
if (this.maximizedRef) {
|
this.updateMaximizedZoom();
|
||||||
this.updateMaximizedZoom();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private zoomToolbar: HTMLElement | null = null;
|
||||||
private zoomButton: HTMLElement | null = null;
|
private zoomButton: HTMLElement | null = null;
|
||||||
private normalRef: HTMLDivElement | null = null;
|
private normalRef: HTMLDivElement | null = null;
|
||||||
|
|
||||||
setNormalRef(ref: HTMLDivElement | null) {
|
setContentRef(ref: HTMLDivElement | null) {
|
||||||
this.normalRef = ref;
|
this.normalRef = ref;
|
||||||
if (ref) {
|
if (ref) {
|
||||||
this.zoomButton = ref.querySelector("#maximize-button") as HTMLDivElement | null;
|
this.zoomToolbar = ref.querySelector("#zoom-toolbar") as HTMLDivElement | null;
|
||||||
|
this.zoomButton = ref.querySelector("#zoom-button") as HTMLDivElement | null;
|
||||||
this.resizeObserver = new ResizeObserver(() => {
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
this.requestZoomUpdate();
|
this.requestZoomUpdate();
|
||||||
});
|
});
|
||||||
@@ -261,36 +299,15 @@ const AutoZoom = withStyles(
|
|||||||
if (this.resizeObserver) {
|
if (this.resizeObserver) {
|
||||||
this.resizeObserver.disconnect();
|
this.resizeObserver.disconnect();
|
||||||
this.resizeObserver = null;
|
this.resizeObserver = null;
|
||||||
this.zoomButton = null;
|
this.zoomToolbar = null;
|
||||||
}
|
}
|
||||||
this.zoomStartRect = null;
|
this.zoomStartRect = null;
|
||||||
|
this.zoomToolbar = null;
|
||||||
|
this.zoomButton = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private maximizedRef: HTMLDivElement | null = null;
|
|
||||||
private maximedResizeObserver: ResizeObserver | null = null;
|
|
||||||
|
|
||||||
setMaximizedRef(ref: HTMLDivElement | null) {
|
|
||||||
this.maximizedRef = ref;
|
|
||||||
if (ref) {
|
|
||||||
this.maximedResizeObserver = new ResizeObserver(() => {
|
|
||||||
this.requestMaximizedZoomUpdate();
|
|
||||||
});
|
|
||||||
this.maximedResizeObserver.observe(ref);
|
|
||||||
let child = ref.firstElementChild as HTMLElement | null;
|
|
||||||
if (child) {
|
|
||||||
this.maximedResizeObserver.observe(child);
|
|
||||||
}
|
|
||||||
this.requestMaximizedZoomUpdate();
|
|
||||||
} else {
|
|
||||||
if (this.maximedResizeObserver) {
|
|
||||||
this.maximedResizeObserver.disconnect();
|
|
||||||
this.maximedResizeObserver = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private zoomStartRect: Rect | null = null;
|
private zoomStartRect: Rect | null = null;
|
||||||
|
|
||||||
startZoom() {
|
startZoom() {
|
||||||
@@ -300,70 +317,77 @@ const AutoZoom = withStyles(
|
|||||||
this.props.setShowZoomed(true);
|
this.props.setShowZoomed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
content() {
|
||||||
const classes = withStyles.getClasses(this.props);
|
const classes = withStyles.getClasses(this.props);
|
||||||
void classes; // suppress unused variable warning
|
void classes; // suppress unused variable warning
|
||||||
const landscape = this.state.screenWidth > this.state.screenHeight;
|
return (
|
||||||
return (<div style={{ overflow: "hidden", height: "100%", width: "100%" }} ref={(ref) => { this.setNormalRef(ref); }}>
|
<div ref={(ref) => { this.setContentRef(ref); }}
|
||||||
<div style={{
|
style={{ width: "100%", height: "100%" }}
|
||||||
display: "inline-block",
|
|
||||||
position: "absolute",
|
|
||||||
visibility: this.props.contentReady ? "visible" : "hidden",
|
|
||||||
|
|
||||||
}}>
|
|
||||||
{!this.props.showZoomed && this.props.children}
|
|
||||||
</div>
|
|
||||||
<div id="maximize-button" style={{
|
|
||||||
display: "none", position: "absolute", left: 0, top: 0, width: 52, height: 64, zIndex: 1101,
|
|
||||||
borderRadius: "0px 26px 26px 0px",
|
|
||||||
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<IconButtonEx tooltip="Fullscreen view"
|
<div style={{
|
||||||
style={{ margin: 2, background: isDarkMode() ? "#444" : "#eee" }}
|
display: "inline-block",
|
||||||
onClick={() => {
|
position: "absolute",
|
||||||
this.startZoom();
|
visibility: this.props.contentReady ? "visible" : "hidden"
|
||||||
|
|
||||||
|
}}>
|
||||||
|
{this.props.children}
|
||||||
|
</div>
|
||||||
|
<div id="zoom-toolbar" className={classes.noToolbar}
|
||||||
|
style={{
|
||||||
|
visibility: this.props.contentReady ? "visible" : "hidden"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FullscreenIcon style={{ color: "white" }} />
|
{!this.props.showZoomed ? (
|
||||||
</IconButtonEx>
|
<IconButtonEx id="zoom-button" tooltip="Fullscreen view"
|
||||||
</div>
|
onClick={() => {
|
||||||
{this.props.showZoomed && (
|
this.startZoom();
|
||||||
<Backdrop id="modGuiZoomBackdrop"
|
|
||||||
sx={(theme) => ({
|
|
||||||
zIndex: this.props.showZoomed ? 1101 : -1,
|
|
||||||
overflow: "clip",
|
|
||||||
background: theme.palette.mode === 'dark' ? 'rgba(0, 0, 0, 0.9)' : 'rgba(255, 255, 255, 0.9)'
|
|
||||||
})}
|
|
||||||
open={this.props.showZoomed}
|
|
||||||
>
|
|
||||||
<div ref={(ref) => { this.setMaximizedRef(ref); }}
|
|
||||||
style={{
|
|
||||||
position: "absolute", left: 0, top: 0, right: 0, bottom: 0, overflow: "hidden",
|
|
||||||
visibility: this.props.contentReady ? "visible" : "hidden"
|
|
||||||
}}>
|
|
||||||
|
|
||||||
<div style={{ display: "inline-block", position: "relative" }}>
|
|
||||||
{
|
|
||||||
this.props.showZoomed && this.props.children
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<IconButtonEx tooltip="Exit fullscreen"
|
|
||||||
style={{
|
|
||||||
position: "absolute",
|
|
||||||
right: landscape? 80: 16, // avoid potential cutout in landscape mode
|
|
||||||
top: 16, zIndex: 1104,
|
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<FullscreenIcon style={{ opacity: 0.6 }}
|
||||||
|
/>
|
||||||
|
</IconButtonEx>
|
||||||
|
|
||||||
|
) : (
|
||||||
|
<IconButtonEx tooltip="Exit fullscreen"
|
||||||
|
style={{}}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
this.props.setShowZoomed(false);
|
this.props.setShowZoomed(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CloseIcon />
|
<ArrowBackIcon style={{
|
||||||
|
opacity: 0.6,
|
||||||
|
}} />
|
||||||
</IconButtonEx>
|
</IconButtonEx>
|
||||||
</div>
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
{this.props.toolbarChildren && this.props.toolbarChildren.map((child, index) => (
|
||||||
|
<div key={index} style={{ display: "inline-block" }}>
|
||||||
|
{child}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const classes = withStyles.getClasses(this.props);
|
||||||
|
void classes; // suppress unused variable warning
|
||||||
|
|
||||||
|
return (<div style={{ overflow: "hidden", height: "100%", width: "100%" }} >
|
||||||
|
{!this.props.showZoomed && this.content()}
|
||||||
|
|
||||||
|
{this.props.showZoomed && (
|
||||||
|
<Backdrop id="modGuiZoomBackdrop"
|
||||||
|
className={classes.backdrop}
|
||||||
|
open={this.props.showZoomed}
|
||||||
|
>
|
||||||
|
{this.content()}
|
||||||
|
|
||||||
</Backdrop>
|
</Backdrop>
|
||||||
)}
|
)}
|
||||||
</div>);
|
</div>);
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export class Port implements Deserializable<Port> {
|
|||||||
this.scale_points = ScalePoint.deserialize_array(input.scale_points);
|
this.scale_points = ScalePoint.deserialize_array(input.scale_points);
|
||||||
this.is_input = input.is_input;
|
this.is_input = input.is_input;
|
||||||
this.is_output = input.is_output;
|
this.is_output = input.is_output;
|
||||||
|
this.is_sidechain = input.is_sidechain;
|
||||||
this.is_control_port = input.is_control_port;
|
this.is_control_port = input.is_control_port;
|
||||||
this.is_audio_port = input.is_audio_port;
|
this.is_audio_port = input.is_audio_port;
|
||||||
this.is_atom_port = input.is_atom_port;
|
this.is_atom_port = input.is_atom_port;
|
||||||
@@ -80,6 +81,7 @@ export class Port implements Deserializable<Port> {
|
|||||||
is_output: boolean = false
|
is_output: boolean = false
|
||||||
is_control_port: boolean = false;
|
is_control_port: boolean = false;
|
||||||
is_audio_port: boolean = false;
|
is_audio_port: boolean = false;
|
||||||
|
is_sidechain: boolean = false;
|
||||||
is_atom_port: boolean = false;
|
is_atom_port: boolean = false;
|
||||||
is_valid: boolean = false;
|
is_valid: boolean = false;
|
||||||
supports_midi: boolean = false;
|
supports_midi: boolean = false;
|
||||||
@@ -92,9 +94,11 @@ export class Port implements Deserializable<Port> {
|
|||||||
|
|
||||||
export class PortGroup {
|
export class PortGroup {
|
||||||
deserialize(input: any): PortGroup {
|
deserialize(input: any): PortGroup {
|
||||||
|
this.isA = input.isA;
|
||||||
this.uri = input.uri;
|
this.uri = input.uri;
|
||||||
this.symbol = input.symbol;
|
this.symbol = input.symbol;
|
||||||
this.name = input.name;
|
this.name = input.name;
|
||||||
|
this.sideChainof = input.sideChainOf;
|
||||||
this.parent_group = input.parent_group;
|
this.parent_group = input.parent_group;
|
||||||
this.program_list_id = input.program_list_id ?? -1;
|
this.program_list_id = input.program_list_id ?? -1;
|
||||||
|
|
||||||
@@ -108,9 +112,12 @@ export class PortGroup {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isA: string[] = [];
|
||||||
uri: string = "";
|
uri: string = "";
|
||||||
symbol: string = "";
|
symbol: string = "";
|
||||||
name: string = "";
|
name: string = "";
|
||||||
|
sideChainof: string = "";
|
||||||
|
|
||||||
parent_group: string = "";
|
parent_group: string = "";
|
||||||
program_list_id: number = -1;
|
program_list_id: number = -1;
|
||||||
};
|
};
|
||||||
@@ -967,6 +974,8 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
|||||||
this.author_name = input.author_name;
|
this.author_name = input.author_name;
|
||||||
this.author_homepage = input.author_homepage;
|
this.author_homepage = input.author_homepage;
|
||||||
this.audio_inputs = input.audio_inputs;
|
this.audio_inputs = input.audio_inputs;
|
||||||
|
this.audio_side_chain_inputs = input.audio_side_chain_inputs ?? 0;
|
||||||
|
this.audio_side_chain_title = input.audio_side_chain_title ?? "";
|
||||||
this.audio_outputs = input.audio_outputs;
|
this.audio_outputs = input.audio_outputs;
|
||||||
this.has_midi_input = input.has_midi_input;
|
this.has_midi_input = input.has_midi_input;
|
||||||
this.has_midi_output = input.has_midi_output;
|
this.has_midi_output = input.has_midi_output;
|
||||||
@@ -1057,7 +1066,9 @@ export class UiPlugin implements Deserializable<UiPlugin> {
|
|||||||
author_name: string = "";
|
author_name: string = "";
|
||||||
author_homepage: string = "";
|
author_homepage: string = "";
|
||||||
audio_inputs: number = 0;
|
audio_inputs: number = 0;
|
||||||
|
audio_side_chain_inputs: number = 0;
|
||||||
audio_outputs: number = 0;
|
audio_outputs: number = 0;
|
||||||
|
audio_side_chain_title: string = "";
|
||||||
has_midi_input: number = 0;
|
has_midi_input: number = 0;
|
||||||
has_midi_output: number = 0;
|
has_midi_output: number = 0;
|
||||||
description: string = "";
|
description: string = "";
|
||||||
@@ -1084,6 +1095,7 @@ export function makeSplitUiPlugin(): UiPlugin {
|
|||||||
author_name: "",
|
author_name: "",
|
||||||
author_homepage: "",
|
author_homepage: "",
|
||||||
audio_inputs: 1,
|
audio_inputs: 1,
|
||||||
|
audio_side_chain_inputs: 0,
|
||||||
audio_outputs: 1,
|
audio_outputs: 1,
|
||||||
has_midi_input: 0,
|
has_midi_input: 0,
|
||||||
has_midi_output: 0,
|
has_midi_output: 0,
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
|
|||||||
this.pathProperties = input.pathProperties;
|
this.pathProperties = input.pathProperties;
|
||||||
this.useModUi = input.useModUi ?? false;
|
this.useModUi = input.useModUi ?? false;
|
||||||
this.iconColor = input.iconColor??"";
|
this.iconColor = input.iconColor??"";
|
||||||
|
this.sideChainInputId = input.sideChainInputId ?? -1;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -217,6 +218,7 @@ export class PedalboardItem implements Deserializable<PedalboardItem> {
|
|||||||
pathProperties: {[Name: string]: string} = {};
|
pathProperties: {[Name: string]: string} = {};
|
||||||
useModUi: boolean = false; // true if this item should use the mod-ui.
|
useModUi: boolean = false; // true if this item should use the mod-ui.
|
||||||
iconColor: string = "";
|
iconColor: string = "";
|
||||||
|
sideChainInputId: number = -1; // -1 means no sidechain input.
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SnapshotValue {
|
export class SnapshotValue {
|
||||||
@@ -392,6 +394,7 @@ export class Pedalboard implements Deserializable<Pedalboard> {
|
|||||||
pathProperties: {[Name: string]: string} = {};
|
pathProperties: {[Name: string]: string} = {};
|
||||||
selectedPlugin: number = -1;
|
selectedPlugin: number = -1;
|
||||||
|
|
||||||
|
// yields all items in the pedalboard, including split items. Splits are yielded before their children.
|
||||||
*itemsGenerator(): Generator<PedalboardItem, void, undefined> {
|
*itemsGenerator(): Generator<PedalboardItem, void, undefined> {
|
||||||
let it = itemGenerator_(this.items);
|
let it = itemGenerator_(this.items);
|
||||||
while (true)
|
while (true)
|
||||||
@@ -401,6 +404,16 @@ export class Pedalboard implements Deserializable<Pedalboard> {
|
|||||||
yield v.value;
|
yield v.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// same as itemsGenerator, but yields split items after their chains.
|
||||||
|
*itemsGeneratorSplitAfter(): Generator<PedalboardItem, void, undefined> {
|
||||||
|
let it = itemGeneratorSplitAfter_(this.items);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
let v = it.next();
|
||||||
|
if (v.done) break;
|
||||||
|
yield v.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
makeSnapshot(): Snapshot {
|
makeSnapshot(): Snapshot {
|
||||||
let result = new Snapshot();
|
let result = new Snapshot();
|
||||||
@@ -791,4 +804,28 @@ function* itemGenerator_(items: PedalboardItem[]): Generator<PedalboardItem, voi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* itemGeneratorSplitAfter_(items: PedalboardItem[]): Generator<PedalboardItem, void, undefined> {
|
||||||
|
for (let i = 0; i < items.length; ++i) {
|
||||||
|
let item = items[i];
|
||||||
|
if (item.uri === SPLIT_PEDALBOARD_ITEM_URI) {
|
||||||
|
|
||||||
|
let splitItem = item as PedalboardSplitItem;
|
||||||
|
|
||||||
|
let it = itemGenerator_(splitItem.topChain);
|
||||||
|
while (true) {
|
||||||
|
let v = it.next();
|
||||||
|
if (v.done) break;
|
||||||
|
yield v.value;
|
||||||
|
}
|
||||||
|
it = itemGenerator_(splitItem.bottomChain);
|
||||||
|
while (true) {
|
||||||
|
let v = it.next();
|
||||||
|
if (v.done) break;
|
||||||
|
yield v.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -550,19 +550,16 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
);
|
);
|
||||||
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
|
zoomedUiControl: ObservableProperty<ZoomedControlInfo | undefined> = new ObservableProperty<ZoomedControlInfo | undefined>(undefined);
|
||||||
|
|
||||||
|
uiPluginsByUri: Map<string, UiPlugin> = new Map<string, UiPlugin>();
|
||||||
|
|
||||||
svgImgUrl(svgImage: string): string {
|
svgImgUrl(svgImage: string): string {
|
||||||
//return this.varServerUrl + "img/" + svgImage;
|
// return this.varServerUrl + "img/" + svgImage;
|
||||||
return "img/" + svgImage;
|
return "img/" + svgImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getUiPlugin(uri: string): UiPlugin | null {
|
getUiPlugin(uri: string): UiPlugin | null {
|
||||||
let plugins: UiPlugin[] = this.ui_plugins.get();
|
return this.uiPluginsByUri.get(uri) ?? null;
|
||||||
|
|
||||||
for (let plugin of plugins) {
|
|
||||||
if (plugin.uri === uri) return plugin;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
androidHost?: AndroidHostInterface;
|
androidHost?: AndroidHostInterface;
|
||||||
@@ -662,6 +659,7 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private setModelPedalboard(pedalboard: Pedalboard) {
|
private setModelPedalboard(pedalboard: Pedalboard) {
|
||||||
|
this.removeInvalidSidechains(pedalboard);
|
||||||
this.pedalboard.set(pedalboard);
|
this.pedalboard.set(pedalboard);
|
||||||
this.selectedSnapshot.set(pedalboard.selectedSnapshot);
|
this.selectedSnapshot.set(pedalboard.selectedSnapshot);
|
||||||
this.updateEnabledItems(pedalboard);
|
this.updateEnabledItems(pedalboard);
|
||||||
@@ -1210,6 +1208,11 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
this.ui_plugins.set(
|
this.ui_plugins.set(
|
||||||
UiPlugin.deserialize_array(await this.getWebSocket().request<any>("plugins"))
|
UiPlugin.deserialize_array(await this.getWebSocket().request<any>("plugins"))
|
||||||
);
|
);
|
||||||
|
// index ui plugins.
|
||||||
|
this.uiPluginsByUri = new Map<string, UiPlugin>();
|
||||||
|
for (let i of this.ui_plugins.get()) {
|
||||||
|
this.uiPluginsByUri.set(i.uri, i);
|
||||||
|
}
|
||||||
this.setModelPedalboard(
|
this.setModelPedalboard(
|
||||||
new Pedalboard().deserialize(
|
new Pedalboard().deserialize(
|
||||||
await this.getWebSocket().request<Pedalboard>("currentPedalboard")
|
await this.getWebSocket().request<Pedalboard>("currentPedalboard")
|
||||||
@@ -1761,13 +1764,17 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
let it = newPedalboard.itemsGenerator();
|
let it = newPedalboard.itemsGenerator();
|
||||||
|
let oldInstanceId = -1;
|
||||||
|
let newInstanceId = -1;
|
||||||
while (true) {
|
while (true) {
|
||||||
let v = it.next();
|
let v = it.next();
|
||||||
if (v.done) break;
|
if (v.done) break;
|
||||||
let item = v.value;
|
let item = v.value;
|
||||||
if (item.instanceId === itemId) {
|
if (item.instanceId === itemId) {
|
||||||
|
oldInstanceId = item.instanceId;
|
||||||
item.deserialize(new PedalboardItem()); // skeezy way to re-initialize.
|
item.deserialize(new PedalboardItem()); // skeezy way to re-initialize.
|
||||||
item.instanceId = ++newPedalboard.nextInstanceId;
|
item.instanceId = ++newPedalboard.nextInstanceId;
|
||||||
|
newInstanceId = item.instanceId;
|
||||||
item.uri = selectedUri;
|
item.uri = selectedUri;
|
||||||
item.pluginName = plugin.name;
|
item.pluginName = plugin.name;
|
||||||
item.controlValues = this.getDefaultValues(item.uri);
|
item.controlValues = this.getDefaultValues(item.uri);
|
||||||
@@ -1782,6 +1789,9 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
item.pathProperties[fileProperty.patchProperty] = "null";
|
item.pathProperties[fileProperty.patchProperty] = "null";
|
||||||
}
|
}
|
||||||
newPedalboard.selectedPlugin = item.instanceId;
|
newPedalboard.selectedPlugin = item.instanceId;
|
||||||
|
if (oldInstanceId !== -1) {
|
||||||
|
this.updateSidechainReferences(newPedalboard, oldInstanceId, newInstanceId);
|
||||||
|
}
|
||||||
this.setModelPedalboard(newPedalboard);
|
this.setModelPedalboard(newPedalboard);
|
||||||
this.updateServerPedalboard()
|
this.updateServerPedalboard()
|
||||||
return item.instanceId;
|
return item.instanceId;
|
||||||
@@ -1936,6 +1946,9 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
newPedalboard.replaceItem(fromInstanceId, emptyItem);
|
newPedalboard.replaceItem(fromInstanceId, emptyItem);
|
||||||
newPedalboard.replaceItem(toInstanceId, fromItem);
|
newPedalboard.replaceItem(toInstanceId, fromItem);
|
||||||
newPedalboard.selectedPlugin = fromItem.instanceId;
|
newPedalboard.selectedPlugin = fromItem.instanceId;
|
||||||
|
if (!toItem.isEmpty()) {
|
||||||
|
this.updateSidechainReferences(newPedalboard, toItem.instanceId, fromItem.instanceId);
|
||||||
|
}
|
||||||
this.setModelPedalboard(newPedalboard);
|
this.setModelPedalboard(newPedalboard);
|
||||||
this.updateServerPedalboard();
|
this.updateServerPedalboard();
|
||||||
|
|
||||||
@@ -3543,14 +3556,66 @@ export class PiPedalModel //implements PiPedalModel
|
|||||||
|
|
||||||
}
|
}
|
||||||
requestBankPresets(bankInstanceId: number): Promise<PresetIndexEntry[]> {
|
requestBankPresets(bankInstanceId: number): Promise<PresetIndexEntry[]> {
|
||||||
return nullCast(this.webSocket).request<PresetIndexEntry[]>("requestBankPresets", {bankInstanceId: bankInstanceId});
|
return nullCast(this.webSocket).request<PresetIndexEntry[]>("requestBankPresets", { bankInstanceId: bankInstanceId });
|
||||||
}
|
}
|
||||||
|
|
||||||
importPresetsFromBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
importPresetsFromBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
||||||
return nullCast(this.webSocket).request<number>("importPresetsFromBank", {bankInstanceId: bankInstanceId, presets: presets});
|
return nullCast(this.webSocket).request<number>("importPresetsFromBank", { bankInstanceId: bankInstanceId, presets: presets });
|
||||||
}
|
}
|
||||||
copyPresetsToBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
copyPresetsToBank(bankInstanceId: number, presets: number[]): Promise<number> {
|
||||||
return nullCast(this.webSocket).request<number>("copyPresetsToBank", {bankInstanceId: bankInstanceId, presets: presets});
|
return nullCast(this.webSocket).request<number>("copyPresetsToBank", { bankInstanceId: bankInstanceId, presets: presets });
|
||||||
|
}
|
||||||
|
setPedalboardSideChainInput(instanceId: number, sideChainInputId: number): void {
|
||||||
|
let pedalboard = this.pedalboard.get().clone();
|
||||||
|
let pedalboardItem = pedalboard.getItem(instanceId);
|
||||||
|
if (!pedalboardItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pedalboardItem.sideChainInputId = sideChainInputId;
|
||||||
|
let oldId = pedalboardItem.instanceId;
|
||||||
|
let newId = ++pedalboard.nextInstanceId;
|
||||||
|
|
||||||
|
pedalboardItem.instanceId = newId; // force reload of pedalboard.
|
||||||
|
pedalboard.selectedPlugin = pedalboardItem.instanceId;
|
||||||
|
|
||||||
|
this.updateSidechainReferences(pedalboard, oldId, newId);
|
||||||
|
this.setModelPedalboard(pedalboard);
|
||||||
|
this.updateServerPedalboard();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
removeInvalidSidechains(pedalboard: Pedalboard) {
|
||||||
|
let it = pedalboard.itemsGeneratorSplitAfter();
|
||||||
|
let previousItemIds: Set<number> = new Set<number>();
|
||||||
|
previousItemIds.add(-2); // start is visible.
|
||||||
|
while (true) {
|
||||||
|
let r = it.next();
|
||||||
|
if (r.done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let item = r.value;
|
||||||
|
if (item.sideChainInputId !== -1) {
|
||||||
|
if (!previousItemIds.has(item.sideChainInputId)) {
|
||||||
|
item.sideChainInputId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!item.isEmpty()) { // empty items are not valid sidechain targets.
|
||||||
|
previousItemIds.add(item.instanceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateSidechainReferences(pedalboard: Pedalboard, oldItemId: number, newItemId: number) {
|
||||||
|
let it = pedalboard.itemsGenerator();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
let r = it.next();
|
||||||
|
if (r.done) break;
|
||||||
|
let item = r.value;
|
||||||
|
if (item.sideChainInputId === oldItemId) {
|
||||||
|
item.sideChainInputId = newItemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.removeInvalidSidechains(pedalboard);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ import { Theme } from '@mui/material/styles';
|
|||||||
import WithStyles, { withTheme } from './WithStyles';
|
import WithStyles, { withTheme } from './WithStyles';
|
||||||
import { createStyles } from './WithStyles';
|
import { createStyles } from './WithStyles';
|
||||||
import { css } from '@emotion/react';
|
import { css } from '@emotion/react';
|
||||||
|
import IconButtonEx from './IconButtonEx';
|
||||||
|
|
||||||
|
import SidechainConnectIcon from './svg/ic_sidechain_open_48.svg?react';
|
||||||
|
|
||||||
import AutoZoom from './AutoZoom';
|
import AutoZoom from './AutoZoom';
|
||||||
|
|
||||||
@@ -37,6 +40,7 @@ import {
|
|||||||
} from './Pedalboard';
|
} from './Pedalboard';
|
||||||
import PluginControl from './PluginControl';
|
import PluginControl from './PluginControl';
|
||||||
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
import ResizeResponsiveComponent from './ResizeResponsiveComponent';
|
||||||
|
import SideChainSelectControl, {SideChainSelectDialog} from './SideChainSelectControl';
|
||||||
import VuMeter from './VuMeter';
|
import VuMeter from './VuMeter';
|
||||||
import { nullCast } from './Utility'
|
import { nullCast } from './Utility'
|
||||||
import { PiPedalStateError } from './PiPedalError';
|
import { PiPedalStateError } from './PiPedalError';
|
||||||
@@ -66,6 +70,11 @@ export interface ICustomizationHost {
|
|||||||
isLandscapeGrid(): boolean;
|
isLandscapeGrid(): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface SideChainSelectItem {
|
||||||
|
instanceId: number;
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
function makeIoPluginInfo(name: string, uri: string): UiPlugin {
|
function makeIoPluginInfo(name: string, uri: string): UiPlugin {
|
||||||
let result = new UiPlugin();
|
let result = new UiPlugin();
|
||||||
result.name = name;
|
result.name = name;
|
||||||
@@ -367,11 +376,12 @@ type PluginControlViewState = {
|
|||||||
dialogFileValue: string,
|
dialogFileValue: string,
|
||||||
modGuiContentReady: boolean,
|
modGuiContentReady: boolean,
|
||||||
showModGuiZoomed: boolean,
|
showModGuiZoomed: boolean,
|
||||||
|
sidechainDialogOpen: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
const PluginControlView =
|
const PluginControlView =
|
||||||
withTheme(withStyles(
|
withTheme(withStyles(
|
||||||
class extends ResizeResponsiveComponent<PluginControlViewProps, PluginControlViewState> implements ICustomizationHost {
|
class extends ResizeResponsiveComponent<PluginControlViewProps, PluginControlViewState> {
|
||||||
model: PiPedalModel;
|
model: PiPedalModel;
|
||||||
|
|
||||||
constructor(props: PluginControlViewProps) {
|
constructor(props: PluginControlViewProps) {
|
||||||
@@ -387,7 +397,8 @@ const PluginControlView =
|
|||||||
dialogFileProperty: new UiFileProperty(),
|
dialogFileProperty: new UiFileProperty(),
|
||||||
dialogFileValue: "",
|
dialogFileValue: "",
|
||||||
modGuiContentReady: false,
|
modGuiContentReady: false,
|
||||||
showModGuiZoomed: false
|
showModGuiZoomed: false,
|
||||||
|
sidechainDialogOpen: false
|
||||||
|
|
||||||
}
|
}
|
||||||
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
|
this.onPedalboardChanged = this.onPedalboardChanged.bind(this);
|
||||||
@@ -553,6 +564,68 @@ const PluginControlView =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSidechainSelectItems(): SideChainSelectItem[] {
|
||||||
|
let myInstanceId = this.props.item.instanceId;
|
||||||
|
|
||||||
|
let items: SideChainSelectItem[] = [];
|
||||||
|
items.push({ instanceId: -1, title: "None" });
|
||||||
|
items.push({ instanceId: -2, title: "Input" });
|
||||||
|
|
||||||
|
let pedalboard = this.model.pedalboard.get();
|
||||||
|
if (!pedalboard) return items;
|
||||||
|
|
||||||
|
let it = pedalboard.itemsGenerator();
|
||||||
|
|
||||||
|
let found = false;
|
||||||
|
while (true) {
|
||||||
|
let v = it.next();
|
||||||
|
if (v.done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let pedalboardItem = v.value;
|
||||||
|
if (pedalboardItem.isSplit()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pedalboardItem.instanceId === myInstanceId) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pedalboardItem.uri.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let pluginInfo = this.model.getUiPlugin(pedalboardItem.uri);
|
||||||
|
if (!pluginInfo) continue;
|
||||||
|
let name = pluginInfo.name;
|
||||||
|
if (pedalboardItem.title.length !== 0) {
|
||||||
|
name = pedalboardItem.title;
|
||||||
|
}
|
||||||
|
items.push({ instanceId: pedalboardItem.instanceId, title: name });
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
return [{ instanceId: -1, title: "None" }];
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private makeSideChainSelect(uiPlugin: UiPlugin) {
|
||||||
|
let items = this.getSidechainSelectItems();
|
||||||
|
let selectedInstanceId = this.props.item.sideChainInputId;
|
||||||
|
let title = uiPlugin.audio_side_chain_title ? uiPlugin.audio_side_chain_title : "Side chain";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SideChainSelectControl
|
||||||
|
title={title}
|
||||||
|
selectItems={items}
|
||||||
|
selectedInstanceId={selectedInstanceId}
|
||||||
|
onChanged={(instanceId: number) => {
|
||||||
|
this.model.setPedalboardSideChainInput(this.props.item.instanceId, instanceId);
|
||||||
|
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
isLandscapeGrid(): boolean {
|
isLandscapeGrid(): boolean {
|
||||||
return this.state.landscapeGrid;
|
return this.state.landscapeGrid;
|
||||||
}
|
}
|
||||||
@@ -575,7 +648,7 @@ const PluginControlView =
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div key={key} className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}
|
<div key={key} className={!isLandscapeGrid ? classes.portGroup : classes.portGroupLandscape}
|
||||||
style={{ borderWidth: (controlGroup.name === "" ? 0: undefined) }}
|
style={{ borderWidth: (controlGroup.name === "" ? 0 : undefined) }}
|
||||||
>
|
>
|
||||||
{controlGroup.name !== "" && (
|
{controlGroup.name !== "" && (
|
||||||
<div className={classes.portGroupTitle}>
|
<div className={classes.portGroupTitle}>
|
||||||
@@ -711,6 +784,11 @@ const PluginControlView =
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (plugin.audio_side_chain_inputs !== 0) {
|
||||||
|
|
||||||
|
result.push(this.makeSideChainSelect(plugin));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -803,6 +881,9 @@ const PluginControlView =
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleSelectSidechainInput() {
|
||||||
|
this.setState({sidechainDialogOpen: true});
|
||||||
|
}
|
||||||
|
|
||||||
handleModGuiFileProperty(instanceId: number, filePropertyUri: string, selectedFile: string) {
|
handleModGuiFileProperty(instanceId: number, filePropertyUri: string, selectedFile: string) {
|
||||||
let plugin = this.model.getUiPlugin(this.props.item.uri);
|
let plugin = this.model.getUiPlugin(this.props.item.uri);
|
||||||
@@ -827,10 +908,30 @@ const PluginControlView =
|
|||||||
if (!uiPlugin) {
|
if (!uiPlugin) {
|
||||||
return (<div />);
|
return (<div />);
|
||||||
}
|
}
|
||||||
|
let toolBarChildren: ReactNode[] = [];
|
||||||
|
if (uiPlugin.audio_side_chain_inputs > 0) {
|
||||||
|
toolBarChildren.push(
|
||||||
|
<IconButtonEx tooltip="Select sidechain input"
|
||||||
|
onClick={() => {
|
||||||
|
this.handleSelectSidechainInput();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SidechainConnectIcon
|
||||||
|
style={{
|
||||||
|
opacity: 0.6,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
fill: this.props.theme.palette.text.primary
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</IconButtonEx>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div style={{ width: "100%", height: "100%", }}>
|
<div style={{ width: "100%", height: "100%", }}>
|
||||||
<AutoZoom leftPad={36} rightPad={52} contentReady={this.state.modGuiContentReady}
|
<AutoZoom leftPad={36} rightPad={52} contentReady={this.state.modGuiContentReady}
|
||||||
showZoomed={this.state.showModGuiZoomed}
|
showZoomed={this.state.showModGuiZoomed}
|
||||||
|
toolbarChildren={toolBarChildren}
|
||||||
setShowZoomed={
|
setShowZoomed={
|
||||||
(value) => { this.setState({ showModGuiZoomed: value }); }
|
(value) => { this.setState({ showModGuiZoomed: value }); }
|
||||||
}
|
}
|
||||||
@@ -1012,6 +1113,16 @@ const PluginControlView =
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{this.state.sidechainDialogOpen && (
|
||||||
|
<SideChainSelectDialog open={this.state.sidechainDialogOpen}
|
||||||
|
onClose={()=>{ this.setState({sidechainDialogOpen: false});}}
|
||||||
|
selectItems={this.getSidechainSelectItems()}
|
||||||
|
selectedInstanceId={this.props.item.sideChainInputId}
|
||||||
|
onChanged={(instanceId: number) => {
|
||||||
|
this.model.setPedalboardSideChainInput(this.props.item.instanceId, instanceId);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{/* xxx: I don't think we need this anyore. */}
|
{/* xxx: I don't think we need this anyore. */}
|
||||||
<FullScreenIME uiControl={this.state.imeUiControl} value={this.state.imeValue}
|
<FullScreenIME uiControl={this.state.imeUiControl} value={this.state.imeValue}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Theme } from '@mui/material/styles';
|
import { Theme } from '@mui/material/styles';
|
||||||
import WithStyles from './WithStyles';
|
import WithStyles from './WithStyles';
|
||||||
import {createStyles} from './WithStyles';
|
import { createStyles } from './WithStyles';
|
||||||
|
|
||||||
import { withStyles } from "tss-react/mui";
|
import { withStyles } from "tss-react/mui";
|
||||||
import { UiControl } from './Lv2Plugin';
|
import { UiControl } from './Lv2Plugin';
|
||||||
@@ -47,8 +47,7 @@ const defaultVuColors: VuColor[] = [
|
|||||||
|
|
||||||
function getVuColor(vuColors: VuColor[], levelDb: number): string {
|
function getVuColor(vuColors: VuColor[], levelDb: number): string {
|
||||||
let ix = 0;
|
let ix = 0;
|
||||||
for (let i = 0; i < vuColors.length; ++i)
|
for (let i = 0; i < vuColors.length; ++i) {
|
||||||
{
|
|
||||||
let c = vuColors[i];
|
let c = vuColors[i];
|
||||||
if (levelDb > c.minDb && levelDb <= c.maxDb) {
|
if (levelDb > c.minDb && levelDb <= c.maxDb) {
|
||||||
ix = i;
|
ix = i;
|
||||||
@@ -122,18 +121,18 @@ const styles = (theme: Theme) => createStyles({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
titleSection: css({
|
titleSection: css({
|
||||||
flex: "0 0 auto", alignSelf:"stretch", marginBottom: 8, marginLeft: 0, marginRight: 0
|
flex: "0 0 auto", alignSelf: "stretch", marginBottom: 8, marginLeft: 0, marginRight: 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
midSection: css({
|
midSection: css({
|
||||||
flex: "1 1 1", display: "flex",flexFlow: "column nowrap",alignContent: "center",justifyContent: "center"
|
flex: "1 1 1", display: "flex", flexFlow: "column nowrap", alignContent: "center", justifyContent: "center"
|
||||||
}),
|
}),
|
||||||
|
|
||||||
editSection: css({
|
editSection: css({
|
||||||
flex: "0 0 28", position: "relative", width: 60, height: 28, minHeight: 28
|
flex: "0 0 28", position: "relative", width: 60, height: 28, minHeight: 28
|
||||||
}),
|
}),
|
||||||
editSectionNoContent: css({
|
editSectionNoContent: css({
|
||||||
flex: "0 0 28", position: "relative", width: 1, height: 28, minHeight: 28
|
flex: "0 0 28", position: "relative", width: 1, height: 28, minHeight: 28
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
@@ -153,12 +152,12 @@ const PluginOutputControl =
|
|||||||
class extends Component<PluginOutputControlProps, PluginOutputControlState> {
|
class extends Component<PluginOutputControlProps, PluginOutputControlState> {
|
||||||
|
|
||||||
private model: PiPedalModel;
|
private model: PiPedalModel;
|
||||||
private vuRef: React.RefObject<HTMLDivElement|null>;
|
private vuRef: React.RefObject<HTMLDivElement | null>;
|
||||||
private progressRef: React.RefObject<HTMLDivElement|null>;
|
private progressRef: React.RefObject<HTMLDivElement | null>;
|
||||||
private dbVuRef: React.RefObject<HTMLDivElement|null>;
|
private dbVuRef: React.RefObject<HTMLDivElement | null>;
|
||||||
private dbVuTelltaleRef: React.RefObject<HTMLDivElement|null>;
|
private dbVuTelltaleRef: React.RefObject<HTMLDivElement | null>;
|
||||||
private dbVuTextRef: React.RefObject<HTMLDivElement|null>;
|
private dbVuTextRef: React.RefObject<HTMLDivElement | null>;
|
||||||
private lampRef: React.RefObject<HTMLDivElement|null>;
|
private lampRef: React.RefObject<HTMLDivElement | null>;
|
||||||
|
|
||||||
|
|
||||||
constructor(props: PluginOutputControlProps) {
|
constructor(props: PluginOutputControlProps) {
|
||||||
@@ -210,7 +209,7 @@ const PluginOutputControl =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PROGRESS_WIDTH = 40-4;
|
private PROGRESS_WIDTH = 40 - 4;
|
||||||
private VU_HEIGHT = 60 - 4;
|
private VU_HEIGHT = 60 - 4;
|
||||||
private DB_VU_HEIGHT = 60 - 4;
|
private DB_VU_HEIGHT = 60 - 4;
|
||||||
private animationHandle: number | undefined = undefined;
|
private animationHandle: number | undefined = undefined;
|
||||||
@@ -240,26 +239,23 @@ const PluginOutputControl =
|
|||||||
}
|
}
|
||||||
if (this.dbVuTextRef.current) {
|
if (this.dbVuTextRef.current) {
|
||||||
let text: string;
|
let text: string;
|
||||||
if (this.dbVuTelltale <= this.props.uiControl.min_value)
|
if (this.dbVuTelltale <= this.props.uiControl.min_value) {
|
||||||
{
|
|
||||||
text = "-";
|
text = "-";
|
||||||
} else {
|
} else {
|
||||||
if (Math.abs(this.dbVuTelltale) >= 99.5)
|
if (Math.abs(this.dbVuTelltale) >= 99.5) {
|
||||||
{
|
|
||||||
text = Math.round(this.dbVuTelltale).toString();
|
text = Math.round(this.dbVuTelltale).toString();
|
||||||
} else {
|
} else {
|
||||||
text = this.dbVuTelltale.toFixed(1);
|
text = this.dbVuTelltale.toFixed(1);
|
||||||
}
|
}
|
||||||
if (!text.startsWith("-")) {
|
if (!text.startsWith("-")) {
|
||||||
text = '+'+text;
|
text = '+' + text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.lastDbText !== text)
|
if (this.lastDbText !== text) {
|
||||||
{
|
|
||||||
this.lastDbText = text;
|
this.lastDbText = text;
|
||||||
this.dbVuTextRef.current.innerText = text;
|
this.dbVuTextRef.current.innerText = text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.animationHandle = undefined;
|
this.animationHandle = undefined;
|
||||||
this.updateDbVuTelltale();
|
this.updateDbVuTelltale();
|
||||||
}
|
}
|
||||||
@@ -322,7 +318,7 @@ const PluginOutputControl =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (this.vuRef.current) {
|
else if (this.vuRef.current) {
|
||||||
let control = this.props.uiControl;
|
let control = this.props.uiControl;
|
||||||
let range = (value - control.min_value) / (control.max_value - control.min_value);
|
let range = (value - control.min_value) / (control.max_value - control.min_value);
|
||||||
@@ -389,8 +385,7 @@ const PluginOutputControl =
|
|||||||
if (value > control.max_value) {
|
if (value > control.max_value) {
|
||||||
value = control.max_value;
|
value = control.max_value;
|
||||||
}
|
}
|
||||||
if (value < control.min_value)
|
if (value < control.min_value) {
|
||||||
{
|
|
||||||
value = control.min_value;
|
value = control.min_value;
|
||||||
}
|
}
|
||||||
let y = (control.max_value - value) * this.DB_VU_HEIGHT / (control.max_value - control.min_value);
|
let y = (control.max_value - value) * this.DB_VU_HEIGHT / (control.max_value - control.min_value);
|
||||||
@@ -439,13 +434,13 @@ const PluginOutputControl =
|
|||||||
} else if (control.isProgress()) {
|
} else if (control.isProgress()) {
|
||||||
item_width = undefined;
|
item_width = undefined;
|
||||||
return (
|
return (
|
||||||
<div className={classes.controlFrame}
|
<div className={classes.controlFrame}
|
||||||
style={{ width: item_width }}>
|
style={{ width: item_width }}>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div className={classes.titleSection}
|
<div className={classes.titleSection}
|
||||||
style={{ width: "100%" }}>
|
style={{ width: "100%" }}>
|
||||||
<ControlTooltip uiControl={control}>
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography variant="caption" display="block" style={{
|
<Typography variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
||||||
@@ -453,15 +448,18 @@ const PluginOutputControl =
|
|||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div className={classes.midSection}
|
<div className={classes.midSection}
|
||||||
style={{ flex: "1 1 1", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
|
style={{ flex: "1 1 1", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
|
||||||
<div style={{ width: this.PROGRESS_WIDTH+2, height: 12, marginLeft: 8, marginRight: 8, background: "#181818", }}>
|
<div style={{ width: this.PROGRESS_WIDTH + 2, height: 12, marginLeft: 8, marginRight: 8, background: "#181818", }}>
|
||||||
<div style={{ height: 8, width: this.PROGRESS_WIDTH, overflow: "hidden", position: "absolute",
|
<div style={{
|
||||||
margin: "1px 1px 1px 1px", background: "#282828" }}>
|
height: 8, width: this.PROGRESS_WIDTH, overflow: "hidden", position: "absolute",
|
||||||
<div ref={this.progressRef} style={{ height: 10, width: this.PROGRESS_WIDTH, position: "absolute", marginTop: 0, background: "#0C0" }} />
|
margin: "1px 1px 1px 1px", background: "#282828"
|
||||||
<div style={{ height: 10, width: this.PROGRESS_WIDTH, position: "absolute",
|
}}>
|
||||||
|
<div ref={this.progressRef} style={{ height: 10, width: this.PROGRESS_WIDTH, position: "absolute", marginTop: 0, background: "#0C0" }} />
|
||||||
|
<div style={{
|
||||||
|
height: 10, width: this.PROGRESS_WIDTH, position: "absolute",
|
||||||
boxShadow: "inset 0px 2px 4px #000D", background: "transparent"
|
boxShadow: "inset 0px 2px 4px #000D", background: "transparent"
|
||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -478,45 +476,48 @@ const PluginOutputControl =
|
|||||||
let vuColors = defaultVuColors;
|
let vuColors = defaultVuColors;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.controlFrame}
|
<div className={classes.controlFrame}
|
||||||
style={{ width: item_width }}>
|
style={{ width: item_width }}>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div className={classes.titleSection}
|
<div className={classes.titleSection}
|
||||||
style={{ width: "100%" }}>
|
style={{ width: "100%" }}>
|
||||||
<ControlTooltip uiControl={control}>
|
<Typography variant="caption" display="block" style={{
|
||||||
<Typography variant="caption" display="block" style={{
|
width: "100%",
|
||||||
width: "100%",
|
textAlign: "center"
|
||||||
textAlign: "center"
|
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
||||||
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
|
||||||
</ControlTooltip>
|
|
||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div className={classes.midSection}
|
<div className={classes.midSection}
|
||||||
style={{ flex: "1 1 1", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
|
style={{ flex: "1 1 1", display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
|
||||||
<div style={{ width: 8, height: this.DB_VU_HEIGHT + 4, background: "#000", }}>
|
<ControlTooltip uiControl={control}>
|
||||||
<div style={{ height: this.DB_VU_HEIGHT, width: 4, overflow: "hidden", position: "absolute", margin: 2 }}>
|
|
||||||
<div style={{ width: 4, height: this.DB_VU_HEIGHT, position: "absolute", left: 0, top: 0 }}>
|
|
||||||
{
|
|
||||||
vuColors.map((vuColor,ix)=>{
|
|
||||||
let top = Math.floor(this.dbVuMap(vuColor.maxDb));
|
|
||||||
let bottom = Math.ceil(this.dbVuMap(vuColor.minDb))+1;
|
|
||||||
|
|
||||||
return (
|
<div style={{ width: 8, height: this.DB_VU_HEIGHT + 4, background: "#000", }}>
|
||||||
<div key={ix}
|
<div style={{ height: this.DB_VU_HEIGHT, width: 4, overflow: "hidden", position: "absolute", margin: 2 }}>
|
||||||
style={{ position: "absolute", width: 4, height: (bottom-top),
|
<div style={{ width: 4, height: this.DB_VU_HEIGHT, position: "absolute", left: 0, top: 0 }}>
|
||||||
top: top, left:0, background: vuColor.color }} />
|
{
|
||||||
);
|
vuColors.map((vuColor, ix) => {
|
||||||
})
|
let top = Math.floor(this.dbVuMap(vuColor.maxDb));
|
||||||
}
|
let bottom = Math.ceil(this.dbVuMap(vuColor.minDb)) + 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={ix}
|
||||||
|
style={{
|
||||||
|
position: "absolute", width: 4, height: (bottom - top),
|
||||||
|
top: top, left: 0, background: vuColor.color
|
||||||
|
}} />
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ref={this.dbVuRef} style={{
|
||||||
|
width: 4, position: "absolute", marginTop: 0, height: this.VU_HEIGHT, background: "#000"
|
||||||
|
}} />
|
||||||
|
<div ref={this.dbVuTelltaleRef} style={{ width: 4, position: "absolute", marginTop: 100, height: 3, background: "#C00" }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref={this.dbVuRef} style={{
|
|
||||||
width: 4, position: "absolute", marginTop: 0, height: this.VU_HEIGHT, background: "#000"
|
|
||||||
}} />
|
|
||||||
<div ref={this.dbVuTelltaleRef} style={{ width: 4, position: "absolute", marginTop: 100, height: 3, background: "#C00" }} />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ControlTooltip>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.editSection}>
|
<div className={classes.editSection}>
|
||||||
@@ -533,26 +534,28 @@ const PluginOutputControl =
|
|||||||
else if (control.isVu()) {
|
else if (control.isVu()) {
|
||||||
item_width = undefined;
|
item_width = undefined;
|
||||||
return (
|
return (
|
||||||
<div className={classes.controlFrame} style={{ width: item_width}}>
|
<div className={classes.controlFrame} style={{ width: item_width }}>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div className={classes.titleSection}
|
<div className={classes.titleSection}
|
||||||
style={{ width: "100%" }}>
|
style={{ width: "100%" }}>
|
||||||
<ControlTooltip uiControl={control}>
|
|
||||||
<Typography noWrap display="block" variant="caption" style={{
|
<Typography noWrap display="block" variant="caption" style={{
|
||||||
width: item_width,
|
width: item_width,
|
||||||
textAlign: "center"
|
textAlign: "center"
|
||||||
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
||||||
</ControlTooltip>
|
|
||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div className={classes.midSection}
|
<div className={classes.midSection}
|
||||||
style={{ display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
|
style={{ display: "flex", justifyContent: "center", alignItems: "start", flexFlow: "row nowrap" }}>
|
||||||
<div style={{ width: 8, height: this.VU_HEIGHT + 4, background: "#000", }}>
|
<ControlTooltip uiControl={control}>
|
||||||
<div style={{ height: this.VU_HEIGHT, overflow: "hidden", position: "absolute", margin: 2 }}>
|
<div style={{ width: 8, height: this.VU_HEIGHT + 4, background: "#000", }}>
|
||||||
<div ref={this.vuRef} style={{ width: 4, height: this.VU_HEIGHT, background: "#0C0", }} />
|
<div style={{ height: this.VU_HEIGHT, overflow: "hidden", position: "absolute", margin: 2 }}>
|
||||||
|
<div ref={this.vuRef} style={{ width: 4, height: this.VU_HEIGHT, background: "#0C0", }} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ControlTooltip>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -575,11 +578,11 @@ const PluginOutputControl =
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className={classes.controlFrame}
|
<div className={classes.controlFrame}
|
||||||
style={{width: attachedLamp? 15: item_width}}
|
style={{ width: attachedLamp ? 15 : item_width }}
|
||||||
>
|
>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div className={classes.titleSection}
|
<div className={classes.titleSection}
|
||||||
style={{ flex: "0 0 auto", width: "100%"}}>
|
style={{ flex: "0 0 auto", width: "100%" }}>
|
||||||
<ControlTooltip uiControl={control}>
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography noWrap variant="caption" display="block" style={{
|
<Typography noWrap variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -589,7 +592,7 @@ const PluginOutputControl =
|
|||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div className={classes.midSection}
|
<div className={classes.midSection}
|
||||||
style={{
|
style={{
|
||||||
display: "flex", justifyContent: "center", alignItems: "center", flexFlow: "row nowrap",
|
display: "flex", justifyContent: "center", alignItems: "center", flexFlow: "row nowrap",
|
||||||
}}>
|
}}>
|
||||||
@@ -613,23 +616,23 @@ const PluginOutputControl =
|
|||||||
);
|
);
|
||||||
} if (control.isOutputText()) {
|
} if (control.isOutputText()) {
|
||||||
return (
|
return (
|
||||||
<div className={classes.controlFrame}
|
<div className={classes.controlFrame}
|
||||||
style={{ display: "flex", flexDirection: "column", width: item_width }}>
|
style={{ display: "flex", flexDirection: "column", width: item_width }}>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div className={classes.titleSection}
|
<div className={classes.titleSection}
|
||||||
style={{ flex: "0 0 auto", width: "100%" }}>
|
style={{ flex: "0 0 auto", width: "100%" }}>
|
||||||
<ControlTooltip uiControl={control}>
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography noWrap variant="caption" display="block" style={{
|
<Typography noWrap variant="caption" display="block" style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "left"
|
textAlign: "left"
|
||||||
}}> {control.name === "" ? "\u00A0": control.name}</Typography>
|
}}> {control.name === "" ? "\u00A0" : control.name}</Typography>
|
||||||
</ControlTooltip>
|
</ControlTooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div className={classes.midSection} style={{
|
<div className={classes.midSection} style={{
|
||||||
display: "flex", justifyContent: "center",
|
display: "flex", justifyContent: "center",
|
||||||
flexFlow: "row nowrap", paddingTop: 6
|
flexFlow: "row nowrap", paddingTop: 6
|
||||||
|
|
||||||
}}>
|
}}>
|
||||||
@@ -646,10 +649,10 @@ const PluginOutputControl =
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className={classes.controlFrame}
|
<div className={classes.controlFrame}
|
||||||
style={{ display: "flex", flexDirection: "column", width: item_width }}>
|
style={{ display: "flex", flexDirection: "column", width: item_width }}>
|
||||||
{/* TITLE SECTION */}
|
{/* TITLE SECTION */}
|
||||||
<div className={classes.titleSection}
|
<div className={classes.titleSection}
|
||||||
style={{ flex: "0 0 auto", width: "100%" }}>
|
style={{ flex: "0 0 auto", width: "100%" }}>
|
||||||
<ControlTooltip uiControl={control}>
|
<ControlTooltip uiControl={control}>
|
||||||
<Typography noWrap variant="caption" display="block" style={{
|
<Typography noWrap variant="caption" display="block" style={{
|
||||||
@@ -660,7 +663,7 @@ const PluginOutputControl =
|
|||||||
</div>
|
</div>
|
||||||
{/* CONTROL SECTION */}
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
<div className={classes.midSection}
|
<div className={classes.midSection}
|
||||||
style={{ display: "flex", justifyContent: "start", alignItems: "center", flexFlow: "row nowrap" }}>
|
style={{ display: "flex", justifyContent: "start", alignItems: "center", flexFlow: "row nowrap" }}>
|
||||||
<Typography noWrap variant="caption" display="block" style={{ width: "100%" }}>
|
<Typography noWrap variant="caption" display="block" style={{ width: "100%" }}>
|
||||||
{text}
|
{text}
|
||||||
|
|||||||
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) Robin E. R. Davies
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to
|
||||||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
* so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Component } from 'react';
|
||||||
|
import { Theme } from '@mui/material/styles';
|
||||||
|
import { css } from '@emotion/react';
|
||||||
|
|
||||||
|
import DialogEx from './DialogEx';
|
||||||
|
import DialogTitle from '@mui/material/DialogTitle';
|
||||||
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
|
import DialogContent from '@mui/material/DialogContent';
|
||||||
|
import IconButtonEx from './IconButtonEx';
|
||||||
|
import Typography from '@mui/material/Typography';
|
||||||
|
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
|
||||||
|
import Select from '@mui/material/Select';
|
||||||
|
import MenuItem from '@mui/material/MenuItem';
|
||||||
|
|
||||||
|
|
||||||
|
export const StandardItemSize = { width: 80, height: 140 }
|
||||||
|
|
||||||
|
|
||||||
|
import { withStyles } from "tss-react/mui";
|
||||||
|
import WithStyles from './WithStyles';
|
||||||
|
import { withTheme } from './WithStyles';
|
||||||
|
|
||||||
|
const styles = (theme: Theme) => {
|
||||||
|
return {
|
||||||
|
frame: css({
|
||||||
|
position: "relative",
|
||||||
|
margin: "12px"
|
||||||
|
}),
|
||||||
|
controlFrame: css({
|
||||||
|
display: "flex", flexDirection: "column", alignItems: "start", justifyContent: "space-between", height: 116
|
||||||
|
}),
|
||||||
|
displayValue: css({
|
||||||
|
position: "absolute",
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 4,
|
||||||
|
textAlign: "center",
|
||||||
|
background: theme.mainBackground,
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
// zIndex: -1,
|
||||||
|
}),
|
||||||
|
titleSection: css({
|
||||||
|
flex: "0 0 auto", alignSelf: "stretch", marginBottom: 8, marginLeft: 8, marginRight: 0
|
||||||
|
}),
|
||||||
|
midSection: css({
|
||||||
|
flex: "1 1 1", display: "flex", flexFlow: "column nowrap", alignContent: "center", justifyContent: "center"
|
||||||
|
}),
|
||||||
|
editSection: css({
|
||||||
|
flex: "0 0 0", position: "relative", width: 60, height: 28, minHeight: 28
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
export interface SideChainSelectControlProps extends WithStyles<typeof styles> {
|
||||||
|
title: string;
|
||||||
|
selectItems: { instanceId: number, title: string }[];
|
||||||
|
selectedInstanceId: number;
|
||||||
|
onChanged(instanceId: number): void;
|
||||||
|
theme: Theme;
|
||||||
|
}
|
||||||
|
type SideChainSelectControlState = {
|
||||||
|
};
|
||||||
|
|
||||||
|
const SideChainSelectControl =
|
||||||
|
withTheme(withStyles(
|
||||||
|
class extends Component<SideChainSelectControlProps, SideChainSelectControlState> {
|
||||||
|
|
||||||
|
model: PiPedalModel;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(props: SideChainSelectControlProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
this.model = PiPedalModelFactory.getInstance();
|
||||||
|
this.onStateChanged = this.onStateChanged.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onStateChanged(state: State) {
|
||||||
|
}
|
||||||
|
mounted: boolean = false;
|
||||||
|
componentDidMount() {
|
||||||
|
this.model.state.addOnChangedHandler(this.onStateChanged);
|
||||||
|
this.mounted = true;
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.mounted = false;
|
||||||
|
this.model.state.removeOnChangedHandler(this.onStateChanged);
|
||||||
|
}
|
||||||
|
componentDidUpdate(prevProps: Readonly<SideChainSelectControlProps>, prevState: Readonly<SideChainSelectControlState>, snapshot?: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
//const classes = withStyles.getClasses(this.props);
|
||||||
|
|
||||||
|
const classes = withStyles.getClasses(this.props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.controlFrame}
|
||||||
|
style={{ width: 120 }}>
|
||||||
|
{/* TITLE SECTION */}
|
||||||
|
<div className={classes.titleSection}
|
||||||
|
>
|
||||||
|
<Typography variant="caption" display="block" noWrap style={{
|
||||||
|
width: "100%",
|
||||||
|
textAlign: "start"
|
||||||
|
}}> {this.props.title}</Typography>
|
||||||
|
</div>
|
||||||
|
{/* CONTROL SECTION */}
|
||||||
|
|
||||||
|
<div className={classes.midSection} style={{ width: "100%", paddingLeft: 8 }}>
|
||||||
|
<Select
|
||||||
|
variant="standard"
|
||||||
|
onChange={(event) => {
|
||||||
|
this.props.onChanged(event.target.value as number);
|
||||||
|
}}
|
||||||
|
value={this.props.selectedInstanceId}
|
||||||
|
style={{ width: "100%", fontSize: "0.8rem" }}
|
||||||
|
>
|
||||||
|
{this.props.selectItems.map((item) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={item.instanceId} value={item.instanceId}
|
||||||
|
selected={item.instanceId === this.props.selectedInstanceId}>
|
||||||
|
{item.title}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* LABEL/EDIT SECTION*/}
|
||||||
|
<div className={classes.editSection} >
|
||||||
|
</div>
|
||||||
|
</div >
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, styles)
|
||||||
|
)
|
||||||
|
;
|
||||||
|
export default SideChainSelectControl;
|
||||||
|
|
||||||
|
export interface SideChainSelectDialogProps {
|
||||||
|
open: boolean,
|
||||||
|
onClose: () => void,
|
||||||
|
|
||||||
|
selectItems: { instanceId: number, title: string }[];
|
||||||
|
selectedInstanceId: number;
|
||||||
|
onChanged(instanceId: number): void;
|
||||||
|
|
||||||
|
}
|
||||||
|
export function SideChainSelectDialog(props: SideChainSelectDialogProps) {
|
||||||
|
let { open, onClose, selectItems, selectedInstanceId, onChanged } = props;
|
||||||
|
return (
|
||||||
|
<DialogEx tag="nameDialog" open={open} fullWidth maxWidth="xs" onClose={onClose} aria-labelledby="Rename-dialog-title"
|
||||||
|
style={{ userSelect: "none" }}
|
||||||
|
onEnterKey={() => { }}
|
||||||
|
>
|
||||||
|
<DialogTitle id="alert-dialog-title" style={{ userSelect: "none", padding: 0, margin: 0 }}>
|
||||||
|
<Toolbar style={{ paddingLeft: 24, paddingRight: 24, margin: 0 }} >
|
||||||
|
<IconButtonEx
|
||||||
|
tooltip="Back" edge="start" color="inherit" onClick={() => { onClose(); }} aria-label="back"
|
||||||
|
>
|
||||||
|
<ArrowBackIcon style={{opacity: 0.6}} />
|
||||||
|
</IconButtonEx>
|
||||||
|
|
||||||
|
<Typography noWrap variant="body1" style={{ flex: "1 1 auto" }}>Sidechain Input</Typography>
|
||||||
|
</Toolbar>
|
||||||
|
</DialogTitle>
|
||||||
|
|
||||||
|
<DialogContent >
|
||||||
|
<Select
|
||||||
|
variant="standard"
|
||||||
|
onChange={(event) => {
|
||||||
|
onChanged(event.target.value as number);
|
||||||
|
}}
|
||||||
|
value={selectedInstanceId}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
{selectItems.map((item) => {
|
||||||
|
return (
|
||||||
|
<MenuItem key={item.instanceId} value={item.instanceId}
|
||||||
|
selected={item.instanceId === selectedInstanceId}>
|
||||||
|
{item.title}
|
||||||
|
</MenuItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</DialogContent>
|
||||||
|
</DialogEx>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ import CloseIcon from '@mui/icons-material/Close';
|
|||||||
import AppBar from '@mui/material/AppBar';
|
import AppBar from '@mui/material/AppBar';
|
||||||
import Toolbar from '@mui/material/Toolbar';
|
import Toolbar from '@mui/material/Toolbar';
|
||||||
import CssBaseline from '@mui/material/CssBaseline';
|
import CssBaseline from '@mui/material/CssBaseline';
|
||||||
import {createStyles} from './WithStyles';
|
import { createStyles } from './WithStyles';
|
||||||
|
|
||||||
import { withStyles } from "tss-react/mui";
|
import { withStyles } from "tss-react/mui";
|
||||||
import IconButtonEx from './IconButtonEx';
|
import IconButtonEx from './IconButtonEx';
|
||||||
@@ -148,10 +148,12 @@ const SnapshotEditor = withStyles(
|
|||||||
|
|
||||||
this.model_.zoomedUiControl.addOnChangedHandler(
|
this.model_.zoomedUiControl.addOnChangedHandler(
|
||||||
() => {
|
() => {
|
||||||
this.setState({
|
if (this.mounted93) {
|
||||||
zoomedControlOpen: this.model_.zoomedUiControl.get() !== undefined,
|
this.setState({
|
||||||
zoomedControlInfo: this.model_.zoomedUiControl.get()
|
zoomedControlOpen: this.model_.zoomedUiControl.get() !== undefined,
|
||||||
});
|
zoomedControlInfo: this.model_.zoomedUiControl.get()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -182,9 +184,11 @@ const SnapshotEditor = withStyles(
|
|||||||
this.setState({ isFullScreen: !this.state.isFullScreen });
|
this.setState({ isFullScreen: !this.state.isFullScreen });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private mounted93: boolean = false;
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
||||||
super.componentDidMount();
|
super.componentDidMount();
|
||||||
|
this.mounted93 = true;
|
||||||
this.model_.showStatusMonitor.addOnChangedHandler(this.showStatusMonitorHandler);
|
this.model_.showStatusMonitor.addOnChangedHandler(this.showStatusMonitorHandler);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -206,6 +210,7 @@ const SnapshotEditor = withStyles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
this.mounted93 = false;
|
||||||
super.componentWillUnmount();
|
super.componentWillUnmount();
|
||||||
this.model_.banks.removeOnChangedHandler(this.showStatusMonitorHandler);
|
this.model_.banks.removeOnChangedHandler(this.showStatusMonitorHandler);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 6.35 6.35"
|
||||||
|
version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
id="path4452"
|
||||||
|
d="M 3.1501953 1.1797729 C 2.3438819 1.1900494 1.6500313 1.6826477 1.3451375 2.38125 L 1.786971 2.38125 C 2.0624356 1.9000342 2.5807156 1.5761312 3.1760335 1.5761312 C 4.0608593 1.5761312 4.7733521 2.2912075 4.7733521 3.1760335 C 4.7733521 4.0608594 4.0608593 4.7733521 3.1760335 4.7733521 C 2.580068 4.7733521 2.0611725 4.450254 1.7859375 3.96875 L 1.3446208 3.96875 C 1.6524938 4.6748172 2.3583381 5.1697103 3.1760335 5.1697103 C 4.2753461 5.1697103 5.1697103 4.2753461 5.1697103 3.1760335 C 5.1697103 2.0767208 4.2753461 1.1797729 3.1760335 1.1797729 C 3.1674451 1.1797729 3.1587586 1.1796638 3.1501953 1.1797729 z " />
|
||||||
|
<path
|
||||||
|
id="ellipse4674"
|
||||||
|
d="M 3.1760335 2.3300903 C 2.7944551 2.3300903 2.4622893 2.5720679 2.3455933 2.9098999 L 0.64078776 2.9098999 L 0.64078776 3.4395833 L 2.3450765 3.4395833 C 2.4612025 3.7778767 2.7937654 4.019393 3.1760335 4.0193929 C 3.651938 4.0193929 4.0488484 3.6453545 4.0488485 3.1760335 C 4.0488485 2.7067124 3.6519381 2.3300904 3.1760335 2.3300903 z M 3.1760335 2.7264486 C 3.4466224 2.7264486 3.6524902 2.9307799 3.6524902 3.1760335 C 3.6524901 3.4212871 3.4466224 3.6230347 3.1760335 3.6230347 C 2.9054446 3.6230347 2.6975099 3.4212871 2.6975098 3.1760335 C 2.6975098 2.9307799 2.9054446 2.7264486 3.1760335 2.7264486 z " />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
Reference in New Issue
Block a user