Browse Source

Import temper plugin, fix to build with C++11

tags/2020-07-14
falkTX 5 years ago
parent
commit
4ccd6e7226
100 changed files with 50869 additions and 0 deletions
  1. +4
    -0
      ports/Makefile
  2. +19
    -0
      ports/temper/LV2/premake.lua
  3. +19
    -0
      ports/temper/VST/premake.lua
  4. +19645
    -0
      ports/temper/source/BinaryData.cpp
  5. +44
    -0
      ports/temper/source/BinaryData.h
  6. +43
    -0
      ports/temper/source/FaustUIBridge.cpp
  7. +132
    -0
      ports/temper/source/FaustUIBridge.h
  8. +34
    -0
      ports/temper/source/JuceHeader.h
  9. +139
    -0
      ports/temper/source/JucePluginCharacteristics.h
  10. +337
    -0
      ports/temper/source/MainComponent.cpp
  11. +90
    -0
      ports/temper/source/MainComponent.h
  12. +60
    -0
      ports/temper/source/PluginEditor.cpp
  13. +54
    -0
      ports/temper/source/PluginEditor.h
  14. +283
    -0
      ports/temper/source/PluginProcessor.cpp
  15. +79
    -0
      ports/temper/source/PluginProcessor.h
  16. +55
    -0
      ports/temper/source/RestrictionProcessor.cpp
  17. +66
    -0
      ports/temper/source/RestrictionProcessor.h
  18. +131
    -0
      ports/temper/source/SpectroscopeComponent.cpp
  19. +60
    -0
      ports/temper/source/SpectroscopeComponent.h
  20. +339
    -0
      ports/temper/source/TemperDsp.hpp
  21. +96
    -0
      ports/temper/source/TemperLookAndFeel.cpp
  22. +31
    -0
      ports/temper/source/TemperLookAndFeel.h
  23. +449
    -0
      ports/temper/source/faust/au/AUUI.h
  24. +728
    -0
      ports/temper/source/faust/audio/alsa-dsp.h
  25. +479
    -0
      ports/temper/source/faust/audio/android-dsp.h
  26. +71
    -0
      ports/temper/source/faust/audio/audio.h
  27. +95
    -0
      ports/temper/source/faust/audio/channels.h
  28. +1518
    -0
      ports/temper/source/faust/audio/coreaudio-dsp.h
  29. +727
    -0
      ports/temper/source/faust/audio/coreaudio-ios-dsp.h
  30. +135
    -0
      ports/temper/source/faust/audio/dummy-audio.h
  31. +597
    -0
      ports/temper/source/faust/audio/jack-dsp.h
  32. +357
    -0
      ports/temper/source/faust/audio/netjack-dsp.h
  33. +641
    -0
      ports/temper/source/faust/audio/opensles-android-dsp.h
  34. +115
    -0
      ports/temper/source/faust/audio/osc-dsp.h
  35. +245
    -0
      ports/temper/source/faust/audio/portaudio-dsp.h
  36. +215
    -0
      ports/temper/source/faust/audio/rtaudio-dsp.h
  37. +109
    -0
      ports/temper/source/faust/dsp/dsp-adapter.h
  38. +382
    -0
      ports/temper/source/faust/dsp/dsp-bench.h
  39. +246
    -0
      ports/temper/source/faust/dsp/dsp-combiner.h
  40. +191
    -0
      ports/temper/source/faust/dsp/dsp.h
  41. +68
    -0
      ports/temper/source/faust/dsp/faust-engine.h
  42. +627
    -0
      ports/temper/source/faust/dsp/faust-poly-engine.h
  43. +661
    -0
      ports/temper/source/faust/dsp/poly-dsp.h
  44. +277
    -0
      ports/temper/source/faust/dsp/proxy-dsp.h
  45. +287
    -0
      ports/temper/source/faust/dsp/timed-dsp.h
  46. +472
    -0
      ports/temper/source/faust/gui/APIUI.h
  47. +130
    -0
      ports/temper/source/faust/gui/ControlUI.h
  48. +181
    -0
      ports/temper/source/faust/gui/FUI.h
  49. +261
    -0
      ports/temper/source/faust/gui/GUI.h
  50. +97
    -0
      ports/temper/source/faust/gui/HTTPDControler.h
  51. +318
    -0
      ports/temper/source/faust/gui/JSONUI.h
  52. +2167
    -0
      ports/temper/source/faust/gui/JuceGUI.h
  53. +164
    -0
      ports/temper/source/faust/gui/JuceOSCUI.h
  54. +157
    -0
      ports/temper/source/faust/gui/MapUI.h
  55. +343
    -0
      ports/temper/source/faust/gui/MetaDataUI.h
  56. +609
    -0
      ports/temper/source/faust/gui/MidiUI.h
  57. +672
    -0
      ports/temper/source/faust/gui/OCVUI.h
  58. +118
    -0
      ports/temper/source/faust/gui/OSCControler.h
  59. +179
    -0
      ports/temper/source/faust/gui/OSCUI.h
  60. +65
    -0
      ports/temper/source/faust/gui/PathBuilder.h
  61. +119
    -0
      ports/temper/source/faust/gui/PrintUI.h
  62. +471
    -0
      ports/temper/source/faust/gui/RosCI.h
  63. +463
    -0
      ports/temper/source/faust/gui/RosUI.h
  64. +460
    -0
      ports/temper/source/faust/gui/SimpleParser.h
  65. +5
    -0
      ports/temper/source/faust/gui/Styles/Blue.qrc
  66. +177
    -0
      ports/temper/source/faust/gui/Styles/Blue.qss
  67. +5
    -0
      ports/temper/source/faust/gui/Styles/Default.qrc
  68. +117
    -0
      ports/temper/source/faust/gui/Styles/Default.qss
  69. +5
    -0
      ports/temper/source/faust/gui/Styles/Grey.qrc
  70. +174
    -0
      ports/temper/source/faust/gui/Styles/Grey.qss
  71. +5
    -0
      ports/temper/source/faust/gui/Styles/Salmon.qrc
  72. +171
    -0
      ports/temper/source/faust/gui/Styles/Salmon.qss
  73. +117
    -0
      ports/temper/source/faust/gui/UI.h
  74. +527
    -0
      ports/temper/source/faust/gui/ValueConverter.h
  75. +287
    -0
      ports/temper/source/faust/gui/console.h
  76. +1380
    -0
      ports/temper/source/faust/gui/faustgtk.h
  77. +1838
    -0
      ports/temper/source/faust/gui/faustqt.h
  78. +366
    -0
      ports/temper/source/faust/gui/httpdUI.h
  79. +82
    -0
      ports/temper/source/faust/gui/jsonfaustui.h
  80. +31
    -0
      ports/temper/source/faust/gui/meta.h
  81. +406
    -0
      ports/temper/source/faust/gui/ring-buffer.h
  82. +2948
    -0
      ports/temper/source/faust/midi/RtMidi.cpp
  83. +998
    -0
      ports/temper/source/faust/midi/RtMidi.h
  84. +238
    -0
      ports/temper/source/faust/midi/bela-midi.h
  85. +203
    -0
      ports/temper/source/faust/midi/jack-midi.h
  86. +199
    -0
      ports/temper/source/faust/midi/juce-midi.h
  87. +212
    -0
      ports/temper/source/faust/midi/midi.h
  88. +260
    -0
      ports/temper/source/faust/midi/rt-midi.h
  89. +71
    -0
      ports/temper/source/faust/misc.h
  90. +107
    -0
      ports/temper/source/faust/osc/FaustFactory.h
  91. +96
    -0
      ports/temper/source/faust/osc/FaustNode.h
  92. +263
    -0
      ports/temper/source/faust/osc/Message.h
  93. +131
    -0
      ports/temper/source/faust/osc/MessageDriven.h
  94. +44
    -0
      ports/temper/source/faust/osc/MessageProcessor.h
  95. +115
    -0
      ports/temper/source/faust/osc/RootNode.h
  96. +139
    -0
      ports/temper/source/faust/osc/smartpointer.h
  97. +133
    -0
      ports/temper/source/faust/sound-file.h
  98. +116
    -0
      ports/temper/source/faust/vst/faust.h
  99. +22
    -0
      ports/temper/source/faust/vst/voice.h
  100. +455
    -0
      ports/temper/source/faust/vst/vstui.h

+ 4
- 0
ports/Makefile View File

@@ -71,6 +71,7 @@ else
$(MAKE) -C tal-reverb-2/LV2
$(MAKE) -C tal-reverb-3/LV2
$(MAKE) -C tal-vocoder-2/LV2
$(MAKE) -C temper/LV2
$(MAKE) -C vex/LV2
$(MAKE) -C wolpertinger/LV2
endif
@@ -111,6 +112,7 @@ vst: libs
$(MAKE) -C tal-reverb-2/VST
$(MAKE) -C tal-reverb-3/VST
$(MAKE) -C tal-vocoder-2/VST
$(MAKE) -C temper/VST
$(MAKE) -C vex/VST
$(MAKE) -C wolpertinger/VST

@@ -150,6 +152,7 @@ clean:
$(MAKE) clean -C tal-reverb-2/LV2
$(MAKE) clean -C tal-reverb-3/LV2
$(MAKE) clean -C tal-vocoder-2/LV2
$(MAKE) clean -C temper/LV2
$(MAKE) clean -C vex/LV2
$(MAKE) clean -C wolpertinger/LV2

@@ -185,6 +188,7 @@ clean:
$(MAKE) clean -C tal-reverb-2/VST
$(MAKE) clean -C tal-reverb-3/VST
$(MAKE) clean -C tal-vocoder-2/VST
$(MAKE) clean -C temper/VST
$(MAKE) clean -C vex/VST
$(MAKE) clean -C wolpertinger/VST



+ 19
- 0
ports/temper/LV2/premake.lua View File

@@ -0,0 +1,19 @@
dofile("../../../scripts/make-project.lua")
package = make_juce_lv2_project("Temper")
if (windows) then
-- TODO
elseif (macosx) then
-- TODO
else
package.linkoptions = { package.linkoptions, "`pkg-config --libs gl`" }
end
package.files = {
matchfiles (
"../source/*.cpp",
"../../../libs/juce-plugin/JucePluginMain.cpp"
)
}

+ 19
- 0
ports/temper/VST/premake.lua View File

@@ -0,0 +1,19 @@
dofile("../../../scripts/make-project.lua")
package = make_juce_vst_project("Temper")
if (windows) then
-- TODO
elseif (macosx) then
-- TODO
else
package.linkoptions = { package.linkoptions, "`pkg-config --libs gl`" }
end
package.files = {
matchfiles (
"../source/*.cpp",
"../../../libs/juce-plugin/JucePluginMain.cpp"
)
}

+ 19645
- 0
ports/temper/source/BinaryData.cpp
File diff suppressed because it is too large
View File


+ 44
- 0
ports/temper/source/BinaryData.h View File

@@ -0,0 +1,44 @@
/* =========================================================================================
This is an auto-generated file: Any edits you make may be overwritten!
*/
#pragma once
namespace BinaryData
{
extern const char* Background_png;
const int Background_pngSize = 1105568;
extern const char* BeeStingPreset_xml;
const int BeeStingPreset_xmlSize = 250;
extern const char* DefaultPreset_xml;
const int DefaultPreset_xmlSize = 249;
extern const char* FlyingUnitedPreset_xml;
const int FlyingUnitedPreset_xmlSize = 252;
extern const char* GraphBackground_png;
const int GraphBackground_pngSize = 179814;
extern const char* MontserratLight_otf;
const int MontserratLight_otfSize = 91496;
extern const char* MorningAtTheDMVPreset_xml;
const int MorningAtTheDMVPreset_xmlSize = 254;
extern const char* StubbedToePreset_xml;
const int StubbedToePreset_xmlSize = 252;
// Points to the start of a list of resource names.
extern const char* namedResourceList[];
// Number of elements in the namedResourceList array.
const int namedResourceListSize = 8;
// If you provide the name of one of the binary resource variables above, this function will
// return the corresponding data and its size (or a null pointer if the name isn't found).
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw();
}

+ 43
- 0
ports/temper/source/FaustUIBridge.cpp View File

@@ -0,0 +1,43 @@
/*
==============================================================================
FaustUIBridge.cpp
Created: 9 Feb 2017 5:59:55pm
Author: Nick Thompson
==============================================================================
*/
#include "FaustUIBridge.h"
FaustUIBridge::FaustUIBridge(AudioProcessorValueTreeState& vts)
: valueTreeState(vts)
{
}
FaustUIBridge::~FaustUIBridge()
{
for (int i = 0; i < listenerAssignments.size(); ++i)
{
ParameterListenerPair p = listenerAssignments.getUnchecked(i);
String paramId = p.paramId;
FaustUIBridgeListener* listener = p.listener;
valueTreeState.removeParameterListener(paramId, listener);
}
listenerAssignments.clear();
}
void FaustUIBridge::addHorizontalSlider(const char *label, float *zone, float init, float min, float max, float step)
{
// Create the AudioProcessor parameter if not exists
if (!valueTreeState.getParameter(label))
valueTreeState.createAndAddParameter(label, label, String(),
NormalisableRange<float>(min, max), init, nullptr, nullptr);
// Attach the listener to keep the internal dsp values up to date
FaustUIBridgeListener* l = new FaustUIBridgeListener(zone);
listeners.add(l);
listenerAssignments.add(ParameterListenerPair(String(label), l));
valueTreeState.addParameterListener(label, l);
}

+ 132
- 0
ports/temper/source/FaustUIBridge.h View File

@@ -0,0 +1,132 @@
/*
==============================================================================
FaustUIBridge.h
Created: 9 Feb 2017 5:59:55pm
Author: Nick Thompson
==============================================================================
*/
#ifndef FAUSTUIBRIDGE_H_INCLUDED
#define FAUSTUIBRIDGE_H_INCLUDED
#include "JuceHeader.h"
#include "faust/gui/UI.h"
//==============================================================================
/**
This class interfaces with the Faust UI paradigm, mapping control parameters
into AudioProcessorParameters on a provided AudioProcessorValueTreeState.
*/
class FaustUIBridge : public UI
{
public:
/** Construct a FaustUIBridge instance with the associated AudioProcessorValueTreeState. */
FaustUIBridge(AudioProcessorValueTreeState& vts);
/** Destructor. */
virtual ~FaustUIBridge() override;
//==============================================================================
/** Widget Layout
The following methods implement the widget layout functions.
Because we intend for an AudioProcessorEditor to manage the
visual aspect of the plugin, these methods are no-ops.
*/
virtual void openTabBox(const char* label) override {};
virtual void openHorizontalBox(const char* label) override {};
virtual void openVerticalBox(const char* label) override {};
virtual void closeBox() override {};
//==============================================================================
/** Active Widgets
The following methods implement the active widget functions
by constructing an AudioProcessorParameter and installing a
FaustUIBridgeListener to propagate changes back to the corresponding
zone.
*/
virtual void addButton(const char* label, FAUSTFLOAT* zone) override {};
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) override {};
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) override {};
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) override;
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) override {};
//==============================================================================
/** Passive Widgets
The following methods implement the passive widget functions.
Again, because we intend for an AudioProcessorEditor to manage the
visual aspect of the plugin, these methods are no-ops.
*/
virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) override {};
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) override {};
//==============================================================================
/** Metadata declarations
An additional no-op to implement the last piece of the Faust UI interface.
*/
virtual void declare(FAUSTFLOAT*, const char*, const char*) override {};
//==============================================================================
/** This class implements a simple callback which reacts to a value change on a
given AudioProcessorParameter.
We construct an instance of this class for each Faust zone declared via the
active widget methods above.
*/
class FaustUIBridgeListener : public AudioProcessorValueTreeState::Listener
{
public:
FaustUIBridgeListener(float* zone) : m_zone(zone) {};
virtual ~FaustUIBridgeListener() override {};
virtual void parameterChanged (const String& parameterID, float newValue) override
{
*m_zone = newValue;
};
private:
float* m_zone;
};
private:
//==============================================================================
/**
This struct associates an AudioProcessorParameter id with a FaustUIBridgeListener
object which as been attached to the valueTreeState.
*/
struct ParameterListenerPair
{
//==============================================================================
/** Constructor.
@param paramId The String Id of the AudioProcessorParameter.
@param listener The attached FaustUIBridgeListener.
*/
ParameterListenerPair(String paramId, FaustUIBridgeListener* listener)
: paramId(paramId), listener(listener) {};
String paramId;
FaustUIBridgeListener* listener;
};
// A reference to the AudioProcessor's value tree so that we can map the faust
// UI parameters to AudioProcessor parameters.
AudioProcessorValueTreeState& valueTreeState;
// Maintain an array associating AudioProcessorParameters to the Listeners that have been
// installed on those parameters.
Array<ParameterListenerPair> listenerAssignments;
// And an array of listeners to ensure the mapping between internal value tree values
// match the float* zone members of the faust implementation.
OwnedArray<AudioProcessorValueTreeState::Listener> listeners;
};
#endif // FAUSTUIBRIDGE_H_INCLUDED

+ 34
- 0
ports/temper/source/JuceHeader.h View File

@@ -0,0 +1,34 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
This is the header file that your files should include in order to get all the
JUCE library headers. You should avoid including the JUCE headers directly in
your own source files, because that wouldn't pick up the correct configuration
options for your app.
*/
#ifndef __APPHEADERFILE_JH7QDM__
#define __APPHEADERFILE_JH7QDM__
#include "JucePluginMain.h"
#include "BinaryData.h"
#if ! DONT_SET_USING_JUCE_NAMESPACE
// If your code uses a lot of JUCE classes, then this will obviously save you
// a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
using namespace juce;
#endif
#if ! JUCE_DONT_DECLARE_PROJECTINFO
namespace ProjectInfo
{
const char* const projectName = "Temper";
const char* const versionString = "1.0.3";
const int versionNumber = 0x10003;
}
#endif
#endif // __APPHEADERFILE_JH7QDM__

+ 139
- 0
ports/temper/source/JucePluginCharacteristics.h View File

@@ -0,0 +1,139 @@
/*
IMPORTANT! This file is auto-generated each time you save your
project - if you alter its contents, your changes may be overwritten!
There's a section below where you can add your own custom code safely, and the
Projucer will preserve the contents of that block, but the best way to change
any of these definitions is by using the Projucer's project settings.
Any commented-out settings will assume their default values.
*/
#pragma once
//==============================================================================
#ifndef JucePlugin_Enable_IAA
#define JucePlugin_Enable_IAA 0
#endif
#ifndef JucePlugin_Name
#define JucePlugin_Name "Temper"
#endif
#ifndef JucePlugin_Desc
#define JucePlugin_Desc "Modern digital distortion."
#endif
#ifndef JucePlugin_Manufacturer
#define JucePlugin_Manufacturer "Creative Intent"
#endif
#ifndef JucePlugin_ManufacturerWebsite
#define JucePlugin_ManufacturerWebsite "http://www.creativeintent.co"
#endif
#ifndef JucePlugin_ManufacturerEmail
#define JucePlugin_ManufacturerEmail ""
#endif
#ifndef JucePlugin_ManufacturerCode
#define JucePlugin_ManufacturerCode 0x4376696e // 'Cvin'
#endif
#ifndef JucePlugin_PluginCode
#define JucePlugin_PluginCode 0x546d7072 // 'Tmpr'
#endif
#ifndef JucePlugin_IsSynth
#define JucePlugin_IsSynth 0
#endif
#ifndef JucePlugin_WantsMidiInput
#define JucePlugin_WantsMidiInput 0
#endif
#ifndef JucePlugin_ProducesMidiOutput
#define JucePlugin_ProducesMidiOutput 0
#endif
#ifndef JucePlugin_IsMidiEffect
#define JucePlugin_IsMidiEffect 0
#endif
#ifndef JucePlugin_EditorRequiresKeyboardFocus
#define JucePlugin_EditorRequiresKeyboardFocus 0
#endif
#ifndef JucePlugin_Version
#define JucePlugin_Version 1.0.3
#endif
#ifndef JucePlugin_VersionCode
#define JucePlugin_VersionCode 0x10003
#endif
#ifndef JucePlugin_VersionString
#define JucePlugin_VersionString "1.0.3"
#endif
#ifndef JucePlugin_VSTUniqueID
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode
#endif
#ifndef JucePlugin_VSTCategory
#define JucePlugin_VSTCategory kPlugCategEffect
#endif
#ifndef JucePlugin_AUMainType
#define JucePlugin_AUMainType kAudioUnitType_Effect
#endif
#ifndef JucePlugin_AUSubType
#define JucePlugin_AUSubType JucePlugin_PluginCode
#endif
#ifndef JucePlugin_AUExportPrefix
#define JucePlugin_AUExportPrefix TemperAU
#endif
#ifndef JucePlugin_AUExportPrefixQuoted
#define JucePlugin_AUExportPrefixQuoted "TemperAU"
#endif
#ifndef JucePlugin_AUManufacturerCode
#define JucePlugin_AUManufacturerCode JucePlugin_ManufacturerCode
#endif
#ifndef JucePlugin_CFBundleIdentifier
#define JucePlugin_CFBundleIdentifier com.creativeintent.temper
#endif
#ifndef JucePlugin_RTASCategory
#define JucePlugin_RTASCategory ePlugInCategory_None
#endif
#ifndef JucePlugin_RTASManufacturerCode
#define JucePlugin_RTASManufacturerCode JucePlugin_ManufacturerCode
#endif
#ifndef JucePlugin_RTASProductId
#define JucePlugin_RTASProductId JucePlugin_PluginCode
#endif
#ifndef JucePlugin_RTASDisableBypass
#define JucePlugin_RTASDisableBypass 0
#endif
#ifndef JucePlugin_RTASDisableMultiMono
#define JucePlugin_RTASDisableMultiMono 0
#endif
#ifndef JucePlugin_AAXIdentifier
#define JucePlugin_AAXIdentifier com.creativeintent.temper
#endif
#ifndef JucePlugin_AAXManufacturerCode
#define JucePlugin_AAXManufacturerCode JucePlugin_ManufacturerCode
#endif
#ifndef JucePlugin_AAXProductId
#define JucePlugin_AAXProductId JucePlugin_PluginCode
#endif
#ifndef JucePlugin_AAXCategory
#define JucePlugin_AAXCategory AAX_ePlugInCategory_Dynamics
#endif
#ifndef JucePlugin_AAXDisableBypass
#define JucePlugin_AAXDisableBypass 0
#endif
#ifndef JucePlugin_AAXDisableMultiMono
#define JucePlugin_AAXDisableMultiMono 0
#endif
#ifndef JucePlugin_IAAType
#define JucePlugin_IAAType 0x61757278 // 'aurx'
#endif
#ifndef JucePlugin_IAASubType
#define JucePlugin_IAASubType JucePlugin_PluginCode
#endif
#ifndef JucePlugin_IAAName
#define JucePlugin_IAAName "Creative Intent: Temper"
#endif
#define JucePlugin_LV2URI "https://github.com/creativeintent/temper"
#define JucePlugin_LV2Category "DistortionPlugin"
#define JucePlugin_WantsLV2Latency 0
#define JucePlugin_WantsLV2State 0
#define JucePlugin_WantsLV2StateString 0
#define JucePlugin_WantsLV2Presets 1
#define JucePlugin_WantsLV2TimePos 0

+ 337
- 0
ports/temper/source/MainComponent.cpp View File

@@ -0,0 +1,337 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 4.3.0
------------------------------------------------------------------------------
The Projucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright (c) 2015 - ROLI Ltd.
==============================================================================
*/
//[Headers] You can add your own extra header files here...
//[/Headers]
#include "MainComponent.h"
//[MiscUserDefs] You can add your own user definitions and misc code here...
typedef AudioProcessorValueTreeState::SliderAttachment SliderAttachment;
//[/MiscUserDefs]
//==============================================================================
MainComponent::MainComponent (AudioProcessorValueTreeState& vts)
: m_vts(vts)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
addAndMakeVisible (m_cutoffSlider = new Slider ("Cutoff"));
m_cutoffSlider->setRange (100, 20000, 0);
m_cutoffSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_cutoffSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_resoSlider = new Slider ("Resonance"));
m_resoSlider->setRange (1, 8, 0);
m_resoSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_resoSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_driveSlider = new Slider ("Drive"));
m_driveSlider->setRange (-10, 10, 0);
m_driveSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_driveSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_curveSlider = new Slider ("Curve"));
m_curveSlider->setRange (0.1, 4, 0);
m_curveSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_curveSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_satSlider = new Slider ("Saturation"));
m_satSlider->setRange (0, 1, 0);
m_satSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_satSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_feedbackSlider = new Slider ("Feedback"));
m_feedbackSlider->setRange (-60, -24, 0);
m_feedbackSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_feedbackSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_gainSlider = new Slider ("Level"));
m_gainSlider->setRange (-24, 24, 0);
m_gainSlider->setSliderStyle (Slider::RotaryHorizontalVerticalDrag);
m_gainSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
addAndMakeVisible (m_cutoffLabel = new Label ("Cutoff Label",
TRANS("CUTOFF")));
m_cutoffLabel->setFont (Font (15.00f, Font::plain));
m_cutoffLabel->setJustificationType (Justification::centred);
m_cutoffLabel->setEditable (false, false, false);
m_cutoffLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_cutoffLabel->setColour (TextEditor::textColourId, Colours::black);
m_cutoffLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (m_resoLabel = new Label ("Resonance Label",
TRANS("RESONANCE")));
m_resoLabel->setFont (Font (15.00f, Font::plain));
m_resoLabel->setJustificationType (Justification::centred);
m_resoLabel->setEditable (false, false, false);
m_resoLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_resoLabel->setColour (TextEditor::textColourId, Colours::black);
m_resoLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (m_driveLabel = new Label ("Drive Label",
TRANS("DRIVE")));
m_driveLabel->setFont (Font (15.00f, Font::plain));
m_driveLabel->setJustificationType (Justification::centred);
m_driveLabel->setEditable (false, false, false);
m_driveLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_driveLabel->setColour (TextEditor::textColourId, Colours::black);
m_driveLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (m_curveLabel = new Label ("Curve Label",
TRANS("CURVE")));
m_curveLabel->setFont (Font (15.00f, Font::plain));
m_curveLabel->setJustificationType (Justification::centred);
m_curveLabel->setEditable (false, false, false);
m_curveLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_curveLabel->setColour (TextEditor::textColourId, Colours::black);
m_curveLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (m_satLabel = new Label ("Saturation Label",
TRANS("SATURATION")));
m_satLabel->setFont (Font (15.00f, Font::plain));
m_satLabel->setJustificationType (Justification::centred);
m_satLabel->setEditable (false, false, false);
m_satLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_satLabel->setColour (TextEditor::textColourId, Colours::black);
m_satLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (m_feedbackLabel = new Label ("Feedback Label",
TRANS("FEEDBACK")));
m_feedbackLabel->setFont (Font (15.00f, Font::plain));
m_feedbackLabel->setJustificationType (Justification::centred);
m_feedbackLabel->setEditable (false, false, false);
m_feedbackLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_feedbackLabel->setColour (TextEditor::textColourId, Colours::black);
m_feedbackLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
addAndMakeVisible (m_gainLabel = new Label ("Gain Label",
TRANS("LEVEL")));
m_gainLabel->setFont (Font (15.00f, Font::plain));
m_gainLabel->setJustificationType (Justification::centred);
m_gainLabel->setEditable (false, false, false);
m_gainLabel->setColour (Label::textColourId, Colour (0xffff8917));
m_gainLabel->setColour (TextEditor::textColourId, Colours::black);
m_gainLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
drawable1 = Drawable::createFromImageData (BinaryData::Background_png, BinaryData::Background_pngSize);
//[UserPreSize]
//[/UserPreSize]
setSize (744, 476);
//[Constructor] You can add your own custom stuff here..
filterFreqAttachment = new SliderAttachment(m_vts, "Cutoff", *m_cutoffSlider);
filterResoAttachment = new SliderAttachment(m_vts, "Resonance", *m_resoSlider);
driveAttachment = new SliderAttachment(m_vts, "Drive", *m_driveSlider);
curveAttachment = new SliderAttachment(m_vts, "Curve", *m_curveSlider);
satAttachment = new SliderAttachment(m_vts, "Saturation", *m_satSlider);
feedbackAttachment = new SliderAttachment(m_vts, "Feedback", *m_feedbackSlider);
levelAttachment = new SliderAttachment(m_vts, "Level", *m_gainSlider);
m_cutoffSlider->setTextValueSuffix("Hz");
m_cutoffSlider->setSkewFactorFromMidPoint(800.0);
m_feedbackSlider->setTextValueSuffix("dB");
m_gainSlider->setTextValueSuffix("dB");
//[/Constructor]
}
MainComponent::~MainComponent()
{
//[Destructor_pre]. You can add your own custom destruction code here..
// This has to happen before we null out the Sliders themselves because
// when the ScopedPointer<> delete policy tries to remove Listeners from
// the SliderAttachment it refers to the Sliders themselves. If the Sliders
// have already been deleted at that point then we get a null pointer error.
filterFreqAttachment = nullptr;
filterResoAttachment = nullptr;
driveAttachment = nullptr;
curveAttachment = nullptr;
satAttachment = nullptr;
feedbackAttachment = nullptr;
levelAttachment = nullptr;
//[/Destructor_pre]
m_cutoffSlider = nullptr;
m_resoSlider = nullptr;
m_driveSlider = nullptr;
m_curveSlider = nullptr;
m_satSlider = nullptr;
m_feedbackSlider = nullptr;
m_gainSlider = nullptr;
m_cutoffLabel = nullptr;
m_resoLabel = nullptr;
m_driveLabel = nullptr;
m_curveLabel = nullptr;
m_satLabel = nullptr;
m_feedbackLabel = nullptr;
m_gainLabel = nullptr;
drawable1 = nullptr;
//[Destructor]. You can add your own custom destruction code here..
//[/Destructor]
}
//==============================================================================
void MainComponent::paint (Graphics& g)
{
//[UserPrePaint] Add your own custom painting code here..
//[/UserPrePaint]
g.setColour (Colours::black);
jassert (drawable1 != 0);
if (drawable1 != 0)
drawable1->drawWithin (g, Rectangle<float> (0, 0, 744, 476),
RectanglePlacement::stretchToFit, 1.000f);
//[UserPaint] Add your own custom painting code here..
//[/UserPaint]
}
void MainComponent::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
m_cutoffSlider->setBounds (28, 149, 72, 72);
m_resoSlider->setBounds (28, 277, 72, 72);
m_driveSlider->setBounds (336, 357, 72, 72);
m_curveSlider->setBounds (219, 370, 50, 50);
m_satSlider->setBounds (475, 370, 50, 50);
m_feedbackSlider->setBounds (640, 148, 72, 72);
m_gainSlider->setBounds (640, 277, 72, 72);
m_cutoffLabel->setBounds (24, 111, 80, 20);
m_resoLabel->setBounds (24, 369, 80, 20);
m_driveLabel->setBounds (332, 450, 80, 20);
m_curveLabel->setBounds (204, 440, 80, 20);
m_satLabel->setBounds (462, 440, 80, 20);
m_feedbackLabel->setBounds (637, 111, 80, 20);
m_gainLabel->setBounds (639, 369, 80, 20);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
//[/MiscUserCode]
//==============================================================================
#if 0
/* -- Projucer information section --
This is where the Projucer stores the metadata that describe this GUI layout, so
make changes in here at your peril!
BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="MainComponent" componentName=""
parentClasses="public Component" constructorParams="AudioProcessorValueTreeState&amp; vts"
variableInitialisers="m_vts(vts)" snapPixels="8" snapActive="1"
snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="744"
initialHeight="476">
<BACKGROUND backgroundColour="ffffff">
<IMAGE pos="0 0 744 476" resource="BinaryData::Background_png" opacity="1"
mode="0"/>
</BACKGROUND>
<SLIDER name="Cutoff" id="80edd5c38c704dd5" memberName="m_cutoffSlider"
virtualName="" explicitFocusOrder="0" pos="28 149 72 72" min="100"
max="20000" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<SLIDER name="Resonance" id="3bb5cf0ab68e9733" memberName="m_resoSlider"
virtualName="" explicitFocusOrder="0" pos="28 277 72 72" min="1"
max="8" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<SLIDER name="Drive" id="9909e31099819864" memberName="m_driveSlider"
virtualName="" explicitFocusOrder="0" pos="336 357 72 72" min="-10"
max="10" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<SLIDER name="Curve" id="a56ea73f883bdf8f" memberName="m_curveSlider"
virtualName="" explicitFocusOrder="0" pos="219 370 50 50" min="0.10000000000000000555"
max="4" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<SLIDER name="Saturation" id="a1e434d9a7eda8a0" memberName="m_satSlider"
virtualName="" explicitFocusOrder="0" pos="475 370 50 50" min="0"
max="1" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<SLIDER name="Feedback" id="ecd475fce33f4b83" memberName="m_feedbackSlider"
virtualName="" explicitFocusOrder="0" pos="640 148 72 72" min="-60"
max="-24" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<SLIDER name="Level" id="bf47d1ef820213ea" memberName="m_gainSlider"
virtualName="" explicitFocusOrder="0" pos="640 277 72 72" min="-24"
max="24" int="0" style="RotaryHorizontalVerticalDrag" textBoxPos="NoTextBox"
textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1"
needsCallback="0"/>
<LABEL name="Cutoff Label" id="8c36484c7dd57b99" memberName="m_cutoffLabel"
virtualName="" explicitFocusOrder="0" pos="24 111 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="CUTOFF" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
<LABEL name="Resonance Label" id="cc33e12b86f2a86a" memberName="m_resoLabel"
virtualName="" explicitFocusOrder="0" pos="24 369 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="RESONANCE" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
<LABEL name="Drive Label" id="195ded46976233cb" memberName="m_driveLabel"
virtualName="" explicitFocusOrder="0" pos="332 450 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="DRIVE" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
<LABEL name="Curve Label" id="30073a37efa500cc" memberName="m_curveLabel"
virtualName="" explicitFocusOrder="0" pos="204 440 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="CURVE" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
<LABEL name="Saturation Label" id="e8a8527f3f6976cf" memberName="m_satLabel"
virtualName="" explicitFocusOrder="0" pos="462 440 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="SATURATION" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
<LABEL name="Feedback Label" id="5547950683b7ca1f" memberName="m_feedbackLabel"
virtualName="" explicitFocusOrder="0" pos="637 111 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="FEEDBACK" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
<LABEL name="Gain Label" id="719d91e31d43fa34" memberName="m_gainLabel"
virtualName="" explicitFocusOrder="0" pos="639 369 80 20" textCol="ffff8917"
edTextCol="ff000000" edBkgCol="0" labelText="LEVEL" editableSingleClick="0"
editableDoubleClick="0" focusDiscardsChanges="0" fontname="Default font"
fontsize="15" bold="0" italic="0" justification="36"/>
</JUCER_COMPONENT>
END_JUCER_METADATA
*/
#endif
//[EndFile] You can add extra defines here...
//[/EndFile]

+ 90
- 0
ports/temper/source/MainComponent.h View File

@@ -0,0 +1,90 @@
/*
==============================================================================
This is an automatically generated GUI class created by the Projucer!
Be careful when adding custom code to these files, as only the code within
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Projucer version: 4.3.0
------------------------------------------------------------------------------
The Projucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright (c) 2015 - ROLI Ltd.
==============================================================================
*/
#ifndef __JUCE_HEADER_9002020A4DD09B20__
#define __JUCE_HEADER_9002020A4DD09B20__
//[Headers] -- You can add your own extra header files here --
#include "JuceHeader.h"
//[/Headers]
//==============================================================================
/**
//[Comments]
An auto-generated component, created by the Projucer.
Describe your class and how it works here!
//[/Comments]
*/
class MainComponent : public Component
{
public:
//==============================================================================
MainComponent (AudioProcessorValueTreeState& vts);
~MainComponent();
//==============================================================================
//[UserMethods] -- You can add your own custom methods in this section.
//[/UserMethods]
void paint (Graphics& g) override;
void resized() override;
private:
//[UserVariables] -- You can add your own custom variables in this section.
AudioProcessorValueTreeState& m_vts;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> filterFreqAttachment;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> filterResoAttachment;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> driveAttachment;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> satAttachment;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> curveAttachment;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> feedbackAttachment;
ScopedPointer<AudioProcessorValueTreeState::SliderAttachment> levelAttachment;
//[/UserVariables]
//==============================================================================
ScopedPointer<Slider> m_cutoffSlider;
ScopedPointer<Slider> m_resoSlider;
ScopedPointer<Slider> m_driveSlider;
ScopedPointer<Slider> m_curveSlider;
ScopedPointer<Slider> m_satSlider;
ScopedPointer<Slider> m_feedbackSlider;
ScopedPointer<Slider> m_gainSlider;
ScopedPointer<Label> m_cutoffLabel;
ScopedPointer<Label> m_resoLabel;
ScopedPointer<Label> m_driveLabel;
ScopedPointer<Label> m_curveLabel;
ScopedPointer<Label> m_satLabel;
ScopedPointer<Label> m_feedbackLabel;
ScopedPointer<Label> m_gainLabel;
ScopedPointer<Drawable> drawable1;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};
//[EndFile] You can add extra defines here...
//[/EndFile]
#endif // __JUCE_HEADER_9002020A4DD09B20__

+ 60
- 0
ports/temper/source/PluginEditor.cpp View File

@@ -0,0 +1,60 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin editor.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
//==============================================================================
TemperAudioProcessorEditor::TemperAudioProcessorEditor (TemperAudioProcessor& p, AudioProcessorValueTreeState& vts)
: AudioProcessorEditor (&p), processor (p), m_vts(vts)
{
addAndMakeVisible(m_main = new MainComponent(m_vts));
addAndMakeVisible(m_vizPre = new SpectroscopeComponent());
addAndMakeVisible(m_vizPost = new SpectroscopeComponent());
m_main->setAlwaysOnTop(true);
m_vizPre->setColours(Colour::fromRGBA(255, 51, 34, 255),
Colour::fromRGBA(223, 19, 19, 255).withAlpha(0.7f),
Colour::fromRGBA(123, 0, 0, 255).withAlpha(0.7f));
m_vizPost->setColours(Colour::fromRGBA(255, 186, 34, 255),
Colour::fromRGBA(253, 174, 25, 255).withAlpha(0.7f),
Colour::fromRGBA(255, 126, 0, 255).withAlpha(0.7f));
m_vizPre->toBehind(m_vizPost);

m_glContext.setComponentPaintingEnabled(true);
m_glContext.attachTo(*this);
setSize (744, 476);
setLookAndFeel(&laf);
}
TemperAudioProcessorEditor::~TemperAudioProcessorEditor()
{
m_glContext.detach();
setLookAndFeel(nullptr);
}
//==============================================================================
void TemperAudioProcessorEditor::paint (Graphics& g)
{
Image graphBackground = ImageCache::getFromMemory(BinaryData::GraphBackground_png,
BinaryData::GraphBackground_pngSize);
g.drawImageAt(graphBackground.rescaled(396, 134), 194, 181);
}
void TemperAudioProcessorEditor::resized()
{
m_main->setBounds(0, 0, 744, 476);
m_vizPre->setBounds(194, 181, 396, 134);
m_vizPost->setBounds(194, 181, 396, 134);
}

+ 54
- 0
ports/temper/source/PluginEditor.h View File

@@ -0,0 +1,54 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin editor.
==============================================================================
*/
#ifndef PLUGINEDITOR_H_INCLUDED
#define PLUGINEDITOR_H_INCLUDED
#include "JuceHeader.h"
#include "TemperLookAndFeel.h"
#include "PluginProcessor.h"
#include "MainComponent.h"
#include "SpectroscopeComponent.h"
typedef AudioProcessorValueTreeState::SliderAttachment SliderAttachment;
//==============================================================================
/**
*/
class TemperAudioProcessorEditor : public AudioProcessorEditor
{
public:
TemperAudioProcessorEditor (TemperAudioProcessor&, AudioProcessorValueTreeState&);
~TemperAudioProcessorEditor();
//==============================================================================
void paint (Graphics&) override;
void resized() override;
//==============================================================================
ScopedPointer<SpectroscopeComponent> m_vizPre;
ScopedPointer<SpectroscopeComponent> m_vizPost;
private:
// This reference is provided as a quick way for your editor to
// access the processor object that created it.
TemperAudioProcessor& processor;
TemperLookAndFeel laf;
OpenGLContext m_glContext;
AudioProcessorValueTreeState& m_vts;
ScopedPointer<MainComponent> m_main;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemperAudioProcessorEditor)
};
#endif // PLUGINEDITOR_H_INCLUDED

+ 283
- 0
ports/temper/source/PluginProcessor.cpp View File

@@ -0,0 +1,283 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#include "PluginProcessor.h"
#include "PluginEditor.h"
#include "TemperDsp.hpp"
const int kOversampleFactor = 3;
//==============================================================================
TemperAudioProcessor::TemperAudioProcessor()
#ifndef JucePlugin_PreferredChannelConfigurations
: AudioProcessor (BusesProperties()
#if ! JucePlugin_IsMidiEffect
#if ! JucePlugin_IsSynth
.withInput ("Input", AudioChannelSet::stereo(), true)
#endif
.withOutput ("Output", AudioChannelSet::stereo(), true)
#endif
),
m_params (*this, nullptr)
#else
: m_params (*this, nullptr)
#endif
{
m_restriction = new RestrictionProcessor();
m_bridge = new FaustUIBridge(m_params);
m_lastKnownSampleRate = 0.0;
m_currentProgram = -1;
// Initialize the dsp units
for (int i = 0; i < getTotalNumInputChannels(); ++i)
{
TemperDsp* dsp = new TemperDsp();
dsp->buildUserInterface(m_bridge);
m_dsps.add(dsp);
}
// Initialize the AudioProcessorValueTreeState root
ValueTree root (Identifier("TEMPER"));
m_params.state = root;
}
TemperAudioProcessor::~TemperAudioProcessor()
{
}
//==============================================================================
const String TemperAudioProcessor::getName() const
{
return JucePlugin_Name;
}
bool TemperAudioProcessor::acceptsMidi() const
{
#if JucePlugin_WantsMidiInput
return true;
#else
return false;
#endif
}
bool TemperAudioProcessor::producesMidi() const
{
#if JucePlugin_ProducesMidiOutput
return true;
#else
return false;
#endif
}
double TemperAudioProcessor::getTailLengthSeconds() const
{
return 0.0;
}
int TemperAudioProcessor::getNumPrograms()
{
return 5; // NB: some hosts don't cope very well if you tell them there are 0 programs,
// so this should be at least 1, even if you're not really implementing programs.
}
int TemperAudioProcessor::getCurrentProgram()
{
return m_currentProgram;
}
void TemperAudioProcessor::setCurrentProgram (int index)
{
switch (index) {
case 0:
setStateInformation(BinaryData::DefaultPreset_xml,
BinaryData::DefaultPreset_xmlSize);
break;
case 1:
setStateInformation(BinaryData::StubbedToePreset_xml,
BinaryData::StubbedToePreset_xmlSize);
break;
case 2:
setStateInformation(BinaryData::BeeStingPreset_xml,
BinaryData::BeeStingPreset_xmlSize);
break;
case 3:
setStateInformation(BinaryData::MorningAtTheDMVPreset_xml,
BinaryData::MorningAtTheDMVPreset_xmlSize);
break;
case 4:
setStateInformation(BinaryData::FlyingUnitedPreset_xml,
BinaryData::FlyingUnitedPreset_xmlSize);
break;
default:
break;
}
m_currentProgram = index;
}
const String TemperAudioProcessor::getProgramName (int index)
{
switch (index) {
case 0:
return String("Default");
case 1:
return String("Stubbed Toe");
case 2:
return String("Bee Sting");
case 3:
return String("Morning at the DMV");
case 4:
return String("Flying United");
default:
return String();
}
}
void TemperAudioProcessor::changeProgramName (int index, const String& newName)
{
}
//==============================================================================
void TemperAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
auto filterType = juce::dsp::Oversampling<float>::filterHalfBandPolyphaseIIR;
m_oversampler = std::unique_ptr<juce::dsp::Oversampling<float>>(new juce::dsp::Oversampling<float>(getTotalNumInputChannels(),
kOversampleFactor, filterType, false));
// Re-initialize the dsp modules at the upsampled rate.
if (m_lastKnownSampleRate == 0.0)
for (int i = 0; i < m_dsps.size(); ++i)
m_dsps.getUnchecked(i)->init(sampleRate * pow(2, kOversampleFactor));
else
for (int i = 0; i < m_dsps.size(); ++i)
m_dsps.getUnchecked(i)->instanceConstants(sampleRate * pow(2, kOversampleFactor));
m_oversampler->initProcessing(static_cast<size_t> (samplesPerBlock));
m_restriction->prepareToPlay(samplesPerBlock, sampleRate);
m_lastKnownSampleRate = sampleRate;
setLatencySamples(static_cast<int>(m_oversampler->getLatencyInSamples()));
}
void TemperAudioProcessor::releaseResources()
{
// When playback stops, you can use this as an opportunity to free up any
// spare memory, etc.
}
#ifndef JucePlugin_PreferredChannelConfigurations
bool TemperAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
{
#if JucePlugin_IsMidiEffect
ignoreUnused (layouts);
return true;
#else
// This is the place where you check if the layout is supported.
// In this template code we only support mono or stereo.
if (layouts.getMainOutputChannelSet() != AudioChannelSet::mono()
&& layouts.getMainOutputChannelSet() != AudioChannelSet::stereo())
return false;
// This checks if the input layout matches the output layout
#if ! JucePlugin_IsSynth
if (layouts.getMainOutputChannelSet() != layouts.getMainInputChannelSet())
return false;
#endif
return true;
#endif
}
#endif
void TemperAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
const int totalNumInputChannels = getTotalNumInputChannels();
const int totalNumOutputChannels = getTotalNumOutputChannels();
TemperAudioProcessorEditor* editor = static_cast<TemperAudioProcessorEditor*>(getActiveEditor());
// In case we have more outputs than inputs, this code clears any output
// channels that didn't contain input data, (because these aren't
// guaranteed to be empty - they may contain garbage).
// This is here to avoid people getting screaming feedback
// when they first compile a plugin, but obviously you don't need to keep
// this code if your algorithm always overwrites all the output channels.
for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
buffer.clear (i, 0, buffer.getNumSamples());
// Push input buffer into the Pre spectroscope component.
if (editor)
editor->m_vizPre->pushBuffer(buffer);
// Now the guts of the processing; oversampling and applying the Faust dsp module.
const int numInputChannels = buffer.getNumChannels();
const int numInputSamples = buffer.getNumSamples();
juce::dsp::AudioBlock<float> block (buffer.getArrayOfWritePointers(),
numInputChannels,
numInputSamples);
juce::dsp::AudioBlock<float> oversampledBlock = m_oversampler->processSamplesUp(block);
// Run the faust processors on each channel of the oversampled block.
for (int i = 0; i < numInputChannels; ++i)
{
auto* processor = m_dsps.getUnchecked(i);
auto* data = oversampledBlock.getChannelPointer(i);
int len = static_cast<int>(oversampledBlock.getNumSamples());
processor->compute(len, &data, &data);
}
m_oversampler->processSamplesDown(block);
#ifdef TEMPER_DEMO_BUILD
// After the Faust processing, add the demo restriction to the output stream
m_restriction->processBlock(buffer);
#endif
// Push resulting buffer into the Post spectroscope component.
if (editor)
editor->m_vizPost->pushBuffer(buffer);
}
//==============================================================================
bool TemperAudioProcessor::hasEditor() const
{
return true; // (change this to false if you choose to not supply an editor)
}
AudioProcessorEditor* TemperAudioProcessor::createEditor()
{
return new TemperAudioProcessorEditor (*this, m_params);
}
//==============================================================================
void TemperAudioProcessor::getStateInformation (MemoryBlock& destData)
{
ScopedPointer<XmlElement> xml (m_params.state.createXml());
copyXmlToBinary(*xml, destData);
}
void TemperAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
{
ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
if (xmlState != nullptr)
if (xmlState->hasTagName (m_params.state.getType()))
m_params.state = ValueTree::fromXml (*xmlState);
}
//==============================================================================
// This creates new instances of the plugin..
AudioProcessor* JUCE_CALLTYPE createPluginFilter()
{
return new TemperAudioProcessor();
}

+ 79
- 0
ports/temper/source/PluginProcessor.h View File

@@ -0,0 +1,79 @@
/*
==============================================================================
This file was auto-generated!
It contains the basic framework code for a JUCE plugin processor.
==============================================================================
*/
#ifndef PLUGINPROCESSOR_H_INCLUDED
#define PLUGINPROCESSOR_H_INCLUDED
#include "JuceHeader.h"
#include "FaustUIBridge.h"
#include "RestrictionProcessor.h"
#include "faust/dsp/dsp.h"
//==============================================================================
/**
*/
class TemperAudioProcessor : public AudioProcessor
{
public:
//==============================================================================
TemperAudioProcessor();
~TemperAudioProcessor();
//==============================================================================
void prepareToPlay (double sampleRate, int samplesPerBlock) override;
void releaseResources() override;
#ifndef JucePlugin_PreferredChannelConfigurations
bool isBusesLayoutSupported (const BusesLayout& layouts) const override;
#endif
void processBlock (AudioSampleBuffer&, MidiBuffer&) override;
//==============================================================================
AudioProcessorEditor* createEditor() override;
bool hasEditor() const override;
//==============================================================================
const String getName() const override;
bool acceptsMidi() const override;
bool producesMidi() const override;
double getTailLengthSeconds() const override;
//==============================================================================
int getNumPrograms() override;
int getCurrentProgram() override;
void setCurrentProgram (int index) override;
const String getProgramName (int index) override;
void changeProgramName (int index, const String& newName) override;
//==============================================================================
void getStateInformation (MemoryBlock& destData) override;
void setStateInformation (const void* data, int sizeInBytes) override;
private:
AudioProcessorValueTreeState m_params;
OwnedArray<::dsp> m_dsps;
ScopedPointer<FaustUIBridge> m_bridge;
ScopedPointer<RestrictionProcessor> m_restriction;
std::unique_ptr<juce::dsp::Oversampling<float>> m_oversampler;
double m_lastKnownSampleRate;
int m_currentProgram;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemperAudioProcessor)
};
#endif // PLUGINPROCESSOR_H_INCLUDED

+ 55
- 0
ports/temper/source/RestrictionProcessor.cpp View File

@@ -0,0 +1,55 @@
/*
==============================================================================
RestrictionProcessor.cpp
Created: 15 Feb 2017 10:03:51pm
Author: Nick Thompson
==============================================================================
*/
#include "RestrictionProcessor.h"
const double kFreq = 0.05; // Twenty second period.
const double kDuty = 0.75; // Fifteen seconds of audio, five seconds of silence.
//==============================================================================
RestrictionProcessor::RestrictionProcessor()
{
m_smoothing = new LinearSmoothedValue<float>();
}
//==============================================================================
void RestrictionProcessor::prepareToPlay(int samplesPerBlockExpected, double sampleRate)
{
m_sampleRate = sampleRate;
m_delta = kFreq / m_sampleRate;
m_currentAngle = 0.0;
m_smoothing->reset(sampleRate, 1.0);
}
void RestrictionProcessor::releaseResources() {}
void RestrictionProcessor::processBlock(AudioSampleBuffer &buffer)
{
const int numChannels = buffer.getNumChannels();
const int numSamples = buffer.getNumSamples();
float** channelData = buffer.getArrayOfWritePointers();
for (int j = 0; j < numSamples; ++j)
{
const float targetGain = static_cast<float>(m_currentAngle <= kDuty);
m_smoothing->setValue(targetGain);
const float gain = m_smoothing->getNextValue();
for (int i = 0; i < numChannels; ++i)
{
const float in = channelData[i][j];
channelData[i][j] = gain * in;
}
m_currentAngle = fmod(m_currentAngle + m_delta, 1.0);
}
}

+ 66
- 0
ports/temper/source/RestrictionProcessor.h View File

@@ -0,0 +1,66 @@
/*
==============================================================================
RestrictionProcessor.h
Created: 15 Feb 2017 10:03:51pm
Author: Nick Thompson
==============================================================================
*/
#ifndef RESTRICTIONPROCESSOR_H_INCLUDED
#define RESTRICTIONPROCESSOR_H_INCLUDED
#include "JuceHeader.h"
//==============================================================================
/**
A simple variant on the JUCE AudioSource for managing the trial version
restrictions and plugin validation.
When a source needs to be played, it is first put into a 'prepared' state by a call to
prepareToPlay(), and then repeated calls will be made to its processBlock() method to
process the audio data.
*/
class RestrictionProcessor
{
public:
//==============================================================================
/** Creates an AudioSource. */
RestrictionProcessor();
/** Destructor. */
virtual ~RestrictionProcessor() {}
//==============================================================================
/** Tells the processor to prepare for playing.
*/
void prepareToPlay (int samplesPerBlockExpected, double sampleRate);
/** Allows the source to release anything it no longer needs after playback has stopped.
This will be called when the source is no longer going to have its processBlock()
method called, so it should release any spare memory, etc. that it might have
allocated during the prepareToPlay() call.
*/
void releaseResources();
/** Called repeatedly to fetch subsequent blocks of audio data.
After calling the prepareToPlay() method, this callback will be made each
time the audio playback hardware (or whatever other destination the audio
data is going to) needs another block of data.
*/
void processBlock (AudioSampleBuffer& buffer);
private:
//==============================================================================
ScopedPointer<LinearSmoothedValue<float>> m_smoothing;
//==============================================================================
double m_sampleRate;
double m_delta;
double m_currentAngle;
};
#endif // RESTRICTIONPROCESSOR_H_INCLUDED

+ 131
- 0
ports/temper/source/SpectroscopeComponent.cpp View File

@@ -0,0 +1,131 @@
/*
==============================================================================
SpectroscopeComponent.cpp
Created: 8 Apr 2017 12:46:51pm
Author: Nick Thompson
==============================================================================
*/
#include "JuceHeader.h"
#include "SpectroscopeComponent.h"
//==============================================================================
SpectroscopeComponent::SpectroscopeComponent()
: m_fifoIndex(0),
m_fftBlockReady(false),
m_forwardFFT(kFFTOrder),
m_window(kFFTSize, juce::dsp::WindowingFunction<float>::hann),
m_strokeColour(Colours::white),
m_fillStartColour(Colours::white.withAlpha(0.2f)),
m_fillStopColour(Colours::white.withAlpha(0.8f))
{
zeromem(m_outputData, sizeof(m_outputData));
setSize(700, 200);
startTimerHz(30);
}
SpectroscopeComponent::~SpectroscopeComponent()
{
stopTimer();
}
void SpectroscopeComponent::paint (Graphics& g)
{
const float width = (float) getWidth();
const float height = (float) getHeight();
// Clear the drawing target
g.setColour(Colours::transparentBlack);
g.fillAll();
// The values in the output bins after the FFT have a range that I don't understand
// and isn't explained in the docs. It seems that if I scale down by the size of the
// fft buffer, I get somewhat reasonable results on the graph. But in examples I've
// seen, we would just divide here by the maximum value in the bins at the time of
// drawing. Seeing as that would be inconsistent between frames, I'm defaulting to the
// size of the fft here unless the max value in the bins is larger.
Range<float> maxBin = FloatVectorOperations::findMinAndMax(m_outputData, kOutputSize);
const float scale = 1.0f / jmax((float) kFFTSize, maxBin.getEnd());
g.setColour(m_fillStartColour);
for (int i = 0; i < kOutputSize; ++i)
{
float x = std::log10 (1 + 39 * ((i + 1.0f) / kOutputSize)) / std::log10 (40.0f) * width;
const float yMag = scale * m_outputData[i];
const float yDecibel = Decibels::gainToDecibels(yMag);
const float y = jmap(yDecibel, -90.0f, -12.0f, height, 0.0f);
g.drawVerticalLine((int) x, y, height);
}
}
void SpectroscopeComponent::resized()
{
}
void SpectroscopeComponent::timerCallback()
{
if (m_fftBlockReady)
{
// Compute the frequency transform
m_window.multiplyWithWindowingTable(m_fftData, kFFTSize);
m_forwardFFT.performFrequencyOnlyForwardTransform(m_fftData);
// Copy the frequency bins into the output data buffer, taking
// max(output[i], fftData[i]) for each bin. Note that after computing the
// FrequencyOnlyForwardTransform on an array A of size N, A[N/2, N) is full
// of zeros, and A[0, N/4) is a mirror of A[N/4, N/2). Therefore we only copy
// kFFTSize / 2 samples into the output data buffer here.
FloatVectorOperations::max(m_outputData, m_outputData, m_fftData, kOutputSize);
m_fftBlockReady = false;
}
// Decay the output bin magnitudes
for (int i = 0; i < kOutputSize; ++i)
m_outputData[i] *= 0.707f;
repaint();
}
void SpectroscopeComponent::pushBuffer(AudioSampleBuffer &buffer)
{
if (buffer.getNumChannels() > 0)
{
const int numSamples = buffer.getNumSamples();
const float* channelData = buffer.getReadPointer(0);
for (int i = 0; i < numSamples; ++i)
pushSample(channelData[i]);
}
}
inline void SpectroscopeComponent::pushSample(float sample)
{
// When we wrap around the fifo table, we copy the data into the
// FFT buffer and prepare to perform the transform.
if (m_fifoIndex == kFFTSize)
{
if (!m_fftBlockReady)
{
zeromem(m_fftData, sizeof(m_fftData));
memcpy(m_fftData, m_fifo, sizeof(m_fifo));
m_fftBlockReady = true;
}
m_fifoIndex = 0;
}
m_fifo[m_fifoIndex++] = sample;
}
void SpectroscopeComponent::setColours(Colour strokeColour, Colour fillStartColour, Colour fillStopColour)
{
m_strokeColour = strokeColour;
m_fillStartColour = fillStartColour;
m_fillStopColour = fillStopColour;
}

+ 60
- 0
ports/temper/source/SpectroscopeComponent.h View File

@@ -0,0 +1,60 @@
/*
==============================================================================
SpectroscopeComponent.h
Created: 8 Apr 2017 12:46:51pm
Author: Nick Thompson
==============================================================================
*/
#ifndef SPECTROSCOPECOMPONENT_H_INCLUDED
#define SPECTROSCOPECOMPONENT_H_INCLUDED
#include "JuceHeader.h"
//==============================================================================
/*
*/
class SpectroscopeComponent : public Component,
private Timer
{
public:
SpectroscopeComponent();
~SpectroscopeComponent();
void paint (Graphics&) override;
void resized() override;
void timerCallback() override;
void pushBuffer (AudioSampleBuffer& buffer);
inline void pushSample (float sample);
void setColours (Colour strokeColour, Colour fillStartColour, Colour fillStopColour);
enum {
kFFTOrder = 11,
kFFTSize = 2048, // 2^11
kOutputSize = 1024, // 2048 / 2
};
private:
float m_fifo [kFFTSize];
float m_fftData [2 * kFFTSize];
float m_outputData [kOutputSize];
unsigned int m_fifoIndex;
bool m_fftBlockReady;
juce::dsp::FFT m_forwardFFT;
juce::dsp::WindowingFunction<float> m_window;
Colour m_strokeColour;
Colour m_fillStartColour;
Colour m_fillStopColour;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SpectroscopeComponent)
};
#endif // SPECTROSCOPECOMPONENT_H_INCLUDED

+ 339
- 0
ports/temper/source/TemperDsp.hpp View File

@@ -0,0 +1,339 @@
/* ------------------------------------------------------------
name: "temper"
Code generated with Faust 2.5.32 (https://faust.grame.fr)
Compilation options: cpp, -scal -ftz 0
------------------------------------------------------------ */

#ifndef __TemperDsp_H__
#define __TemperDsp_H__

/************************************************************************
************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------

This is sample code. This file is provided as an example of minimal
FAUST architecture file. Redistribution and use in source and binary
forms, with or without modification, in part or in full are permitted.
In particular you can create a derived work of this FAUST architecture
and distribute that work under terms of your choice.

This sample code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
************************************************************************
************************************************************************/
#include <math.h>
#include <algorithm>

#include "faust/gui/UI.h"
#include "faust/gui/meta.h"
#include "faust/dsp/dsp.h"

using std::max;
using std::min;

/******************************************************************************
*******************************************************************************

VECTOR INTRINSICS

*******************************************************************************
*******************************************************************************/


/******************************************************************************
*******************************************************************************

ABSTRACT USER INTERFACE

*******************************************************************************
*******************************************************************************/

//----------------------------------------------------------------------------
// FAUST generated signal processor
//----------------------------------------------------------------------------

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include <cmath>
#include <math.h>

float TemperDsp_faustpower2_f(float value) {
return (value * value);
}

#ifndef FAUSTCLASS
#define FAUSTCLASS TemperDsp
#endif
#ifdef __APPLE__
#define exp10f __exp10f
#define exp10 __exp10
#endif

class TemperDsp : public ::dsp {
private:
FAUSTFLOAT fHslider0;
float fRec3[2];
FAUSTFLOAT fHslider1;
float fRec4[2];
int fSamplingFreq;
float fConst0;
float fConst1;
FAUSTFLOAT fHslider2;
float fRec6[2];
FAUSTFLOAT fHslider3;
float fRec7[2];
float fRec5[3];
float fConst2;
float fConst3;
float fRec8[2];
FAUSTFLOAT fHslider4;
float fRec9[2];
FAUSTFLOAT fHslider5;
float fRec10[2];
float fVec0[2];
float fRec2[2];
float fRec1[2];
float fRec0[2];
FAUSTFLOAT fHslider6;
float fRec11[2];
public:
void metadata(Meta* m) {
m->declare("analyzers.lib/name", "Faust Analyzer Library");
m->declare("analyzers.lib/version", "0.0");
m->declare("basics.lib/name", "Faust Basic Element Library");
m->declare("basics.lib/version", "0.0");
m->declare("filename", "temper");
m->declare("filters.lib/name", "Faust Filters Library");
m->declare("filters.lib/version", "0.0");
m->declare("maths.lib/author", "GRAME");
m->declare("maths.lib/copyright", "GRAME");
m->declare("maths.lib/license", "LGPL with exception");
m->declare("maths.lib/name", "Faust Math Library");
m->declare("maths.lib/version", "2.1");
m->declare("name", "temper");
m->declare("signals.lib/name", "Faust Signal Routing Library");
m->declare("signals.lib/version", "0.0");
}

virtual int getNumInputs() {
return 1;
}
virtual int getNumOutputs() {
return 1;
}
virtual int getInputRate(int channel) {
int rate;
switch (channel) {
case 0: {
rate = 1;
break;
}
default: {
rate = -1;
break;
}
}
return rate;
}
virtual int getOutputRate(int channel) {
int rate;
switch (channel) {
case 0: {
rate = 1;
break;
}
default: {
rate = -1;
break;
}
}
return rate;
}
static void classInit(int samplingFreq) {
}
virtual void instanceConstants(int samplingFreq) {
fSamplingFreq = samplingFreq;
fConst0 = min(192000.0f, max(1.0f, float(fSamplingFreq)));
fConst1 = (3.14159274f / fConst0);
fConst2 = expf((0.0f - (25.0f / fConst0)));
fConst3 = (1.0f - fConst2);
}
virtual void instanceResetUserInterface() {
fHslider0 = FAUSTFLOAT(1.0f);
fHslider1 = FAUSTFLOAT(-60.0f);
fHslider2 = FAUSTFLOAT(20000.0f);
fHslider3 = FAUSTFLOAT(1.0f);
fHslider4 = FAUSTFLOAT(4.0f);
fHslider5 = FAUSTFLOAT(1.0f);
fHslider6 = FAUSTFLOAT(-3.0f);
}
virtual void instanceClear() {
for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
fRec3[l0] = 0.0f;
}
for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
fRec4[l1] = 0.0f;
}
for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
fRec6[l2] = 0.0f;
}
for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
fRec7[l3] = 0.0f;
}
for (int l4 = 0; (l4 < 3); l4 = (l4 + 1)) {
fRec5[l4] = 0.0f;
}
for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
fRec8[l5] = 0.0f;
}
for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
fRec9[l6] = 0.0f;
}
for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) {
fRec10[l7] = 0.0f;
}
for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
fVec0[l8] = 0.0f;
}
for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
fRec2[l9] = 0.0f;
}
for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) {
fRec1[l10] = 0.0f;
}
for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) {
fRec0[l11] = 0.0f;
}
for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
fRec11[l12] = 0.0f;
}
}
virtual void init(int samplingFreq) {
classInit(samplingFreq);
instanceInit(samplingFreq);
}
virtual void instanceInit(int samplingFreq) {
instanceConstants(samplingFreq);
instanceResetUserInterface();
instanceClear();
}
virtual TemperDsp* clone() {
return new TemperDsp();
}
virtual int getSampleRate() {
return fSamplingFreq;
}
virtual void buildUserInterface(UI* ui_interface) {
ui_interface->openVerticalBox("temper");
ui_interface->addHorizontalSlider("Curve", &fHslider5, 1.0f, 0.100000001f, 4.0f, 0.00100000005f);
ui_interface->addHorizontalSlider("Cutoff", &fHslider2, 20000.0f, 100.0f, 20000.0f, 1.0f);
ui_interface->addHorizontalSlider("Drive", &fHslider4, 4.0f, -10.0f, 10.0f, 0.00100000005f);
ui_interface->addHorizontalSlider("Feedback", &fHslider1, -60.0f, -60.0f, -24.0f, 1.0f);
ui_interface->addHorizontalSlider("Level", &fHslider6, -3.0f, -24.0f, 24.0f, 1.0f);
ui_interface->addHorizontalSlider("Resonance", &fHslider3, 1.0f, 1.0f, 8.0f, 0.00100000005f);
ui_interface->addHorizontalSlider("Saturation", &fHslider0, 1.0f, 0.0f, 1.0f, 0.00100000005f);
ui_interface->closeBox();
}
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
FAUSTFLOAT* input0 = inputs[0];
FAUSTFLOAT* output0 = outputs[0];
float fSlow0 = (0.00499999989f * float(fHslider0));
float fSlow1 = (0.00499999989f * powf(10.0f, (0.0500000007f * float(fHslider1))));
float fSlow2 = (0.00499999989f / tanf((fConst1 * float(fHslider2))));
float fSlow3 = (0.00499999989f * float(fHslider3));
float fSlow4 = (0.00499999989f * float(fHslider4));
float fSlow5 = (0.00499999989f * float(fHslider5));
float fSlow6 = (0.00499999989f * powf(10.0f, (0.0500000007f * float(fHslider6))));
for (int i = 0; (i < count); i = (i + 1)) {
fRec3[0] = (fSlow0 + (0.995000005f * fRec3[1]));
fRec4[0] = (fSlow1 + (0.995000005f * fRec4[1]));
fRec6[0] = (fSlow2 + (0.995000005f * fRec6[1]));
fRec7[0] = (fSlow3 + (0.995000005f * fRec7[1]));
float fTemp0 = (1.0f / fRec7[0]);
float fTemp1 = ((fRec6[0] * (fRec6[0] + fTemp0)) + 1.0f);
fRec5[0] = (float(input0[i]) - (((((fRec6[0] * (fRec6[0] - fTemp0)) + 1.0f) * fRec5[2]) + (2.0f * (fRec5[1] * (1.0f - TemperDsp_faustpower2_f(fRec6[0]))))) / fTemp1));
float fTemp2 = ((fRec4[0] * fRec0[1]) + (((fRec5[0] + (2.0f * fRec5[1])) + fRec5[2]) / fTemp1));
float fTemp3 = fabsf(fTemp2);
fRec8[0] = max(fTemp3, ((fConst3 * fTemp3) + (fConst2 * fRec8[1])));
fRec9[0] = (fSlow4 + (0.995000005f * fRec9[1]));
float fTemp4 = min(3.0f, max(-3.0f, (fRec8[0] + (fRec9[0] * fTemp2))));
fRec10[0] = (fSlow5 + (0.995000005f * fRec10[1]));
float fTemp5 = TemperDsp_faustpower2_f(fRec10[0]);
float fTemp6 = (TemperDsp_faustpower2_f(fTemp4) * fTemp5);
float fTemp7 = ((fTemp4 * (fTemp6 + 27.0f)) * ((9.0f * fTemp5) + 27.0f));
float fTemp8 = (((9.0f * fTemp6) + 27.0f) * (fTemp5 + 27.0f));
float fTemp9 = (((1.0f - fRec3[0]) * fTemp2) + (0.239999995f * ((fTemp7 * fRec3[0]) / fTemp8)));
fVec0[0] = fTemp9;
fRec2[0] = (fVec0[1] + (((0.0f - (0.239999995f * (fTemp7 / fTemp8))) * fRec2[1]) + (0.239999995f * ((fTemp7 * fTemp9) / fTemp8))));
fRec1[0] = ((fRec2[0] + (0.995000005f * fRec1[1])) - fRec2[1]);
fRec0[0] = fRec1[0];
fRec11[0] = (fSlow6 + (0.995000005f * fRec11[1]));
output0[i] = FAUSTFLOAT((4.0f * (fRec0[0] * fRec11[0])));
fRec3[1] = fRec3[0];
fRec4[1] = fRec4[0];
fRec6[1] = fRec6[0];
fRec7[1] = fRec7[0];
fRec5[2] = fRec5[1];
fRec5[1] = fRec5[0];
fRec8[1] = fRec8[0];
fRec9[1] = fRec9[0];
fRec10[1] = fRec10[0];
fVec0[1] = fVec0[0];
fRec2[1] = fRec2[0];
fRec1[1] = fRec1[0];
fRec0[1] = fRec0[0];
fRec11[1] = fRec11[0];
}
}

};


#endif

+ 96
- 0
ports/temper/source/TemperLookAndFeel.cpp View File

@@ -0,0 +1,96 @@
/*
==============================================================================
TemperLookAndFeel.cpp
Created: 1 Mar 2017 8:15:09pm
Author: Nick Thompson
==============================================================================
*/
#include "TemperLookAndFeel.h"
TemperLookAndFeel::TemperLookAndFeel()
{
setColour(Slider::rotarySliderFillColourId, Colour::fromRGBA(226, 115, 0, 255));
}
Font TemperLookAndFeel::getBaseFont()
{
return Font(Typeface::createSystemTypefaceFor(BinaryData::MontserratLight_otf,
BinaryData::MontserratLight_otfSize));
}
Font TemperLookAndFeel::getLabelFont(Label &)
{
return getBaseFont().withPointHeight(10);
}
Font TemperLookAndFeel::getSliderReadoutFont()
{
return getBaseFont().withPointHeight(14);
}
void TemperLookAndFeel::drawLabel(Graphics& g, Label& l)
{
Colour labelColour = Colour::fromRGB(149, 89, 17);
Font labelFont = getLabelFont(l);
g.setColour(labelColour);
g.setFont(labelFont);
Rectangle<int> textArea (l.getBorderSize().subtractedFrom (l.getLocalBounds()));
g.drawFittedText (l.getText(), textArea, l.getJustificationType(),
jmax (1, (int) (textArea.getHeight() / labelFont.getHeight())),
l.getMinimumHorizontalScale());
}
void TemperLookAndFeel::drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
const float rotaryStartAngle, const float rotaryEndAngle, Slider& slider)
{
const float radius = jmin (width / 2, height / 2) - 2.0f;
const float centreX = x + width * 0.5f;
const float centreY = y + height * 0.5f;
const float rx = centreX - radius;
const float ry = centreY - radius;
const float rw = radius * 2.0f;
const float angle = rotaryStartAngle + sliderPos * (rotaryEndAngle - rotaryStartAngle);
const bool isMouseOver = slider.isMouseOverOrDragging() && slider.isEnabled();
// Draw the readout
Colour readoutColour = Colour::fromRGB(254, 173, 29).withAlpha(isMouseOver ? 1.0f : 0.9f);
const double value = slider.getValue();
String readoutValue = (value >= 1000.0 ? String(value / 1000.0, 1) + "k" : String(value, 1));
String readout = readoutValue + slider.getTextValueSuffix();
g.setColour(readoutColour);
g.setFont(getSliderReadoutFont());
g.drawText(readout, centreX - radius, centreY - 10.0f, rw, 24.0f, Justification::centred);
// Draw the track
g.setColour (slider.findColour (Slider::rotarySliderOutlineColourId));
Path track;
track.addArc(rx, ry, rw, rw, rotaryStartAngle, rotaryEndAngle, true);
g.strokePath(track, PathStrokeType(3.0f));
// Draw the slider position
Colour sliderFillStart = Colour::fromRGBA(245, 121, 35, 255).withAlpha(isMouseOver ? 1.0f : 0.9f);
Colour sliderFillStop = Colour::fromRGBA(255, 184, 23, 255).withAlpha(isMouseOver ? 1.0f : 0.9f);
ColourGradient sliderFill = ColourGradient(sliderFillStart,
(float) x,
(float) 0,
sliderFillStop,
(float) width,
(float) 0,
false);
g.setGradientFill(sliderFill);
Path filledArc;
filledArc.addArc(rx, ry, rw, rw, rotaryStartAngle, angle, true);
PathStrokeType(3.0f).createStrokedPath(filledArc, filledArc);
g.fillPath(filledArc);
}

+ 31
- 0
ports/temper/source/TemperLookAndFeel.h View File

@@ -0,0 +1,31 @@
/*
==============================================================================
TemperLookAndFeel.h
Created: 1 Mar 2017 8:15:08pm
Author: Nick Thompson
==============================================================================
*/
#ifndef TEMPERLOOKANDFEEL_H_INCLUDED
#define TEMPERLOOKANDFEEL_H_INCLUDED
#include "JuceHeader.h"
class TemperLookAndFeel : public LookAndFeel_V2
{
public:
TemperLookAndFeel();
Font getBaseFont ();
Font getLabelFont (Label&) override;
Font getSliderReadoutFont ();
void drawLabel (Graphics&, Label&) override;
void drawRotarySlider (Graphics&, int x, int y, int width, int height,
float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle,
Slider&) override;
};
#endif // TEMPERLOOKANDFEEL_H_INCLUDED

+ 449
- 0
ports/temper/source/faust/au/AUUI.h View File

@@ -0,0 +1,449 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Audio Unit UI
Copyright (C) 2013 Reza Payami
All rights reserved.
----------------------------BSD License------------------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Remy Muller nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------Audio Unit SDK----------------------------------
In order to compile a AU (TM) Synth plugin with this architecture file
you will need the proprietary AU SDK from Apple. Please check
the corresponding license.
************************************************************************/
#include <set>

#include "faust/gui/UI.h"

using namespace std;

class auUI;

class auUIObject {
public:
string fLabel;
float* fZone;
float range(float min, float max, float val) { // AU parameters are normalized in the range [0;1]
val = min + val * (max - min);
return (val < min) ? min : (val > max) ? max : val;
}
public:
auUIObject(const char* label, FAUSTFLOAT* zone) :
fLabel(label), fZone(zone) {
}
virtual ~auUIObject() {
}
virtual void GetName(char *text) {
std::strcpy(text, fLabel.c_str());
}
virtual void SetValue(double f) {
*fZone = range(0.0f, 1.0f, (float) f);
}
virtual float GetValue() {
return *fZone;
}
virtual void GetDisplay(char *text) {
std::sprintf(text, "%f", *fZone);
}
virtual long GetID() { /* returns the sum of all the ASCII characters contained in the parameter's label */
int i;
long acc;
for (i = 0, acc = 0; i < fLabel.length(); i++)
acc += (fLabel.c_str())[i];
return acc;
}
};

/**********************************************************************************/
class auToggleButton: public auUIObject {
public:
auToggleButton(const char* label, FAUSTFLOAT* zone) :
auUIObject(label, zone) {
}
virtual ~auToggleButton() {
}
virtual float GetValue() {
return *fZone;
}
virtual void SetValue(double f) {
*fZone = (f > 0.5f) ? 1.0f : 0.0f;
}
virtual void GetDisplay(char *text) {
(*fZone > 0.5f) ? std::strcpy(text, "ON") : std::strcpy(text, "OFF");
}
};

/**********************************************************************************/
class auCheckButton: public auUIObject {
public:
auCheckButton(const char* label, FAUSTFLOAT* zone) :
auUIObject(label, zone) {
}
virtual ~auCheckButton() {
}
virtual float GetValue() {
return *fZone;
}
virtual void SetValue(double f) {
*fZone = (f > 0.5f) ? 1.0f : 0.0f;
}
virtual void GetDisplay(char *text) {
(*fZone > 0.5f) ? std::strcpy(text, "ON") : std::strcpy(text, "OFF");
}
};

/**********************************************************************************/
class auButton: public auUIObject {
public:
auButton(const char* label, FAUSTFLOAT* zone) :
auUIObject(label, zone) {
}
virtual ~auButton() {
}
virtual float GetValue() {
return *fZone;
}
virtual void SetValue(double f) {
*fZone = (f > 0.5f) ? 1.0f : 0.0f;
}
virtual void GetDisplay(char *text) {
(*fZone > 0.5f) ? std::strcpy(text, "ON") : std::strcpy(text, "OFF");
}
};

/**********************************************************************************/
class auSlider: public auUIObject {
public:
float fInit;
float fMin;
float fMax;
float fStep;
bool fIsVertical;
public:
auSlider(const char* label, FAUSTFLOAT* zone, float init, float min, float max,
float step, bool isVertical) :
auUIObject(label, zone), fInit(init), fMin(min), fMax(max), fStep(step), fIsVertical(isVertical) {
}
virtual ~auSlider() {
}
virtual float GetValue() {
return (*fZone - fMin) / (fMax - fMin);
} // normalize
virtual void SetValue(double f) {
*fZone = range(fMin, fMax, (float) f);
} // expand
};


/**********************************************************************************/


class auBargraph: public auUIObject {
public:
float fInit;
float fMin;
float fMax;
float fStep;
bool fIsVertical;
public:
auBargraph(const char* label, FAUSTFLOAT* zone, float min, float max, bool isVertical) :
auUIObject(label, zone), fMin(min), fMax(max), fIsVertical(isVertical){
}
virtual ~auBargraph() {
}
virtual float GetValue() {
return (*fZone - fMin) / (fMax - fMin);
} // normalize
virtual void SetValue(double f) {
*fZone = range(fMin, fMax, (float) f);
} // expand
};

/**********************************************************************************/

class auBox: public auUIObject {
public:
vector<auUIObject*> children;
bool isVertical;
auBox* parent;
public:
auBox(const char* label, auBox* inParent, bool inIsVertical) :
auUIObject(label, NULL), parent(inParent), isVertical(inIsVertical) {
}
void add(auUIObject* child) {
children.push_back(child);
}
virtual ~auBox() {
}
};


/**********************************************************************************/
//eunum Direction {HORIZONTAL, VERTICAL}; //TODO

class auUI: public UI {
public:
vector<auUIObject*> fUITable;
std::set <float*>knobSet;
auBox* currentBox = NULL;
auBox* boundingBox = NULL;
public:
auUI() {
currentBox = boundingBox = new auBox("", NULL, true);
}
virtual ~auUI() {
for (vector<auUIObject*>::iterator iter = fUITable.begin();
iter != fUITable.end(); iter++)
delete *iter;
//TODO delete boxes
}
virtual void declare(float* zone, const char* key, const char* value)
{
if (zone == 0)
{
if (strcmp(key, "hidden") == 0)
{

}
}
else
{
if (strcmp(key,"size") == 0)
{
}
else if (strcmp(key,"tooltip") == 0)
{
}
else if (strcmp(key,"unit") == 0)
{
}
if (strcmp(key,"hidden") == 0)
{

}
else if (strcmp(key,"style") == 0)
{
if (strstr(value, "knob")) //TODO
{
knobSet.insert(zone);
}
}
else if (strcmp(key,"color") == 0)
{
}
else if (strcmp(key,"accx") == 0
|| strcmp(key,"accy") == 0
|| strcmp(key,"accz") == 0
|| strcmp(key,"gyrox") == 0
|| strcmp(key,"gyroy") == 0
|| strcmp(key,"gyroz") == 0
|| strcmp(key,"compass") == 0)
{
}
}
}
void addButton(const char* label, FAUSTFLOAT* zone) {
auButton* button = new auButton(label, zone);
fUITable.push_back(button);
currentBox->add(button);
}
void openTabBox(const char* label) {
}
void addCheckButton(const char* label, FAUSTFLOAT* zone) {
auCheckButton* checkButton= new auCheckButton(label, zone);
fUITable.push_back(checkButton);
currentBox->add(checkButton);
}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, float init, float min,
float max, float step) {
auSlider* slider = new auSlider(label, zone, init, min, max, step, true);
fUITable.push_back(slider);
currentBox->add(slider);
}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, float init, float min,
float max, float step) {
auSlider* slider = new auSlider(label, zone, init, min, max, step, false);
fUITable.push_back(slider);
currentBox->add(slider);
}
void addNumEntry(const char* label, FAUSTFLOAT* zone, float init, float min, float max,
float step) {
auSlider* slider = new auSlider(label, zone, init, min, max, step, false);
fUITable.push_back(slider);
currentBox->add(slider);
}
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, float min, float max) {
auBargraph* bargraph = new auBargraph(label, zone, min, max, false);
fUITable.push_back(bargraph);
currentBox->add(bargraph);
}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, float min, float max) {
auBargraph* bargraph = new auBargraph(label, zone, min, max, true);
fUITable.push_back(bargraph);
currentBox->add(bargraph);
}
void openHorizontalBox(const char* label) {
auBox* box = new auBox(label, currentBox, false);
currentBox->add(box);
currentBox = box;
}
void openVerticalBox(const char* label) {
auBox* box = new auBox(label, currentBox, true);
currentBox->add(box);
currentBox = box;
}
void closeBox() {
if (currentBox) //TODO else?
currentBox = currentBox->parent;
}
void SetValue(int index, double f) {
assert(index < fUITable.size());
fUITable[index]->SetValue(f);
}
float GetValue(long index) {
assert(index < fUITable.size());
return fUITable[index]->GetValue();
}
void GetDisplay(long index, char *text) {
assert(index < fUITable.size());
fUITable[index]->GetDisplay(text);
}
void GetName(long index, char *text) {
assert(index < fUITable.size());
fUITable[index]->GetName(text);
}
long GetNumParams() {
return fUITable.size();
}
long makeID()
/* Creates a (unique) id by summing all the parameter's labels,
* then wrapping it in the range [0;maxNumberOfId] and adding
* this number to the offset made by the Four Character ID: 'FAUS'
*/
{
const long maxNumberOfId = 128;
long baseid = 'FAUS';
long id = 0;
for (int i = 0; i < fUITable.size(); i++)
id += fUITable[i]->GetID();
return baseid + id % maxNumberOfId;
}
void addNumDisplay(char* label, float* zone, int precision) {
}
void addTextDisplay(char* label, float* zone, char* names[], float min,
float max) {
}
};



+ 728
- 0
ports/temper/source/faust/audio/alsa-dsp.h View File

@@ -0,0 +1,728 @@
/************************************************************************

IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef __alsa_dsp__
#define __alsa_dsp__

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <pwd.h>
#include <limits.h>

#include <alsa/asoundlib.h>
#include "faust/audio/audio.h"
#include "faust/dsp/dsp.h"

/**
DEFAULT ALSA PARAMETERS CONTROLLED BY ENVIRONMENT VARIABLES

Some default parameters of Faust's ALSA applications are controlled by the following environment variables :

FAUST2ALSA_DEVICE = "hw:0"
FAUST2ALSA_FREQUENCY= 44100
FAUST2ALSA_BUFFER = 512
FAUST2ALSA_PERIODS = 2
*/

// handle 32/64 bits int size issues

#ifdef __x86_64__

#define uint32 unsigned int
#define uint64 unsigned long int

#define int32 int
#define int64 long int

#else

#define uint32 unsigned int
#define uint64 unsigned long long int

#define int32 int
#define int64 long long int
#endif

// check 32/64 bits issues are correctly handled

#define check_error(err) if (err) { printf("%s:%d, alsa error %d : %s\n", __FILE__, __LINE__, err, snd_strerror(err)); exit(1); }
#define check_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); exit(1); }
#define display_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); }

/**
* Used to set the priority and scheduling of the audi#include <sys/types.h>
#include <pwd.h>
o thread
*/
static bool setRealtimePriority ()
{
struct passwd * pw;
int err;
uid_t uid;
struct sched_param param;

uid = getuid ();
pw = getpwnam ("root");
err = setuid (pw->pw_uid);
if (err==0) {
param.sched_priority = 50; /* 0 to 99 */
err = sched_setscheduler(0, SCHED_RR, &param);
err = setuid (uid);
}
return (err != -1);
}

/******************************************************************************
*******************************************************************************

AUDIO INTERFACE

*******************************************************************************
*******************************************************************************/

enum { kRead = 1, kWrite = 2, kReadWrite = 3 };

/**
* A convenient class to pass parameters to AudioInterface
*/
struct AudioParam
{
const char* fCardName;
unsigned int fFrequency;
unsigned int fBuffering;
unsigned int fPeriods;

unsigned int fSoftInputs;
unsigned int fSoftOutputs;

AudioParam() :
fCardName("hw:0"),
fFrequency(44100),
fBuffering(512),
fPeriods(2),
fSoftInputs(2),
fSoftOutputs(2)
{}

AudioParam& cardName(const char* n) { fCardName = n; return *this; }
AudioParam& frequency(int f) { fFrequency = f; return *this; }
AudioParam& buffering(int fpb) { fBuffering = fpb; return *this; }
AudioParam& periods(int p) { fPeriods = p; return *this; }
AudioParam& inputs(int n) { fSoftInputs = n; return *this; }
AudioParam& outputs(int n) { fSoftOutputs = n; return *this; }
};

/**
* An ALSA audio interface
*/
struct AudioInterface : public AudioParam
{

snd_pcm_t* fOutputDevice;
snd_pcm_t* fInputDevice;
snd_pcm_hw_params_t* fInputParams;
snd_pcm_hw_params_t* fOutputParams;

snd_pcm_format_t fSampleFormat;
snd_pcm_access_t fSampleAccess;

unsigned int fCardInputs;
unsigned int fCardOutputs;

unsigned int fChanInputs;
unsigned int fChanOutputs;

bool fDuplexMode;

// interleaved mode audiocard buffers
void* fInputCardBuffer;
void* fOutputCardBuffer;

// non interleaved mode audiocard buffers
void* fInputCardChannels[256];
void* fOutputCardChannels[256];

// non interleaved mod, floating point software buffers
float* fInputSoftChannels[256];
float* fOutputSoftChannels[256];

const char* cardName() { return fCardName; }
int frequency() { return fFrequency; }
int buffering() { return fBuffering; }
int periods() { return fPeriods; }

float** inputSoftChannels() { return fInputSoftChannels; }
float** outputSoftChannels() { return fOutputSoftChannels; }

bool duplexMode() { return fDuplexMode; }

AudioInterface(const AudioParam& ap = AudioParam()) : AudioParam(ap)
{

fInputDevice = 0;
fOutputDevice = 0;
fInputParams = 0;
fOutputParams = 0;
}

/**
* Open the audio interface
*/
void open()
{
int err;

// try to open output device, quit if fail to open output device
err = snd_pcm_open( &fOutputDevice, fCardName, SND_PCM_STREAM_PLAYBACK, 0 ); check_error(err)

// setup output device parameters
err = snd_pcm_hw_params_malloc ( &fOutputParams ); check_error(err)
setAudioParams(fOutputDevice, fOutputParams);

fCardOutputs = fSoftOutputs;
snd_pcm_hw_params_set_channels_near(fOutputDevice, fOutputParams, &fCardOutputs);
err = snd_pcm_hw_params (fOutputDevice, fOutputParams ); check_error(err);

// allocate alsa output buffers
if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
fOutputCardBuffer = calloc(interleavedBufferSize(fOutputParams), 1);
} else {
for (unsigned int i = 0; i < fCardOutputs; i++) {
fOutputCardChannels[i] = calloc(noninterleavedBufferSize(fOutputParams), 1);
}
}

// check for duplex mode (if we need and have an input device)
if (fSoftInputs == 0) {
fDuplexMode = false;
fCardInputs = 0;
} else {
// try to open input device
err = snd_pcm_open( &fInputDevice, fCardName, SND_PCM_STREAM_CAPTURE, 0 );
if (err == 0) {
fDuplexMode = true;
} else {
printf("Warning : no input device");
fDuplexMode = false;
fCardInputs = 0;
}
}

if (fDuplexMode) {

// we have and need an input device
// set the number of physical inputs close to what we need
err = snd_pcm_hw_params_malloc ( &fInputParams ); check_error(err);
setAudioParams(fInputDevice, fInputParams);
fCardInputs = fSoftInputs;
snd_pcm_hw_params_set_channels_near(fInputDevice, fInputParams, &fCardInputs);
err = snd_pcm_hw_params (fInputDevice, fInputParams ); check_error(err);

// allocation of alsa buffers
if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
fInputCardBuffer = calloc(interleavedBufferSize(fInputParams), 1);
} else {
for (unsigned int i = 0; i < fCardInputs; i++) {
fInputCardChannels[i] = calloc(noninterleavedBufferSize(fInputParams), 1);
}
}
}

printf("inputs : %u, outputs : %u\n", fCardInputs, fCardOutputs);

// allocation of floating point buffers needed by the dsp code

fChanInputs = max(fSoftInputs, fCardInputs); assert (fChanInputs < 256);
fChanOutputs = max(fSoftOutputs, fCardOutputs); assert (fChanOutputs < 256);

for (unsigned int i = 0; i < fChanInputs; i++) {
fInputSoftChannels[i] = (float*) calloc (fBuffering, sizeof(float));
for (unsigned int j = 0; j < fBuffering; j++) {
fInputSoftChannels[i][j] = 0.0;
}
}

for (unsigned int i = 0; i < fChanOutputs; i++) {
fOutputSoftChannels[i] = (float*) calloc (fBuffering, sizeof(float));
for (unsigned int j = 0; j < fBuffering; j++) {
fOutputSoftChannels[i][j] = 0.0;
}
}
}

void setAudioParams(snd_pcm_t* stream, snd_pcm_hw_params_t* params)
{
int err;

// set params record with initial values
err = snd_pcm_hw_params_any ( stream, params );
check_error_msg(err, "unable to init parameters")

// set alsa access mode (and fSampleAccess field) either to non interleaved or interleaved

err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
if (err) {
err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_INTERLEAVED );
check_error_msg(err, "unable to set access mode neither to non-interleaved or to interleaved");
}
snd_pcm_hw_params_get_access(params, &fSampleAccess);

// search for 32-bits or 16-bits format
err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S32);
if (err) {
err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S16);
check_error_msg(err, "unable to set format to either 32-bits or 16-bits");
}
snd_pcm_hw_params_get_format(params, &fSampleFormat);
// set sample frequency
snd_pcm_hw_params_set_rate_near (stream, params, &fFrequency, 0);

// set period and period size (buffering)
err = snd_pcm_hw_params_set_period_size (stream, params, fBuffering, 0);
check_error_msg(err, "period size not available");

err = snd_pcm_hw_params_set_periods (stream, params, fPeriods, 0);
check_error_msg(err, "number of periods not available");
}

ssize_t interleavedBufferSize (snd_pcm_hw_params_t* params)
{
_snd_pcm_format format; snd_pcm_hw_params_get_format(params, &format);
snd_pcm_uframes_t psize; snd_pcm_hw_params_get_period_size(params, &psize, NULL);
unsigned int channels; snd_pcm_hw_params_get_channels(params, &channels);
ssize_t bsize = snd_pcm_format_size (format, psize * channels);
return bsize;
}

ssize_t noninterleavedBufferSize (snd_pcm_hw_params_t* params)
{
_snd_pcm_format format; snd_pcm_hw_params_get_format(params, &format);
snd_pcm_uframes_t psize; snd_pcm_hw_params_get_period_size(params, &psize, NULL);
ssize_t bsize = snd_pcm_format_size (format, psize);
return bsize;
}

void close()
{}

/**
* Read audio samples from the audio card. Convert samples to floats and take
* care of interleaved buffers
*/
void read()
{
if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {

int count = snd_pcm_readi(fInputDevice, fInputCardBuffer, fBuffering);
if (count < 0) {
//display_error_msg(count, "reading samples");
snd_pcm_prepare(fInputDevice);
//check_error_msg(err, "preparing input stream");
}

if (fSampleFormat == SND_PCM_FORMAT_S16) {

short* buffer16b = (short*)fInputCardBuffer;
for (unsigned int s = 0; s < fBuffering; s++) {
for (unsigned int c = 0; c < fCardInputs; c++) {
fInputSoftChannels[c][s] = float(buffer16b[c + s*fCardInputs])*(1.0/float(SHRT_MAX));
}
}

} else if (fSampleFormat == SND_PCM_FORMAT_S32) {

int32* buffer32b = (int32*)fInputCardBuffer;
for (unsigned int s = 0; s < fBuffering; s++) {
for (unsigned int c = 0; c < fCardInputs; c++) {
fInputSoftChannels[c][s] = float(buffer32b[c + s*fCardInputs])*(1.0/float(INT_MAX));
}
}
} else {

printf("unrecognized input sample format : %u\n", fSampleFormat);
exit(1);
}

} else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) {

int count = snd_pcm_readn(fInputDevice, fInputCardChannels, fBuffering);
if (count < 0) {
//display_error_msg(count, "reading samples");
snd_pcm_prepare(fInputDevice);
//check_error_msg(err, "preparing input stream");
}

if (fSampleFormat == SND_PCM_FORMAT_S16) {

for (unsigned int c = 0; c < fCardInputs; c++) {
short* chan16b = (short*)fInputCardChannels[c];
for (unsigned int s = 0; s < fBuffering; s++) {
fInputSoftChannels[c][s] = float(chan16b[s])*(1.0/float(SHRT_MAX));
}
}

} else if (fSampleFormat == SND_PCM_FORMAT_S32) {

for (unsigned int c = 0; c < fCardInputs; c++) {
int32* chan32b = (int32*)fInputCardChannels[c];
for (unsigned int s = 0; s < fBuffering; s++) {
fInputSoftChannels[c][s] = float(chan32b[s])*(1.0/float(INT_MAX));
}
}
} else {
printf("unrecognized input sample format : %u\n", fSampleFormat);
exit(1);
}

} else {
check_error_msg(-10000, "unknown access mode");
}
}

/**
* write the output soft channels to the audio card. Convert sample
* format and interleaves buffers when needed
*/
void write()
{
recovery :

if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {

if (fSampleFormat == SND_PCM_FORMAT_S16) {

short* buffer16b = (short*)fOutputCardBuffer;
for (unsigned int f = 0; f < fBuffering; f++) {
for (unsigned int c = 0; c < fCardOutputs; c++) {
float x = fOutputSoftChannels[c][f];
buffer16b[c + f*fCardOutputs] = short( max(min(x,1.0f),-1.0f) * float(SHRT_MAX) ) ;
}
}

} else if (fSampleFormat == SND_PCM_FORMAT_S32) {

int32* buffer32b = (int32*)fOutputCardBuffer;
for (unsigned int f = 0; f < fBuffering; f++) {
for (unsigned int c = 0; c < fCardOutputs; c++) {
float x = fOutputSoftChannels[c][f];
buffer32b[c + f*fCardOutputs] = int( max(min(x,1.0f),-1.0f) * float(INT_MAX) ) ;
}
}
} else {

printf("unrecognized output sample format : %u\n", fSampleFormat);
exit(1);
}

int count = snd_pcm_writei(fOutputDevice, fOutputCardBuffer, fBuffering);
if (count<0) {
//display_error_msg(count, "w3");
snd_pcm_prepare(fOutputDevice);
//check_error_msg(err, "preparing output stream");
goto recovery;
}


} else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) {

if (fSampleFormat == SND_PCM_FORMAT_S16) {

for (unsigned int c = 0; c < fCardOutputs; c++) {
short* chan16b = (short*) fOutputCardChannels[c];
for (unsigned int f = 0; f < fBuffering; f++) {
float x = fOutputSoftChannels[c][f];
chan16b[f] = short( max(min(x,1.0f),-1.0f) * float(SHRT_MAX) ) ;
}
}

} else if (fSampleFormat == SND_PCM_FORMAT_S32) {

for (unsigned int c = 0; c < fCardOutputs; c++) {
int32* chan32b = (int32*) fOutputCardChannels[c];
for (unsigned int f = 0; f < fBuffering; f++) {
float x = fOutputSoftChannels[c][f];
chan32b[f] = int( max(min(x,1.0f),-1.0f) * float(INT_MAX) ) ;
}
}

} else {

printf("unrecognized output sample format : %u\n", fSampleFormat);
exit(1);
}

int count = snd_pcm_writen(fOutputDevice, fOutputCardChannels, fBuffering);
if (count<0) {
//display_error_msg(count, "w3");
snd_pcm_prepare(fOutputDevice);
//check_error_msg(err, "preparing output stream");
goto recovery;
}

} else {
check_error_msg(-10000, "unknown access mode");
}
}

/**
* print short information on the audio device
*/
void shortinfo()
{
int err;
snd_ctl_card_info_t* card_info;
snd_ctl_t* ctl_handle;
err = snd_ctl_open (&ctl_handle, fCardName, 0); check_error(err);
snd_ctl_card_info_alloca (&card_info);
err = snd_ctl_card_info(ctl_handle, card_info); check_error(err);
printf("%s|%d|%d|%d|%d|%s\n",
snd_ctl_card_info_get_driver(card_info),
fCardInputs, fCardOutputs,
fFrequency, fBuffering,
snd_pcm_format_name((_snd_pcm_format)fSampleFormat));
}

/**
* print more detailled information on the audio device
*/
void longinfo()
{
int err;
snd_ctl_card_info_t* card_info;
snd_ctl_t* ctl_handle;

printf("Audio Interface Description :\n");
printf("Sampling Frequency : %d, Sample Format : %s, buffering : %d\n",
fFrequency, snd_pcm_format_name((_snd_pcm_format)fSampleFormat), fBuffering);
printf("Software inputs : %2d, Software outputs : %2d\n", fSoftInputs, fSoftOutputs);
printf("Hardware inputs : %2d, Hardware outputs : %2d\n", fCardInputs, fCardOutputs);
printf("Channel inputs : %2d, Channel outputs : %2d\n", fChanInputs, fChanOutputs);

// affichage des infos de la carte
err = snd_ctl_open (&ctl_handle, fCardName, 0); check_error(err);
snd_ctl_card_info_alloca (&card_info);
err = snd_ctl_card_info(ctl_handle, card_info); check_error(err);
printCardInfo(card_info);

// affichage des infos liees aux streams d'entree-sortie
if (fSoftInputs > 0) printHWParams(fInputParams);
if (fSoftOutputs > 0) printHWParams(fOutputParams);
}

void printCardInfo(snd_ctl_card_info_t* ci)
{
printf("Card info (address : %p)\n", ci);
printf("\tID = %s\n", snd_ctl_card_info_get_id(ci));
printf("\tDriver = %s\n", snd_ctl_card_info_get_driver(ci));
printf("\tName = %s\n", snd_ctl_card_info_get_name(ci));
printf("\tLongName = %s\n", snd_ctl_card_info_get_longname(ci));
printf("\tMixerName = %s\n", snd_ctl_card_info_get_mixername(ci));
printf("\tComponents = %s\n", snd_ctl_card_info_get_components(ci));
printf("--------------\n");
}

void printHWParams( snd_pcm_hw_params_t* params )
{
printf("HW Params info (address : %p)\n", params);
#if 0
printf("\tChannels = %d\n", snd_pcm_hw_params_get_channels(params));
printf("\tFormat = %s\n", snd_pcm_format_name((_snd_pcm_format)snd_pcm_hw_params_get_format(params)));
printf("\tAccess = %s\n", snd_pcm_access_name((_snd_pcm_access)snd_pcm_hw_params_get_access(params)));
printf("\tRate = %d\n", snd_pcm_hw_params_get_rate(params, NULL));
printf("\tPeriods = %d\n", snd_pcm_hw_params_get_periods(params, NULL));
printf("\tPeriod size = %d\n", (int)snd_pcm_hw_params_get_period_size(params, NULL));
printf("\tPeriod time = %d\n", snd_pcm_hw_params_get_period_time(params, NULL));
printf("\tBuffer size = %d\n", (int)snd_pcm_hw_params_get_buffer_size(params));
printf("\tBuffer time = %d\n", snd_pcm_hw_params_get_buffer_time(params, NULL));
#endif
printf("--------------\n");
}

};

// lopt : Scan Command Line long int Arguments
long lopt(int argc, char *argv[], const char* longname, const char* shortname, long def)
{
for (int i=2; i<argc; i++)
if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
return atoi(argv[i]);
return def;
}

// sopt : Scan Command Line string Arguments
const char* sopt(int argc, char *argv[], const char* longname, const char* shortname, const char* def)
{
for (int i=2; i<argc; i++)
if ( strcmp(argv[i-1], shortname) == 0 || strcmp(argv[i-1], longname) == 0 )
return argv[i];
return def;
}

// fopt : Scan Command Line flag option (without argument), return true if the flag
bool fopt(int argc, char *argv[], const char* longname, const char* shortname)
{
for (int i=1; i<argc; i++)
if ( strcmp(argv[i], shortname) == 0 || strcmp(argv[i], longname) == 0 )
return true;
return false;
}

/**
* Return the value of an environment variable or defval if undefined.
*/
static int getDefaultEnv(const char* name, int defval)
{
const char* str = getenv(name);
if (str) {
return atoi(str);
} else {
return defval;
}
}

/**
* Return the value of an environment variable or defval if undefined.
*/
static const char* getDefaultEnv(const char* name, const char* defval)
{
const char* str = getenv(name);
if (str) {
return str;
} else {
return defval;
}
}

/******************************************************************************
*******************************************************************************

ALSA audio interface

*******************************************************************************
*******************************************************************************/
static void* __run(void* ptr);

class alsaaudio : public audio
{
AudioInterface* fAudio;
dsp* fDSP;
pthread_t fAudioThread;
bool fRunning;

public:

alsaaudio(int argc, char *argv[], dsp* DSP) : fDSP(DSP), fRunning(false)
{
fAudio = new AudioInterface(AudioParam().cardName(sopt(argc, argv, "--device", "-d", getDefaultEnv("FAUST2ALSA_DEVICE", "hw:0")))
.frequency(lopt(argc, argv, "--frequency", "-f", getDefaultEnv("FAUST2ALSA_FREQUENCY", 44100)))
.buffering(lopt(argc, argv, "--buffer", "-b", getDefaultEnv("FAUST2ALSA_BUFFER", 512)))
.periods(lopt(argc, argv, "--periods", "-p", getDefaultEnv("FAUST2ALSA_PERIODS", 2)))
.inputs(DSP->getNumInputs())
.outputs(DSP->getNumOutputs()));
}
alsaaudio(int srate, int bsize) : fDSP(0), fRunning(false)
{
fAudio = new AudioInterface(AudioParam().cardName("hw:0")
.frequency(srate)
.buffering(bsize)
.periods(2));
}

virtual ~alsaaudio() { stop(); delete fAudio; }

virtual bool init(const char */*name*/, dsp* DSP)
{
fAudio->inputs(DSP->getNumInputs());
fAudio->outputs(DSP->getNumOutputs());
fAudio->open();
DSP->init(fAudio->frequency());
return true;
}

virtual bool start()
{
fRunning = true;
if (pthread_create(&fAudioThread, 0, __run, this)) {
fRunning = false;
}
return fRunning;
}

virtual void stop() {
if (fRunning) {
fRunning = false;
pthread_join(fAudioThread, 0);
}
}
virtual int get_buffer_size() { return fAudio->buffering(); }
virtual int get_sample_rate() { return fAudio->frequency(); }

virtual void run() {
bool rt = setRealtimePriority();
printf(rt ? "RT : ":"NRT: "); fAudio->shortinfo();
AVOIDDENORMALS;
if (fAudio->duplexMode()) {
fAudio->write();
fAudio->write();
while (fRunning) {
fAudio->read();
fDSP->compute(fAudio->buffering(), fAudio->inputSoftChannels(), fAudio->outputSoftChannels());
fAudio->write();
}
} else {
fAudio->write();
while (fRunning) {
fDSP->compute(fAudio->buffering(), fAudio->inputSoftChannels(), fAudio->outputSoftChannels());
fAudio->write();
}
}
}
};

void* __run (void* ptr)
{
alsaaudio * alsa = (alsaaudio*)ptr;
alsa->run();
return 0;
}

#endif

/********************END ARCHITECTURE SECTION (part 2/2)****************/


+ 479
- 0
ports/temper/source/faust/audio/android-dsp.h View File

@@ -0,0 +1,479 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2015-2015 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.
************************************************************************
*************************************************************************/

#ifndef __android_dsp__
#define __android_dsp__

#include <android/log.h>
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <time.h>

#include "faust/audio/audio.h"

#define CONV16BIT 32767.f
#define CONVMYFLT (1.f/32767.f)

#define NUM_INPUTS 2
#define NUM_OUTPUTS 2
#define CPU_TABLE_SIZE 16

struct CircularBuffer {
short* fBuffer;
int fReadIndex;
int fWriteIndex;
int fSize;
int fChan;
CircularBuffer(int frames, int chan)
{
fBuffer = new short[frames * chan];
memset(fBuffer, 0, sizeof(short) * frames * chan);
fSize = frames;
fChan = chan;
fReadIndex = 0;
fWriteIndex = frames/2; // Set write index in the middle
}
~CircularBuffer()
{
delete [] fBuffer;
}
short* getWritePtr() { return &fBuffer[fWriteIndex * fChan]; }
short* getReadPtr() { return &fBuffer[fReadIndex * fChan]; }
void moveWritePtr(int frames)
{
//__android_log_print(ANDROID_LOG_ERROR, "Faust", "moveWritePtr %x fWriteIndex = %ld", this, fWriteIndex);
fWriteIndex = (fWriteIndex + frames) % fSize;
}
void moveReadPtr(int frames)
{
//__android_log_print(ANDROID_LOG_ERROR, "Faust", "moveReadPtr %x fReadIndex = %ld", this, fReadIndex);
fReadIndex = (fReadIndex + frames) % fSize;
}
};

//http://stackoverflow.com/questions/17188761/how-to-obtain-computation-time-in-ndk

class androidaudio : public audio {
protected:
dsp* fDsp;
int fNumInChans;
int fNumOutChans;
unsigned int fSampleRate;
unsigned int fBufferSize;
int64_t fCPUTable[CPU_TABLE_SIZE];
int fCPUTableIndex;
float** fInputs;
float** fOutputs;
CircularBuffer fOpenSLInputs;
CircularBuffer fOpenSLOutputs;
SLObjectItf fOpenSLEngine, fOutputMix, fInputBufferQueue, fOutputBufferQueue;
SLAndroidSimpleBufferQueueItf fOutputBufferQueueInterface, fInputBufferQueueInterface;
SLRecordItf fRecordInterface;
SLPlayItf fPlayInterface;
int64_t getTimeUsec()
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
return ((int64_t) now.tv_sec * 1000000000LL + now.tv_nsec)/1000;
}
void processAudio()
{
int64_t t1 = getTimeUsec();
// Converting short input to float
if (fNumInChans > 0) {
short* input = fOpenSLInputs.getReadPtr();
for (int chan = 0; chan < NUM_INPUTS; chan++) {
for (int i = 0; i < fBufferSize; i++) {
fInputs[chan][i] = float(input[i * NUM_INPUTS + chan] * CONVMYFLT);
}
}
fOpenSLInputs.moveReadPtr(fBufferSize);
}
// Compute DSP
fDsp->compute(fBufferSize, fInputs, fOutputs);
// Converting float to short output
if (fNumOutChans > 0) {
short* output = fOpenSLOutputs.getWritePtr();
for (int chan = 0; chan < NUM_OUTPUTS; chan++) {
for (int i = 0; i < fBufferSize; i++) {
output[i * NUM_OUTPUTS + chan] = short(min(1.f, max(-1.f, fOutputs[chan][i])) * CONV16BIT);
}
}
fOpenSLOutputs.moveWritePtr(fBufferSize);
}
int64_t t2 = getTimeUsec();
fCPUTable[(fCPUTableIndex++)&(CPU_TABLE_SIZE-1)] = t2 - t1;
}
static void inputCallback(SLAndroidSimpleBufferQueueItf caller, void* arg)
{
androidaudio* obj = (androidaudio*)arg;
obj->inputCallback(caller);
}
void inputCallback(SLAndroidSimpleBufferQueueItf caller)
{
SLresult result = (*caller)->Enqueue(caller, fOpenSLInputs.getWritePtr(), fBufferSize * sizeof(short) * NUM_INPUTS);
fOpenSLInputs.moveWritePtr(fBufferSize);
if (result != SL_RESULT_SUCCESS) {
__android_log_print(ANDROID_LOG_ERROR, "Faust", "inputCallback Enqueue error = %d", int(result));
}
}
static void outputCallback(SLAndroidSimpleBufferQueueItf caller, void* arg)
{
androidaudio* obj = (androidaudio*)arg;
obj->outputCallback(caller);
}
void outputCallback(SLAndroidSimpleBufferQueueItf caller)
{
// Output callback drives DSP computation
processAudio();
SLresult result = (*caller)->Enqueue(caller, fOpenSLOutputs.getReadPtr(), fBufferSize * sizeof(short) * NUM_OUTPUTS);
fOpenSLOutputs.moveReadPtr(fBufferSize);
if (result != SL_RESULT_SUCCESS) {
__android_log_print(ANDROID_LOG_ERROR, "Faust", "outputCallback Enqueue error = %d", int(result));
}
}
public:
androidaudio(long srate, long bsize)
: fDsp(0), fSampleRate(srate),
fBufferSize(bsize), fCPUTableIndex(0), fNumInChans(0), fNumOutChans(0),
fOpenSLEngine(0), fOutputMix(0), fInputBufferQueue(0), fOutputBufferQueue(0),
fOpenSLInputs(bsize * 4, NUM_INPUTS), fOpenSLOutputs(bsize * 4, NUM_OUTPUTS)
{
__android_log_print(ANDROID_LOG_ERROR, "Faust", "Constructor");
// Allocating memory for input channels.
fInputs = new float*[NUM_INPUTS];
for (int i = 0; i < NUM_INPUTS; i++) {
fInputs[i] = new float[fBufferSize];
memset(fInputs[i], 0, fBufferSize * sizeof(float));
}
// Allocating memory for output channels.
fOutputs = new float*[NUM_OUTPUTS];
for (int i = 0; i < NUM_OUTPUTS; i++) {
fOutputs[i] = new float[fBufferSize];
memset(fOutputs[i], 0, fBufferSize * sizeof(float));
}
}

virtual ~androidaudio()
{
__android_log_print(ANDROID_LOG_ERROR, "Faust", "Destructor");
if (fInputBufferQueue) {
(*fInputBufferQueue)->Destroy(fInputBufferQueue);
fInputBufferQueue = NULL;
}
if (fOutputBufferQueue) {
(*fOutputBufferQueue)->Destroy(fOutputBufferQueue);
fOutputBufferQueue = NULL;
}
if (fOutputMix) {
(*fOutputMix)->Destroy(fOutputMix);
fOutputMix = NULL;
}
if (fOpenSLEngine) {
(*fOpenSLEngine)->Destroy(fOpenSLEngine);
fOpenSLEngine = NULL;
}
for (int i = 0; i < NUM_INPUTS; i++) {
delete [] fInputs[i];
}
delete [] fInputs;
for (int i = 0; i < NUM_OUTPUTS; i++) {
delete [] fOutputs[i];
}
delete [] fOutputs;
}
// DSP CPU load in percentage of the buffer size duration
float getCPULoad()
{
float sum = 0.f;
for (int i = 0; i < CPU_TABLE_SIZE; i++) {
sum += fCPUTable[i];
}
return (sum/float(CPU_TABLE_SIZE))/(10000.f*float(fBufferSize)/float(fSampleRate));
}
virtual bool init(const char* name, dsp* DSP)
{
__android_log_print(ANDROID_LOG_ERROR, "Faust", "init");
fDsp = DSP;
fNumInChans = fDsp->getNumInputs();
fNumOutChans = fDsp->getNumOutputs();
fDsp->init(fSampleRate);
static const SLboolean requireds[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
SLresult result;
SLuint32 sr;
switch (fSampleRate) {
case 8000:
sr = SL_SAMPLINGRATE_8;
break;
case 11025:
sr = SL_SAMPLINGRATE_11_025;
break;
case 16000:
sr = SL_SAMPLINGRATE_16;
break;
case 22050:
sr = SL_SAMPLINGRATE_22_05;
break;
case 24000:
sr = SL_SAMPLINGRATE_24;
break;
case 32000:
sr = SL_SAMPLINGRATE_32;
break;
case 44100:
sr = SL_SAMPLINGRATE_44_1;
break;
case 48000:
sr = SL_SAMPLINGRATE_48;
break;
case 64000:
sr = SL_SAMPLINGRATE_64;
break;
case 88200:
sr = SL_SAMPLINGRATE_88_2;
break;
case 96000:
sr = SL_SAMPLINGRATE_96;
break;
case 192000:
sr = SL_SAMPLINGRATE_192;
break;
default:
return false;
}
// Create the OpenSL ES engine.
result = slCreateEngine(&fOpenSLEngine, 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fOpenSLEngine)->Realize(fOpenSLEngine, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) return false;
SLEngineItf openSLEngineInterface = NULL;
result = (*fOpenSLEngine)->GetInterface(fOpenSLEngine, SL_IID_ENGINE, &openSLEngineInterface);
if (result != SL_RESULT_SUCCESS) return false;
// Create the output mix.
result = (*openSLEngineInterface)->CreateOutputMix(openSLEngineInterface, &fOutputMix, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fOutputMix)->Realize(fOutputMix, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) return false;
SLDataLocator_OutputMix outputMixLocator = { SL_DATALOCATOR_OUTPUTMIX, fOutputMix };
if (fNumInChans > 0) {
// Create the input buffer queue.
SLDataLocator_IODevice deviceInputLocator = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
SLDataSource inputSource = { &deviceInputLocator, NULL };
SLDataLocator_AndroidSimpleBufferQueue inputLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
SLDataFormat_PCM inputFormat = { SL_DATAFORMAT_PCM, 2, sr, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN };
SLDataSink inputSink = { &inputLocator, &inputFormat };
const SLInterfaceID inputInterfaces[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
result = (*openSLEngineInterface)->CreateAudioRecorder(openSLEngineInterface, &fInputBufferQueue, &inputSource, &inputSink, 2, inputInterfaces, requireds);
if (result != SL_RESULT_SUCCESS) return false;
#if DISABLE_AGC
SLAndroidConfigurationItf configObject;
result = (*fInputBufferQueue)->GetInterface(fInputBufferQueue, SL_IID_ANDROIDCONFIGURATION, &configObject);
if (result == SL_RESULT_SUCCESS) {
//SLuint32 mode = SL_ANDROID_RECORDING_PRESET_GENERIC;
SLuint32 mode = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
result = (*configObject)->SetConfiguration(configObject, SL_ANDROID_KEY_RECORDING_PRESET, &mode, sizeof(mode));
if (result != SL_RESULT_SUCCESS) {
__android_log_print(ANDROID_LOG_ERROR, "Faust", "SetConfiguration SL_ANDROID_KEY_RECORDING_PRESET error %d", result);
}
} else {
__android_log_print(ANDROID_LOG_ERROR, "Faust", "GetInterface SL_IID_ANDROIDCONFIGURATION error %d", result);
}
#endif
result = (*fInputBufferQueue)->Realize(fInputBufferQueue, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) return false;
}
if (fNumOutChans > 0) {
// Create the output buffer queue.
SLDataLocator_AndroidSimpleBufferQueue outputLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
SLDataFormat_PCM outputFormat = { SL_DATAFORMAT_PCM, 2, sr, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, SL_BYTEORDER_LITTLEENDIAN };
SLDataSource outputSource = { &outputLocator, &outputFormat };
const SLInterfaceID outputInterfaces[1] = { SL_IID_BUFFERQUEUE };
SLDataSink outputSink = { &outputMixLocator, NULL };
result = (*openSLEngineInterface)->CreateAudioPlayer(openSLEngineInterface, &fOutputBufferQueue, &outputSource, &outputSink, 1, outputInterfaces, requireds);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fOutputBufferQueue)->Realize(fOutputBufferQueue, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS) return false;
}
if (fNumInChans > 0) { // Initialize
result = (*fInputBufferQueue)->GetInterface(fInputBufferQueue, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &fInputBufferQueueInterface);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fInputBufferQueueInterface)->RegisterCallback(fInputBufferQueueInterface, inputCallback, this);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fInputBufferQueue)->GetInterface(fInputBufferQueue, SL_IID_RECORD, &fRecordInterface);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fInputBufferQueueInterface)->Enqueue(fInputBufferQueueInterface,
fOpenSLInputs.getWritePtr(),
fBufferSize * sizeof(short) * NUM_INPUTS);
fOpenSLInputs.moveWritePtr(fBufferSize);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fRecordInterface)->SetRecordState(fRecordInterface, SL_RECORDSTATE_STOPPED);
if (result != SL_RESULT_SUCCESS) __android_log_print(ANDROID_LOG_ERROR, "Faust", "stop: SetRecordState error");
}
if (fNumOutChans > 0) { // Initialize
result = (*fOutputBufferQueue)->GetInterface(fOutputBufferQueue, SL_IID_BUFFERQUEUE, &fOutputBufferQueueInterface);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fOutputBufferQueueInterface)->RegisterCallback(fOutputBufferQueueInterface, outputCallback, this);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fOutputBufferQueue)->GetInterface(fOutputBufferQueue, SL_IID_PLAY, &fPlayInterface);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fOutputBufferQueueInterface)->Enqueue(fOutputBufferQueueInterface,
fOpenSLOutputs.getReadPtr(),
fBufferSize * sizeof(short) * NUM_OUTPUTS);
fOpenSLOutputs.moveReadPtr(fBufferSize);
if (result != SL_RESULT_SUCCESS) return false;
result = (*fPlayInterface)->SetPlayState(fPlayInterface, SL_PLAYSTATE_STOPPED);
if (result != SL_RESULT_SUCCESS) __android_log_print(ANDROID_LOG_ERROR, "Faust", "stop: SetPlayState error");
}
return true;
}
virtual bool start()
{
__android_log_print(ANDROID_LOG_ERROR, "Faust", "start");
SLresult result;
if (fNumInChans > 0) {
// start the inout buffer queue.
result = (*fRecordInterface)->SetRecordState(fRecordInterface, SL_RECORDSTATE_RECORDING);
if (result != SL_RESULT_SUCCESS) return false;
}
if (fNumOutChans > 0) {
// start the output buffer queue.
result = (*fPlayInterface)->SetPlayState(fPlayInterface, SL_PLAYSTATE_PLAYING);
if (result != SL_RESULT_SUCCESS) return false;
}
return true;
}
virtual void stop()
{
__android_log_print(ANDROID_LOG_ERROR, "Faust", "stop");
SLresult result;
if (fNumInChans > 0) {
result = (*fRecordInterface)->SetRecordState(fRecordInterface, SL_RECORDSTATE_PAUSED);
if (result != SL_RESULT_SUCCESS) __android_log_print(ANDROID_LOG_ERROR, "Faust", "stop: SetRecordState error");
}
if (fNumOutChans > 0) {
result = (*fPlayInterface)->SetPlayState(fPlayInterface, SL_PLAYSTATE_PAUSED);
if (result != SL_RESULT_SUCCESS) __android_log_print(ANDROID_LOG_ERROR, "Faust", "stop: SetPlayState error");
}
}
virtual int get_buffer_size()
{
return fBufferSize;
}
virtual int get_sample_rate()
{
return fSampleRate;
}
virtual int get_num_inputs()
{
return fNumInChans;
}
virtual int get_num_outputs()
{
return fNumOutChans;
}
};

#endif

+ 71
- 0
ports/temper/source/faust/audio/audio.h View File

@@ -0,0 +1,71 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
/******************************************************************************
*******************************************************************************

An abstraction layer over audio layer

*******************************************************************************
*******************************************************************************/

#ifndef __audio__
#define __audio__
class dsp;

typedef void (* shutdown_callback)(const char* message, void* arg);

class audio {
public:
audio() {}
virtual ~audio() {}
virtual bool init(const char* name, dsp*) = 0;
virtual bool start() = 0;
virtual void stop() = 0;
virtual void shutdown(shutdown_callback cb, void* arg) {}
virtual int get_buffer_size() = 0;
virtual int get_sample_rate() = 0;
virtual int get_num_inputs() { return -1; }
virtual int get_num_outputs() { return -1; }
virtual float get_cpu_load() { return 0.f; }
};
#endif

+ 95
- 0
ports/temper/source/faust/audio/channels.h View File

@@ -0,0 +1,95 @@
/************************************************************************
************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

************************************************************************
************************************************************************/

#ifndef __audio_channels__
#define __audio_channels__

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

class channels
{
private:
int fNumFrames;
int fNumChannels;
FAUSTFLOAT** fBuffers;

public:

channels(int nframes, int nchannels)
{
fBuffers = new FAUSTFLOAT*[nchannels];
fNumFrames = nframes;
fNumChannels = nchannels;

// allocate audio channels
for (int i = 0; i < fNumChannels; i++) {
fBuffers[i] = new FAUSTFLOAT[fNumFrames];
}
}

void zero()
{
// allocate audio channels
for (int i = 0; i < fNumChannels; i++) {
for (int f = 0; f < fNumFrames; f++) {
fBuffers[i][f] = FAUSTFLOAT(0.0);
}
}
}

void impulse()
{
// allocate audio channels
for (int i = 0; i < fNumChannels; i++) {
fBuffers[i][0] = FAUSTFLOAT(1.0);
for (int f = 1; f < fNumFrames; f++) {
fBuffers[i][f] = FAUSTFLOAT(0.0);
}
}
}
void display()
{
for (int i = 0; i < fNumChannels; i++) {
for (int f = 0; f < fNumFrames; f++) {
std::cout << "chan = " << i << " frame = " << f << " value = " << fBuffers[i][f] << std::endl;
}
}
}

virtual ~channels()
{
// free separate input channels
for (int i = 0; i < fNumChannels; i++) {
delete [] fBuffers[i];
}
delete [] fBuffers;
}

FAUSTFLOAT** buffers() { return fBuffers; }
};

#endif


+ 1518
- 0
ports/temper/source/faust/audio/coreaudio-dsp.h
File diff suppressed because it is too large
View File


+ 727
- 0
ports/temper/source/faust/audio/coreaudio-ios-dsp.h View File

@@ -0,0 +1,727 @@
/************************************************************************

IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef __coreaudio_ios_dsp__
#define __coreaudio_ios_dsp__

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <errno.h>
#include <time.h>

#include "faust/audio/audio.h"
#include "faust/dsp/dsp.h"

#include <AudioToolbox/AudioConverter.h>
#include <AudioToolbox/AudioServices.h>
#include <AudioUnit/AudioUnit.h>

using namespace std;

/******************************************************************************
*******************************************************************************

COREAUDIO INTERFACE

*******************************************************************************
*******************************************************************************/

#define OPEN_ERR -1
#define NO_ERR 0

class TiPhoneCoreAudioRenderer
{
protected:

AudioUnit fAUHAL;

int fDevNumInChans;
int fDevNumOutChans;

int fHWNumInChans;
int fHWNumOutChans;
dsp* fDSP;

AudioBufferList* fCAInputData;

static void PrintStreamDesc(AudioStreamBasicDescription *inDesc)
{
printf("- - - - - - - - - - - - - - - - - - - -\n");
printf(" Sample Rate:%f\n", inDesc->mSampleRate);
printf(" Format ID:%.*s\n", (int) sizeof(inDesc->mFormatID), (char*)&inDesc->mFormatID);
printf(" Format Flags:%lX\n", inDesc->mFormatFlags);
printf(" Bytes per Packet:%ld\n", inDesc->mBytesPerPacket);
printf(" Frames per Packet:%ld\n", inDesc->mFramesPerPacket);
printf(" Bytes per Frame:%ld\n", inDesc->mBytesPerFrame);
printf(" Channels per Frame:%ld\n", inDesc->mChannelsPerFrame);
printf(" Bits per Channel:%ld\n", inDesc->mBitsPerChannel);
printf("- - - - - - - - - - - - - - - - - - - -\n");
}
static void printError(OSStatus err)
{
switch (err) {
case kAudioConverterErr_FormatNotSupported:
printf("error code : kAudioConverterErr_FormatNotSupported\n");
break;
case kAudioConverterErr_OperationNotSupported:
printf("error code : kAudioConverterErr_OperationNotSupported\n");
break;
case kAudioConverterErr_PropertyNotSupported:
printf("error code : kAudioConverterErr_PropertyNotSupported\n");
break;
case kAudioConverterErr_InvalidInputSize:
printf("error code : kAudioConverterErr_InvalidInputSize\n");
break;
case kAudioConverterErr_InvalidOutputSize:
printf("error code : kAudioConverterErr_InvalidOutputSize\n");
break;
case kAudioConverterErr_UnspecifiedError:
printf("error code : kAudioConverterErr_UnspecifiedError\n");
break;
case kAudioConverterErr_BadPropertySizeError:
printf("error code : kAudioConverterErr_BadPropertySizeError\n");
break;
case kAudioConverterErr_RequiresPacketDescriptionsError:
printf("error code : kAudioConverterErr_RequiresPacketDescriptionsError\n");
break;
case kAudioConverterErr_InputSampleRateOutOfRange:
printf("error code : kAudioConverterErr_InputSampleRateOutOfRange\n");
break;
case kAudioConverterErr_OutputSampleRateOutOfRange:
printf("error code : kAudioConverterErr_OutputSampleRateOutOfRange\n");
break;
default:
printf("error code : unknown\n");
break;
}
}
static OSStatus Render(void *inRefCon,AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
return static_cast<TiPhoneCoreAudioRenderer*>(inRefCon)->Render(ioActionFlags, inTimeStamp, inNumberFrames, ioData);
}
OSStatus Render(AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
OSStatus err = noErr;
if (fDevNumInChans > 0) {
err = AudioUnitRender(fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, fCAInputData);
}
if (err == noErr) {
float* fInChannel[fDevNumInChans];
float* fOutChannel[fDevNumOutChans];
for (int chan = 0; chan < fDevNumInChans; chan++) {
fInChannel[chan] = (float*)fCAInputData->mBuffers[chan].mData;
}
for (int chan = 0; chan < fDevNumOutChans; chan++) {
fOutChannel[chan] = (float*)ioData->mBuffers[chan].mData;
}
fDSP->compute((int)inNumberFrames, fInChannel, fOutChannel);
}
return err;
}
static void InterruptionListener(void *inClientData, UInt32 inInterruption)
{
TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inClientData;
printf("Session interrupted! --- %s ---", (inInterruption == kAudioSessionBeginInterruption) ? "Begin Interruption" : "End Interruption");
if (inInterruption == kAudioSessionEndInterruption) {
// Make sure we are again the active session
AudioSessionSetActive(true);
obj->SetupMixing();
AudioOutputUnitStart(obj->fAUHAL);
}
if (inInterruption == kAudioSessionBeginInterruption) {
AudioOutputUnitStop(obj->fAUHAL);
}
}
int SetupMixing()
{
OSStatus err;
/*
01/07/2014 : cause iRig to fail, so deactivated for now...
CFStringRef route;
UInt32 routesize = sizeof(route);
OSStatus err = AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routesize, &route);
if (err == noErr) {
if (CFStringCompare(route, CFSTR("ReceiverAndMicrophone"), 0) == kCFCompareEqualTo || CFStringCompare(route,CFSTR("Receiver"), 0) == kCFCompareEqualTo) {
// Re-route audio to the speaker (not the receiver, which no music app will ever want)
printf("Rerouting audio to speaker\n");
UInt32 newRoute = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(newRoute), &newRoute);
}
}
*/
UInt32 allowMixing = true;
err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);
if (err != noErr) {
printf("Could not set audio session mixing\n");
printError(err);
return -1;
} else {
return 0;
}
}
static void AudioSessionPropertyListener(void* inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void* inData)
{
TiPhoneCoreAudioRenderer *obj = (TiPhoneCoreAudioRenderer*)inData;
switch (inID) {
case kAudioSessionProperty_ServerDied: {
printf("kAudioSessionProperty_ServerDied\n");
break;
}
case kAudioSessionProperty_AudioRouteChange: {
printf("kAudioSessionProperty_AudioRouteChange\n");
obj->SetupMixing();
break;
}
case kAudioSessionProperty_AudioInputAvailable: {
printf("kAudioSessionProperty_AudioInputAvailable\n");
obj->SetupMixing();
break;
}
}
}
static int SetAudioCategory(int input, int output)
{
// Set the audioCategory the way Faust DSP wants
UInt32 audioCategory;
if ((input > 0) && (output > 0)) {
audioCategory = kAudioSessionCategory_PlayAndRecord;
printf("AudioCategory kAudioSessionCategory_PlayAndRecord\n");
} else if (input > 0) {
audioCategory = kAudioSessionCategory_RecordAudio;
printf("AudioCategory kAudioSessionCategory_RecordAudio\n");
} else if (output > 0) {
audioCategory = kAudioSessionCategory_MediaPlayback;
printf("AudioCategory kAudioSessionCategory_MediaPlayback\n");
}
OSStatus err = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory);
if (err != noErr) {
printf("Couldn't set audio category\n");
printError(err);
return OPEN_ERR;
}
// 09/07/2015 : https://developer.apple.com/library/ios/qa/qa1754/_index.html
if (audioCategory == kAudioSessionCategory_PlayAndRecord) {
UInt32 overrideAudioRoute = 1;
err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(UInt32), &overrideAudioRoute);
if (err != noErr) {
printf("Error setting kAudioSessionProperty_OverrideCategoryDefaultToSpeaker\n");
printError(err);
}
UInt32 allowBluetoothInput = 1;
err = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryEnableBluetoothInput, sizeof(UInt32), &allowBluetoothInput);
if (err != noErr) {
printf("Error setting kAudioSessionProperty_OverrideCategoryEnableBluetoothInput\n");
printError(err);
}
}
#if NOAGC
// If input is used, disable AGC
if (audioCategory == kAudioSessionCategory_RecordAudio || audioCategory == kAudioSessionCategory_PlayAndRecord) {
UInt32 sessionMode = kAudioSessionMode_Measurement;
err = AudioSessionSetProperty(kAudioSessionProperty_Mode, sizeof(sessionMode), &sessionMode);
if (err != noErr) {
printf("Error setting kAudioSessionMode_Measurement\n");
printError(err);
}
UInt32 availableGain;
UInt32 outSize = sizeof(availableGain);
err = AudioSessionGetProperty(kAudioSessionProperty_InputGainAvailable, &outSize, &availableGain);
if (err != noErr) {
printf("Error getting kAudioSessionProperty_InputGainAvailable\n");
printError(err);
} else {
Float32 gain;
printf("Getting kAudioSessionProperty_InputGainAvailable OK\n");
outSize = sizeof(Float32);
AudioSessionGetProperty(kAudioSessionProperty_InputGainScalar, &outSize, &gain);
printf("Getting kAudioSessionProperty_InputGainScalar : %f\n", gain);
gain = 1.0f;
err = AudioSessionSetProperty(kAudioSessionProperty_InputGainScalar, sizeof(Float32), &gain);
if (err != noErr) {
printf("Error setting kAudioSessionProperty_InputGainScalar\n");
printError(err);
} else {
printf("Setting kAudioSessionProperty_InputGainAvailable to 1.0 OK\n");
}
}
}
#endif
return NO_ERR;
}
int SetParameters(int bufferSize, int samplerate)
{
OSStatus err;
UInt32 outSize;
UInt32 enableIO;
AudioStreamBasicDescription srcFormat, dstFormat;
printf("SetParameters fDevNumInChans = %d fDevNumOutChans = %d bufferSize = %d samplerate = %d\n", fDevNumInChans, fDevNumOutChans, bufferSize, samplerate);
err = AudioSessionSetActive(true);
if (err != noErr) {
printf("Couldn't set audio session active\n");
printError(err);
return OPEN_ERR;
}
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, AudioSessionPropertyListener, this);
AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, AudioSessionPropertyListener, this);
AudioSessionAddPropertyListener(kAudioSessionProperty_ServerDied, AudioSessionPropertyListener, this);
if (SetAudioCategory(fDevNumInChans, fDevNumOutChans) != NO_ERR) {
return OPEN_ERR;
}
// Scan Hardware
outSize = sizeof(fHWNumInChans);
err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &fHWNumInChans);
if (err != noErr) {
fHWNumInChans = 0;
printf("Couldn't get hw input channels\n");
printError(err);
} else {
printf("Get hw input channels %d\n", fHWNumInChans);
}
outSize = sizeof(fHWNumOutChans);
err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &fHWNumOutChans);
if (err != noErr) {
fHWNumOutChans = 0;
printf("Couldn't get hw output channels\n");
printError(err);
} else {
printf("Get hw output channels %d\n", fHWNumOutChans);
}
// Possibly reset the audioCategory the way hardware allows
if (SetAudioCategory(fHWNumInChans, fHWNumOutChans) != NO_ERR) {
return OPEN_ERR;
}
if (SetupMixing() < 0) {
return OPEN_ERR;
}
Float64 hwSampleRate;
outSize = sizeof(hwSampleRate);
err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate);
if (err != noErr) {
printf("Couldn't get hw sample rate\n");
printError(err);
return OPEN_ERR;
} else {
printf("Get hw sample rate %f\n", hwSampleRate);
}
Float32 hwBufferSize;
outSize = sizeof(hwBufferSize);
err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize);
if (err != noErr) {
printf("Couldn't get hw buffer duration\n");
printError(err);
return OPEN_ERR;
} else {
printf("Get hw buffer duration %f\n", hwBufferSize);
}
Float32 preferredPeriodDuration = float(bufferSize) / float(samplerate);
printf("preferredPeriodDuration %f \n", preferredPeriodDuration);
err = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredPeriodDuration), &preferredPeriodDuration);
if (err != noErr) {
printf("Couldn't set i/o buffer duration\n");
printError(err);
return OPEN_ERR;
}
Float32 actualPeriodDuration;
outSize = sizeof(actualPeriodDuration);
err = AudioSessionGetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, &outSize, &actualPeriodDuration);
if (err != noErr) {
printf("Couldn't get hw buffer duration\n");
printError(err);
return OPEN_ERR;
}
printf("preferredPeriodDuration %f actualPeriodDuration %f\n", preferredPeriodDuration, actualPeriodDuration);
if (preferredPeriodDuration != actualPeriodDuration) {
printf("Couldn't set hw buffer duration\n");
return OPEN_ERR;
}
Float64 preferredSamplerate = float(samplerate);
err = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareSampleRate, sizeof(preferredSamplerate), &preferredSamplerate);
if (err != noErr) {
printf("Couldn't set i/o sample rate\n");
printError(err);
return OPEN_ERR;
}
Float32 inputLatency;
outSize = sizeof(inputLatency);
err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency, &outSize, &inputLatency);
if (err != noErr) {
printf("Couldn't get inputLatency\n");
printError(err);
} else {
printf("inputLatency in sec : %f\n", inputLatency);
}
Float32 outputLatency;
outSize = sizeof(outputLatency);
err = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, &outSize, &outputLatency);
if (err != noErr) {
printf("Couldn't get outputLatency\n");
printError(err);
} else {
printf("outputLatency in sec : %f\n", outputLatency);
}
// AUHAL
AudioComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_RemoteIO, kAudioUnitManufacturer_Apple, 0, 0};
AudioComponent HALOutput = AudioComponentFindNext(NULL, &cd);
err = AudioComponentInstanceNew(HALOutput, &fAUHAL);
if (err != noErr) {
printf("Error calling OpenAComponent\n");
printError(err);
goto error;
}
enableIO = 1;
err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output\n");
printError(err);
goto error;
}
enableIO = 1;
err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input\n");
printError(err);
goto error;
}
UInt32 maxFPS;
outSize = sizeof(maxFPS);
err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, &outSize);
if (err != noErr) {
printf("Couldn't get kAudioUnitProperty_MaximumFramesPerSlice\n");
printError(err);
goto error;
} else {
printf("Get kAudioUnitProperty_MaximumFramesPerSlice %d\n", (unsigned int)maxFPS);
}
err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*)&bufferSize, sizeof(UInt32));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
printError(err);
goto error;
}
err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*)&bufferSize, sizeof(UInt32));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice\n");
printError(err);
goto error;
}
err = AudioUnitInitialize(fAUHAL);
if (err != noErr) {
printf("Cannot initialize AUHAL unit\n");
printError(err);
goto error;
}
// Setting format
if (fDevNumInChans > 0) {
outSize = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, &outSize);
if (err != noErr) {
printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
printError(err);
}
PrintStreamDesc(&srcFormat);
srcFormat.mFormatID = kAudioFormatLinearPCM;
srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
srcFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
srcFormat.mFramesPerPacket = 1;
srcFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
srcFormat.mChannelsPerFrame = fDevNumInChans;
srcFormat.mBitsPerChannel = 32;
PrintStreamDesc(&srcFormat);
err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &srcFormat, sizeof(AudioStreamBasicDescription));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output\n");
printError(err);
}
}
if (fDevNumOutChans > 0) {
outSize = sizeof(AudioStreamBasicDescription);
err = AudioUnitGetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, &outSize);
if (err != noErr) {
printf("Error calling AudioUnitGetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
printError(err);
}
PrintStreamDesc(&dstFormat);
dstFormat.mFormatID = kAudioFormatLinearPCM;
dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
dstFormat.mBytesPerPacket = sizeof(AudioUnitSampleType);
dstFormat.mFramesPerPacket = 1;
dstFormat.mBytesPerFrame = sizeof(AudioUnitSampleType);
dstFormat.mChannelsPerFrame = fDevNumOutChans;
dstFormat.mBitsPerChannel = 32;
PrintStreamDesc(&dstFormat);
err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &dstFormat, sizeof(AudioStreamBasicDescription));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input\n");
printError(err);
}
}
if (fDevNumInChans > 0 && fDevNumOutChans == 0) {
AURenderCallbackStruct output;
output.inputProc = Render;
output.inputProcRefCon = this;
err = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1\n");
printError(err);
goto error;
}
} else {
AURenderCallbackStruct output;
output.inputProc = Render;
output.inputProcRefCon = this;
err = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
if (err != noErr) {
printf("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0\n");
printError(err);
goto error;
}
}
// Possibly prepare input buffers
if (fDevNumInChans > 0) {
fCAInputData = (AudioBufferList*)malloc(sizeof(float) + fDevNumInChans * sizeof(AudioBuffer));
fCAInputData->mNumberBuffers = fDevNumInChans;
for (int i = 0; i < fDevNumInChans; i++) {
fCAInputData->mBuffers[i].mNumberChannels = 1;
fCAInputData->mBuffers[i].mDataByteSize = bufferSize * sizeof(float);
fCAInputData->mBuffers[i].mData = malloc(bufferSize * sizeof(float));
}
}
return NO_ERR;
error:
AudioUnitUninitialize(fAUHAL);
AudioComponentInstanceDispose(fAUHAL);
return OPEN_ERR;
}

public:

TiPhoneCoreAudioRenderer()
:fAUHAL(0), fDevNumInChans(0), fDevNumOutChans(0),
fHWNumInChans(0), fHWNumOutChans(0),
fDSP(0), fCAInputData(NULL)
{}

virtual ~TiPhoneCoreAudioRenderer()
{
if (fCAInputData) {
for (int i = 0; i < fDevNumInChans; i++) {
free(fCAInputData->mBuffers[i].mData);
}
free(fCAInputData);
}
}
int Open(dsp* dsp, int inChan, int outChan, int buffersize, int samplerate)
{
fDSP = dsp;
fDevNumInChans = inChan;
fDevNumOutChans = outChan;
// Initialize and configure the audio session
OSStatus err = AudioSessionInitialize(NULL, NULL, InterruptionListener, this);
if (err != noErr && err != kAudioSessionAlreadyInitialized) {
printf("Couldn't initialize audio session\n");
printError(err);
return OPEN_ERR;
}
if (SetParameters(buffersize, samplerate) < 0) {
printf("Cannot set parameters to CoreAudio device\n");
return OPEN_ERR;
}
return NO_ERR;
}
int Close()
{
AudioUnitUninitialize(fAUHAL);
AudioComponentInstanceDispose(fAUHAL);
return NO_ERR;
}
int Start()
{
AudioSessionSetActive(true);
if (AudioOutputUnitStart(fAUHAL) != noErr) {
printf("Error while opening device : device open error\n");
return OPEN_ERR;
} else {
return NO_ERR;
}
}
int Stop()
{
AudioSessionSetActive(false);
if (AudioOutputUnitStop(fAUHAL) != noErr) {
printf("Error while closing device : device close error\n");
return OPEN_ERR;
} else {
return NO_ERR;
}
}

};

/******************************************************************************
*******************************************************************************
CORE AUDIO INTERFACE
*******************************************************************************
*******************************************************************************/
class iosaudio : public audio {

protected:
TiPhoneCoreAudioRenderer fAudioDevice;
int fSampleRate, fBufferSize;
public:
iosaudio(int srate, int bsize) : fSampleRate(srate), fBufferSize(bsize) {}
virtual ~iosaudio() { fAudioDevice.Close(); }
virtual bool init(const char* /*name*/, dsp* DSP)
{
DSP->init(fSampleRate);
if (fAudioDevice.Open(DSP, DSP->getNumInputs(), DSP->getNumOutputs(), fBufferSize, fSampleRate) < 0) {
printf("Cannot open iOS audio device\n");
return false;
}
return true;
}
virtual bool start()
{
if (fAudioDevice.Start() < 0) {
printf("Cannot start iOS audio device\n");
return false;
}
return true;
}
virtual void stop()
{
fAudioDevice.Stop();
}
virtual int get_buffer_size() { return fBufferSize; }
virtual int get_sample_rate() { return fSampleRate; }
};

#endif

/********************END ARCHITECTURE SECTION (part 2/2)****************/



+ 135
- 0
ports/temper/source/faust/audio/dummy-audio.h View File

@@ -0,0 +1,135 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
/******************************************************************************
*******************************************************************************

A dummy audio driver

*******************************************************************************
*******************************************************************************/

#ifndef __dummy_audio__
#define __dummy_audio__

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "faust/dsp/dsp.h"
#include "faust/audio/audio.h"

#define BUFFER_TO_RENDER 10

class dummy_audio : public audio {

private:

dsp* fDSP;

long fSampleRate;
long fBufferSize;

FAUSTFLOAT** fInChannel;
FAUSTFLOAT** fOutChannel;

int fCount;

public:

dummy_audio(int count = 10)
:fSampleRate(48000), fBufferSize(512), fCount(count) {}
dummy_audio(int srate, int bsize, int count = 10)
:fSampleRate(srate), fBufferSize(bsize), fCount(count) {}
virtual ~dummy_audio()
{
for (int i = 0; i < fDSP->getNumInputs(); i++) {
delete[] fInChannel[i];
}
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
delete[] fOutChannel[i];
}
delete [] fInChannel;
delete [] fOutChannel;
}

virtual bool init(const char* name, dsp* dsp)
{
fDSP = dsp;
fDSP->init(fSampleRate);
fInChannel = new FAUSTFLOAT*[fDSP->getNumInputs()];
fOutChannel = new FAUSTFLOAT*[fDSP->getNumOutputs()];
for (int i = 0; i < fDSP->getNumInputs(); i++) {
fInChannel[i] = new FAUSTFLOAT[fBufferSize];
memset(fInChannel[i], 0, sizeof(FAUSTFLOAT) * fBufferSize);
}
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
fOutChannel[i] = new FAUSTFLOAT[fBufferSize];
memset(fOutChannel[i], 0, sizeof(FAUSTFLOAT) * fBufferSize);
}
return true;
}
virtual bool start()
{
while (--fCount > 0) {
printf("Render one buffer\n");
render();
}
return true;
}
virtual void stop()
{}

void render()
{
fDSP->compute(fBufferSize, fInChannel, fOutChannel);
if (fDSP->getNumInputs() > 0) {
printf("First in = %f \n", fInChannel[0][0]);
}
if (fDSP->getNumOutputs() > 0) {
printf("First out = %f \n", fOutChannel[0][0]);
}
}

virtual int get_buffer_size() { return 0; }
virtual int get_sample_rate() { return 0; }
};
#endif

+ 597
- 0
ports/temper/source/faust/audio/jack-dsp.h View File

@@ -0,0 +1,597 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/
/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef __jack_dsp__
#define __jack_dsp__

#include <stdio.h>
#include <cstdlib>
#include <list>
#include <vector>
#include <string.h>
#include <jack/jack.h>
#include <jack/midiport.h>
#ifdef JACK_IOS
#include <jack/custom.h>
#endif
#include "faust/audio/audio.h"
#include "faust/dsp/dsp.h"
#include "faust/midi/jack-midi.h"

#if defined(_WIN32) && !defined(__MINGW32__)
#define snprintf _snprintf_s
#endif

/******************************************************************************
*******************************************************************************

JACK AUDIO INTERFACE

*******************************************************************************
*******************************************************************************/

class jackaudio : public audio {

protected:

dsp* fDSP; // FAUST DSP
jack_client_t* fClient; // JACK client

std::vector<jack_port_t*> fInputPorts; // JACK input ports
std::vector<jack_port_t*> fOutputPorts; // JACK output ports

std::vector<char*> fPhysicalInputs;
std::vector<char*> fPhysicalOutputs;

shutdown_callback fShutdown; // Shutdown callback to be called by libjack
void* fShutdownArg; // Shutdown callback data
void* fIconData; // iOS specific
int fIconSize; // iOS specific
bool fAutoConnect; // autoconnect with system in/out ports

std::list<std::pair<std::string, std::string> > fConnections; // Connections list

static int _jack_srate(jack_nframes_t nframes, void* arg)
{
fprintf(stdout, "The sample rate is now %u/sec\n", nframes);
return 0;
}

static void _jack_shutdown(void* arg)
{}

static void _jack_info_shutdown(jack_status_t code, const char* reason, void* arg)
{
fprintf(stderr, "%s\n", reason);
static_cast<jackaudio*>(arg)->shutdown(reason);
}

static int _jack_process(jack_nframes_t nframes, void* arg)
{
return static_cast<jackaudio*>(arg)->process(nframes);
}

static int _jack_buffersize(jack_nframes_t nframes, void* arg)
{
fprintf(stdout, "The buffer size is now %u/sec\n", nframes);
return 0;
}

#ifdef _OPENMP
static void* _jack_thread(void* arg)
{
jackaudio* audio = (jackaudio*)arg;
audio->process_thread();
return 0;
}
#endif

void shutdown(const char* message)
{
fClient = NULL;

if (fShutdown) {
fShutdown(message, fShutdownArg);
} else {
exit(1); // By default
}
}

// Save client connections
virtual bool save_connections()
{
if (fClient) {
fConnections.clear();

for (int i = 0; i < fInputPorts.size(); i++) {
const char** connected_port = jack_port_get_all_connections(fClient, fInputPorts[i]);
if (connected_port != NULL) {
for (int port = 0; connected_port[port]; port++) {
fConnections.push_back(std::make_pair(connected_port[port], jack_port_name(fInputPorts[i])));
// printf("INPUT %s ==> %s\n", connected_port[port], jack_port_name(fInputPorts[i]));
}
jack_free(connected_port);
}
}

for (int i = 0; i < fOutputPorts.size(); i++) {
const char** connected_port = jack_port_get_all_connections(fClient, fOutputPorts[i]);
if (connected_port != NULL) {
for (int port = 0; connected_port[port]; port++) {
fConnections.push_back(std::make_pair(jack_port_name(fOutputPorts[i]), connected_port[port]));
// printf("OUTPUT %s ==> %s\n", jack_port_name(fOutputPorts[i]), connected_port[port]);
}
jack_free(connected_port);
}
}
return true;
} else {
fprintf(stdout, "Client no more running...\n");
return false;
}
}

// Load client connections
void load_connections()
{
std::list<std::pair<std::string, std::string> >::const_iterator it;
for (it = fConnections.begin(); it != fConnections.end(); it++) {
std::pair<std::string, std::string> connection = *it;
jack_connect(fClient, connection.first.c_str(), connection.second.c_str());
}
}

#ifdef _OPENMP
void process_thread()
{
jack_nframes_t nframes;
while (1) {
nframes = jack_cycle_wait(fClient);
process(nframes);
jack_cycle_signal(fClient, 0);
}
}
#endif

// JACK callbacks
virtual int process(jack_nframes_t nframes)
{
AVOIDDENORMALS;

// Retrieve JACK inputs/output audio buffers
float** fInChannel = (float**)alloca(fInputPorts.size() * sizeof(float*));
for (int i = 0; i < fInputPorts.size(); i++) {
fInChannel[i] = (float*)jack_port_get_buffer(fInputPorts[i], nframes);
}

float** fOutChannel = (float**)alloca(fOutputPorts.size() * sizeof(float*));
for (int i = 0; i < fOutputPorts.size(); i++) {
fOutChannel[i] = (float*)jack_port_get_buffer(fOutputPorts[i], nframes);
}

fDSP->compute(nframes, fInChannel, fOutChannel);
return 0;
}

public:

jackaudio(const void* icon_data = 0, size_t icon_size = 0, bool auto_connect = true)
: fDSP(0), fClient(0), fShutdown(0), fShutdownArg(0), fAutoConnect(auto_connect)
{
if (icon_data) {
fIconData = malloc(icon_size);
fIconSize = icon_size;
memcpy(fIconData, icon_data, icon_size);
} else {
fIconData = NULL;
fIconSize = 0;
}
}

virtual ~jackaudio()
{
if (fClient) {
stop();

for (int i = 0; i < fInputPorts.size(); i++) {
jack_port_unregister(fClient, fInputPorts[i]);
}
for (int i = 0; i < fOutputPorts.size(); i++) {
jack_port_unregister(fClient, fOutputPorts[i]);
}
jack_client_close(fClient);

if (fIconData) {
free(fIconData);
}
}
}

virtual bool init(const char* name, dsp* dsp)
{
if (init(name)) {
if (dsp) { set_dsp(dsp); }
return true;
} else {
return false;
}
}

virtual bool init(const char* name)
{
if ((fClient = jack_client_open(name, JackNullOption, NULL)) == 0) {
fprintf(stderr, "JACK server not running ?\n");
return false;
}
#ifdef JACK_IOS
jack_custom_publish_data(fClient, "icon.png", fIconData, fIconSize);
#endif

#ifdef _OPENMP
jack_set_process_thread(fClient, _jack_thread, this);
#else
jack_set_process_callback(fClient, _jack_process, this);
#endif

jack_set_sample_rate_callback(fClient, _jack_srate, this);
jack_set_buffer_size_callback(fClient, _jack_buffersize, this);
jack_on_info_shutdown(fClient, _jack_info_shutdown, this);

// Get Physical inputs
int inputs = 0;
char** physicalInPorts = (char**)jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical|JackPortIsOutput);
if (physicalInPorts != NULL) {
while (physicalInPorts[inputs]) {
fPhysicalInputs.push_back(physicalInPorts[inputs]);
printf("physical input %s\n", physicalInPorts[inputs]);
inputs++;
}
jack_free(physicalInPorts);
}

// Get Physical outputs
int outputs = 0;
char** physicalOutPorts = (char**)jack_get_ports(fClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical|JackPortIsInput);
if (physicalOutPorts != NULL) {
while (physicalOutPorts[outputs]) {
fPhysicalOutputs.push_back(physicalOutPorts[outputs]);
printf("physical output %s\n", physicalOutPorts[outputs]);
outputs++;
}
jack_free(physicalOutPorts);
}

return true;
}

virtual bool start()
{
if (jack_activate(fClient)) {
fprintf(stderr, "Cannot activate client\n");
return false;
}

if (fConnections.size() > 0) {
load_connections();
} else if (fAutoConnect) {
default_connections();
}

return true;
}

virtual void stop()
{
if (fClient) {
save_connections();
jack_deactivate(fClient);
}
}

virtual void shutdown(shutdown_callback cb, void* arg)
{
fShutdown = cb;
fShutdownArg = arg;
}

virtual int get_buffer_size() { return jack_get_buffer_size(fClient); }
virtual int get_sample_rate() { return jack_get_sample_rate(fClient); }

virtual int get_num_inputs()
{
return fPhysicalInputs.size();
}

virtual int get_num_outputs()
{
return fPhysicalOutputs.size();
}

// Additional public API

jack_client_t* get_client() { return fClient; }

// Connect to physical inputs/outputs
void default_connections()
{
// To avoid feedback at launch time, don't connect hardware inputs
/*
for (int i = 0; i < fInputPorts.size() && i < fPhysicalOutputs.size(); i++) {
jack_connect(fClient, fPhysicalInputs[i], jack_port_name(fInputPorts[i]));
}
*/
for (int i = 0; i < fOutputPorts.size() && i < fPhysicalInputs.size(); i++) {
jack_connect(fClient, jack_port_name(fOutputPorts[i]), fPhysicalOutputs[i]);
}
}

virtual void set_dsp(dsp* dsp)
{
fDSP = dsp;

for (int i = 0; i < fDSP->getNumInputs(); i++) {
char buf[256];
snprintf(buf, 256, "in_%d", i);
fInputPorts.push_back(jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0));
}
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
char buf[256];
snprintf(buf, 256, "out_%d", i);
fOutputPorts.push_back(jack_port_register(fClient, buf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0));
}

fDSP->init(jack_get_sample_rate(fClient));
}

void connect(jackaudio* driver, int src, int dst, bool reverse)
{
if (driver) {
// Connection between drivers
jack_port_t* src_port = get_output_port(src);
jack_port_t* dst_port = driver->get_input_port(src);
if (src_port && dst_port) {
jack_connect(fClient, jack_port_name(src_port), jack_port_name(dst_port));
}
} else if (reverse) {
// Connection to physical input
if (src > fPhysicalInputs.size()) return;
jack_port_t* dst_port = get_input_port(dst);
if (dst_port) {
jack_connect(fClient, fPhysicalInputs[src], jack_port_name(dst_port));
}
} else {
// Connection to physical output
if (dst > fPhysicalOutputs.size()) return;
jack_port_t* src_port = get_output_port(src);
if (src_port) {
jack_connect(fClient, jack_port_name(src_port), fPhysicalOutputs[dst]);
}
}
}

void disconnect(jackaudio* driver, int src, int dst, bool reverse)
{
if (driver) {
// Connection between drivers
jack_port_t* src_port = get_output_port(src);
jack_port_t* dst_port = driver->get_input_port(src);
if (src_port && dst_port) {
jack_disconnect(fClient, jack_port_name(src_port), jack_port_name(dst_port));
}
} else if (reverse) {
// Connection to physical input
if (src > fPhysicalInputs.size()) return;
jack_port_t* dst_port = get_input_port(dst);
if (dst_port) {
jack_disconnect(fClient, fPhysicalInputs[src], jack_port_name(dst_port));
}
} else {
// Connection to physical output
if (dst > fPhysicalOutputs.size()) return;
jack_port_t* src_port = get_output_port(src);
if (src_port) {
jack_disconnect(fClient, jack_port_name(src_port), fPhysicalOutputs[dst]);
}
}
}

bool is_connected(jackaudio* driver, int src, int dst, bool reverse)
{
if (driver) {
// Connection between drivers
jack_port_t* src_port = get_output_port(src);
jack_port_t* dst_port = driver->get_input_port(src);
if (src_port && dst_port) {
return jack_port_connected_to(src_port, jack_port_name(dst_port));
} else {
return false;
}
} else if (reverse) {
// Connection to physical input
if (src > fPhysicalInputs.size()) return false;
jack_port_t* dst_port = get_input_port(dst);
if (dst_port) {
return jack_port_connected_to(dst_port, fPhysicalInputs[src]);
} else {
return false;
}
} else {
// Connection to physical output
if (dst > fPhysicalOutputs.size()) return false;
jack_port_t* src_port = get_output_port(src);
if (src_port) {
return jack_port_connected_to(src_port, fPhysicalOutputs[dst]);
} else {
return false;
}
}
}

jack_port_t* get_input_port(int port) { return (port >= 0 && port < fInputPorts.size()) ? fInputPorts[port] : 0; }
jack_port_t* get_output_port(int port) { return (port >= 0 && port < fOutputPorts.size()) ? fOutputPorts[port] : 0; }

};

// Add JACK MIDI

class jackaudio_midi : public jackaudio, public jack_midi_handler {

protected:

jack_port_t* fInputMidiPort; // JACK input MIDI port
jack_port_t* fOutputMidiPort; // JACK output MIDI port

virtual bool save_connections()
{
if (jackaudio::save_connections()) { // Audio connections can be saved, so try MIDI
if (fInputMidiPort) {
const char** connected_port = jack_port_get_all_connections(fClient, fInputMidiPort);
if (connected_port != NULL) {
for (int port = 0; connected_port[port]; port++) {
fConnections.push_back(std::make_pair(connected_port[port], jack_port_name(fInputMidiPort)));
// printf("INPUT %s ==> %s\n", connected_port[port], jack_port_name(fInputPorts[i]));
}
jack_free(connected_port);
}
}

if (fOutputMidiPort) {
const char** connected_port = jack_port_get_all_connections(fClient, fOutputMidiPort);
if (connected_port != NULL) {
for (int port = 0; connected_port[port]; port++) {
fConnections.push_back(std::make_pair(jack_port_name(fOutputMidiPort), connected_port[port]));
// printf("OUTPUT %s ==> %s\n", jack_port_name(fOutputPorts[i]), connected_port[port]);
}
jack_free(connected_port);
}
}
return true;
} else {
return false;
}
}

virtual void processMidiIn(jack_nframes_t nframes)
{
// MIDI input
if (fInputMidiPort) {
processMidiInBuffer(jack_port_get_buffer(fInputMidiPort, nframes));
}
}

virtual void processAudio(jack_nframes_t nframes)
{
// Audio
AVOIDDENORMALS;

// Retrieve JACK inputs/output audio buffers
float** fInChannel = (float**)alloca(fInputPorts.size() * sizeof(float*));
for (int i = 0; i < fInputPorts.size(); i++) {
fInChannel[i] = (float*)jack_port_get_buffer(fInputPorts[i], nframes);
}

float** fOutChannel = (float**)alloca(fOutputPorts.size() * sizeof(float*));
for (int i = 0; i < fOutputPorts.size(); i++) {
fOutChannel[i] = (float*)jack_port_get_buffer(fOutputPorts[i], nframes);
}

// By convention timestamp of -1 means 'no timestamp conversion' : events already have a timestamp espressed in frames
fDSP->compute(-1, nframes, fInChannel, fOutChannel);
}

virtual void processMidiOut(jack_nframes_t nframes)
{
// MIDI output
if (fOutputMidiPort) {
processMidiOutBuffer(jack_port_get_buffer(fOutputMidiPort, nframes));
}
}

virtual int process(jack_nframes_t nframes)
{
// MIDI in
processMidiIn(nframes);

// Audio
processAudio(nframes);

// MIDI out
processMidiOut(nframes);
return 0;
}

public:

jackaudio_midi(const void* icon_data = 0, size_t icon_size = 0, bool auto_connect = true)
:jackaudio(icon_data, icon_size, auto_connect), jack_midi_handler("JACKMidi"),
fInputMidiPort(0), fOutputMidiPort(0)
{}

virtual ~jackaudio_midi()
{
if (fClient) {
if (fInputMidiPort) { jack_port_unregister(fClient, fInputMidiPort); }
if (fOutputMidiPort) { jack_port_unregister(fClient, fOutputMidiPort); }
}
}

virtual bool init(const char* name, dsp* dsp, bool midi = false)
{
if (jackaudio::init(name)) {
if (dsp) { set_dsp(dsp); }
if (midi) {
fInputMidiPort = jack_port_register(fClient, "midi_in_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
fOutputMidiPort = jack_port_register(fClient, "midi_out_1", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
}
return true;
} else {
return false;
}
}

virtual bool start()
{
return jackaudio::start();
}

virtual void stop()
{
jackaudio::stop();
}

};

#endif

+ 357
- 0
ports/temper/source/faust/audio/netjack-dsp.h View File

@@ -0,0 +1,357 @@
/************************************************************************

IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef __netjack_dsp__
#define __netjack_dsp__

#include <stdio.h>
#include "faust/audio/audio.h"
#include "faust/dsp/dsp.h"
#include "faust/gui/ControlUI.h"
#include "faust/midi/jack-midi.h"

#include <jack/net.h>
#include <string>
#include <assert.h>

class netjackaudio : public audio
{

protected:
dsp* fDSP;
jack_net_slave_t* fNet;
int fNetFormat;
std::string fMasterIP;
int fMasterPort;
int fMTU;
int fLatency;
jack_master_t fResult;

#ifdef RESTART_CB_API
static int net_restart(void* arg)
{
printf("Network failure, restart...\n");
return static_cast<netjackaudio*>(arg)->restart_cb();
}
#else
static void net_shutdown(void* arg)
{
printf("Network failure, shutdown...\n");
static_cast<netjackaudio*>(arg)->shutdown_cb();
}
#endif
static int net_sample_rate(jack_nframes_t nframes, void* arg)
{
return static_cast<netjackaudio*>(arg)->set_sample_rate(nframes);
}
static int net_buffer_size(jack_nframes_t nframes, void* arg)
{
return static_cast<netjackaudio*>(arg)->set_buffer_size(nframes);
}
static void net_error(int error_code, void* arg)
{
return static_cast<netjackaudio*>(arg)->error_cb(error_code);
}
static int net_process(jack_nframes_t buffer_size,
int,
float** audio_inputs,
int,
void** midi_inputs,
int,
float** audio_outputs,
int,
void** midi_outputs,
void* arg)
{
static_cast<netjackaudio*>(arg)->process(buffer_size, audio_inputs, audio_outputs, midi_inputs, midi_outputs);
return 0;
}

bool init_aux(const char* name, dsp* DSP, int audio_inputs, int audio_outputs, int midi_inputs, int midi_outputs)
{
if (init_aux(name, audio_inputs, audio_outputs, midi_inputs, midi_outputs)) {
set_dsp(DSP);
return true;
} else {
return false;
}
}
bool init_aux(const char* name, int audio_inputs, int audio_outputs, int midi_inputs, int midi_outputs)
{
jack_slave_t request = {
audio_inputs,
audio_outputs,
midi_inputs,
midi_outputs,
fMTU,
2,
(fNetFormat > 0) ? JackOpusEncoder : ((fNetFormat == -1) ? JackFloatEncoder : JackIntEncoder),
(fNetFormat > 0) ? fNetFormat : 0,
fLatency
};
if ((fNet = jack_net_slave_open(fMasterIP.c_str(), fMasterPort, name, &request, &fResult)) == 0) {
printf("JACK remote server not running ?\n");
return false;
}

jack_set_net_slave_process_callback(fNet, net_process, this);
#ifdef RESTART_CB_API
jack_set_net_slave_restart_callback(fNet, net_restart, this);
#else
jack_set_net_slave_shutdown_callback(fNet, net_shutdown, this);
#endif
jack_set_net_slave_sample_rate_callback(fNet, net_sample_rate, this);
jack_set_net_slave_buffer_size_callback(fNet, net_buffer_size, this);
jack_set_net_slave_error_callback(fNet, net_error, this);

return true;
}
// Possibly to be redefined by subclasses
virtual int restart_cb()
{
return 0;
}
virtual void shutdown_cb()
{}
virtual void error_cb(int error_code)
{}
virtual int set_sample_rate(jack_nframes_t nframes)
{
return 0;
}
virtual int set_buffer_size(jack_nframes_t nframes)
{
return 0;
}

virtual void process(int count, float** audio_inputs, float** audio_outputs, void** midi_inputs, void** midi_outputs)
{
AVOIDDENORMALS;
fDSP->compute(count, audio_inputs, audio_outputs);
}

public:

netjackaudio(int net_format, const std::string& master_ip, int master_port, int mtu, int latency = 2)
: fDSP(0), fNet(0), fNetFormat(net_format), fMasterIP(master_ip), fMasterPort(master_port), fMTU(mtu), fLatency(latency)
{}
virtual ~netjackaudio()
{
if (fNet) {
stop();
jack_net_slave_close(fNet);
}
}

virtual bool init(const char* name, dsp* DSP)
{
return init_aux(name, DSP, DSP->getNumInputs(), DSP->getNumOutputs(), 0, 0);
}

virtual bool start()
{
if (jack_net_slave_activate(fNet)) {
printf("cannot activate net");
return false;
}
return true;
}

virtual void stop()
{
if (fNet) {
jack_net_slave_deactivate(fNet);
}
}
void set_dsp(dsp* DSP)
{
fDSP = DSP;
fDSP->init(fResult.sample_rate);
}
virtual int get_buffer_size() { return fResult.buffer_size; }
virtual int get_sample_rate() { return fResult.sample_rate; }

};

/*
A special NetJack client that uses one more audio input/output to transmit control values.
*/

class netjackaudio_control : public netjackaudio, public ControlUI {
protected:
virtual void process(int count, float** audio_inputs, float** audio_outputs, void** midi_inputs, void** midi_outputs)
{
AVOIDDENORMALS;
float** inputs_tmp = (float**)alloca(fDSP->getNumInputs()*sizeof(float*));
float** outputs_tmp = (float**)alloca(fDSP->getNumOutputs()*sizeof(float*));
for (int i = 0; i < fDSP->getNumInputs(); i++) {
inputs_tmp[i] = audio_inputs[i+1];
}
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
outputs_tmp[i] = audio_outputs[i+1];
}
// Control buffer always use buffer_size, even if uncomplete data buffer (count < buffer_size) is received
decode_control(audio_inputs[0], fResult.buffer_size);
// "count" may be less than buffer_size
fDSP->compute(count, inputs_tmp, outputs_tmp);
// Control buffer always use buffer_size, even if uncomplete data buffer (count < buffer_size) is received
encode_control(audio_outputs[0], fResult.buffer_size);
}
public:
netjackaudio_control(int net_format, const std::string& master_ip, int master_port, int mtu, int latency)
:netjackaudio(net_format, master_ip, master_port, mtu, latency)
{}
virtual ~netjackaudio_control()
{}
bool is_connexion_active()
{
return jack_net_slave_is_active(fNet);
}
virtual bool init(const char* name, dsp* dsp)
{
dsp->buildUserInterface(this);
return init_aux(name, dsp, dsp->getNumInputs() + 1, dsp->getNumOutputs() + 1, 0, 0); // One more audio port for control
}
virtual int restart_cb()
{
return -1;
}
};

/*
A special NetJack client that uses MIDI input/output to transmit control values.
*/

class netjackaudio_midicontrol : public netjackaudio, public ControlUI, public jack_midi_handler {
protected:
virtual void process(int count, float** audio_inputs, float** audio_outputs, void** midi_inputs, void** midi_outputs)
{
AVOIDDENORMALS;
float** inputs_tmp = (float**)alloca(fDSP->getNumInputs()*sizeof(float*));
float** outputs_tmp = (float**)alloca(fDSP->getNumOutputs()*sizeof(float*));
for (int i = 0; i < fDSP->getNumInputs(); i++) {
inputs_tmp[i] = audio_inputs[i];
}
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
outputs_tmp[i] = audio_outputs[i];
}
// Control buffer always use buffer_size, even if uncomplete data buffer (count < buffer_size) is received
decode_midi_control(midi_inputs[0], fResult.buffer_size);
// Decode MIDI messages
processMidiInBuffer(midi_inputs[1]);
// "count" may be less than buffer_size
fDSP->compute(count, inputs_tmp, outputs_tmp);
// Control buffer always use buffer_size, even if uncomplete data buffer (count < buffer_size) is received
encode_midi_control(midi_outputs[0], fResult.buffer_size);
// Encode MIDI messages
processMidiOutBuffer(midi_outputs[1], true);
}
public:
netjackaudio_midicontrol(int net_format, const std::string& master_ip, int master_port, int mtu, int latency)
:netjackaudio(net_format, master_ip, master_port, mtu, latency)
{}
virtual ~netjackaudio_midicontrol()
{}
bool is_connexion_active()
{
return jack_net_slave_is_active(fNet);
}
virtual bool init(const char* name, dsp* dsp)
{
dsp->buildUserInterface(this);
// One MIDI channel for control, and one MIDI channel for messages in both direction
return init_aux(name, dsp, dsp->getNumInputs(), dsp->getNumOutputs(), 2, 2);
}
virtual int restart_cb()
{
return -1;
}
};

#endif

/********************END ARCHITECTURE SECTION (part 2/2)****************/


+ 641
- 0
ports/temper/source/faust/audio/opensles-android-dsp.h View File

@@ -0,0 +1,641 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2014 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

/*
* This is an interface for OpenSL ES to make it easier to use with Android
* devices.
*/

#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#include <android/log.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct threadLock_ {
pthread_mutex_t m;
pthread_cond_t c;
unsigned char s;
} threadLock;

typedef struct opensl_stream {

// engine interfaces
SLObjectItf engineObject;
SLEngineItf engineEngine;

// output mix interfaces
SLObjectItf outputMixObject;

// buffer queue player interfaces
SLObjectItf bqPlayerObject;
SLPlayItf bqPlayerPlay;
SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
SLEffectSendItf bqPlayerEffectSend;

// recorder interfaces
SLObjectItf recorderObject;
SLRecordItf recorderRecord;
SLAndroidSimpleBufferQueueItf recorderBufferQueue;

// buffer indexes
int currentInputIndex;
int currentOutputIndex;

// current buffer half (0, 1)
int currentOutputBuffer;
int currentInputBuffer;

// buffers
short *outputBuffer[2];
short *inputBuffer[2];

// size of buffers
int outBufSamples;
int inBufSamples;

// locks
void* inlock;
void* outlock;

double time;
int inchannels;
int outchannels;
int sr;

} OPENSL_STREAM;

#define CONV16BIT 32767.f
#define CONVMYFLT (1.f/32767.f)

static void* createThreadLock(void);
static int waitThreadLock(void *lock);
static void notifyThreadLock(void *lock);
static void destroyThreadLock(void *lock);
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context);
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context);

// creates the OpenSL ES audio engine
static SLresult openSLCreateEngine(OPENSL_STREAM *p) {
SLresult result;
// create engine
result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);
if (result != SL_RESULT_SUCCESS)
goto engine_end;

// realize the engine
result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS)
goto engine_end;

// get the engine interface, which is needed in order to create other objects
result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE,
&(p->engineEngine));
if (result != SL_RESULT_SUCCESS)
goto engine_end;

engine_end: return result;
}

// opens the OpenSL ES device for output
static SLresult openSLPlayOpen(OPENSL_STREAM *p) {
SLresult result;
SLuint32 sr = p->sr;
SLuint32 channels = p->outchannels;

if (channels) {
// configure audio source
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };

switch (sr) {

case 8000:
sr = SL_SAMPLINGRATE_8;
break;
case 11025:
sr = SL_SAMPLINGRATE_11_025;
break;
case 16000:
sr = SL_SAMPLINGRATE_16;
break;
case 22050:
sr = SL_SAMPLINGRATE_22_05;
break;
case 24000:
sr = SL_SAMPLINGRATE_24;
break;
case 32000:
sr = SL_SAMPLINGRATE_32;
break;
case 44100:
sr = SL_SAMPLINGRATE_44_1;
break;
case 48000:
sr = SL_SAMPLINGRATE_48;
break;
case 64000:
sr = SL_SAMPLINGRATE_64;
break;
case 88200:
sr = SL_SAMPLINGRATE_88_2;
break;
case 96000:
sr = SL_SAMPLINGRATE_96;
break;
case 192000:
sr = SL_SAMPLINGRATE_192;
break;
default:
return -1;
}

const SLInterfaceID ids[] = { SL_IID_VOLUME };
const SLboolean req[] = { SL_BOOLEAN_FALSE };
result = (*p->engineEngine)->CreateOutputMix(p->engineEngine,
&(p->outputMixObject), 1, ids, req);
//if(result != SL_RESULT_SUCCESS) goto end_openaudio;

// realize the output mix
result = (*p->outputMixObject)->Realize(p->outputMixObject,
SL_BOOLEAN_FALSE);

int speakers;
if (channels > 1)
speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
else
speakers = SL_SPEAKER_FRONT_CENTER;
SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, channels, sr,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
speakers, SL_BYTEORDER_LITTLEENDIAN };

SLDataSource audioSrc = { &loc_bufq, &format_pcm };

// configure audio sink
SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX,
p->outputMixObject };
SLDataSink audioSnk = { &loc_outmix, NULL };

// create audio player
const SLInterfaceID ids1[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean req1[] = { SL_BOOLEAN_TRUE };
result = (*p->engineEngine)->CreateAudioPlayer(p->engineEngine,
&(p->bqPlayerObject), &audioSrc, &audioSnk, 1, ids1, req1);
if (result != SL_RESULT_SUCCESS)
goto end_openaudio;

// realize the player
result = (*p->bqPlayerObject)->Realize(p->bqPlayerObject,
SL_BOOLEAN_FALSE);
if (result != SL_RESULT_SUCCESS)
goto end_openaudio;

// get the play interface
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject,
SL_IID_PLAY, &(p->bqPlayerPlay));
if (result != SL_RESULT_SUCCESS)
goto end_openaudio;

// get the buffer queue interface
result = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject,
SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(p->bqPlayerBufferQueue));
if (result != SL_RESULT_SUCCESS)
goto end_openaudio;

// register callback on the buffer queue
result = (*p->bqPlayerBufferQueue)->RegisterCallback(
p->bqPlayerBufferQueue, bqPlayerCallback, p);
if (result != SL_RESULT_SUCCESS)
goto end_openaudio;

// set the player's state to playing
result = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay,
SL_PLAYSTATE_PLAYING);

end_openaudio: return result;
}
return SL_RESULT_SUCCESS;
}

// Open the OpenSL ES device for input
static SLresult openSLRecOpen(OPENSL_STREAM *p) {

SLresult result;
SLuint32 sr = p->sr;
SLuint32 channels = p->inchannels;

if (channels) {

switch (sr) {

case 8000:
sr = SL_SAMPLINGRATE_8;
break;
case 11025:
sr = SL_SAMPLINGRATE_11_025;
break;
case 16000:
sr = SL_SAMPLINGRATE_16;
break;
case 22050:
sr = SL_SAMPLINGRATE_22_05;
break;
case 24000:
sr = SL_SAMPLINGRATE_24;
break;
case 32000:
sr = SL_SAMPLINGRATE_32;
break;
case 44100:
sr = SL_SAMPLINGRATE_44_1;
break;
case 48000:
sr = SL_SAMPLINGRATE_48;
break;
case 64000:
sr = SL_SAMPLINGRATE_64;
break;
case 88200:
sr = SL_SAMPLINGRATE_88_2;
break;
case 96000:
sr = SL_SAMPLINGRATE_96;
break;
case 192000:
sr = SL_SAMPLINGRATE_192;
break;
default:
return -1;
}

// configure audio source
SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE,
SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
SLDataSource audioSrc = { &loc_dev, NULL };

// configure audio sink
int speakers;
if (channels > 1)
speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
else
speakers = SL_SPEAKER_FRONT_CENTER;
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, channels, sr,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
speakers, SL_BYTEORDER_LITTLEENDIAN };
SLDataSink audioSnk = { &loc_bq, &format_pcm };

// create audio recorder
// (requires the RECORD_AUDIO permission)
const SLInterfaceID id[1] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean req[1] = { SL_BOOLEAN_TRUE };
result = (*p->engineEngine)->CreateAudioRecorder(p->engineEngine,
&(p->recorderObject), &audioSrc, &audioSnk, 1, id, req);
if (SL_RESULT_SUCCESS != result)
goto end_recopen;

// realize the audio recorder
result = (*p->recorderObject)->Realize(p->recorderObject,
SL_BOOLEAN_FALSE);
if (SL_RESULT_SUCCESS != result)
goto end_recopen;

// get the record interface
result = (*p->recorderObject)->GetInterface(p->recorderObject,
SL_IID_RECORD, &(p->recorderRecord));
if (SL_RESULT_SUCCESS != result)
goto end_recopen;

// get the buffer queue interface
result = (*p->recorderObject)->GetInterface(p->recorderObject,
SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(p->recorderBufferQueue));
if (SL_RESULT_SUCCESS != result)
goto end_recopen;

// register callback on the buffer queue
result = (*p->recorderBufferQueue)->RegisterCallback(
p->recorderBufferQueue, bqRecorderCallback, p);
if (SL_RESULT_SUCCESS != result)
goto end_recopen;
result = (*p->recorderRecord)->SetRecordState(p->recorderRecord,
SL_RECORDSTATE_RECORDING);

end_recopen: return result;
} else
return SL_RESULT_SUCCESS;

}

// close the OpenSL IO and destroy the audio engine
static void openSLDestroyEngine(OPENSL_STREAM *p) {

// destroy buffer queue audio player object, and invalidate all associated interfaces
if (p->bqPlayerObject != NULL) {
(*p->bqPlayerObject)->Destroy(p->bqPlayerObject);
p->bqPlayerObject = NULL;
p->bqPlayerPlay = NULL;
p->bqPlayerBufferQueue = NULL;
p->bqPlayerEffectSend = NULL;
}

// destroy audio recorder object, and invalidate all associated interfaces
if (p->recorderObject != NULL) {
(*p->recorderObject)->Destroy(p->recorderObject);
p->recorderObject = NULL;
p->recorderRecord = NULL;
p->recorderBufferQueue = NULL;
}

// destroy output mix object, and invalidate all associated interfaces
if (p->outputMixObject != NULL) {
(*p->outputMixObject)->Destroy(p->outputMixObject);
p->outputMixObject = NULL;
}

// destroy engine object, and invalidate all associated interfaces
if (p->engineObject != NULL) {
(*p->engineObject)->Destroy(p->engineObject);
p->engineObject = NULL;
p->engineEngine = NULL;
}

}

// close the android audio device
void android_CloseAudioDevice(OPENSL_STREAM *p) {

if (p == NULL)
return;

openSLDestroyEngine(p);

if (p->inlock != NULL) {
notifyThreadLock(p->inlock);
destroyThreadLock(p->inlock);
p->inlock = NULL;
}

if (p->outlock != NULL) {
notifyThreadLock(p->outlock);
destroyThreadLock(p->outlock);
p->inlock = NULL;
}

if (p->outputBuffer[0] != NULL) {
free(p->outputBuffer[0]);
p->outputBuffer[0] = NULL;
}

if (p->outputBuffer[1] != NULL) {
free(p->outputBuffer[1]);
p->outputBuffer[1] = NULL;
}

if (p->inputBuffer[0] != NULL) {
free(p->inputBuffer[0]);
p->inputBuffer[0] = NULL;
}

if (p->inputBuffer[1] != NULL) {
free(p->inputBuffer[1]);
p->inputBuffer[1] = NULL;
}

free(p);
}

// open the android audio device for input and/or output
OPENSL_STREAM *android_OpenAudioDevice(int sr, int inchannels, int outchannels,
int bufferframes) {

OPENSL_STREAM *p;
p = (OPENSL_STREAM *) calloc(sizeof(OPENSL_STREAM), 1);

p->inchannels = inchannels;
p->outchannels = outchannels;
p->sr = sr;
p->inlock = createThreadLock();
p->outlock = createThreadLock();

if ((p->outBufSamples = bufferframes * outchannels) != 0) {
if ((p->outputBuffer[0] = (short *) calloc(p->outBufSamples,
sizeof(short))) == NULL || (p->outputBuffer[1] =
(short *) calloc(p->outBufSamples, sizeof(short))) == NULL) {
android_CloseAudioDevice(p);
return NULL;
}
}

if ((p->inBufSamples = bufferframes * inchannels) != 0) {
if ((p->inputBuffer[0] = (short *) calloc(p->inBufSamples,
sizeof(short))) == NULL || (p->inputBuffer[1] =
(short *) calloc(p->inBufSamples, sizeof(short))) == NULL) {
android_CloseAudioDevice(p);
return NULL;
}
}

p->currentInputIndex = 0;
p->currentOutputBuffer = 0;
p->currentInputIndex = p->inBufSamples;
p->currentInputBuffer = 0;

if (openSLCreateEngine(p) != SL_RESULT_SUCCESS) {
android_CloseAudioDevice(p);
return NULL;
}

if (openSLRecOpen(p) != SL_RESULT_SUCCESS) {
android_CloseAudioDevice(p);
return NULL;
}

if (openSLPlayOpen(p) != SL_RESULT_SUCCESS) {
android_CloseAudioDevice(p);
return NULL;
}

notifyThreadLock(p->outlock);
notifyThreadLock(p->inlock);

p->time = 0.;
return p;
}

// returns timestamp of the processed stream
double android_GetTimestamp(OPENSL_STREAM *p) {
return p->time;
}

// this callback handler is called every time a buffer finishes recording
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
OPENSL_STREAM *p = (OPENSL_STREAM *) context;
notifyThreadLock(p->inlock);
}

// gets a buffer of size samples from the device
int android_AudioIn(OPENSL_STREAM *p, float *buffer, int size) {
short *inBuffer;
int i, bufsamps = p->inBufSamples, index = p->currentInputIndex;
if (p == NULL || bufsamps == 0)
return 0;

inBuffer = p->inputBuffer[p->currentInputBuffer];
for (i = 0; i < size; i++) {
if (index >= bufsamps) {
waitThreadLock(p->inlock);
(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, inBuffer,
bufsamps * sizeof(short));
p->currentInputBuffer = (p->currentInputBuffer ? 0 : 1);
index = 0;
inBuffer = p->inputBuffer[p->currentInputBuffer];
}
buffer[i] = (float) inBuffer[index++] * CONVMYFLT;
// TODO: the output buffer should be clicked
//buffer[i] = min(1.f,max(-1.f,buffer[i]));
}
p->currentInputIndex = index;
if (p->outchannels == 0)
p->time += (double) size / (p->sr * p->inchannels);
return i;
}

// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
OPENSL_STREAM *p = (OPENSL_STREAM *) context;
notifyThreadLock(p->outlock);
}

// puts a buffer of size samples to the device
int android_AudioOut(OPENSL_STREAM *p, float **buffer, int size) {

short *outBuffer;
int i, bufsamps = p->outBufSamples, index = p->currentOutputIndex;
if (p == NULL || bufsamps == 0)
return 0;
__android_log_write(ANDROID_LOG_INFO, "FaustCPP", "Error");
outBuffer = p->outputBuffer[p->currentOutputBuffer];
if (p->outchannels == 1) {
for (i = 0; i < size; i++) {
outBuffer[index++] = (short) (min(1.f, max(-1.f, buffer[0][i]))
* CONV16BIT);
if (index >= p->outBufSamples) {
waitThreadLock(p->outlock);
(*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue,
outBuffer, bufsamps * sizeof(short));
p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1);
index = 0;
outBuffer = p->outputBuffer[p->currentOutputBuffer];
}
}
} else {
for (i = 0; i < size; i++) {
outBuffer[index++] = (short) (min(1.f, max(-1.f, buffer[0][i]))
* CONV16BIT);
outBuffer[index++] = (short) (min(1.f, max(-1.f, buffer[1][i]))
* CONV16BIT);
if (index >= p->outBufSamples) {
waitThreadLock(p->outlock);
(*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue,
outBuffer, bufsamps * sizeof(short));
p->currentOutputBuffer = (p->currentOutputBuffer ? 0 : 1);
index = 0;
outBuffer = p->outputBuffer[p->currentOutputBuffer];
}
}
}
p->currentOutputIndex = index;
p->time += (double) size * p->outchannels/ (p->sr * p->outchannels);
return i;
}

//----------------------------------------------------------------------
// thread Locks
// to ensure synchronisation between callbacks and processing code
void* createThreadLock(void) {
threadLock *p;
p = (threadLock*) malloc(sizeof(threadLock));
if (p == NULL)
return NULL;
memset(p, 0, sizeof(threadLock));
if (pthread_mutex_init(&(p->m), (pthread_mutexattr_t*) NULL) != 0) {
free((void*) p);
return NULL;
}
if (pthread_cond_init(&(p->c), (pthread_condattr_t*) NULL) != 0) {
pthread_mutex_destroy(&(p->m));
free((void*) p);
return NULL;
}
p->s = (unsigned char) 1;

return p;
}

int waitThreadLock(void *lock) {
threadLock *p;
int retval = 0;
p = (threadLock*) lock;
pthread_mutex_lock(&(p->m));
while (!p->s) {
pthread_cond_wait(&(p->c), &(p->m));
}
p->s = (unsigned char) 0;
pthread_mutex_unlock(&(p->m));
}

void notifyThreadLock(void *lock) {
threadLock *p;
p = (threadLock*) lock;
pthread_mutex_lock(&(p->m));
p->s = (unsigned char) 1;
pthread_cond_signal(&(p->c));
pthread_mutex_unlock(&(p->m));
}

void destroyThreadLock(void *lock) {
threadLock *p;
p = (threadLock*) lock;
if (p == NULL)
return;
notifyThreadLock(p);
pthread_cond_destroy(&(p->c));
pthread_mutex_destroy(&(p->m));
free(p);
}

+ 115
- 0
ports/temper/source/faust/audio/osc-dsp.h View File

@@ -0,0 +1,115 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef __osc_dsp__
#define __osc_dsp__

#include <stdio.h>
#include "faust/audio/audio.h"
#include "faust/dsp/dsp.h"

#include "OSCIO.h"

/******************************************************************************
*******************************************************************************

OSC AUDIO INTERFACE

*******************************************************************************
*******************************************************************************/

#define kMaxBuffer 4096

class oscdsp : public audio, public oscfaust::OSCIO {
dsp* fDsp;
float ** fInBuffers, **fOutBuffers;

public:
oscdsp(const char * dst, int argc, char *argv[]) : OSCIO(dst), fDsp(0), fInBuffers(0), fOutBuffers(0)
{
for (int i = 1; i < argc-1; i++) {
if (!strcmp(argv[i], "-iodst")) setDest (argv[i+1]);
}
}
virtual ~oscdsp()
{
stop();
for (int i = 0; i < numInputs(); i++) {
delete [] fInBuffers[i];
}
for (int i = 0; i < numOutputs(); i++) {
delete [] fOutBuffers[i];
}
delete [] fInBuffers;
delete [] fOutBuffers;
}

virtual bool init(const char*name, dsp* DSP)
{
fDsp = DSP;
fDsp->init(44100);
fInBuffers = new float*[numInputs()];
fOutBuffers = new float*[numOutputs()];
for (int i = 0; i < numInputs(); i++) {
fInBuffers[i] = new float[kMaxBuffer];
}
for (int i = 0; i < numOutputs(); i++) {
fOutBuffers [i] = new float[kMaxBuffer];
}
return true;
}

virtual bool start() { return true; }
virtual void stop() {}

void compute(int nframes)
{
fDsp->compute(nframes, fInBuffers, fOutBuffers);
for (int i= 0; i < numOutputs(); i++) {
send(nframes, fOutBuffers [i], i);
}
}

void receive(int nvalues, float* val)
{
int inChans = numInputs();
if (!inChans) {
compute(nvalues);
return;
}

for (int i=0; i < nvalues; i++) {
int c = i % inChans;
int frame = i / inChans;
fInBuffers[c][frame] = val[i];
}
compute (nvalues / inChans);
}
int numOutputs() const { return fDsp ? fDsp->getNumOutputs() : 0; }
int numInputs() const { return fDsp ? fDsp->getNumInputs() : 0; }
};

#endif

+ 245
- 0
ports/temper/source/faust/audio/portaudio-dsp.h View File

@@ -0,0 +1,245 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.
************************************************************************
************************************************************************/

#ifndef __portaudio_dsp__
#define __portaudio_dsp__

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <portaudio.h>

#include "faust/audio/audio.h"
#include "faust/dsp/dsp-adapter.h"

static bool pa_error(int err)
{
if (err != paNoError) {
printf("PortAudio error: %s\n", Pa_GetErrorText(err));
return true;
} else {
return false;
}
}

/******************************************************************************
*******************************************************************************
PORT AUDIO INTERFACE
*******************************************************************************
*******************************************************************************/

class portaudio : public audio {
protected:
dsp* fDsp;
PaStream* fAudioStream;
long fSampleRate;
long fBufferSize;
PaStreamParameters fInputParameters;
PaStreamParameters fOutputParameters;
//----------------------------------------------------------------------------
// Number of physical input and output channels of the PA device
//----------------------------------------------------------------------------
int fDevNumInChans;
int fDevNumOutChans;
static int audioCallback(const void* ibuf, void* obuf, unsigned long frames, const PaStreamCallbackTimeInfo* time, PaStreamCallbackFlags, void* drv)
{
return static_cast<portaudio*>(drv)->processAudio(time->currentTime,
(float**)ibuf,
static_cast<float**>(obuf),
frames);
}
virtual int processAudio(PaTime current_time, float** ibuf, float** obuf, unsigned long frames)
{
// Cleanup hardware outputs that are not used by DSP
for (int i = fDsp->getNumOutputs(); i < fDevNumOutChans; i++) {
memset(obuf[i], 0, sizeof(FAUSTFLOAT) * fBufferSize);
}
// Process samples
fDsp->compute(current_time * 1000000., frames, ibuf, obuf);
return paContinue;
}
public:
portaudio(long srate, long bsize) :
fDsp(0), fAudioStream(0),
fSampleRate(srate), fBufferSize(bsize),
fDevNumInChans(0), fDevNumOutChans(0) {}
virtual ~portaudio()
{
if (fAudioStream) {
pa_error(Pa_StopStream(fAudioStream));
pa_error(Pa_CloseStream(fAudioStream));
fAudioStream = 0;
}
// Note that Pa_Initialize handled multiple times calls and
// must be matched with a corresponding call to Pa_Terminate
Pa_Terminate();
}
virtual bool init(const char* name, dsp* DSP)
{
if (init(name, DSP->getNumInputs(), DSP->getNumOutputs())) {
set_dsp(DSP);
return true;
} else {
return false;
}
}
bool init(const char* /*name*/, int numInputs, int numOutputs)
{
// Note that Pa_Initialize handled multiple times calls and
// must be matched with a corresponding call to Pa_Terminate
if (pa_error(Pa_Initialize())) {
return false;
}
const PaDeviceInfo* idev = Pa_GetDeviceInfo(Pa_GetDefaultInputDevice());
const PaDeviceInfo* odev = Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice());
printf("DEVICE = %p || %p\n", idev, odev);
//In case there is no audio device, the function fails
if (idev == NULL) {
fDevNumInChans = 0;
} else {
fDevNumInChans = idev->maxInputChannels;
fInputParameters.device = Pa_GetDefaultInputDevice();
fInputParameters.sampleFormat = paFloat32 | paNonInterleaved;
fInputParameters.channelCount = fDevNumInChans;
fInputParameters.hostApiSpecificStreamInfo = 0;
}
if (odev == NULL) {
fDevNumOutChans = 0;
} else{
fDevNumOutChans = odev->maxOutputChannels;
fOutputParameters.device = Pa_GetDefaultOutputDevice();
fOutputParameters.sampleFormat = paFloat32 | paNonInterleaved;;
fOutputParameters.channelCount = fDevNumOutChans;
fOutputParameters.hostApiSpecificStreamInfo = 0;
}
// A DSP that has only outputs or only inputs forces the presence of an output or input device
if (numInputs == 0 && numOutputs != 0 && fDevNumOutChans == 0) {
printf("Devices not adapted to DSP\n");
return false;
}
if (numInputs != 0 && numOutputs == 0 && fDevNumInChans == 0) {
printf("Devices not adapted to DSP\n");
return false;
}
// If no device exists : the function fails
PaError err;
if ((err = Pa_IsFormatSupported(((fDevNumInChans > 0) ? &fInputParameters : 0),
((fDevNumOutChans > 0) ? &fOutputParameters : 0), fSampleRate)) != 0) {
printf("stream format is not supported err = %d\n", err);
return false;
}
if (pa_error(Pa_OpenStream(&fAudioStream, ((fDevNumInChans > 0) ? &fInputParameters : 0),
((fDevNumOutChans > 0) ? &fOutputParameters : 0),
fSampleRate, fBufferSize, paNoFlag, audioCallback, this))) {
return false;
}
return true;
}
void set_dsp(dsp* DSP)
{
fDsp = DSP;
if (fDsp->getNumInputs() > fDevNumInChans || fDsp->getNumOutputs() > fDevNumOutChans) {
printf("DSP has %d inputs and %d outputs, physical inputs = %d physical outputs = %d \n",
fDsp->getNumInputs(), fDsp->getNumOutputs(),
fDevNumInChans, fDevNumOutChans);
fDsp = new dsp_adapter(fDsp, fDevNumInChans, fDevNumOutChans, fBufferSize);
}
fDsp->init(fSampleRate);
}
virtual bool start()
{
if (pa_error(Pa_StartStream(fAudioStream))) {
return false;
} else {
return true;
}
}
virtual void stop()
{
if (fAudioStream) {
pa_error(Pa_StopStream(fAudioStream));
}
}
virtual int get_buffer_size()
{
return fBufferSize;
}
virtual int get_sample_rate()
{
return fSampleRate;
}
virtual int get_num_inputs()
{
return fDevNumInChans;
}
virtual int get_num_outputs()
{
return fDevNumOutChans;
}
};

#endif

+ 215
- 0
ports/temper/source/faust/audio/rtaudio-dsp.h View File

@@ -0,0 +1,215 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.
************************************************************************
************************************************************************/

#ifndef __rtaudio_dsp__
#define __rtaudio_dsp__

#include <stdio.h>
#include <assert.h>
#include <RtAudio.h>
#include <stdlib.h>

#include "faust/audio/audio.h"
#include "faust/dsp/dsp-adapter.h"

#define FORMAT RTAUDIO_FLOAT32

/******************************************************************************
*******************************************************************************
RTAUDIO INTERFACE
*******************************************************************************
*******************************************************************************/

class rtaudio : public audio {
protected:
dsp* fDsp;
RtAudio fAudioDAC;
unsigned int fSampleRate;
unsigned int fBufferSize;
//----------------------------------------------------------------------------
// number of physical input and output channels of the PA device
//----------------------------------------------------------------------------
int fDevNumInChans;
int fDevNumOutChans;
virtual int processAudio(double streamTime, void* inbuf, void* outbuf, unsigned long frames)
{
float* inputs[fDsp->getNumInputs()];
float* outputs[fDsp->getNumOutputs()];
for (int i = 0; i < fDsp->getNumInputs(); i++) {
inputs[i] = &(static_cast<float*>(inbuf))[i * frames];
}
for (int i = 0; i < fDsp->getNumOutputs(); i++) {
outputs[i] = &(static_cast<float*>(outbuf))[i * frames];
}

// process samples
fDsp->compute(streamTime * 1000000., frames, inputs, outputs);
return 0;
}
static int audioCallback(void* outputBuffer, void* inputBuffer,
unsigned int nBufferFrames,
double streamTime, RtAudioStreamStatus status,
void* drv)
{
return static_cast<rtaudio*>(drv)->processAudio(streamTime, inputBuffer, outputBuffer, nBufferFrames);
}
public:
rtaudio(int srate, int bsize) : fDsp(0),
fSampleRate(srate), fBufferSize(bsize),
fDevNumInChans(0), fDevNumOutChans(0) {}
virtual ~rtaudio()
{
try {
fAudioDAC.stopStream();
fAudioDAC.closeStream();
} catch (RtAudioError& e) {
std::cout << '\n' << e.getMessage() << '\n' << std::endl;
}
}
virtual bool init(const char* name, dsp* DSP)
{
if (init(name, DSP->getNumInputs(), DSP->getNumOutputs())) {
set_dsp(DSP);
return true;
} else {
return false;
}
}
bool init(const char* /*name*/, int numInputs, int numOutputs)
{
if (fAudioDAC.getDeviceCount() < 1) {
std::cout << "No audio devices found!\n";
return false;
}
RtAudio::DeviceInfo info_in = fAudioDAC.getDeviceInfo(fAudioDAC.getDefaultInputDevice());
RtAudio::DeviceInfo info_out = fAudioDAC.getDeviceInfo(fAudioDAC.getDefaultOutputDevice());
RtAudio::StreamParameters iParams, oParams;
iParams.deviceId = fAudioDAC.getDefaultInputDevice();
fDevNumInChans = info_in.inputChannels;
iParams.nChannels = fDevNumInChans;
iParams.firstChannel = 0;
oParams.deviceId = fAudioDAC.getDefaultOutputDevice();
fDevNumOutChans = info_out.outputChannels;
oParams.nChannels = fDevNumOutChans;
oParams.firstChannel = 0;
RtAudio::StreamOptions options;
options.flags |= RTAUDIO_NONINTERLEAVED;
try {
fAudioDAC.openStream(((numOutputs > 0) ? &oParams : NULL),
((numInputs > 0) ? &iParams : NULL), FORMAT,
fSampleRate, &fBufferSize, audioCallback, this, &options);
} catch (RtAudioError& e) {
std::cout << '\n' << e.getMessage() << '\n' << std::endl;
return false;
}
return true;
}
void set_dsp(dsp* DSP)
{
fDsp = DSP;
if (fDsp->getNumInputs() > fDevNumInChans || fDsp->getNumOutputs() > fDevNumOutChans) {
printf("DSP has %d inputs and %d outputs, physical inputs = %d physical outputs = %d \n",
fDsp->getNumInputs(), fDsp->getNumOutputs(),
fDevNumInChans, fDevNumOutChans);
fDsp = new dsp_adapter(fDsp, fDevNumInChans, fDevNumOutChans, fBufferSize);
}
fDsp->init(fSampleRate);
}
virtual bool start()
{
try {
fAudioDAC.startStream();
} catch (RtAudioError& e) {
std::cout << '\n' << e.getMessage() << '\n' << std::endl;
return false;
}
return true;
}
virtual void stop()
{
try {
fAudioDAC.stopStream();
} catch (RtAudioError& e) {
std::cout << '\n' << e.getMessage() << '\n' << std::endl;
}
}
virtual int get_buffer_size()
{
return fBufferSize;
}
virtual int get_sample_rate()
{
return fSampleRate;
}
virtual int get_num_inputs()
{
return fDevNumInChans;
}
virtual int get_num_outputs()
{
return fDevNumOutChans;
}
};

#endif

+ 109
- 0
ports/temper/source/faust/dsp/dsp-adapter.h View File

@@ -0,0 +1,109 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef __dsp_adapter__
#define __dsp_adapter__

#include <string.h>
#include "faust/dsp/dsp.h"

class dsp_adapter : public decorator_dsp {
private:
FAUSTFLOAT** fAdaptedInputs;
FAUSTFLOAT** fAdaptedOutputs;
int fHardwareInputs;
int fHardwareOutputs;
void adaptBuffers(FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
for (int i = 0; i < fHardwareInputs; i++) {
fAdaptedInputs[i] = inputs[i];
}
for (int i = 0; i < fHardwareOutputs; i++) {
fAdaptedOutputs[i] = outputs[i];
}
}
public:
dsp_adapter(dsp* dsp, int hardware_inputs, int hardware_outputs, int buffer_size):decorator_dsp(dsp)
{
fHardwareInputs = hardware_inputs;
fHardwareOutputs = hardware_outputs;
fAdaptedInputs = new FAUSTFLOAT*[dsp->getNumInputs()];
for (int i = 0; i < dsp->getNumInputs() - fHardwareInputs; i++) {
fAdaptedInputs[i + fHardwareInputs] = new FAUSTFLOAT[buffer_size];
memset(fAdaptedInputs[i + fHardwareInputs], 0, sizeof(FAUSTFLOAT) * buffer_size);
}
fAdaptedOutputs = new FAUSTFLOAT*[dsp->getNumOutputs()];
for (int i = 0; i < dsp->getNumOutputs() - fHardwareOutputs; i++) {
fAdaptedOutputs[i + fHardwareOutputs] = new FAUSTFLOAT[buffer_size];
memset(fAdaptedOutputs[i + fHardwareOutputs], 0, sizeof(FAUSTFLOAT) * buffer_size);
}
}
virtual ~dsp_adapter()
{
for (int i = 0; i < fDSP->getNumInputs() - fHardwareInputs; i++) {
delete [] fAdaptedInputs[i + fHardwareInputs];
}
delete [] fAdaptedInputs;
for (int i = 0; i < fDSP->getNumOutputs() - fHardwareOutputs; i++) {
delete [] fAdaptedOutputs[i + fHardwareOutputs];
}
delete [] fAdaptedOutputs;
}
virtual int getNumInputs() { return fHardwareInputs; }
virtual int getNumOutputs() { return fHardwareOutputs; }
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
adaptBuffers(inputs, outputs);
fDSP->compute(date_usec, count, fAdaptedInputs, fAdaptedOutputs);
}
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
adaptBuffers(inputs, outputs);
fDSP->compute(count, fAdaptedInputs, fAdaptedOutputs);
}
};

#endif

+ 382
- 0
ports/temper/source/faust/dsp/dsp-bench.h View File

@@ -0,0 +1,382 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.
************************************************************************/

#ifndef __dsp_bench__
#define __dsp_bench__

#include <limits.h>
#include <sys/time.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <assert.h>
#include <string.h>

#include "faust/dsp/dsp.h"

// Handle 32/64 bits int size issues
#ifdef __x86_64__
#define uint32 unsigned int
#define uint64 unsigned long int
#define int32 int
#define int64 long int
#else
#define uint32 unsigned int
#define uint64 unsigned long long int
#define int32 int
#define int64 long long int
#endif

/*
A class to do do timing measurements
*/

class time_bench {
protected:
int fMeasure;
int fMeasureCount;
int fSkip;
// These values are used to determine the number of clocks in a second
uint64 fFirstRDTSC;
uint64 fLastRDTSC;
// These tables contains the last fMeasureCount in clocks
uint64* fStarts;
uint64* fStops;
struct timeval fTv1;
struct timeval fTv2;
/**
* Returns the number of clock cycles elapsed since the last reset of the processor
*/
inline uint64 rdtsc(void)
{
union {
uint32 i32[2];
uint64 i64;
} count;
__asm__ __volatile__("rdtsc" : "=a" (count.i32[0]), "=d" (count.i32[1]));
return count.i64;
}

/**
* return the number of RDTSC clocks per seconds
*/
double rdtscpersec()
{
// If the environment variable CLOCKSPERSEC is defined
// we use it instead of our own measurement
char* str = getenv("CLOCKSPERSEC");
if (str) {
int64 cps = (int64)atoll(str);
if (cps > 1000000000) {
return cps;
}
}
return double(fLastRDTSC - fFirstRDTSC)
/ (((double(fTv2.tv_sec) * 1000000 + double(fTv2.tv_usec)) - (double(fTv1.tv_sec) * 1000000 + double(fTv1.tv_usec)))
/ 1000000);
}
/**
* Converts a duration, expressed in RDTSC clocks, into seconds
*/
double rdtsc2sec(uint64 clk)
{
return double(clk) / rdtscpersec();
}
double rdtsc2sec(double clk)
{
return clk / rdtscpersec();
}
/**
* Converts RDTSC clocks into Megabytes/seconds according to the
* number of frames processed during the period, the number of channels
* and 4 bytes samples.
*/
double megapersec(int frames, int chans, uint64 clk)
{
return double(frames) * double(chans) * 4 / double(1024 * 1024 * rdtsc2sec(clk));
}
/**
* Compute the mean value of a vector of measures
*/
uint64 meanValue(std::vector<uint64>::const_iterator a, std::vector<uint64>::const_iterator b)
{
uint64 r = 0;
unsigned int n = 0;
while (a != b) { r += *a++; n++; }
return (n > 0) ? r/n : 0;
}
public:
time_bench(int count, int skip)
{
fSkip = skip;
fMeasureCount = count;
fMeasure = 0;
fFirstRDTSC = 0;
fLastRDTSC = 0;
fStarts = new uint64[fMeasureCount];
fStops = new uint64[fMeasureCount];
}
virtual ~time_bench()
{
delete [] fStarts;
delete [] fStops;
}
void startMeasure() { fStarts[fMeasure % fMeasureCount] = rdtsc(); }
void stopMeasure() { fStops[fMeasure % fMeasureCount] = rdtsc(); fMeasure++; }
void openMeasure()
{
struct timezone tz;
gettimeofday(&fTv1, &tz);
fFirstRDTSC = rdtsc();
fMeasure = 0;
}
void closeMeasure()
{
struct timezone tz;
gettimeofday(&fTv2, &tz);
fLastRDTSC = rdtsc();
}
double measureDurationUsec()
{
return ((double(fTv2.tv_sec) * 1000000 + double(fTv2.tv_usec)) - (double(fTv1.tv_sec) * 1000000 + double(fTv1.tv_usec)));
}
/**
* Returns best estimation.
*/
double getStats(int bsize, int ichans, int ochans)
{
//std::cout << "getStats fMeasure = " << fMeasure << " fMeasureCount = " << fMeasureCount << std::endl;
assert(fMeasure > fMeasureCount);
std::vector<uint64> V(fMeasureCount);
for (int i = 0; i < fMeasureCount; i++) {
V[i] = fStops[i] - fStarts[i];
}
sort(V.begin(), V.end());
// Mean of 10 best values (gives relatively stable results)
uint64 meavalx = meanValue(V.begin(), V.begin() + 10);
return megapersec(bsize, ichans + ochans, meavalx);
}

/**
* Print the median value (in Megabytes/second) of fMeasureCount throughputs measurements.
*/
void printStats(const char* applname, int bsize, int ichans, int ochans)
{
assert(fMeasure > fMeasureCount);
std::vector<uint64> V(fMeasureCount);
for (int i = 0; i < fMeasureCount; i++) {
V[i] = fStops[i] - fStarts[i];
}
sort(V.begin(), V.end());
// Mean of 10 best values (gives relatively stable results)
uint64 meaval00 = meanValue(V.begin(), V.begin()+ 5);
uint64 meaval25 = meanValue(V.begin() + fMeasureCount / 4 - 2, V.begin()+fMeasureCount / 4 + 3);
uint64 meaval50 = meanValue(V.begin() + fMeasureCount / 2 - 2, V.begin()+fMeasureCount / 2 + 3);
uint64 meaval75 = meanValue(V.begin() + 3 * fMeasureCount / 4 - 2, V.begin() + 3 * fMeasureCount / 4 + 3);
uint64 meaval100 = meanValue(V.end() - 5, V.end());
// Printing
std::cout << applname
<< '\t' << megapersec(bsize, ichans+ochans, meaval00)
<< '\t' << megapersec(bsize, ichans+ochans, meaval25)
<< '\t' << megapersec(bsize, ichans+ochans, meaval50)
<< '\t' << megapersec(bsize, ichans+ochans, meaval75)
<< '\t' << megapersec(bsize, ichans+ochans, meaval100)
<< std::endl;
}
bool isRunning() { return (fMeasure <= (fMeasureCount + fSkip)); }

};

/*
A class to measure DSP CPU use.
*/

class measure_dsp : public decorator_dsp {
protected:
FAUSTFLOAT** fInputs;
FAUSTFLOAT** fOutputs;
time_bench* fBench;
int fBufferSize;
void init()
{
fInputs = new FAUSTFLOAT*[fDSP->getNumInputs()];
for (int i = 0; i < fDSP->getNumInputs(); i++) {
fInputs[i] = new FAUSTFLOAT[fBufferSize];
memset(fInputs[i], 0, sizeof(FAUSTFLOAT) * fBufferSize);
}
fOutputs = new FAUSTFLOAT*[fDSP->getNumOutputs()];
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
fOutputs[i] = new FAUSTFLOAT[fBufferSize];
memset(fOutputs[i], 0, sizeof(FAUSTFLOAT) * fBufferSize);
}
}
public:
/**
* Constructor.
*
* @param dsp - the dsp to be measured.
* @param buffer_size - the buffer size used when calling 'computeAll'
* @param count - the number of cycles using in 'computeAll'
* @param skip - ??
*
*/
measure_dsp(dsp* dsp, int buffer_size, int count, int skip)
:decorator_dsp(dsp), fBufferSize(buffer_size)
{
init();
fBench = new time_bench(count, 10);
}
measure_dsp(dsp* dsp, int buffer_size, double duration_in_sec)
:decorator_dsp(dsp), fBufferSize(buffer_size)
{
init();
fBench = new time_bench(500, 10);
measure();
double duration = fBench->measureDurationUsec();
int cout = int (500 * (duration_in_sec * 1e6 / duration));
std::cout << "duration = " << duration << " count = " << cout << std::endl;
delete fBench;
fBench = new time_bench(cout, 10);
}
virtual ~measure_dsp()
{
for (int i = 0; i < fDSP->getNumInputs(); i++) {
delete [] fInputs[i];
}
delete [] fInputs;
for (int i = 0; i < fDSP->getNumOutputs(); i++) {
delete [] fOutputs[i];
}
delete[] fOutputs;
}
/*
Measure the duration of the compute call
*/
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
fBench->startMeasure();
fDSP->compute(count, inputs, outputs);
fBench->stopMeasure();
}
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
compute(count, inputs, outputs);
}
/*
Measure the duration of 'count' (given in constructor) calls to compute
*/
void computeAll()
{
AVOIDDENORMALS;
do {
compute(0, fBufferSize, fInputs, fOutputs);
} while (fBench->isRunning());
}
/**
* Initialize measure datas
*/
void openMeasure() { fBench->openMeasure(); }
/**
* Terminate measurement
*/
void closeMeasure() { fBench->closeMeasure(); }
double measureDurationUsec()
{
return fBench->measureDurationUsec();
}
void measure()
{
openMeasure();
computeAll();
closeMeasure();
}
/**
* Returns best estimation
*/
double getStats()
{
return fBench->getStats(fBufferSize, fDSP->getNumInputs(), fDSP->getNumOutputs());
}
/**
* Print the median value (in Megabytes/second) of fMeasureCount throughputs measurements
*/
void printStats(const char* applname)
{
fBench->printStats(applname, fBufferSize, fDSP->getNumInputs(), fDSP->getNumOutputs());
}
bool isRunning() { return fBench->isRunning(); }
};

#endif


+ 246
- 0
ports/temper/source/faust/dsp/dsp-combiner.h View File

@@ -0,0 +1,246 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef __dsp_combiner__
#define __dsp_combiner__

#include <string.h>
#include <assert.h>
#include "faust/dsp/dsp.h"

// Combine two DSP in sequence

class dsp_sequencer : public dsp {
private:
dsp* fDSP1;
dsp* fDSP2;
FAUSTFLOAT** fSeqBuffer;
public:
dsp_sequencer(dsp* dsp1, dsp* dsp2, int buffer_size = 4096)
:fDSP1(dsp1), fDSP2(dsp2)
{
assert(fDSP1->getNumOutputs() == fDSP2->getNumInputs());
fSeqBuffer = new FAUSTFLOAT*[fDSP1->getNumOutputs()];
for (int i = 0; i < fDSP1->getNumOutputs(); i++) {
fSeqBuffer[i] = new FAUSTFLOAT[buffer_size];
}
}
virtual ~dsp_sequencer()
{
for (int i = 0; i < fDSP1->getNumOutputs(); i++) {
delete [] fSeqBuffer[i];
}
delete [] fSeqBuffer;
delete fDSP1;
delete fDSP2;
}
virtual int getNumInputs() { return fDSP1->getNumInputs(); }
virtual int getNumOutputs() { return fDSP2->getNumOutputs(); }
virtual void buildUserInterface(UI* ui_interface)
{
ui_interface->openTabBox("Sequencer");
ui_interface->openVerticalBox("DSP1");
fDSP1->buildUserInterface(ui_interface);
ui_interface->closeBox();
ui_interface->openVerticalBox("DSP2");
fDSP2->buildUserInterface(ui_interface);
ui_interface->closeBox();
ui_interface->closeBox();
}
virtual int getSampleRate()
{
return fDSP1->getSampleRate();
}
virtual void init(int samplingRate)
{
fDSP1->init(samplingRate);
fDSP2->init(samplingRate);
}
virtual void instanceInit(int samplingRate)
{
fDSP1->instanceInit(samplingRate);
fDSP2->instanceInit(samplingRate);
}
virtual void instanceConstants(int samplingRate)
{
fDSP1->instanceConstants(samplingRate);
fDSP2->instanceConstants(samplingRate);
}
virtual void instanceResetUserInterface()
{
fDSP1->instanceResetUserInterface();
fDSP2->instanceResetUserInterface();
}
virtual void instanceClear()
{
fDSP1->instanceClear();
fDSP2->instanceClear();
}
virtual dsp* clone()
{
return new dsp_sequencer(fDSP1->clone(), fDSP2->clone());
}
virtual void metadata(Meta* m)
{
fDSP1->metadata(m);
fDSP2->metadata(m);
}
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
fDSP1->compute(count, inputs, fSeqBuffer);
fDSP2->compute(count, fSeqBuffer, outputs);
}
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
};

// Combine two DSP in parallel

class dsp_parallelizer : public dsp {
private:
dsp* fDSP1;
dsp* fDSP2;
public:
dsp_parallelizer(dsp* dsp1, dsp* dsp2, int buffer_size = 4096)
:fDSP1(dsp1), fDSP2(dsp2)
{}
virtual ~dsp_parallelizer()
{
delete fDSP1;
delete fDSP2;
}
virtual int getNumInputs() { return fDSP1->getNumInputs() + fDSP2->getNumInputs(); }
virtual int getNumOutputs() { return fDSP1->getNumOutputs() + fDSP2->getNumOutputs(); }
virtual void buildUserInterface(UI* ui_interface)
{
ui_interface->openTabBox("Parallelizer");
ui_interface->openVerticalBox("DSP1");
fDSP1->buildUserInterface(ui_interface);
ui_interface->closeBox();
ui_interface->openVerticalBox("DSP2");
fDSP2->buildUserInterface(ui_interface);
ui_interface->closeBox();
ui_interface->closeBox();
}
virtual int getSampleRate()
{
return fDSP1->getSampleRate();
}
virtual void init(int samplingRate)
{
fDSP1->init(samplingRate);
fDSP2->init(samplingRate);
}
virtual void instanceInit(int samplingRate)
{
fDSP1->instanceInit(samplingRate);
fDSP2->instanceInit(samplingRate);
}
virtual void instanceConstants(int samplingRate)
{
fDSP1->instanceConstants(samplingRate);
fDSP2->instanceConstants(samplingRate);
}
virtual void instanceResetUserInterface()
{
fDSP1->instanceResetUserInterface();
fDSP2->instanceResetUserInterface();
}
virtual void instanceClear()
{
fDSP1->instanceClear();
fDSP2->instanceClear();
}
virtual dsp* clone()
{
return new dsp_parallelizer(fDSP1->clone(), fDSP2->clone());
}

virtual void metadata(Meta* m)
{
fDSP1->metadata(m);
fDSP2->metadata(m);
}
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
fDSP1->compute(count, inputs, outputs);
// Shift inputs/outputs channels for fDSP2
FAUSTFLOAT** inputs_dsp2 = (FAUSTFLOAT**)alloca(fDSP2->getNumInputs() * sizeof(FAUSTFLOAT*));
for (int chan = 0; chan < fDSP2->getNumInputs(); chan++) {
inputs_dsp2[chan] = inputs[fDSP1->getNumInputs() + chan];
}
FAUSTFLOAT** outputs_dsp2 = (FAUSTFLOAT**)alloca(fDSP2->getNumOutputs() * sizeof(FAUSTFLOAT*));
for (int chan = 0; chan < fDSP2->getNumOutputs(); chan++) {
outputs_dsp2[chan] = inputs[fDSP1->getNumOutputs() + chan];
}
fDSP2->compute(count, inputs_dsp2, outputs_dsp2);
}
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
};

#endif

+ 191
- 0
ports/temper/source/faust/dsp/dsp.h View File

@@ -0,0 +1,191 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/
/******************************************************************************
*******************************************************************************

FAUST DSP

*******************************************************************************
*******************************************************************************/

#ifndef __dsp__
#define __dsp__

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

class UI;
struct Meta;

/**
* Signal processor definition.
*/

class dsp {

public:

dsp() {}
virtual ~dsp() {}

/* Return instance number of audio inputs */
virtual int getNumInputs() = 0;
/* Return instance number of audio outputs */
virtual int getNumOutputs() = 0;
/**
* Trigger the UI* parameter with instance specific calls
* to 'addBtton', 'addVerticalSlider'... in order to build the UI.
*
* @param ui_interface - the UI* user interface builder
*/
virtual void buildUserInterface(UI* ui_interface) = 0;
/* Returns the sample rate currently used by the instance */
virtual int getSampleRate() = 0;
/** Global init, calls the following methods :
* - static class 'classInit' : static table initialisation
* - 'instanceInit' : constants and instance table initialisation
*
* @param samplingRate - the sampling rate in Herz
*/
virtual void init(int samplingRate) = 0;
/** Init instance state
*
* @param samplingRate - the sampling rate in Herz
*/
virtual void instanceInit(int samplingRate) = 0;
/** Init instance constant state
*
* @param samplingRate - the sampling rate in Herz
*/
virtual void instanceConstants(int samplingRate) = 0;
/* Init default control parameters values */
virtual void instanceResetUserInterface() = 0;
/* Init instance state (delay lines...) */
virtual void instanceClear() = 0;
/**
* Return a clone of the instance.
*
* @return a copy of the instance on success, otherwise a null pointer.
*/
virtual dsp* clone() = 0;
/**
* Trigger the Meta* parameter with instance specific calls to 'declare' (key, value metadata).
*
* @param m - the Meta* meta user
*/
virtual void metadata(Meta* m) = 0;
/**
* DSP instance computation, to be called with sucessive in/out audio buffers.
*
* @param count - the nomber of frames to compute
* @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, doucbe or quad)
* @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, doucbe or quad)
*
*/
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
/**
* DSP instance computation : alternative method to be used by subclasses.
*
* @param date_usec - the timestamp in microsec given by audio driver.
* @param count - the nomber of frames to compute
* @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, doucbe or quad)
* @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, doucbe or quad)
*
*/
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
};

/**
* Generic DSP decorator.
*/

class decorator_dsp : public ::dsp {

protected:

dsp* fDSP;

public:

decorator_dsp(dsp* dsp = 0):fDSP(dsp) {}
virtual ~decorator_dsp() { delete fDSP; }

virtual int getNumInputs() { return fDSP->getNumInputs(); }
virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
virtual int getSampleRate() { return fDSP->getSampleRate(); }
virtual void init(int samplingRate) { fDSP->init(samplingRate); }
virtual void instanceInit(int samplingRate) { fDSP->instanceInit(samplingRate); }
virtual void instanceConstants(int samplingRate) { fDSP->instanceConstants(samplingRate); }
virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
virtual void instanceClear() { fDSP->instanceClear(); }
virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
virtual void metadata(Meta* m) { return fDSP->metadata(m); }
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
};

/**
* On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
* flags to avoid costly denormals.
*/

#ifdef __SSE__
#include <xmmintrin.h>
#ifdef __SSE2__
#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
#else
#define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
#endif
#else
#define AVOIDDENORMALS
#endif

#endif

+ 68
- 0
ports/temper/source/faust/dsp/faust-engine.h View File

@@ -0,0 +1,68 @@
/************************************************************************
************************************************************************
FAUST Polyphonic Architecture File
Copyright (C) 2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------

This is sample code. This file is provided as an example of minimal
FAUST architecture file. Redistribution and use in source and binary
forms, with or without modification, in part or in full are permitted.
In particular you can create a derived work of this FAUST architecture
and distribute that work under terms of your choice.

This sample code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
************************************************************************
************************************************************************/

#ifndef __faust_engine__
#define __faust_engine__

#ifdef __cplusplus
extern "C" {
#endif

void* create(int, int); // To be implemented
void destroy(void*);

bool start(void*);
void stop(void*);
bool isRunning(void*);

long keyOn(void*, int, int);
int keyOff(void*, int);
void propagateMidi(void*, int, double, int, int, int, int);

const char* getJSONUI(void*);
const char* getJSONMeta(void*);

int getParamsCount(void*);

void setParamValue(void*, const char*, float);
float getParamValue(void*, const char*);
void setParamIdValue(void*, int, float);
float getParamIdValue(void*, int);

void setVoiceParamValue(void*, const char*, long, float);
float getVoiceParamValue(void*, const char*, long);

const char* getParamAddress(void*, int);

void propagateAcc(void*, int, float);
void setAccConverter(void*, int, int, int, float, float, float);

void propagateGyr(void*, int, float);
void setGyrConverter(void*, int, int, int, float, float, float);

float getCPULoad(void*);
int getScreenColor(void*);

#ifdef __cplusplus
}
#endif

#endif // __faust_engine__

+ 627
- 0
ports/temper/source/faust/dsp/faust-poly-engine.h View File

@@ -0,0 +1,627 @@
/************************************************************************
************************************************************************
FAUST Polyphonic Architecture File
Copyright (C) 2013 GRAME, Romain Michon, CCRMA - Stanford University
Copyright (C) 2003-2015 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------

This is sample code. This file is provided as an example of minimal
FAUST architecture file. Redistribution and use in source and binary
forms, with or without modification, in part or in full are permitted.
In particular you can create a derived work of this FAUST architecture
and distribute that work under terms of your choice.

This sample code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
************************************************************************
************************************************************************/

#ifndef __faust_poly_engine__
#define __faust_poly_engine__

#include <math.h>
#include <stdio.h>
#include <string.h>

#include "faust/misc.h"
#include "faust/dsp/dsp.h"
#include "faust/audio/audio.h"
#include "faust/gui/meta.h"
#include "faust/gui/JSONUI.h"
#include "faust/gui/APIUI.h"
#include "faust/dsp/poly-dsp.h"
#include "faust/dsp/faust-engine.h"
#include "faust/dsp/dsp-combiner.h"

//**************************************************************
// Mono or polyphonic audio DSP engine
//**************************************************************

using namespace std;

struct MyMeta : public Meta, public std::map<const char*, const char*>
{
void declare(const char* key, const char* value)
{
(*this)[key] = value;
}
const char* get(const char* key, const char* def)
{
if (this->find(key) != this->end()) {
return (*this)[key];
} else {
return def;
}
}
};

static void analyseMeta(bool& midi_sync, int& nvoices)
{
mydsp* tmp_dsp = new mydsp();
JSONUI jsonui;
tmp_dsp->buildUserInterface(&jsonui);
std::string json = jsonui.JSON();
midi_sync = ((json.find("midi") != std::string::npos) &&
((json.find("start") != std::string::npos) ||
(json.find("stop") != std::string::npos) ||
(json.find("clock") != std::string::npos)));
#ifdef NVOICES
nvoices = NVOICES;
#else
MyMeta meta;
tmp_dsp->metadata(&meta);
const char* numVoices = meta.get("nvoices", "0");
nvoices = atoi(numVoices);
if (nvoices < 0) nvoices = 0;
#endif
delete tmp_dsp;
}

class FaustPolyEngine {
protected:

mydsp_poly* fPolyDSP; // the polyphonic Faust object
dsp* fFinalDSP; // the "final" dsp object submitted to the audio driver
APIUI fAPIUI; // the UI description

string fJSONUI;
string fJSONMeta;
bool fRunning;
audio* fDriver;
midi_handler fMidiHandler;
MidiUI fMidiUI;
public:

FaustPolyEngine(audio* driver = NULL):fMidiUI(&fMidiHandler)
{
bool midi_sync = false;
int nvoices = 1;
fDriver = driver;
fRunning = false;
mydsp* mono_dsp = new mydsp();
analyseMeta(midi_sync, nvoices);
// Getting the UI JSON
JSONUI jsonui1(mono_dsp->getNumInputs(), mono_dsp->getNumOutputs());
mono_dsp->buildUserInterface(&jsonui1);
fJSONUI = jsonui1.JSON();
// Getting the metadata JSON
JSONUI jsonui1M(mono_dsp->getNumInputs(), mono_dsp->getNumOutputs());
mono_dsp->metadata(&jsonui1M);
fJSONMeta = jsonui1M.JSON();

if (fJSONUI.find("keyboard") != std::string::npos
|| fJSONUI.find("poly") != std::string::npos
|| nvoices > 1) {
fPolyDSP = new mydsp_poly(mono_dsp, nvoices, true);

#if POLY2
fFinalDSP = new dsp_sequencer(fPolyDSP, new effect());
#else
fFinalDSP = fPolyDSP;
#endif
// Update JSONs with Poly version
JSONUI jsonui2(mono_dsp->getNumInputs(), mono_dsp->getNumOutputs());
fFinalDSP->buildUserInterface(&jsonui2);
fJSONUI = jsonui2.JSON();
JSONUI jsonui2M(mono_dsp->getNumInputs(), mono_dsp->getNumOutputs());
fFinalDSP->metadata(&jsonui2M);
fJSONMeta = jsonui2M.JSON();
} else {
fPolyDSP = NULL;
fFinalDSP = mono_dsp;
}
fFinalDSP->buildUserInterface(&fMidiUI);
fFinalDSP->buildUserInterface(&fAPIUI);

fDriver->init("Dummy", fFinalDSP);
}

virtual ~FaustPolyEngine()
{
delete fDriver;
delete fFinalDSP;
}

/*
* start()
* Begins the processing and return true if the connection
* with the audio device was successful and false if not.
*/
bool start()
{
if (!fRunning) {
fRunning = fDriver->start();
}
return fRunning;
}
/*
* isRunning()
* Returns true if the DSP frames are being computed and
* false if not.
*/
bool isRunning()
{
return fRunning;
}

/*
* stop()
* Stops the processing, closes the audio engine.
*/
void stop()
{
if (fRunning) {
fRunning = false;
fDriver->stop();
}
}
/*
* keyOn(pitch, velocity)
* Instantiates a new polyphonic voice where velocity
* and pitch are MIDI numbers (0-127). keyOn can only
* be used if the [style:poly] metadata is used in the
* Faust code. keyOn will return 0 if the object is not
* polyphonic and the allocated voice otherwise.
*/
MapUI* keyOn(int pitch, int velocity)
{
if (fPolyDSP) {
return fPolyDSP->keyOn(0, pitch, velocity); // MapUI* passed to Java as an integer
} else {
return 0;
}
}

/*
* keyOff(pitch)
* De-instantiates a polyphonic voice where pitch is the
* MIDI number of the note (0-127). keyOff can only be
* used if the [style:poly] metadata is used in the Faust
* code. keyOn will return 0 if the object is not polyphonic
* and 1 otherwise.
*/
int keyOff(int pitch, int velocity = 127)
{
if (fPolyDSP) {
fPolyDSP->keyOff(0, pitch, velocity);
return 1;
} else {
return 0;
}
}

/*
* newVoice()
* Instantiate a new voice and returns the corresponding mapUI.
*/
MapUI* newVoice()
{
if (fPolyDSP) {
return fPolyDSP->newVoice();
} else {
return 0;
}
}

/*
* deleteVoice(MapUI* voice)
* Delete a voice based on its MapUI*.
*/
int deleteVoice(MapUI* voice)
{
if (fPolyDSP) {
fPolyDSP->deleteVoice(voice);
return 1;
} else {
return 0;
}
}

/*
* deleteVoice(long voice)
* Delete a voice based on its MapUI* casted as a long.
*/
int deleteVoice(long voice)
{
return deleteVoice(reinterpret_cast<MapUI*>(voice));
}
/*
* allNotesOff()
* Gently terminates all the active voices.
*/
void allNotesOff()
{
if (fPolyDSP) {
fPolyDSP->allNotesOff();
}
}
/*
* Propagate MIDI data to the Faust object.
*/
void propagateMidi(int count, double time, int type, int channel, int data1, int data2)
{
if (count == 3) fMidiHandler.handleData2(time, type, channel, data1, data2);
else if (count == 2) fMidiHandler.handleData1(time, type, channel, data1);
else if (count == 1) fMidiHandler.handleSync(time, type);
GUI::updateAllGuis();
}
/*
* getJSONUI()
* Returns a string containing a JSON description of the
* UI of the Faust object.
*/
const char* getJSONUI()
{
return fJSONUI.c_str();
}
/*
* getJSONMeta()
* Returns a string containing a JSON description of the
* metadata of the Faust object.
*/
const char* getJSONMeta()
{
return fJSONMeta.c_str();
}
/*
* buildUserInterface(ui)
* Calls the polyphonic of monophonic buildUserInterface with the ui parameter.
*/
void buildUserInterface(UI* ui_interface)
{
fFinalDSP->buildUserInterface(ui_interface);
}

/*
* getParamsCount()
* Returns the number of control parameters of the Faust object.
*/
int getParamsCount()
{
return fAPIUI.getParamsCount();
}
/*
* setParamValue(address, value)
* Sets the value of the parameter associated with address.
*/
void setParamValue(const char* address, float value)
{
int id = fAPIUI.getParamIndex(address);
if (id >= 0) {
fAPIUI.setParamValue(id, value);
// In POLY mode, update all voices
GUI::updateAllGuis();
}
}

/*
* getParamValue(address)
* Takes the address of a parameter and returns its current
* value.
*/
float getParamValue(const char* address)
{
int id = fAPIUI.getParamIndex(address);
return (id >= 0) ? fAPIUI.getParamValue(id) : 0.f;
}
/*
* setParamValue(id, value)
* Sets the value of the parameter associated with id.
*/
void setParamValue(int id, float value)
{
fAPIUI.setParamValue(id, value);
// In POLY mode, update all voices
GUI::updateAllGuis();
}
/*
* getParamValue(id)
* Takes the id of a parameter and returns its current
* value.
*/
float getParamValue(int id)
{
return fAPIUI.getParamValue(id);
}

/*
* setVoiceParamValue(address, voice, value)
* Sets the value of the parameter associated with address for
* the voice. setVoiceParamValue can only be
* used if the [style:poly] metadata is used in the Faust code.
*/
void setVoiceParamValue(const char* address, long voice, float value)
{
reinterpret_cast<MapUI*>(voice)->setParamValue(address, value);
}

/*
* setVoiceParamValue(id, voice, value)
* Sets the value of the parameter associated with the id for
* the voice. setVoiceParamValue can only be
* used if the [style:poly] metadata is used in the Faust code.
*/
void setVoiceParamValue(int id, long voice, float value)
{
reinterpret_cast<MapUI*>(voice)->setParamValue(reinterpret_cast<MapUI*>(voice)->getParamAddress(id), value);
}
/*
* getVoiceParamValue(address, voice)
* Gets the parameter value associated with address for the voice.
* getVoiceParamValue can only be used if the [style:poly] metadata
* is used in the Faust code.
*/
float getVoiceParamValue(const char* address, long voice)
{
return reinterpret_cast<MapUI*>(voice)->getParamValue(address);
}

/*
* getVoiceParamValue(id, voice)
* Gets the parameter value associated with the id for the voice.
* getVoiceParamValue can only be used if the [style:poly] metadata
* is used in the Faust code.
*/
float getVoiceParamValue(int id, long voice)
{
return reinterpret_cast<MapUI*>(voice)->getParamValue(reinterpret_cast<MapUI*>(voice)->getParamAddress(id));
}
/*
* getParamAddress(id)
* Returns the address of a parameter in function of its "id".
*/
const char* getParamAddress(int id)
{
return fAPIUI.getParamAddress(id);
}

/*
* getVoiceParamAddress(id, voice)
* Returns the address of a parameter for a specific voice
* in function of its "id".
*/
const char* getVoiceParamAddress(int id, long voice)
{
return reinterpret_cast<MapUI*>(voice)->getParamAddress(id).c_str();
}
/*
* getParamMin(address)
* Returns the minimum value of a parameter.
*/
float getParamMin(const char* address)
{
int id = fAPIUI.getParamIndex(address);
return (id >= 0) ? fAPIUI.getParamMin(id) : 0.f;
}
/*
* getParamMin(id)
* Returns the minimum value of a parameter.
*/
float getParamMin(int id)
{
return fAPIUI.getParamMin(id);
}
/*
* getParamMax(address)
* Returns the maximum value of a parameter.
*/
float getParamMax(const char* address)
{
int id = fAPIUI.getParamIndex(address);
return (id >= 0) ? fAPIUI.getParamMax(id) : 0.f;
}
/*
* getParamMax(id)
* Returns the maximum value of a parameter.
*/
float getParamMax(int id)
{
return fAPIUI.getParamMax(id);
}
/*
* getParamInit(address)
* Returns the default value of a parameter.
*/
float getParamInit(const char* address)
{
int id = fAPIUI.getParamIndex(address);
return (id >= 0) ? fAPIUI.getParamInit(id) : 0.f;
}
/*
* getParamInit(id)
* Returns the default value of a parameter.
*/
float getParamInit(int id)
{
return fAPIUI.getParamInit(id);
}
/*
* getParamTooltip(address)
* Returns the tooltip of a parameter.
*/
const char* getParamTooltip(const char* address)
{
int id = fAPIUI.getParamIndex(address);
return (id >= 0) ? fAPIUI.getParamTooltip(id) : "";
}
/*
* getParamTooltip(id)
* Returns the tooltip of a parameter.
*/
const char* getParamTooltip(int id)
{
return fAPIUI.getParamTooltip(id);
}

/*
* propagateAcc(int acc, float v)
* Propage accelerometer value to the curve conversion layer.
*/
void propagateAcc(int acc, float v)
{
fAPIUI.propagateAcc(acc, v);
GUI::updateAllGuis();
}

/*
* setAccConverter(int p, int acc, int curve, float amin, float amid, float amax)
* Change accelerometer curve mapping.
*/
void setAccConverter(int p, int acc, int curve, float amin, float amid, float amax)
{
fAPIUI.setAccConverter(p, acc, curve, amin, amid, amax);
}

/*
* propagateGyr(int gyr, float v)
* Propage gyroscope value to the curve conversion layer.
*/
void propagateGyr(int gyr, float v)
{
fAPIUI.propagateGyr(gyr, v);
GUI::updateAllGuis();
}

/*
* setGyrConverter(int p, int acc, int curve, float amin, float amid, float amax)
* Change gyroscope curve mapping.
*/
void setGyrConverter(int p, int gyr, int curve, float amin, float amid, float amax)
{
fAPIUI.setGyrConverter(p, gyr, curve, amin, amid, amax);
}
/*
* getCPULoad()
* Return DSP CPU load.
*/
float getCPULoad() { return fDriver->get_cpu_load(); }

/*
* getScreenColor() -> c:int
* Get the requested screen color c :
* c < 0 : no screen color requested (keep regular UI)
* c >= 0 : requested color (no UI but a colored screen)
*/
int getScreenColor()
{
return fAPIUI.getScreenColor();
}

};

// Public C API

#ifdef __cplusplus
extern "C" {
#endif
void destroy(void* dsp) { delete reinterpret_cast<FaustPolyEngine*>(dsp); }

bool start(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->start(); }
void stop(void* dsp) { reinterpret_cast<FaustPolyEngine*>(dsp)->stop(); }
bool isRunning(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->isRunning(); }

long keyOn(void* dsp, int pitch, int velocity) { return (long)reinterpret_cast<FaustPolyEngine*>(dsp)->keyOn(pitch, velocity); }
int keyOff(void* dsp, int pitch) { return reinterpret_cast<FaustPolyEngine*>(dsp)->keyOff(pitch); }
void propagateMidi(void* dsp, int count, double time, int type, int channel, int data1, int data2)
{
reinterpret_cast<FaustPolyEngine*>(dsp)->propagateMidi(count, time, type, channel, data1, data2);
}

const char* getJSONUI(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getJSONUI(); }
const char* getJSONMeta(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getJSONMeta(); }

int getParamsCount(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getParamsCount(); }
void setParamValue(void* dsp, const char* address, float value) { reinterpret_cast<FaustPolyEngine*>(dsp)->setParamValue(address, value); }
float getParamValue(void* dsp, const char* address) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getParamValue(address); }
void setParamIdValue(void* dsp, int id, float value) { reinterpret_cast<FaustPolyEngine*>(dsp)->setParamValue(id, value); }
float getParamIdValue(void* dsp, int id) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getParamValue(id); }
void setVoiceParamValue(void* dsp, const char* address, long voice, float value)
{
reinterpret_cast<FaustPolyEngine*>(dsp)->setVoiceParamValue(address, voice, value);
}
float getVoiceParamValue(void* dsp, const char* address, long voice) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getVoiceParamValue(address, voice); }
const char* getParamAddress(void* dsp, int id) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getParamAddress(id); }

void propagateAcc(void* dsp, int acc, float v) { reinterpret_cast<FaustPolyEngine*>(dsp)->propagateAcc(acc, v); }
void setAccConverter(void* dsp, int p, int acc, int curve, float amin, float amid, float amax)
{
reinterpret_cast<FaustPolyEngine*>(dsp)->setAccConverter(p, acc, curve, amin, amid, amax);
}
void propagateGyr(void* dsp, int acc, float v) { reinterpret_cast<FaustPolyEngine*>(dsp)->propagateGyr(acc, v); }
void setGyrConverter(void* dsp, int p, int gyr, int curve, float amin, float amid, float amax)
{
reinterpret_cast<FaustPolyEngine*>(dsp)->setGyrConverter(p, gyr, curve, amin, amid, amax);
}

float getCPULoad(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getCPULoad(); }
int getScreenColor(void* dsp) { return reinterpret_cast<FaustPolyEngine*>(dsp)->getScreenColor(); }
#ifdef __cplusplus
}
#endif

#endif // __faust_poly_engine__

+ 661
- 0
ports/temper/source/faust/dsp/poly-dsp.h View File

@@ -0,0 +1,661 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/
/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.
EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.
************************************************************************
************************************************************************/

#ifndef __poly_dsp__
#define __poly_dsp__

#include <stdio.h>
#include <string>
#include <math.h>
#include <float.h>
#include <algorithm>
#include <ostream>
#include <sstream>
#include <vector>
#include <limits.h>

#include "faust/gui/MidiUI.h"
#include "faust/gui/JSONUI.h"
#include "faust/gui/MapUI.h"
#include "faust/dsp/proxy-dsp.h"

#define kActiveVoice 0
#define kFreeVoice -1
#define kReleaseVoice -2
#define kNoVoice -3

#define VOICE_STOP_LEVEL 0.001
#define MIX_BUFFER_SIZE 16384

#define FLOAT_MAX(a, b) (((a) < (b)) ? (b) : (a))

// ends_with(<str>,<end>) : returns true if <str> ends with <end>
static inline bool ends_with(std::string const& str, std::string const& end)
{
size_t l1 = str.length();
size_t l2 = end.length();
return (l1 >= l2) && (0 == str.compare(l1 - l2, l2, end));
}

static inline double midiToFreq(double note)
{
return 440.0 * pow(2.0, (note-69.0)/12.0);
}

static inline unsigned int isPowerOfTwo(unsigned int n)
{
return !(n & (n - 1));
}

class GroupUI : public GUI, public PathBuilder
{
private:
std::map<std::string, uiGroupItem*> fLabelZoneMap;
void insertMap(std::string label, FAUSTFLOAT* zone)
{
if (!ends_with(label, "/gate")
&& !ends_with(label, "/freq")
&& !ends_with(label, "/gain")) {
// Groups all controller except 'freq', 'gate', and 'gain'
if (fLabelZoneMap.find(label) != fLabelZoneMap.end()) {
fLabelZoneMap[label]->addZone(zone);
} else {
fLabelZoneMap[label] = new uiGroupItem(this, zone);
}
}
}
uiCallbackItem* fPanic;
public:
GroupUI(FAUSTFLOAT* zone, uiCallback cb, void* arg)
{
fPanic = new uiCallbackItem(this, zone, cb, arg);
};
virtual ~GroupUI()
{
// 'fPanic' is kept and deleted in GUI, so do not delete here
};
// -- widget's layouts
void openTabBox(const char* label)
{
fControlsLevel.push_back(label);
}
void openHorizontalBox(const char* label)
{
fControlsLevel.push_back(label);
}
void openVerticalBox(const char* label)
{
fControlsLevel.push_back(label);
}
void closeBox()
{
fControlsLevel.pop_back();
}
// -- active widgets
void addButton(const char* label, FAUSTFLOAT* zone)
{
insertMap(buildPath(label), zone);
}
void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
insertMap(buildPath(label), zone);
}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
insertMap(buildPath(label), zone);
}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
insertMap(buildPath(label), zone);
}
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
insertMap(buildPath(label), zone);
}
// -- passive widgets
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT fmin, FAUSTFLOAT fmax)
{
insertMap(buildPath(label), zone);
}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT fmin, FAUSTFLOAT fmax)
{
insertMap(buildPath(label), zone);
}
// -- metadata declarations
void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{}
};

// One voice of polyphony
struct dsp_voice : public MapUI, public decorator_dsp {
int fNote; // Playing note actual pitch
int fDate; // KeyOn date
bool fTrigger; // True if stolen note and need for envelop re-trigger
FAUSTFLOAT fLevel; // Last audio block level

dsp_voice(dsp* dsp):decorator_dsp(dsp)
{
dsp->buildUserInterface(this);
fNote = kFreeVoice;
fLevel = FAUSTFLOAT(0);
fDate = 0;
fTrigger = false;
}
void extractLabels(std::string& gate, std::string& freq, std::string& gain)
{
// Keep gain, freq and gate labels
std::map<std::string, FAUSTFLOAT*>::iterator it;
for (it = getMap().begin(); it != getMap().end(); it++) {
std::string label = (*it).first;
if (ends_with(label, "/gate")) {
gate = label;
} else if (ends_with(label, "/freq")) {
freq = label;
} else if (ends_with(label, "/gain")) {
gain = label;
}
}
}
void computeSlice(int offset, int slice, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
if (slice > 0) {
FAUSTFLOAT** inputs_slice = (FAUSTFLOAT**)alloca(getNumInputs() * sizeof(FAUSTFLOAT*));
for (int chan = 0; chan < getNumInputs(); chan++) {
inputs_slice[chan] = &(inputs[chan][offset]);
}
FAUSTFLOAT** outputs_slice = (FAUSTFLOAT**)alloca(getNumOutputs() * sizeof(FAUSTFLOAT*));
for (int chan = 0; chan < getNumOutputs(); chan++) {
outputs_slice[chan] = &(outputs[chan][offset]);
}
compute(slice, inputs_slice, outputs_slice);
}
}
};

/**
* Polyphonic DSP : group a set of DSP to be played together or triggered by MIDI.
*/

class mydsp_poly : public dsp, public midi {

private:
dsp* fDSP;
std::vector<dsp_voice*> fVoiceTable; // Individual voices
dsp* fVoiceGroup; // Voices group to be used for GUI grouped control
std::string fGateLabel;
std::string fGainLabel;
std::string fFreqLabel;
FAUSTFLOAT fPanic;
int fPolyphony;
bool fVoiceControl;
bool fGroupControl;
GroupUI fGroups;
FAUSTFLOAT** fMixBuffer;
int fNumOutputs;
int fDate;
std::vector<MidiUI*> fMidiUIList;
inline FAUSTFLOAT mixVoice(int count, FAUSTFLOAT** outputBuffer, FAUSTFLOAT** mixBuffer)
{
FAUSTFLOAT level = 0;
for (int i = 0; i < fNumOutputs; i++) {
FAUSTFLOAT* mixChannel = mixBuffer[i];
FAUSTFLOAT* outChannel = outputBuffer[i];
for (int j = 0; j < count; j++) {
level = FLOAT_MAX(level, (FAUSTFLOAT)fabs(outChannel[j]));
mixChannel[j] += outChannel[j];
}
}
return level;
}
inline void clearOutput(int count, FAUSTFLOAT** mixBuffer)
{
for (int i = 0; i < fNumOutputs; i++) {
memset(mixBuffer[i], 0, count * sizeof(FAUSTFLOAT));
}
}
inline int getVoice(int note, bool steal = false)
{
for (int i = 0; i < fPolyphony; i++) {
if (fVoiceTable[i]->fNote == note) {
if (steal) {
fVoiceTable[i]->fDate = fDate++;
}
return i;
}
}
if (steal) {
int voice_release = kNoVoice;
int voice_playing = kNoVoice;
int oldest_date_release = INT_MAX;
int oldest_date_playing = INT_MAX;
// Scan all voices
for (int i = 0; i < fPolyphony; i++) {
if (fVoiceTable[i]->fNote == kReleaseVoice) {
// Keeps oldest release voice
if (fVoiceTable[i]->fDate < oldest_date_release) {
oldest_date_release = fVoiceTable[i]->fDate;
voice_release = i;
}
} else {
// Otherwise keeps oldest playing voice
if (fVoiceTable[i]->fDate < oldest_date_playing) {
oldest_date_playing = fVoiceTable[i]->fDate;
voice_playing = i;
}
}
}
// Then decide which one to steal
if (oldest_date_release != INT_MAX) {
std::cout << "Steal release voice : voice_date " << fVoiceTable[voice_release]->fDate << " cur_date = " << fDate << " voice = " << voice_release << std::endl;
fVoiceTable[voice_release]->fDate = fDate++;
fVoiceTable[voice_release]->fTrigger = true;
return voice_release;
} else if (oldest_date_playing != INT_MAX) {
std::cout << "Steal playing voice : voice_date " << fVoiceTable[voice_playing]->fDate << " cur_date = " << fDate << " voice = " << voice_playing << std::endl;
fVoiceTable[voice_playing]->fDate = fDate++;
fVoiceTable[voice_playing]->fTrigger = true;
return voice_playing;
} else {
assert(false);
return kNoVoice;
}
} else {
return kNoVoice;
}
}
inline void init(dsp* dsp, int max_polyphony, bool control, bool group)
{
fDSP = dsp;
fVoiceControl = control;
fGroupControl = group;
fPolyphony = max_polyphony;
fFreqLabel = fGateLabel = fGainLabel = "";
// Create voices
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable.push_back(new dsp_voice(dsp->clone()));
}
// Init audio output buffers
fNumOutputs = fVoiceTable[0]->getNumOutputs();
fMixBuffer = new FAUSTFLOAT*[fNumOutputs];
for (int i = 0; i < fNumOutputs; i++) {
fMixBuffer[i] = new FAUSTFLOAT[MIX_BUFFER_SIZE];
}
// Groups all uiItem for a given path
fVoiceGroup = new proxy_dsp(fVoiceTable[0]);
fVoiceGroup->buildUserInterface(&fGroups);
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->buildUserInterface(&fGroups);
}
fDate = 0;
// Keep gain, freq and gate labels
fVoiceTable[0]->extractLabels(fGateLabel, fFreqLabel, fGainLabel);
}
void uIBuilder(UI* ui_interface)
{
ui_interface->openTabBox("Polyphonic");
// Grouped voices UI
ui_interface->openVerticalBox("Voices");
ui_interface->addButton("Panic", &fPanic);
fVoiceGroup->buildUserInterface(ui_interface);
ui_interface->closeBox();
// In not group, also add individual voices UI
if (!fGroupControl) {
for (int i = 0; i < fPolyphony; i++) {
char buffer[32];
snprintf(buffer, 31, ((fPolyphony < 8) ? "Voice%d" : "V%d"), i+1);
ui_interface->openHorizontalBox(buffer);
fVoiceTable[i]->buildUserInterface(ui_interface);
ui_interface->closeBox();
}
}
ui_interface->closeBox();
}
static void panic(FAUSTFLOAT val, void* arg)
{
if (val == FAUSTFLOAT(1)) {
static_cast<mydsp_poly*>(arg)->hardAllNotesOff();
}
}
inline bool checkPolyphony()
{
if (fFreqLabel == "") {
std::cout << "DSP is not polyphonic...\n";
return false;
} else {
return true;;
}
}
// Always returns a voice
int newVoiceAux()
{
int voice = getVoice(kFreeVoice, true);
assert(voice != kNoVoice);
fVoiceTable[voice]->fNote = kActiveVoice;
return voice;
}
public:
/**
* Constructor.
*
* @param dsp - the dsp to be used for one voice. Beware : mydsp_poly will use and finally delete the pointer.
* @param max_polyphony - number of voices of polyphony
* @param control - whether voices will be dynamically allocated and controlled (typically by a MIDI controler).
* If false all voices are always running.
* @param group - if true, voices are not individually accessible, a global "Voices" tab will automatically dispatch
* a given control on all voices, assuming GUI::updateAllGuis() is called.
* If false, all voices can be individually controlled.
*
*/
mydsp_poly(dsp* dsp,
int max_polyphony,
bool control = false,
bool group = true): fPanic(FAUSTFLOAT(0)), fGroups(&fPanic, panic, this)
{
init(dsp, max_polyphony, control, group);
}
void metadata(Meta* meta) { fVoiceTable[0]->metadata(meta); }

virtual ~mydsp_poly()
{
for (int i = 0; i < fNumOutputs; i++) {
delete[] fMixBuffer[i];
}
delete[] fMixBuffer;
for (int i = 0; i < fPolyphony; i++) {
delete fVoiceTable[i];
}
delete fVoiceGroup;
// Remove object from all MidiUI interfaces that handle it
for (int i = 0; i < fMidiUIList.size(); i++) {
fMidiUIList[i]->removeMidiIn(this);
}
delete fDSP;
}
void init(int sample_rate)
{
// Init voices
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->init(sample_rate);
}
}
void instanceInit(int sample_rate)
{
// Init voices
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->instanceInit(sample_rate);
}
}
void instanceConstants(int sample_rate)
{
// Init voices
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->instanceConstants(sample_rate);
}
}
void instanceResetUserInterface()
{
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->instanceResetUserInterface();
}
}
void instanceClear()
{
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->instanceClear();
}
}
virtual int getSampleRate() { return fVoiceTable[0]->getSampleRate(); }
virtual mydsp_poly* clone()
{
return new mydsp_poly(fDSP->clone(), fPolyphony, fVoiceControl, fGroupControl);
}
void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
assert(count < MIX_BUFFER_SIZE);
// First clear the outputs
clearOutput(count, outputs);
if (fVoiceControl) {
// Mix all playing voices
for (int i = 0; i < fPolyphony; i++) {
if (fVoiceTable[i]->fNote != kFreeVoice) {
if (fVoiceTable[i]->fTrigger) {
// New note, so re-trigger
fVoiceTable[i]->fTrigger = false;
fVoiceTable[i]->setParamValue(fGateLabel, 0.0f);
fVoiceTable[i]->computeSlice(0, 1, inputs, fMixBuffer);
fVoiceTable[i]->setParamValue(fGateLabel, 1.0f);
fVoiceTable[i]->computeSlice(1, count - 1, inputs, fMixBuffer);
} else {
// Compute regular voice
fVoiceTable[i]->compute(count, inputs, fMixBuffer);
}
// Mix it in result
fVoiceTable[i]->fLevel = mixVoice(count, fMixBuffer, outputs);
// Check the level to possibly set the voice in kFreeVoice again
if ((fVoiceTable[i]->fLevel < VOICE_STOP_LEVEL) && (fVoiceTable[i]->fNote == kReleaseVoice)) {
fVoiceTable[i]->fNote = kFreeVoice;
}
}
}
} else {
// Mix all voices
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->compute(count, inputs, fMixBuffer);
mixVoice(count, fMixBuffer, outputs);
}
}
}
int getNumInputs()
{
return fVoiceTable[0]->getNumInputs();
}
int getNumOutputs()
{
return fVoiceTable[0]->getNumOutputs();
}
void buildUserInterface(UI* ui_interface)
{
// Add itself to the MidiUI object
MidiUI* midi_ui = dynamic_cast<MidiUI*>(ui_interface);
if (midi_ui) {
fMidiUIList.push_back(midi_ui);
midi_ui->addMidiIn(this);
}
if (fPolyphony > 1) {
uIBuilder(ui_interface);
} else {
fVoiceTable[0]->buildUserInterface(ui_interface);
}
}
MapUI* newVoice()
{
return fVoiceTable[newVoiceAux()];
}
void deleteVoice(MapUI* voice)
{
std::vector<dsp_voice*>::iterator it = find(fVoiceTable.begin(), fVoiceTable.end(), reinterpret_cast<dsp_voice*>(voice));
if (it != fVoiceTable.end()) {
(*it)->setParamValue(fGateLabel, 0.0f);
// Release voice
(*it)->fNote = kReleaseVoice;
} else {
std::cout << "Voice not found\n";
}
}
// Pure MIDI control
MapUI* keyOn(int channel, int pitch, int velocity)
{
if (checkPolyphony()) {
int voice = newVoiceAux();
fVoiceTable[voice]->setParamValue(fFreqLabel, midiToFreq(pitch));
fVoiceTable[voice]->setParamValue(fGainLabel, float(velocity)/127.f);
fVoiceTable[voice]->fNote = pitch;
fVoiceTable[voice]->fTrigger = true; // so that envelop is always re-initialized
return fVoiceTable[voice];
} else {
return 0;
}
}
void keyOff(int channel, int pitch, int velocity = 127)
{
if (checkPolyphony()) {
int voice = getVoice(pitch);
if (voice != kNoVoice) {
// No use of velocity for now...
fVoiceTable[voice]->setParamValue(fGateLabel, 0.0f);
// Release voice
fVoiceTable[voice]->fNote = kReleaseVoice;
} else {
std::cout << "Playing pitch = " << pitch << " not found\n";
}
}
}
void pitchWheel(int channel, int wheel)
{}
void ctrlChange(int channel, int ctrl, int value)
{
if (ctrl == ALL_NOTES_OFF || ctrl == ALL_SOUND_OFF) {
allNotesOff();
}
}
void progChange(int channel, int pgm)
{}
void keyPress(int channel, int pitch, int press)
{}
void chanPress(int channel, int press)
{}
void ctrlChange14bits(int channel, int ctrl, int value)
{}
// Gently terminates all the active voice
void allNotesOff()
{
if (checkPolyphony()) {
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->setParamValue(fGateLabel, 0.0f);
fVoiceTable[i]->fNote = kReleaseVoice;
}
}
}
// Kill immediately all the active voices
void hardAllNotesOff()
{
if (checkPolyphony()) {
for (int i = 0; i < fPolyphony; i++) {
fVoiceTable[i]->setParamValue(fGateLabel, 0.0f);
// Stops immediately
fVoiceTable[i]->fNote = kFreeVoice;
fVoiceTable[i]->fTrigger = false;
}
}
}
};

#endif // __poly_dsp__

+ 277
- 0
ports/temper/source/faust/dsp/proxy-dsp.h View File

@@ -0,0 +1,277 @@
/************************************************************************
IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef __proxy_dsp__
#define __proxy_dsp__

#include <vector>
#include <map>

#include "faust/dsp/dsp.h"
#include "faust/gui/SimpleParser.h"
#include "faust/gui/JSONUI.h"

#ifdef _WIN32
#include <windows.h>
#define snprintf _snprintf
#endif

inline FAUSTFLOAT STR2REAL(const std::string& s) { return (strtod(s.c_str(), NULL)); }

//-------------------------------------------------------------------
// Decode a dsp JSON description and implement 'buildUserInterface'
//-------------------------------------------------------------------

struct JSONUIDecoder {

std::string fName;
std::map<std::string, std::string> fMetadatas;
std::vector<itemInfo*> fUiItems;
FAUSTFLOAT* fInControl;
FAUSTFLOAT* fOutControl;
std::string fJSON;
int fNumInputs, fNumOutputs;
int fInputItems, fOutputItems;

JSONUIDecoder(const std::string& json)
{
fJSON = json;
const char* p = fJSON.c_str();
parseJson(p, fMetadatas, fUiItems);
// fMetadatas will contain the "meta" section as well as <name : val>, <inputs : val>, <ouputs : val> pairs
if (fMetadatas.find("name") != fMetadatas.end()) {
fName = fMetadatas["name"];
fMetadatas.erase("name");
} else {
fName = "";
}
if (fMetadatas.find("inputs") != fMetadatas.end()) {
fNumInputs = atoi(fMetadatas["inputs"].c_str());
fMetadatas.erase("inputs");
} else {
fNumInputs = -1;
}
if (fMetadatas.find("outputs") != fMetadatas.end()) {
fNumOutputs = atoi(fMetadatas["outputs"].c_str());
fMetadatas.erase("outputs");
} else {
fNumOutputs = -1;
}
vector<itemInfo*>::iterator it;
fInputItems = 0;
fOutputItems = 0;
for (it = fUiItems.begin(); it != fUiItems.end(); it++) {
string type = (*it)->type;
if (type == "vslider" || type == "hslider" || type == "nentry" || type == "button") {
fInputItems++;
} else if (type == "hbargraph" || type == "vbargraph") {
fOutputItems++;
}
}
fInControl = new FAUSTFLOAT[fInputItems];
fOutControl = new FAUSTFLOAT[fOutputItems];
}
virtual ~JSONUIDecoder()
{
vector<itemInfo*>::iterator it;
for (it = fUiItems.begin(); it != fUiItems.end(); it++) {
delete(*it);
}
delete [] fInControl;
delete [] fOutControl;
}
void metadata(Meta* m)
{
std::map<std::string, std::string>::iterator it;
for (it = fMetadatas.begin(); it != fMetadatas.end(); it++) {
m->declare((*it).first.c_str(), (*it).second.c_str());
}
}
void buildUserInterface(UI* ui)
{
// To be sure the floats are correctly encoded
char* tmp_local = setlocale(LC_ALL, NULL);
setlocale(LC_ALL, "C");

int counterIn = 0;
int counterOut = 0;
vector<itemInfo*>::iterator it;
for (it = fUiItems.begin(); it != fUiItems.end(); it++) {
bool isInItem = false;
bool isOutItem = false;
string type = (*it)->type;
FAUSTFLOAT init = STR2REAL((*it)->init);
FAUSTFLOAT min = STR2REAL((*it)->min);
FAUSTFLOAT max = STR2REAL((*it)->max);
FAUSTFLOAT step = STR2REAL((*it)->step);
if (type == "vslider" || type == "hslider" || type == "nentry" || type == "button") {
isInItem = true;
} else if (type == "hbargraph" || type == "vbargraph") {
isOutItem = true;
}
// Meta data declaration for input items
if ((*it)->type.find("group") == string::npos && (*it)->type.find("bargraph") == string::npos && (*it)->type != "close") {
fInControl[counterIn] = init;
for (int i = 0; i < (*it)->meta.size(); i++) {
ui->declare(&fInControl[counterIn], (*it)->meta[i].first.c_str(), (*it)->meta[i].second.c_str());
}
}
// Meta data declaration for output items
else if ((*it)->type.find("bargraph") != string::npos) {
fOutControl[counterOut] = init;
for (int i = 0; i < (*it)->meta.size(); i++) {
ui->declare(&fOutControl[counterOut], (*it)->meta[i].first.c_str(), (*it)->meta[i].second.c_str());
}
}
// Meta data declaration for group opening or closing
else {
for (int i = 0; i < (*it)->meta.size(); i++) {
ui->declare(0, (*it)->meta[i].first.c_str(), (*it)->meta[i].second.c_str());
}
}
if (type == "hgroup") {
ui->openHorizontalBox((*it)->label.c_str());
} else if (type == "vgroup") {
ui->openVerticalBox((*it)->label.c_str());
} else if (type == "tgroup") {
ui->openTabBox((*it)->label.c_str());
} else if (type == "vslider") {
ui->addVerticalSlider((*it)->label.c_str(), &fInControl[counterIn], init, min, max, step);
} else if (type == "hslider") {
ui->addHorizontalSlider((*it)->label.c_str(), &fInControl[counterIn], init, min, max, step);
} else if (type == "checkbox") {
ui->addCheckButton((*it)->label.c_str(), &fInControl[counterIn]);
} else if (type == "hbargraph") {
ui->addHorizontalBargraph((*it)->label.c_str(), &fOutControl[counterOut], min, max);
} else if (type == "vbargraph") {
ui->addVerticalBargraph((*it)->label.c_str(), &fOutControl[counterOut], min, max);
} else if (type == "nentry") {
ui->addNumEntry((*it)->label.c_str(), &fInControl[counterIn], init, min, max, step);
} else if (type == "button") {
ui->addButton((*it)->label.c_str(), &fInControl[counterIn]);
} else if (type == "close") {
ui->closeBox();
}
if (isInItem) {
counterIn++;
}
if (isOutItem) {
counterOut++;
}
}
setlocale(LC_ALL, tmp_local);
}
};

//----------------------------------------------------------------
// Proxy dsp definition created from the DSP JSON description
// This class allows a 'proxy' dsp to control a real dsp
// possibly running somewhere else.
//----------------------------------------------------------------

class proxy_dsp : public dsp {

private:
int fSamplingFreq;
JSONUIDecoder* fDecoder;
public:
proxy_dsp(const string& json)
{
fDecoder = new JSONUIDecoder(json);
fSamplingFreq = -1;
}
proxy_dsp(dsp* dsp)
{
JSONUI builder(dsp->getNumInputs(), dsp->getNumOutputs());
dsp->metadata(&builder);
dsp->buildUserInterface(&builder);
fSamplingFreq = dsp->getSampleRate();
fDecoder = new JSONUIDecoder(builder.JSON());
}
virtual ~proxy_dsp()
{
delete fDecoder;
}
virtual int getNumInputs() { return fDecoder->fNumInputs; }
virtual int getNumOutputs() { return fDecoder->fNumOutputs; }
virtual void buildUserInterface(UI* ui) { fDecoder->buildUserInterface(ui); }
// To possibly implement in a concrete proxy dsp
virtual void init(int samplingRate) { fSamplingFreq = samplingRate; }
virtual void instanceInit(int samplingRate) {}
virtual void instanceConstants(int samplingRate) {}
virtual void instanceResetUserInterface() {}
virtual void instanceClear() {}
virtual int getSampleRate() { return fSamplingFreq; }
virtual proxy_dsp* clone() { return new proxy_dsp(fDecoder->fJSON); }
virtual void metadata(Meta* m) { fDecoder->metadata(m); }
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {}
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {}
};

#endif

+ 287
- 0
ports/temper/source/faust/dsp/timed-dsp.h View File

@@ -0,0 +1,287 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef __timed_dsp__
#define __timed_dsp__

#include "faust/dsp/dsp.h"
#include "faust/gui/GUI.h"
#include "faust/gui/ring-buffer.h"

#include <set>
#include <float.h>
#include <assert.h>

namespace {
#if __APPLE__
#if TARGET_OS_IPHONE
//inline double GetCurrentTimeInUsec() { return double(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000.; }
// TODO
inline double GetCurrentTimeInUsec() { return 0.0; }
#else
#include <CoreAudio/HostTime.h>
inline double GetCurrentTimeInUsec() { return double(AudioConvertHostTimeToNanos(AudioGetCurrentHostTime())) / 1000.; }
#endif
#endif

#if __linux__
#include <sys/time.h>
inline double GetCurrentTimeInUsec()
{
struct timeval tv;
(void)gettimeofday(&tv, (struct timezone *)NULL);
return double((tv.tv_sec * 1000000) + tv.tv_usec);
}
#endif

#if _WIN32
#include <Windows.h>
inline double GetCurrentTimeInUsec(void)
{
LARGE_INTEGER time;
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&time);
return double(time.QuadPart) / double(frequency.QuadPart) * 1000000.0;
}
#endif
}

/**
* ZoneUI : this class collect zones in a set.
*/

struct ZoneUI : public UI
{
std::set<FAUSTFLOAT*> fZoneSet;
ZoneUI() {};
virtual ~ZoneUI() {};
void insertZone(FAUSTFLOAT* zone)
{
if (GUI::gTimedZoneMap.find(zone) != GUI::gTimedZoneMap.end()) {
fZoneSet.insert(zone);
}
}
// -- widget's layouts
void openTabBox(const char* label)
{}
void openHorizontalBox(const char* label)
{}
void openVerticalBox(const char* label)
{}
void closeBox()
{}
// -- active widgets
void addButton(const char* label, FAUSTFLOAT* zone)
{
insertZone(zone);
}
void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
insertZone(zone);
}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
insertZone(zone);
}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
insertZone(zone);
}
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
insertZone(zone);
}
// -- passive widgets
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT fmin, FAUSTFLOAT fmax)
{
insertZone(zone);
}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT fmin, FAUSTFLOAT fmax)
{
insertZone(zone);
}
// -- metadata declarations
void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{}

};

/**
* Timed signal processor that allows to handle the decorated DSP by 'slices'
* that is, calling the 'compute' method several times and changing control
* parameters between slices.
*/

class timed_dsp : public decorator_dsp {

protected:
double fDateUsec; // Compute call date in usec
double fOffsetUsec; // Compute call offset in usec
bool fFirstCallback;
ZoneUI fZoneUI;
void computeSlice(int offset, int slice, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
if (slice > 0) {
FAUSTFLOAT** inputs_slice = (FAUSTFLOAT**)alloca(fDSP->getNumInputs() * sizeof(FAUSTFLOAT*));
for (int chan = 0; chan < fDSP->getNumInputs(); chan++) {
inputs_slice[chan] = &(inputs[chan][offset]);
}
FAUSTFLOAT** outputs_slice = (FAUSTFLOAT**)alloca(fDSP->getNumOutputs() * sizeof(FAUSTFLOAT*));
for (int chan = 0; chan < fDSP->getNumOutputs(); chan++) {
outputs_slice[chan] = &(outputs[chan][offset]);
}
fDSP->compute(slice, inputs_slice, outputs_slice);
}
}
double convertUsecToSample(double usec)
{
return std::max(0., (double(getSampleRate()) * (usec - fDateUsec)) / 1000000.);
}
ztimedmap::iterator getNextControl(DatedControl& res, bool convert_ts)
{
DatedControl date1(DBL_MAX, 0);
ztimedmap::iterator it1, it2 = GUI::gTimedZoneMap.end();
std::set<FAUSTFLOAT*>::iterator it3;
// Find date of next audio slice to compute
for (it3 = fZoneUI.fZoneSet.begin(); it3 != fZoneUI.fZoneSet.end(); it3++) {
// If value list is not empty, get the date and keep the minimal one
it1 = GUI::gTimedZoneMap.find(*it3);
if (it1 != GUI::gTimedZoneMap.end()) { // Check if zone still in global GUI::gTimedZoneMap (since MidiUI may have been desallocated)
DatedControl date2;
if (ringbuffer_peek((*it1).second, (char*)&date2, sizeof(DatedControl)) == sizeof(DatedControl)
&& date2.fDate < date1.fDate) {
it2 = it1;
date1 = date2;
}
}
}
// If needed, convert date1 in samples from begining of the buffer, possible moving to 0 (if negative)
if (convert_ts) {
date1.fDate = convertUsecToSample(date1.fDate);
}
res = date1;
return it2;
}
virtual void computeAux(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs, bool convert_ts)
{
int slice, offset = 0;
ztimedmap::iterator it;
DatedControl next_control;
// Do audio computation "slice" by "slice"
while ((it = getNextControl(next_control, convert_ts)) != GUI::gTimedZoneMap.end()) {
// Compute audio slice
slice = int(next_control.fDate) - offset;
computeSlice(offset, slice, inputs, outputs);
offset += slice;
// Update control
ringbuffer_t* control_values = (*it).second;
*((*it).first) = next_control.fValue;
// Move ringbuffer pointer
ringbuffer_read_advance(control_values, sizeof(DatedControl));
}
// Compute last audio slice
slice = count - offset;
computeSlice(offset, slice, inputs, outputs);
}

public:

timed_dsp(dsp* dsp):decorator_dsp(dsp), fDateUsec(0),fOffsetUsec(0), fFirstCallback(true)
{}
virtual ~timed_dsp()
{}
virtual void init(int samplingRate)
{
fDSP->init(samplingRate);
}
virtual void buildUserInterface(UI* ui_interface)
{
fDSP->buildUserInterface(ui_interface);
// Only keep zones that are in GUI::gTimedZoneMap
fDSP->buildUserInterface(&fZoneUI);
}
virtual timed_dsp* clone()
{
return new timed_dsp(fDSP->clone());
}
// Default method take a timestamp at 'compute' call time
virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
compute(::GetCurrentTimeInUsec(), count, inputs, outputs);
}
virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs)
{
if (date_usec == -1) {
// JACK mode : timestamp is already in frames
computeAux(count, inputs, outputs, false);
} else {
// Save the timestamp offset in the first callback
if (fFirstCallback) {
fOffsetUsec = ::GetCurrentTimeInUsec() - date_usec;
fDateUsec = date_usec + fOffsetUsec;
fFirstCallback = false;
}
// RtMidi mode : timestamp must be converted in frames
computeAux(count, inputs, outputs, true);
// Keep call date
fDateUsec = date_usec + fOffsetUsec;
}
}
};

#endif

+ 472
- 0
ports/temper/source/faust/gui/APIUI.h View File

@@ -0,0 +1,472 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef API_UI_H
#define API_UI_H

#include "faust/gui/meta.h"
#include "faust/gui/UI.h"
#include "faust/gui/PathBuilder.h"
#include "faust/gui/ValueConverter.h"
#include <sstream>
#include <string>
#include <vector>
#include <iostream>
#include <map>

enum { kLin = 0, kLog = 1, kExp = 2 };

class APIUI : public PathBuilder, public Meta, public UI
{
protected:

int fNumParameters;
std::vector<std::string> fName;
std::map<std::string, int> fPathMap;
std::map<std::string, int> fLabelMap;
std::vector<ValueConverter*> fConversion;
std::vector<FAUSTFLOAT*> fZone;
std::vector<FAUSTFLOAT> fInit;
std::vector<FAUSTFLOAT> fMin;
std::vector<FAUSTFLOAT> fMax;
std::vector<FAUSTFLOAT> fStep;
std::vector<std::string> fUnit;
std::vector<std::string> fTooltip;
std::vector<ZoneControl*> fAcc[3];
std::vector<ZoneControl*> fGyr[3];

// Screen color control
// "...[screencolor:red]..." etc.
bool fHasScreenControl; // true if control screen color metadata
ZoneReader* fRedReader;
ZoneReader* fGreenReader;
ZoneReader* fBlueReader;

// Current values controlled by metadata
std::string fCurrentUnit;
int fCurrentScale;
std::string fCurrentAcc;
std::string fCurrentGyr;
std::string fCurrentColor;
std::string fCurrentTooltip;

// Add a generic parameter
virtual void addParameter(const char* label,
FAUSTFLOAT* zone,
FAUSTFLOAT init,
FAUSTFLOAT min,
FAUSTFLOAT max,
FAUSTFLOAT step)
{
std::string path = buildPath(label);
fPathMap[path] = fLabelMap[label] = fNumParameters++;
fName.push_back(path);
fZone.push_back(zone);
fInit.push_back(init);
fMin.push_back(min);
fMax.push_back(max);
fStep.push_back(step);

//handle unit metadata
fUnit.push_back(fCurrentUnit);
fCurrentUnit = "";
//handle tooltip metadata
fTooltip.push_back(fCurrentTooltip);
fCurrentTooltip = "";

//handle scale metadata
switch (fCurrentScale) {
case kLin : fConversion.push_back(new LinearValueConverter(0,1, min, max)); break;
case kLog : fConversion.push_back(new LogValueConverter(0,1, min, max)); break;
case kExp : fConversion.push_back(new ExpValueConverter(0,1, min, max)); break;
}
fCurrentScale = kLin;

// handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
if (fCurrentAcc.size() > 0) {
std::istringstream iss(fCurrentAcc);
int axe, curve;
double amin, amid, amax;
iss >> axe >> curve >> amin >> amid >> amax;

if ((0 <= axe) && (axe < 3) &&
(0 <= curve) && (curve < 4) &&
(amin < amax) && (amin <= amid) && (amid <= amax))
{
fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
} else {
std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
}
}
fCurrentAcc = "";

// handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
if (fCurrentGyr.size() > 0) {
std::istringstream iss(fCurrentGyr);
int axe, curve;
double amin, amid, amax;
iss >> axe >> curve >> amin >> amid >> amax;

if ((0 <= axe) && (axe < 3) &&
(0 <= curve) && (curve < 4) &&
(amin < amax) && (amin <= amid) && (amid <= amax))
{
fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
} else {
std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
}
}
fCurrentGyr = "";

// handle screencolor metadata "...[screencolor:red|green|blue]..."
if (fCurrentColor.size() > 0) {
if ((fCurrentColor == "red") && (fRedReader == 0)) {
fRedReader = new ZoneReader(zone, min, max);
fHasScreenControl = true;
} else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
fGreenReader = new ZoneReader(zone, min, max);
fHasScreenControl = true;
} else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
fBlueReader = new ZoneReader(zone, min, max);
fHasScreenControl = true;
} else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
fRedReader = new ZoneReader(zone, min, max);
fGreenReader = new ZoneReader(zone, min, max);
fBlueReader = new ZoneReader(zone, min, max);
fHasScreenControl = true;
} else {
std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
}
}
fCurrentColor = "";
}

int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
{
FAUSTFLOAT* zone = fZone[p];
for (int i = 0; i < table[val].size(); i++) {
if (zone == table[val][i]->getZone()) return i;
}
return -1;
}
void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
{
int id1 = getZoneIndex(table, p, 0);
int id2 = getZoneIndex(table, p, 1);
int id3 = getZoneIndex(table, p, 2);
// Deactivates everywhere..
if (id1 != -1) table[0][id1]->setActive(false);
if (id2 != -1) table[1][id2]->setActive(false);
if (id3 != -1) table[2][id3]->setActive(false);
if (val == -1) { // Means: no more mapping...
// So stay all deactivated...
} else {
int id4 = getZoneIndex(table, p, val);
if (id4 != -1) {
// Reactivate the one we edit...
table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
table[val][id4]->setActive(true);
} else {
// Allocate a new CurveZoneControl which is 'active' by default
FAUSTFLOAT* zone = fZone[p];
table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
}
}
}
void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
{
int id1 = getZoneIndex(table, p, 0);
int id2 = getZoneIndex(table, p, 1);
int id3 = getZoneIndex(table, p, 2);
if (id1 != -1) {
val = 0;
curve = fAcc[val][id1]->getCurve();
table[val][id1]->getMappingValues(amin, amid, amax);
} else if (id2 != -1) {
val = 1;
curve = fAcc[val][id2]->getCurve();
table[val][id2]->getMappingValues(amin, amid, amax);
} else if (id3 != -1) {
val = 2;
curve = fAcc[val][id3]->getCurve();
table[val][id3]->getMappingValues(amin, amid, amax);
} else {
val = -1; // No mapping
curve = 0;
amin = -100.;
amid = 0.;
amax = 100.;
}
}

public:

APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0)
{}

virtual ~APIUI()
{
std::vector<ValueConverter*>::iterator it1;
for (it1 = fConversion.begin(); it1 != fConversion.end(); it1++) {
delete(*it1);
}

std::vector<ZoneControl*>::iterator it2;
for (int i = 0; i < 3; i++) {
for (it2 = fAcc[i].begin(); it2 != fAcc[i].end(); it2++) {
delete(*it2);
}
for (it2 = fGyr[i].begin(); it2 != fGyr[i].end(); it2++) {
delete(*it2);
}
}
delete fRedReader;
delete fGreenReader;
delete fBlueReader;
}

// -- widget's layouts

virtual void openTabBox(const char* label) { fControlsLevel.push_back(label); }
virtual void openHorizontalBox(const char* label) { fControlsLevel.push_back(label); }
virtual void openVerticalBox(const char* label) { fControlsLevel.push_back(label); }
virtual void closeBox() { fControlsLevel.pop_back(); }

// -- active widgets

virtual void addButton(const char* label, FAUSTFLOAT* zone)
{
addParameter(label, zone, 0, 0, 1, 1);
}

virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
addParameter(label, zone, 0, 0, 1, 1);
}

virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addParameter(label, zone, init, min, max, step);
}

virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addParameter(label, zone, init, min, max, step);
}

virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addParameter(label, zone, init, min, max, step);
}

// -- passive widgets

virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addParameter(label, zone, min, min, max, (max-min)/1000.0);
}

virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addParameter(label, zone, min, min, max, (max-min)/1000.0);
}

// -- metadata declarations

virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
if (strcmp(key, "scale") == 0) {
if (strcmp(val, "log") == 0) {
fCurrentScale = kLog;
} else if (strcmp(val, "exp") == 0) {
fCurrentScale = kExp;
} else {
fCurrentScale = kLin;
}
} else if (strcmp(key, "unit") == 0) {
fCurrentUnit = val;
} else if (strcmp(key, "acc") == 0) {
fCurrentAcc = val;
} else if (strcmp(key, "gyr") == 0) {
fCurrentGyr = val;
} else if (strcmp(key, "screencolor") == 0) {
fCurrentColor = val; // val = "red", "green" or "blue"
} else if (strcmp(key, "tooltip") == 0) {
fCurrentTooltip = val;
}
}

virtual void declare(const char* key, const char* val)
{}

//-------------------------------------------------------------------------------
// Simple API part
//-------------------------------------------------------------------------------
int getParamsCount() { return fNumParameters; }
int getParamIndex(const char* path)
{
if (fPathMap.find(path) != fPathMap.end()) {
return fPathMap[path];
} else if (fLabelMap.find(path) != fLabelMap.end()) {
return fLabelMap[path];
} else {
return -1;
}
}
const char* getParamAddress(int p) { return fName[p].c_str(); }
const char* getParamUnit(int p) { return fUnit[p].c_str(); }
const char* getParamTooltip(int p) { return fTooltip[p].c_str(); }
FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
FAUSTFLOAT getParamInit(int p) { return fInit[p]; }

FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }

double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }

double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }

/**
* Set a new value coming from an accelerometer, propagate it to all relevant float* zones.
*
* @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
* @param value - the new value
*
*/
void propagateAcc(int acc, double value)
{
for (int i = 0; i < fAcc[acc].size(); i++) {
fAcc[acc][i]->update(value);
}
}
/**
* Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
*
* @param p - the UI parameter index
* @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
* @param curve - between 0 and 3
* @param amin - mapping 'min' point
* @param amid - mapping 'middle' point
* @param amax - mapping 'max' point
*
*/
void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
{
setConverter(fAcc, p, acc, curve, amin, amid, amax);
}
/**
* Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
*
* @param p - the UI parameter index
* @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
* @param curve - between 0 and 3
* @param amin - mapping 'min' point
* @param amid - mapping 'middle' point
* @param amax - mapping 'max' point
*
*/
void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
{
setConverter(fGyr, p, gyr, curve, amin, amid, amax);
}
/**
* Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
*
* @param p - the UI parameter index
* @param acc - the acc value to be retrieved (-1 means "no mapping")
* @param curve - the curve value to be retrieved
* @param amin - the amin value to be retrieved
* @param amid - the amid value to be retrieved
* @param amax - the amax value to be retrieved
*
*/
void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
{
getConverter(fAcc, p, acc, curve, amin, amid, amax);
}

/**
* Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
*
* @param p - the UI parameter index
* @param gyr - the gyr value to be retrieved (-1 means "no mapping")
* @param curve - the curve value to be retrieved
* @param amin - the amin value to be retrieved
* @param amid - the amid value to be retrieved
* @param amax - the amax value to be retrieved
*
*/
void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
{
getConverter(fGyr, p, gyr, curve, amin, amid, amax);
}
/**
* Set a new value coming from an gyroscope, propagate it to all relevant float* zones.
*
* @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
* @param value - the new value
*
*/
void propagateGyr(int gyr, double value)
{
for (int i = 0; i < fGyr[gyr].size(); i++) {
fGyr[gyr][i]->update(value);
}
}
// getScreenColor() : -1 means no screen color control (no screencolor metadata found)
// otherwise return 0x00RRGGBB a ready to use color
int getScreenColor()
{
if (fHasScreenControl) {
int r = (fRedReader) ? fRedReader->getValue() : 0;
int g = (fGreenReader) ? fGreenReader->getValue() : 0;
int b = (fBlueReader) ? fBlueReader->getValue() : 0;
return (r<<16) | (g<<8) | b;
} else {
return -1;
}
}

};

#endif

+ 130
- 0
ports/temper/source/faust/gui/ControlUI.h View File

@@ -0,0 +1,130 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef CONTROL_UI_H
#define CONTROL_UI_H

#include "faust/gui/UI.h"
#include <jack/midiport.h>
#include <vector>
#include <assert.h>

class ControlUI : public UI {

protected:
std::vector<FAUSTFLOAT*> fControlIn;
std::vector<FAUSTFLOAT*> fControlOut;
// -- widget's layouts

void openTabBox(const char* label) {}
void openHorizontalBox(const char* label) {}
void openVerticalBox(const char* label) {};
void closeBox() {}

// -- active widgets

void addButton(const char* label, FAUSTFLOAT* zone) { fControlIn.push_back(zone); }
void addCheckButton(const char* label, FAUSTFLOAT* zone) { fControlIn.push_back(zone); }
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) { fControlIn.push_back(zone); };
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) { fControlIn.push_back(zone); };

void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) { fControlIn.push_back(zone); };

// -- passive widgets

void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) { fControlOut.push_back(zone); };
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) { fControlOut.push_back(zone); };
public:
void encode_control(float* control_buffer, unsigned int frames)
{
assert(fControlOut.size() <= frames);
for (unsigned int i = 0; i < fControlOut.size(); i++) {
control_buffer[i] = *fControlOut[i];
}
}
void decode_control(float* control_buffer, unsigned int frames)
{
assert(fControlIn.size() <= frames);
for (unsigned int i = 0; i < fControlIn.size(); i++) {
*fControlIn[i] = control_buffer[i];
}
}
void encode_midi_control(void* midi_control_buffer, unsigned int frames)
{
assert(fControlOut.size() <= frames);
jack_midi_reset_buffer(midi_control_buffer);
for (unsigned int i = 0; i < fControlOut.size(); i++) {
jack_midi_data_t* buffer = jack_midi_event_reserve(midi_control_buffer, i, 4);
assert(buffer);
*((float*)buffer) = *fControlOut[i];
}
}
static void encode_midi_control(void* midi_control_buffer, float* control_buffer, int count)
{
jack_midi_reset_buffer(midi_control_buffer);
for (unsigned int i = 0; i < count; i++) {
jack_midi_data_t* buffer = jack_midi_event_reserve(midi_control_buffer, i, 4);
assert(buffer);
*((float*)buffer) = control_buffer[i];
}
}
void decode_midi_control(void* midi_control_buffer, unsigned int frames)
{
assert(jack_midi_get_event_count(midi_control_buffer) <= frames);
for (int i = 0; i < jack_midi_get_event_count(midi_control_buffer); i++) {
jack_midi_event_t in_event;
jack_midi_event_get(&in_event, midi_control_buffer, i);
*fControlIn[i] = *((float*)in_event.buffer);
}
}
static void decode_midi_control(void* midi_control_buffer, float* control_buffer, int count)
{
assert(jack_midi_get_event_count(midi_control_buffer) <= count);
for (int i = 0; i < jack_midi_get_event_count(midi_control_buffer); i++) {
jack_midi_event_t in_event;
jack_midi_event_get(&in_event, midi_control_buffer, i);
control_buffer[i] = *((float*)(in_event.buffer));
}
}
};

#endif

+ 181
- 0
ports/temper/source/faust/gui/FUI.h View File

@@ -0,0 +1,181 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef FAUST_FUI_H
#define FAUST_FUI_H

#include "faust/gui/UI.h"

#include <string>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <iostream>
#include <fstream>

#if 1

/*******************************************************************************
* FUI : used to save and recall the state of the user interface
* This class provides essentially two new methods saveState() and recallState()
* used to save on file and recall from file the state of the user interface.
* The file is human readable and editable
******************************************************************************/

class FUI : public UI
{

protected:

std::stack<std::string> fGroupStack;
std::vector<std::string> fNameList;
std::map<std::string, FAUSTFLOAT*> fName2Zone;
std::map<FAUSTFLOAT*, bool> fButtons;

// labels are normalized by replacing white spaces by underscores and by removing parenthesis
std::string normalizeLabel(const char* label)
{
std::string s;
char c;

while ((c = *label++)) {
if (isspace(c)) { s += '_'; }
//else if ((c == '(') | (c == ')') ) { }
else { s += c; }
}
return s;
}

// add an element by relating its full name and memory zone
virtual void addElement(const char* label, FAUSTFLOAT* zone, bool button = false)
{
std::string fullname (fGroupStack.top() + '/' + normalizeLabel(label));
fNameList.push_back(fullname);
fName2Zone[fullname] = zone;
fButtons[zone] = button;
}

// keep track of full group names in a stack
virtual void pushGroupLabel(const char* label)
{
if (fGroupStack.empty()) {
fGroupStack.push(normalizeLabel(label));
} else {
fGroupStack.push(fGroupStack.top() + '/' + normalizeLabel(label));
}
}

virtual void popGroupLabel()
{
fGroupStack.pop();
}


public:

FUI() {}
virtual ~FUI() {}

// -- Save and recall methods

// save the zones values and full names
virtual void saveState(const char* filename)
{
std::ofstream f(filename);

for (unsigned int i = 0; i < fNameList.size(); i++) {
std::string n = fNameList[i];
FAUSTFLOAT* z = fName2Zone[n];
f << *z << ' ' << n.c_str() << std::endl;
}

f << std::endl;
f.close();
}

// recall the zones values and full names
virtual void recallState(const char* filename)
{
std::ifstream f(filename);
FAUSTFLOAT v;
std::string n;

while (f.good()) {
f >> v >> n;
if (fName2Zone.count(n) > 0) {
*(fName2Zone[n]) = v;
} else if (n.size() > 0) {
std::cerr << "recallState : parameter not found : " << n << " with value : " << v << std::endl;
}
}
f.close();
}

void setButtons(bool state)
{
std::map<FAUSTFLOAT*, bool>::iterator it;
for (it = fButtons.begin(); it != fButtons.end(); it++) {
FAUSTFLOAT* zone = (*it).first;
if ((*it).second) {
*zone = state;
}
}
}

// -- widget's layouts (just keep track of group labels)

virtual void openTabBox(const char* label) { pushGroupLabel(label); }
virtual void openHorizontalBox(const char* label) { pushGroupLabel(label); }
virtual void openVerticalBox(const char* label) { pushGroupLabel(label); }
virtual void closeBox() { popGroupLabel(); };

// -- active widgets (just add an element)

virtual void addButton(const char* label, FAUSTFLOAT* zone) { addElement(label, zone, true); }
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) { addElement(label, zone); }
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT , FAUSTFLOAT , FAUSTFLOAT , FAUSTFLOAT)
{ addElement(label, zone); }
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT , FAUSTFLOAT , FAUSTFLOAT , FAUSTFLOAT)
{ addElement(label, zone); }
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT , FAUSTFLOAT , FAUSTFLOAT , FAUSTFLOAT)
{ addElement(label, zone); }

// -- passive widgets (are ignored)

virtual void addHorizontalBargraph(const char*, FAUSTFLOAT*, FAUSTFLOAT, FAUSTFLOAT) {};
virtual void addVerticalBargraph(const char*, FAUSTFLOAT*, FAUSTFLOAT, FAUSTFLOAT) {};

// -- metadata are not used

virtual void declare(FAUSTFLOAT*, const char*, const char*) {}

};

#endif

#endif


+ 261
- 0
ports/temper/source/faust/gui/GUI.h View File

@@ -0,0 +1,261 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/
#ifndef FAUST_GUI_H
#define FAUST_GUI_H

#include "faust/gui/UI.h"
#include "faust/gui/ring-buffer.h"

#include <list>
#include <map>
#include <vector>

/*******************************************************************************
* GUI : Abstract Graphic User Interface
* Provides additional mechanisms to synchronize widgets and zones. Widgets
* should both reflect the value of a zone and allow to change this value.
******************************************************************************/

class uiItem;
typedef void (*uiCallback)(FAUSTFLOAT val, void* data);

class clist : public std::list<uiItem*>
{
public:
virtual ~clist();
};

typedef std::map<FAUSTFLOAT*, clist*> zmap;

typedef std::map<FAUSTFLOAT*, ringbuffer_t*> ztimedmap;

class GUI : public UI
{
private:
static std::list<GUI*> fGuiList;
zmap fZoneMap;
bool fStopped;
public:
GUI() : fStopped(false)
{
fGuiList.push_back(this);
}
virtual ~GUI()
{
// delete all
zmap::iterator g;
for (g = fZoneMap.begin(); g != fZoneMap.end(); g++) {
delete (*g).second;
}
// suppress 'this' in static fGuiList
fGuiList.remove(this);
}

// -- registerZone(z,c) : zone management
void registerZone(FAUSTFLOAT* z, uiItem* c)
{
if (fZoneMap.find(z) == fZoneMap.end()) fZoneMap[z] = new clist();
fZoneMap[z]->push_back(c);
}

void updateAllZones();
void updateZone(FAUSTFLOAT* z);
static void updateAllGuis()
{
std::list<GUI*>::iterator g;
for (g = fGuiList.begin(); g != fGuiList.end(); g++) {
(*g)->updateAllZones();
}
}
void addCallback(FAUSTFLOAT* zone, uiCallback foo, void* data);
virtual void show() {};
virtual bool run() { return false; };
virtual void stop() { fStopped = true; }
bool stopped() { return fStopped; }

virtual void declare(FAUSTFLOAT* , const char* , const char*) {}
// Static global for timed zones, shared between all UI that will set timed values
static ztimedmap gTimedZoneMap;

};

/**
* User Interface Item: abstract definition
*/

class uiItem
{
protected:
GUI* fGUI;
FAUSTFLOAT* fZone;
FAUSTFLOAT fCache;

uiItem(GUI* ui, FAUSTFLOAT* zone) : fGUI(ui), fZone(zone), fCache(FAUSTFLOAT(-123456.654321))
{
ui->registerZone(zone, this);
}

public:

virtual ~uiItem()
{}

void modifyZone(FAUSTFLOAT v)
{
fCache = v;
if (*fZone != v) {
*fZone = v;
fGUI->updateZone(fZone);
}
}
FAUSTFLOAT cache() { return fCache; }
virtual void reflectZone() = 0;
};

/**
* Callback Item
*/

struct uiCallbackItem : public uiItem
{
uiCallback fCallback;
void* fData;
uiCallbackItem(GUI* ui, FAUSTFLOAT* zone, uiCallback foo, void* data)
: uiItem(ui, zone), fCallback(foo), fData(data) {}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fCallback(v, fData);
}
};

/**
* Allows to group a set of zones.
*/
class uiGroupItem : public uiItem
{
protected:
std::vector<FAUSTFLOAT*> fZoneMap;

public:
uiGroupItem(GUI* ui, FAUSTFLOAT* zone):uiItem(ui, zone)
{}
virtual ~uiGroupItem()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
// Update all zones of the same group
std::vector<FAUSTFLOAT*>::iterator it;
for (it = fZoneMap.begin(); it != fZoneMap.end(); it++) {
(*(*it)) = v;
}
}
void addZone(FAUSTFLOAT* zone) { fZoneMap.push_back(zone); }

};

// en cours d'installation de callback : a finir!!!!!

/**
* Update all user items reflecting zone z
*/

inline void GUI::updateZone(FAUSTFLOAT* z)
{
FAUSTFLOAT v = *z;
clist* l = fZoneMap[z];
for (clist::iterator c = l->begin(); c != l->end(); c++) {
if ((*c)->cache() != v) (*c)->reflectZone();
}
}

/**
* Update all user items not up to date
*/

inline void GUI::updateAllZones()
{
for (zmap::iterator m = fZoneMap.begin(); m != fZoneMap.end(); m++) {
FAUSTFLOAT* z = m->first;
clist* l = m->second;
if (z) {
FAUSTFLOAT v = *z;
for (clist::iterator c = l->begin(); c != l->end(); c++) {
if ((*c)->cache() != v) (*c)->reflectZone();
}
}
}
}

inline void GUI::addCallback(FAUSTFLOAT* zone, uiCallback foo, void* data)
{
new uiCallbackItem(this, zone, foo, data);
};

inline clist::~clist()
{
std::list<uiItem*>::iterator it;
for (it = begin(); it != end(); it++) {
delete (*it);
}
}

// For precise timestamped control
struct DatedControl {

double fDate;
FAUSTFLOAT fValue;
DatedControl(double d = 0., FAUSTFLOAT v = FAUSTFLOAT(0)):fDate(d), fValue(v) {}

};
#endif

+ 97
- 0
ports/temper/source/faust/gui/HTTPDControler.h View File

@@ -0,0 +1,97 @@
/*

Faust Project

Copyright (C) 2012 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __HTTPDControler__
#define __HTTPDControler__

#include <string>
#include <map>

namespace httpdfaust
{

class HTTPDSetup;
class JSONDesc;
class FaustFactory;
class jsonfactory;
class htmlfactory;

//--------------------------------------------------------------------------
/*!
\brief the main Faust HTTPD Lib API
The HTTPDControler is essentially a glue between the memory representation (in charge of the FaustFactory),
and the network services (in charge of HTTPDSetup).
*/
class HTTPDControler
{
int fTCPPort; // the tcp port number
FaustFactory* fFactory; // a factory to build the memory representation
jsonfactory* fJson;
htmlfactory* fHtml;
HTTPDSetup* fHttpd; // the network manager
std::string fHTML; // the corresponding HTML page
std::map<std::string, std::string> fCurrentMeta; // the current meta declarations

bool fInit;
public:
/*
base udp port is chosen in an unassigned range from IANA PORT NUMBERS (last updated 2011-01-24)
see at http://www.iana.org/assignments/port-numbers
5507-5552 Unassigned
*/
enum { kTCPBasePort = 5510};

HTTPDControler(int argc, char *argv[], const char* applicationname, bool init = true);
virtual ~HTTPDControler();
//--------------------------------------------------------------------------
// addnode, opengroup and closegroup are simply relayed to the factory
//--------------------------------------------------------------------------
template <typename C> void addnode(const char* type, const char* label, C* zone);
template <typename C> void addnode(const char* type, const char* label, C* zone, C min, C max);
template <typename C> void addnode(const char* type, const char* label, C* zone, C init, C min, C max, C step);
void declare(const char* key, const char* val ) { fCurrentMeta[key] = val; }

void opengroup(const char* type, const char* label);
void closegroup();

//--------------------------------------------------------------------------
void run(); // start the httpd server
void stop(); // stop the httpd server
int getTCPPort() { return fTCPPort; }
std::string getJSON();
void setInputs(int numInputs);
void setOutputs(int numOutputs);

static float version(); // the Faust httpd library version number
static const char* versionstr(); // the Faust httpd library version number as a string
};

}

#endif

+ 318
- 0
ports/temper/source/faust/gui/JSONUI.h View File

@@ -0,0 +1,318 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef FAUST_JSONUI_H
#define FAUST_JSONUI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include "faust/gui/UI.h"
#include "faust/gui/PathBuilder.h"
#include "faust/gui/meta.h"

#include <vector>
#include <map>
#include <string>
#include <iostream>
#include <sstream>
#include <assert.h>

/*******************************************************************************
* JSONUI : Faust User Interface
* This class produce a complete JSON decription of the DSP instance.
******************************************************************************/

class JSONUI : public PathBuilder, public Meta, public UI
{

protected:
std::stringstream fJSON;
std::stringstream fUI;
std::stringstream fMeta;
std::vector<std::pair <std::string, std::string> > fMetaAux;
std::string fName;
std::string fExpandedCode;
std::string fSHAKey;
char fCloseUIPar;
char fCloseMetaPar;
int fTab;
int fInputs, fOutputs;
void tab(int n, std::ostream& fout)
{
fout << '\n';
while (n-- > 0) {
fout << '\t';
}
}
void addMeta(int tab_val, bool quote = true)
{
if (fMetaAux.size() > 0) {
tab(tab_val, fUI); fUI << "\"meta\": [";
std::string sep = "";
for (size_t i = 0; i < fMetaAux.size(); i++) {
fUI << sep;
tab(tab_val + 1, fUI); fUI << "{ \"" << fMetaAux[i].first << "\": \"" << fMetaAux[i].second << "\" }";
sep = ",";
}
tab(tab_val, fUI); fUI << ((quote) ? "],": "]");
fMetaAux.clear();
}
}
void init(const std::string& name, int inputs, int outputs, const std::string& sha_key, const std::string& dsp_code)
{
fTab = 1;
// Start Meta generation
tab(fTab, fMeta); fMeta << "\"meta\": [";
fCloseMetaPar = ' ';
// Start UI generation
tab(fTab, fUI); fUI << "\"ui\": [";
fCloseUIPar = ' ';
fTab += 1;
fName = name;
fInputs = inputs;
fOutputs = outputs;
fExpandedCode = dsp_code;
fSHAKey = sha_key;
}
inline std::string flatten(const std::string& src)
{
std::stringstream dst;
for (size_t i = 0; i < src.size(); i++) {
switch (src[i]) {
case '\n':
case '\t':
dst << ' ';
break;
case '"':
dst << "\\" << '"';
break;
default:
dst << src[i];
break;
}
}
return dst.str();
}
public:
JSONUI(const std::string& name, int inputs, int outputs, const std::string& sha_key, const std::string& dsp_code)
{
init(name, inputs, outputs, sha_key, dsp_code);
}

JSONUI(const std::string& name, int inputs, int outputs)
{
init(name, inputs, outputs, "", "");
}

JSONUI(int inputs, int outputs)
{
init("", inputs, outputs, "", "");
}
JSONUI()
{
init("", -1, -1, "", "");
}
virtual ~JSONUI() {}

// -- widget's layouts
virtual void openGenericGroup(const char* label, const char* name)
{
fControlsLevel.push_back(label);
fUI << fCloseUIPar;
tab(fTab, fUI); fUI << "{";
fTab += 1;
tab(fTab, fUI); fUI << "\"type\": \"" << name << "\",";
tab(fTab, fUI); fUI << "\"label\": \"" << label << "\",";
addMeta(fTab + 1);
tab(fTab, fUI); fUI << "\"items\": [";
fCloseUIPar = ' ';
fTab += 1;
}

virtual void openTabBox(const char* label)
{
openGenericGroup(label, "tgroup");
}
virtual void openHorizontalBox(const char* label)
{
openGenericGroup(label, "hgroup");
}
virtual void openVerticalBox(const char* label)
{
openGenericGroup(label, "vgroup");
}
virtual void closeBox()
{
fControlsLevel.pop_back();
fTab -= 1;
tab(fTab, fUI); fUI << "]";
fTab -= 1;
tab(fTab, fUI); fUI << "}";
fCloseUIPar = ',';
}
// -- active widgets
virtual void addGenericButton(const char* label, const char* name)
{
fUI << fCloseUIPar;
tab(fTab, fUI); fUI << "{";
tab(fTab + 1, fUI); fUI << "\"type\": \"" << name << "\",";
tab(fTab + 1, fUI); fUI << "\"label\": \"" << label << "\"" << ",";
tab(fTab + 1, fUI); fUI << "\"address\": \"" << buildPath(label) << "\"" << ((fMetaAux.size() > 0) ? "," : "");
addMeta(fTab + 1, false);
tab(fTab, fUI); fUI << "}";
fCloseUIPar = ',';
}

virtual void addButton(const char* label, FAUSTFLOAT* zone)
{
addGenericButton(label, "button");
}
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
addGenericButton(label, "checkbox");
}

virtual void addGenericEntry(const char* label, const char* name, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
fUI << fCloseUIPar;
tab(fTab, fUI); fUI << "{";
tab(fTab + 1, fUI); fUI << "\"type\": \"" << name << "\",";
tab(fTab + 1, fUI); fUI << "\"label\": \"" << label << "\"" << ",";
tab(fTab + 1, fUI); fUI << "\"address\": \"" << buildPath(label) << "\"" << ",";
addMeta(fTab + 1);
tab(fTab + 1, fUI); fUI << "\"init\": \"" << init << "\",";
tab(fTab + 1, fUI); fUI << "\"min\": \"" << min << "\",";
tab(fTab + 1, fUI); fUI << "\"max\": \"" << max << "\",";
tab(fTab + 1, fUI); fUI << "\"step\": \"" << step << "\"";
tab(fTab, fUI); fUI << "}";
fCloseUIPar = ',';
}
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGenericEntry(label, "vslider", init, min, max, step);
}
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGenericEntry(label, "hslider", init, min, max, step);
}
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGenericEntry(label, "nentry", init, min, max, step);
}

// -- passive widgets
virtual void addGenericBargraph(const char* label, const char* name, FAUSTFLOAT min, FAUSTFLOAT max)
{
fUI << fCloseUIPar;
tab(fTab, fUI); fUI << "{";
tab(fTab + 1, fUI); fUI << "\"type\": \"" << name << "\",";
tab(fTab + 1, fUI); fUI << "\"label\": \"" << label << "\"" << ",";
tab(fTab + 1, fUI); fUI << "\"address\": \"" << buildPath(label) << "\"" << ",";
addMeta(fTab + 1);
tab(fTab + 1, fUI); fUI << "\"min\": \"" << min << "\",";
tab(fTab + 1, fUI); fUI << "\"max\": \"" << max << "\"";
tab(fTab, fUI); fUI << "}";
fCloseUIPar = ',';
}

virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addGenericBargraph(label, "hbargraph", min, max);
}
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addGenericBargraph(label, "vbargraph", min, max);
}

// -- metadata declarations

virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
fMetaAux.push_back(std::make_pair(key, val));
}
// Meta interface
virtual void declare(const char* key, const char* value)
{
fMeta << fCloseMetaPar;
if ((strcmp(key, "name") == 0) && (fName == "")) fName = value;
tab(fTab, fMeta); fMeta << "{ " << "\"" << key << "\"" << ": " << "\"" << value << "\" }";
fCloseMetaPar = ',';
}
std::string JSON(bool flat = false)
{
fTab = 0;
fJSON << "{";
fTab += 1;
tab(fTab, fJSON); fJSON << "\"name\": \"" << fName << "\",";
if (fSHAKey != "") { tab(fTab, fJSON); fJSON << "\"sha_key\": \"" << fSHAKey << "\","; }
if (fExpandedCode != "") { tab(fTab, fJSON); fJSON << "\"code\": \"" << fExpandedCode << "\","; }
tab(fTab, fJSON); fJSON << "\"inputs\": \"" << fInputs << "\",";
tab(fTab, fJSON); fJSON << "\"outputs\": \"" << fOutputs << "\",";
tab(fTab, fMeta); fMeta << "],";
tab(fTab, fUI); fUI << "]";
fTab -= 1;
if (fCloseMetaPar == ',') { // If "declare" has been called, fCloseMetaPar state is now ','
fJSON << fMeta.str() << fUI.str();
} else {
fJSON << fUI.str();
}
tab(fTab, fJSON); fJSON << "}" << std::endl;
return (flat) ? flatten(fJSON.str()) : fJSON.str();
}
};

#endif // FAUST_JSONUI_H

+ 2167
- 0
ports/temper/source/faust/gui/JuceGUI.h
File diff suppressed because it is too large
View File


+ 164
- 0
ports/temper/source/faust/gui/JuceOSCUI.h View File

@@ -0,0 +1,164 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/
#ifndef __juce_osc__
#define __juce_osc__
#include "../JuceLibraryCode/JuceHeader.h"

#include "faust/gui/MapUI.h"
#include "faust/gui/GUI.h"
#include "faust/gui/APIUI.h"

class oscItem : public uiItem {
protected:
OSCSender* fSender;
String fPath;
public:
oscItem(OSCSender* sender, GUI* ui, const String& path, FAUSTFLOAT* zone)
:uiItem(ui, zone), fSender(sender), fPath(path) {}
virtual ~oscItem()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fSender->send(fPath, v);
}
};

class JuceOSCUI : private OSCReceiver, private OSCReceiver::Listener<OSCReceiver::RealtimeCallback>, public GUI {
private:
OSCSender fSender;
String fIP;
int fInputPort, fOutputPort;
APIUI fAPIUI;
Array<oscItem*> fOSCItems; // Pointers are kept and desallocated by the GUI class
public:
JuceOSCUI(const std::string& ip, int in_port, int out_port)
:fIP(ip), fInputPort(in_port), fOutputPort(out_port)
{}
virtual ~JuceOSCUI()
{}
void oscMessageReceived(const OSCMessage& message) override
{
String address = message.getAddressPattern().toString();
for (int i = 0; i < message.size(); ++i) {
if (message[i].isFloat32()) {
fAPIUI.setParamValue(fAPIUI.getParamIndex(address.toStdString().c_str()), message[i].getFloat32());
// "get" message with correct address
} else if (message[i].isString()
&& message[i].getString().equalsIgnoreCase("get")
&& String(fAPIUI.getParamAddress(0)).startsWith(address)) {
for (int p = 0; p < fAPIUI.getParamsCount(); ++p) {
fSender.send(fAPIUI.getParamAddress(p), fAPIUI.getParamValue(p), fAPIUI.getParamMin(p), fAPIUI.getParamMax(p));
}
// "hello" message
} else if (message[i].isString()
&& address.equalsIgnoreCase("/*")
&& message[i].getString().equalsIgnoreCase("hello")) {
String path = fAPIUI.getParamAddress(0);
int pos1 = path.indexOfChar('/');
int pos2 = path.indexOfChar(pos1 + 1, '/');
fSender.send(path.substring(pos1, pos2), fIP, fInputPort, fOutputPort);
}
}
}
bool run() override
{
// Keep all zones for update when OSC messages are received
if (fOSCItems.size() == 0) {
for (int p = 0; p < fAPIUI.getParamsCount(); ++p) {
fOSCItems.add(new oscItem(&fSender, this, fAPIUI.getParamAddress(p), fAPIUI.getParamZone(p)));
}
}
if (!fSender.connect(fIP, fOutputPort)) {
std::cerr << "Error: could not connect to UDP port " << fInputPort << std::endl;
return false;
}
if (!connect(fInputPort)) {
std::cerr << "Error: could not connect to UDP port " << fOutputPort << std::endl;
return false;
}
addListener(this);
return true;
}
void stop() override
{
fSender.disconnect();
disconnect();
removeListener(this);
}
// -- widget's layouts
void openTabBox(const char* label) override { fAPIUI.openTabBox(label); }
void openHorizontalBox(const char* label) override { fAPIUI.openHorizontalBox(label); }
void openVerticalBox(const char* label) override { fAPIUI.openVerticalBox(label); }
void closeBox() override { fAPIUI.closeBox(); }
// -- active widgets
void addButton(const char* label, FAUSTFLOAT* zone) override { fAPIUI.addButton(label, zone); }
void addCheckButton(const char* label, FAUSTFLOAT* zone) override { fAPIUI.addCheckButton(label, zone); }
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) override
{ fAPIUI.addVerticalSlider(label, zone, init, min, max, step); }
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) override
{ fAPIUI.addHorizontalSlider(label, zone, init, min, max, step); }
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) override
{ fAPIUI.addNumEntry(label, zone, init, min, max, step); }
// -- passive widgets
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) override
{ fAPIUI.addHorizontalBargraph(label, zone, min, max); }
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) override
{ fAPIUI.addVerticalBargraph(label, zone, min, max); }
// -- metadata declarations
void declare(FAUSTFLOAT* zone, const char* key, const char* val) override { fAPIUI.declare(zone, key, val); }
};

#endif // __juce_osc__


+ 157
- 0
ports/temper/source/faust/gui/MapUI.h View File

@@ -0,0 +1,157 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef FAUST_MAPUI_H
#define FAUST_MAPUI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include <vector>
#include <map>
#include <string>

#include "faust/gui/UI.h"
#include "faust/gui/PathBuilder.h"

/*******************************************************************************
* MapUI : Faust User Interface
* This class creates a map of complete hierarchical path and zones for each UI items.
******************************************************************************/

class MapUI : public UI, public PathBuilder
{
protected:
// Complete path map
std::map<std::string, FAUSTFLOAT*> fPathZoneMap;
// Label zone map
std::map<std::string, FAUSTFLOAT*> fLabelZoneMap;
public:
MapUI() {};
virtual ~MapUI() {};
// -- widget's layouts
void openTabBox(const char* label)
{
fControlsLevel.push_back(label);
}
void openHorizontalBox(const char* label)
{
fControlsLevel.push_back(label);
}
void openVerticalBox(const char* label)
{
fControlsLevel.push_back(label);
}
void closeBox()
{
fControlsLevel.pop_back();
}
// -- active widgets
void addButton(const char* label, FAUSTFLOAT* zone)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT fmin, FAUSTFLOAT fmax, FAUSTFLOAT step)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
// -- passive widgets
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT fmin, FAUSTFLOAT fmax)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT fmin, FAUSTFLOAT fmax)
{
fPathZoneMap[buildPath(label)] = zone;
fLabelZoneMap[label] = zone;
}
// -- metadata declarations
void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{}
// set/get
void setParamValue(const std::string& path, FAUSTFLOAT value)
{
if (fPathZoneMap.find(path) != fPathZoneMap.end()) {
*fPathZoneMap[path] = value;
} else if (fLabelZoneMap.find(path) != fLabelZoneMap.end()) {
*fLabelZoneMap[path] = value;
}
}
FAUSTFLOAT getParamValue(const std::string& path)
{
if (fPathZoneMap.find(path) != fPathZoneMap.end()) {
return *fPathZoneMap[path];
} else if (fLabelZoneMap.find(path) != fLabelZoneMap.end()) {
return *fLabelZoneMap[path];
} else {
return FAUSTFLOAT(0);
}
}
// map access
std::map<std::string, FAUSTFLOAT*>& getMap() { return fPathZoneMap; }
int getParamsCount() { return fPathZoneMap.size(); }
std::string getParamAddress(int index)
{
std::map<std::string, FAUSTFLOAT*>::iterator it = fPathZoneMap.begin();
while (index-- > 0 && it++ != fPathZoneMap.end()) {}
return (*it).first;
}
};

#endif // FAUST_MAPUI_H

+ 343
- 0
ports/temper/source/faust/gui/MetaDataUI.h View File

@@ -0,0 +1,343 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef MetaData_UI_H
#define MetaData_UI_H

#include <map>
#include <set>
#include <string>
#include <assert.h>

#include "faust/gui/SimpleParser.h"

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

static inline bool startWith(const std::string& str, const std::string& prefix)
{
return (str.substr(0, prefix.size()) == prefix);
}

/**
* Convert a dB value into a scale between 0 and 1 (following IEC standard ?)
*/
static inline FAUSTFLOAT dB2Scale(FAUSTFLOAT dB)
{
FAUSTFLOAT scale = 1.0;
/*if (dB < -70.0f)
scale = 0.0f;
else*/ if (dB < -60.0)
scale = (dB + 70.0) * 0.0025;
else if (dB < -50.0)
scale = (dB + 60.0) * 0.005 + 0.025;
else if (dB < -40.0)
scale = (dB + 50.0) * 0.0075 + 0.075;
else if (dB < -30.0)
scale = (dB + 40.0) * 0.015 + 0.15;
else if (dB < -20.0)
scale = (dB + 30.0) * 0.02 + 0.3;
else if (dB < -0.001 || dB > 0.001) /* if (dB < 0.0) */
scale = (dB + 20.0f) * 0.025 + 0.5;
return scale;
}

/*******************************************************************************
* MetaDataUI : Common class for MetaData handling
******************************************************************************/

//============================= BEGIN GROUP LABEL METADATA===========================
// Unlike widget's label, metadata inside group's label are not extracted directly by
// the Faust compiler. Therefore they must be extracted within the architecture file
//-----------------------------------------------------------------------------------

class MetaDataUI {
protected:
std::string gGroupTooltip;
std::map<FAUSTFLOAT*, FAUSTFLOAT> fGuiSize; // map widget zone with widget size coef
std::map<FAUSTFLOAT*, std::string> fTooltip; // map widget zone with tooltip strings
std::map<FAUSTFLOAT*, std::string> fUnit; // map widget zone to unit string (i.e. "dB")
std::map<FAUSTFLOAT*, std::string> fRadioDescription; // map zone to {'low':440; ...; 'hi':1000.0}
std::map<FAUSTFLOAT*, std::string> fMenuDescription; // map zone to {'low':440; ...; 'hi':1000.0}
std::set<FAUSTFLOAT*> fKnobSet; // set of widget zone to be knobs
std::set<FAUSTFLOAT*> fLedSet; // set of widget zone to be LEDs
std::set<FAUSTFLOAT*> fNumSet; // set of widget zone to be numerical bargraphs
std::set<FAUSTFLOAT*> fLogSet; // set of widget zone having a log UI scale
std::set<FAUSTFLOAT*> fExpSet; // set of widget zone having an exp UI scale
void clearMetadata()
{
fGuiSize.clear();
fTooltip.clear();
fUnit.clear();
fRadioDescription.clear();
fMenuDescription.clear();
fKnobSet.clear();
fLedSet.clear();
fNumSet.clear();
fLogSet.clear();
fExpSet.clear();
}
bool isKnob(FAUSTFLOAT* zone)
{
return fKnobSet.count(zone) > 0;
}
bool isRadio(FAUSTFLOAT* zone)
{
return fRadioDescription.count(zone) > 0;
}
bool isMenu(FAUSTFLOAT* zone)
{
return fMenuDescription.count(zone) > 0;
}
bool isLed(FAUSTFLOAT* zone)
{
return fLedSet.count(zone) > 0;
}
bool isNumerical(FAUSTFLOAT* zone)
{
return fNumSet.count(zone) > 0;
}
/**
* rmWhiteSpaces(): Remove the leading and trailing white spaces of a string
* (but not those in the middle of the string)
*/
std::string rmWhiteSpaces(const std::string& s)
{
size_t i = s.find_first_not_of(" \t");
size_t j = s.find_last_not_of(" \t");
if ((i != std::string::npos) && (j != std::string::npos)) {
return s.substr(i, 1+j-i);
} else {
return "";
}
}
/**
* Extracts metdata from a label : 'vol [unit: dB]' -> 'vol' + metadata(unit=dB)
*/
void extractMetadata(const std::string& fulllabel, std::string& label, std::map<std::string, std::string>& metadata)
{
enum {kLabel, kEscape1, kEscape2, kEscape3, kKey, kValue};
int state = kLabel; int deep = 0;
std::string key, value;
for (unsigned int i = 0; i < fulllabel.size(); i++) {
char c = fulllabel[i];
switch (state) {
case kLabel :
assert(deep == 0);
switch (c) {
case '\\' : state = kEscape1; break;
case '[' : state = kKey; deep++; break;
default : label += c;
}
break;
case kEscape1:
label += c;
state = kLabel;
break;
case kEscape2:
key += c;
state = kKey;
break;
case kEscape3:
value += c;
state = kValue;
break;
case kKey:
assert(deep > 0);
switch (c) {
case '\\':
state = kEscape2;
break;
case '[':
deep++;
key += c;
break;
case ':':
if (deep == 1) {
state = kValue;
} else {
key += c;
}
break;
case ']':
deep--;
if (deep < 1) {
metadata[rmWhiteSpaces(key)] = "";
state = kLabel;
key="";
value="";
} else {
key += c;
}
break;
default : key += c;
}
break;
case kValue:
assert(deep > 0);
switch (c) {
case '\\':
state = kEscape3;
break;
case '[':
deep++;
value += c;
break;
case ']':
deep--;
if (deep < 1) {
metadata[rmWhiteSpaces(key)] = rmWhiteSpaces(value);
state = kLabel;
key = "";
value = "";
} else {
value += c;
}
break;
default : value += c;
}
break;
default:
std::cerr << "ERROR unrecognized state " << state << std::endl;
}
}
label = rmWhiteSpaces(label);
}
/**
* Format tooltip string by replacing some white spaces by
* return characters so that line width doesn't exceed n.
* Limitation : long words exceeding n are not cut
*/
std::string formatTooltip(int n, const std::string& tt)
{
std::string ss = tt; // ss string we are going to format
int lws = 0; // last white space encountered
int lri = 0; // last return inserted
for (int i = 0; i < (int)tt.size(); i++) {
if (tt[i] == ' ') lws = i;
if (((i-lri) >= n) && (lws > lri)) {
// insert return here
ss[lws] = '\n';
lri = lws;
}
}
return ss;
}
public:
virtual ~MetaDataUI()
{}
enum Scale {
kLin,
kLog,
kExp
};
Scale getScale(FAUSTFLOAT* zone)
{
if (fLogSet.count(zone) > 0) return kLog;
if (fExpSet.count(zone) > 0) return kExp;
return kLin;
}
/**
* Analyses the widget zone metadata declarations and takes appropriate actions
*/
void declare(FAUSTFLOAT* zone, const char* key, const char* value)
{
if (zone == 0) {
// special zone 0 means group metadata
if (strcmp(key,"tooltip") == 0) {
// only group tooltip are currently implemented
gGroupTooltip = formatTooltip(30, value);
}
} else {
if (strcmp(key,"size") == 0) {
fGuiSize[zone] = atof(value);
}
else if (strcmp(key,"tooltip") == 0) {
fTooltip[zone] = formatTooltip(30, value);
}
else if (strcmp(key,"unit") == 0) {
fUnit[zone] = value ;
}
else if (strcmp(key,"scale") == 0) {
if (strcmp(value,"log") == 0) {
fLogSet.insert(zone);
} else if (strcmp(value,"exp") == 0) {
fExpSet.insert(zone);
}
}
else if (strcmp(key,"style") == 0) {
// else if ((strcmp(key,"style") == 0) || (strcmp(key,"type") == 0)) {
if (strcmp(value,"knob") == 0) {
fKnobSet.insert(zone);
} else if (strcmp(value,"led") == 0) {
fLedSet.insert(zone);
} else if (strcmp(value,"numerical") == 0) {
fNumSet.insert(zone);
} else {
const char* p = value;
if (parseWord(p, "radio")) {
fRadioDescription[zone] = std::string(p);
} else if (parseWord(p, "menu")) {
fMenuDescription[zone] = std::string(p);
}
}
}
}
}
};

#endif

+ 609
- 0
ports/temper/source/faust/gui/MidiUI.h View File

@@ -0,0 +1,609 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef FAUST_MIDIUI_H
#define FAUST_MIDIUI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include <vector>
#include <string>
#include <utility>
#include <iostream>

#include "faust/gui/GUI.h"
#include "faust/midi/midi.h"
#include "faust/gui/ValueConverter.h"

/*******************************************************************************
* MidiUI : Faust User Interface
* This class decodes MIDI meta data and maps incoming MIDI messages to them.
* Currently "ctrl, keyon, keypress, pgm, chanpress, pitchwheel/pitchbend meta data is handled.
******************************************************************************/
class uiMidiItem : public uiItem {
protected:
midi* fMidiOut;
bool fInputCtrl;

public:
uiMidiItem(midi* midi_out, GUI* ui, FAUSTFLOAT* zone, bool input)
:uiItem(ui, zone), fMidiOut(midi_out), fInputCtrl(input) {}
virtual ~uiMidiItem() {}
};
class uiMidiTimedItem : public uiMidiItem
{
protected:
bool fDelete;
public:
uiMidiTimedItem(midi* midi_out, GUI* ui, FAUSTFLOAT* zone, bool input = true)
:uiMidiItem(midi_out, ui, zone, input)
{
if (GUI::gTimedZoneMap.find(fZone) == GUI::gTimedZoneMap.end()) {
GUI::gTimedZoneMap[fZone] = ringbuffer_create(8192);
fDelete = true;
} else {
fDelete = false;
}
}
virtual ~uiMidiTimedItem()
{
ztimedmap::iterator it;
if (fDelete && ((it = GUI::gTimedZoneMap.find(fZone)) != GUI::gTimedZoneMap.end())) {
ringbuffer_free((*it).second);
GUI::gTimedZoneMap.erase(it);
}
}

void modifyZone(double date, FAUSTFLOAT v)
{
size_t res;
DatedControl dated_val(date, v);
if ((res = ringbuffer_write(GUI::gTimedZoneMap[fZone], (const char*)&dated_val, sizeof(DatedControl))) != sizeof(DatedControl)) {
std::cout << "ringbuffer_write error DatedControl" << std::endl;
}
}
// TODO
virtual void reflectZone() {}

};

// MIDI sync

class uiMidiStart : public uiMidiTimedItem
{
public:
uiMidiStart(midi* midi_out, GUI* ui, FAUSTFLOAT* zone, bool input = true)
:uiMidiTimedItem(midi_out, ui, zone, input)
{}
virtual ~uiMidiStart()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
if (v != FAUSTFLOAT(0)) {
fMidiOut->start_sync(0);
}
}
};

class uiMidiStop : public uiMidiTimedItem
{
public:
uiMidiStop(midi* midi_out, GUI* ui, FAUSTFLOAT* zone, bool input = true)
:uiMidiTimedItem(midi_out, ui, zone, input)
{}
virtual ~uiMidiStop()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
if (v != FAUSTFLOAT(1)) {
fMidiOut->stop_sync(0);
}
}
};

class uiMidiClock : public uiMidiTimedItem
{

private:
bool fState;
public:
uiMidiClock(midi* midi_out, GUI* ui, FAUSTFLOAT* zone, bool input = true)
:uiMidiTimedItem(midi_out, ui, zone, input), fState(false)
{}
virtual ~uiMidiClock()
{}
void modifyZone(double date, FAUSTFLOAT v)
{
if (fInputCtrl) {
fState = !fState;
uiMidiTimedItem::modifyZone(date, FAUSTFLOAT(fState));
}
}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fMidiOut->clock(0);
}
};

class uiMidiProgChange : public uiMidiItem
{
private:
int fPgm;
public:
uiMidiProgChange(midi* midi_out, int pgm, GUI* ui, FAUSTFLOAT* zone, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fPgm(pgm)
{}
virtual ~uiMidiProgChange()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
if (v != FAUSTFLOAT(0)) {
fMidiOut->progChange(0, fPgm);
}
}
};

class uiMidiChanPress : public uiMidiItem
{
private:
int fPress;
public:
uiMidiChanPress(midi* midi_out, int press, GUI* ui, FAUSTFLOAT* zone, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fPress(press)
{}
virtual ~uiMidiChanPress()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
if (v != FAUSTFLOAT(0)) {
fMidiOut->chanPress(0, fPress);
}
}
};

class uiMidiCtrlChange : public uiMidiItem
{
private:
int fCtrl;
LinearValueConverter fConverter;
public:
uiMidiCtrlChange(midi* midi_out, int ctrl, GUI* ui, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fCtrl(ctrl), fConverter(0., 127., double(min), double(max))
{}
virtual ~uiMidiCtrlChange()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fMidiOut->ctrlChange(0, fCtrl, fConverter.faust2ui(v));
}
void modifyZone(int v)
{
if (fInputCtrl) {
uiItem::modifyZone(FAUSTFLOAT(fConverter.ui2faust(v)));
}
}
};

class uiMidiPitchWheel : public uiMidiItem
{

private:
LinearValueConverter fConverter;
public:
uiMidiPitchWheel(midi* midi_out, GUI* ui, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fConverter(0., 16383, double(min), double(max))
{}
virtual ~uiMidiPitchWheel()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fMidiOut->pitchWheel(0, fConverter.faust2ui(v));
}
void modifyZone(int v)
{
if (fInputCtrl) {
uiItem::modifyZone(FAUSTFLOAT(fConverter.ui2faust(v)));
}
}
};

class uiMidiKeyOn : public uiMidiItem
{

private:
int fKeyOn;
LinearValueConverter fConverter;
public:
uiMidiKeyOn(midi* midi_out, int key, GUI* ui, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fKeyOn(key), fConverter(0., 127., double(min), double(max))
{}
virtual ~uiMidiKeyOn()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fMidiOut->keyOn(0, fKeyOn, fConverter.faust2ui(v));
}
void modifyZone(int v)
{
if (fInputCtrl) {
uiItem::modifyZone(FAUSTFLOAT(fConverter.ui2faust(v)));
}
}
};

class uiMidiKeyOff : public uiMidiItem
{

private:
int fKeyOff;
LinearValueConverter fConverter;
public:
uiMidiKeyOff(midi* midi_out, int key, GUI* ui, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fKeyOff(key), fConverter(0., 127., double(min), double(max))
{}
virtual ~uiMidiKeyOff()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fMidiOut->keyOff(0, fKeyOff, fConverter.faust2ui(v));
}
void modifyZone(int v)
{
if (fInputCtrl) {
uiItem::modifyZone(FAUSTFLOAT(fConverter.ui2faust(v)));
}
}
};

class uiMidiKeyPress : public uiMidiItem
{

private:
int fKeyOn;
LinearValueConverter fConverter;
public:
uiMidiKeyPress(midi* midi_out, int key, GUI* ui, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, bool input = true)
:uiMidiItem(midi_out, ui, zone, input), fKeyOn(key), fConverter(0., 127., double(min), double(max))
{}
virtual ~uiMidiKeyPress()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
fMidiOut->keyPress(0, fKeyOn, fConverter.faust2ui(v));
}
void modifyZone(int v)
{
if (fInputCtrl) {
uiItem::modifyZone(FAUSTFLOAT(fConverter.ui2faust(v)));
}
}
};

class MapUI;

class MidiUI : public GUI, public midi
{

protected:
std::map <int, std::vector<uiMidiCtrlChange*> > fCtrlChangeTable;
std::map <int, std::vector<uiMidiProgChange*> > fProgChangeTable;
std::map <int, std::vector<uiMidiChanPress*> > fChanPressTable;
std::map <int, std::vector<uiMidiKeyOn*> > fKeyOnTable;
std::map <int, std::vector<uiMidiKeyOff*> > fKeyOffTable;
std::map <int, std::vector<uiMidiKeyPress*> > fKeyPressTable;
std::vector<uiMidiPitchWheel*> fPitchWheelTable;
std::vector<uiMidiStart*> fStartTable;
std::vector<uiMidiStop*> fStopTable;
std::vector<uiMidiClock*> fClockTable;
std::vector<std::pair <std::string, std::string> > fMetaAux;
midi_handler* fMidiHandler;
void addGenericZone(FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max, bool input = true)
{
if (fMetaAux.size() > 0) {
for (size_t i = 0; i < fMetaAux.size(); i++) {
unsigned num;
if (fMetaAux[i].first == "midi") {
if (sscanf(fMetaAux[i].second.c_str(), "ctrl %u", &num) == 1) {
fCtrlChangeTable[num].push_back(new uiMidiCtrlChange(fMidiHandler, num, this, zone, min, max, input));
} else if (sscanf(fMetaAux[i].second.c_str(), "keyon %u", &num) == 1) {
fKeyOnTable[num].push_back(new uiMidiKeyOn(fMidiHandler, num, this, zone, min, max, input));
} else if (sscanf(fMetaAux[i].second.c_str(), "keyoff %u", &num) == 1) {
fKeyOffTable[num].push_back(new uiMidiKeyOff(fMidiHandler, num, this, zone, min, max, input));
} else if (sscanf(fMetaAux[i].second.c_str(), "keypress %u", &num) == 1) {
fKeyPressTable[num].push_back(new uiMidiKeyPress(fMidiHandler, num, this, zone, min, max, input));
} else if (sscanf(fMetaAux[i].second.c_str(), "pgm %u", &num) == 1) {
fProgChangeTable[num].push_back(new uiMidiProgChange(fMidiHandler, num, this, zone, input));
} else if (sscanf(fMetaAux[i].second.c_str(), "chanpress %u", &num) == 1) {
fChanPressTable[num].push_back(new uiMidiChanPress(fMidiHandler, num, this, zone, input));
} else if (strcmp(fMetaAux[i].second.c_str(), "pitchwheel") == 0
|| strcmp(fMetaAux[i].second.c_str(), "pitchbend") == 0) {
fPitchWheelTable.push_back(new uiMidiPitchWheel(fMidiHandler, this, zone, min, max, input));
// MIDI sync
} else if (strcmp(fMetaAux[i].second.c_str(), "start") == 0) {
fStartTable.push_back(new uiMidiStart(fMidiHandler, this, zone, input));
} else if (strcmp(fMetaAux[i].second.c_str(), "stop") == 0) {
fStopTable.push_back(new uiMidiStop(fMidiHandler, this, zone, input));
} else if (strcmp(fMetaAux[i].second.c_str(), "clock") == 0) {
fClockTable.push_back(new uiMidiClock(fMidiHandler, this, zone, input));
}
}
}
}
fMetaAux.clear();
}

public:

MidiUI(midi_handler* midi_handler)
{
fMidiHandler = midi_handler;
fMidiHandler->addMidiIn(this);
}
virtual ~MidiUI()
{
fMidiHandler->removeMidiIn(this);
}
bool run() { return fMidiHandler->start_midi(); }
void stop() { fMidiHandler->stop_midi(); }
void addMidiIn(midi* midi_dsp) { fMidiHandler->addMidiIn(midi_dsp); }
void removeMidiIn(midi* midi_dsp) { fMidiHandler->removeMidiIn(midi_dsp); }
// -- widget's layouts

virtual void openTabBox(const char* label)
{}
virtual void openHorizontalBox(const char* label)
{}
virtual void openVerticalBox(const char* label)
{}
virtual void closeBox()
{}

// -- active widgets
virtual void addButton(const char* label, FAUSTFLOAT* zone)
{
addGenericZone(zone, FAUSTFLOAT(0), FAUSTFLOAT(1));
}
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
addGenericZone(zone, FAUSTFLOAT(0), FAUSTFLOAT(1));
}
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGenericZone(zone, min, max);
}
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGenericZone(zone, min, max);
}
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGenericZone(zone, min, max);
}

// -- passive widgets

virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addGenericZone(zone, min, max, false);
}
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addGenericZone(zone, min, max, false);
}

// -- metadata declarations

virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
fMetaAux.push_back(std::make_pair(key, val));
}
// -- MIDI API
MapUI* keyOn(double date, int channel, int note, int velocity)
{
if (fKeyOnTable.find(note) != fKeyOnTable.end()) {
for (unsigned int i = 0; i < fKeyOnTable[note].size(); i++) {
fKeyOnTable[note][i]->modifyZone(FAUSTFLOAT(velocity));
}
}
return 0;
}
void keyOff(double date, int channel, int note, int velocity)
{
if (fKeyOffTable.find(note) != fKeyOffTable.end()) {
for (unsigned int i = 0; i < fKeyOffTable[note].size(); i++) {
fKeyOffTable[note][i]->modifyZone(FAUSTFLOAT(velocity));
}
}
}
void ctrlChange(double date, int channel, int ctrl, int value)
{
if (fCtrlChangeTable.find(ctrl) != fCtrlChangeTable.end()) {
for (unsigned int i = 0; i < fCtrlChangeTable[ctrl].size(); i++) {
fCtrlChangeTable[ctrl][i]->modifyZone(FAUSTFLOAT(value));
}
}
}
void progChange(double date, int channel, int pgm)
{
if (fProgChangeTable.find(pgm) != fProgChangeTable.end()) {
for (unsigned int i = 0; i < fProgChangeTable[pgm].size(); i++) {
fProgChangeTable[pgm][i]->modifyZone(FAUSTFLOAT(1));
}
}
}
void pitchWheel(double date, int channel, int wheel)
{
for (unsigned int i = 0; i < fPitchWheelTable.size(); i++) {
fPitchWheelTable[i]->modifyZone(FAUSTFLOAT(wheel));
}
}
void keyPress(double date, int channel, int pitch, int press)
{
if (fKeyPressTable.find(press) != fKeyPressTable.end()) {
for (unsigned int i = 0; i < fKeyPressTable[press].size(); i++) {
fKeyPressTable[press][i]->modifyZone(FAUSTFLOAT(press));
}
}
}
void chanPress(double date, int channel, int press)
{
if (fChanPressTable.find(press) != fChanPressTable.end()) {
for (unsigned int i = 0; i < fChanPressTable[press].size(); i++) {
fChanPressTable[press][i]->modifyZone(FAUSTFLOAT(1));
}
}
}
void ctrlChange14bits(double date, int channel, int ctrl, int value) {}
// MIDI sync
void start_sync(double date)
{
for (unsigned int i = 0; i < fStartTable.size(); i++) {
fStartTable[i]->modifyZone(date, FAUSTFLOAT(1));
}
}
void stop_sync(double date)
{
for (unsigned int i = 0; i < fStopTable.size(); i++) {
fStopTable[i]->modifyZone(date, FAUSTFLOAT(0));
}
}
void clock(double date)
{
for (unsigned int i = 0; i < fClockTable.size(); i++) {
fClockTable[i]->modifyZone(date, FAUSTFLOAT(1));
}
}
};

#endif // FAUST_MIDIUI_H

+ 672
- 0
ports/temper/source/faust/gui/OCVUI.h View File

@@ -0,0 +1,672 @@
/******************************************************************************
*******************************************************************************

OPENCV USER INTERFACE

*******************************************************************************
*******************************************************************************/
#ifndef _OCVUI_H
#define _OCVUI_H

/**
* \file OCVUI.h
* \brief OpenCV user interface
* \author GRAME, Centre National de Création Musicale
* \date 26/01/2015
*
* This architecture file allows the user to use the OpenCV library in order to perform
* image processing and use the result to control audio parameters.
*
* To use this mode, just add the option -ocv with your faust2jack tool.
*
*/

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

// OpenCV includes
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

// Basic includes
#include <iostream>
#include <ctype.h>

// std::thread
#include <pthread.h>

// OpenCV Main Loop Function Prototype

static void* ocvLoop(void*);

//******** OpenCV User Interface CLASS DEFINITION ********//
class OCVUI : public UI
{
public:
// STRUCTURES
/**
* \struct object
* \brief parameters of an object detected in the image
*
* An object is assimilated to a circle, and characterised by
* its color, its center, its area, and its radius.
*
*/
struct object
{
int color; /*!< Object's color */
float centerX; /*!< Object's center's abscissa */
float centerY; /*!< Object's center's ordinate */
float area; /*!< Object's area */
int radius; /*!< Object's radius */
};
/**
* \struct metadata
* \brief metadata for audio parameters
*
* OpenCV metadata specify which object's characteristics you
* want for an audio parameter.
*
*/
struct metadata
{
FAUSTFLOAT* zone; /*!< Audio parameter's address */
int color; /*!< Object's color */
std::string param; /*!< Object's parameter */
bool used; /*!< Bool variable */
};
// FUNCTIONS
//-- UI Functions Redefinition
// Functions inherited from the UI class
// Constructor
OCVUI() : objects_storage_(0), parameters_storage_(0), height_(0), width_(0){};
// Destructor
~OCVUI()
{
exit_ = true;
pthread_join(loop_, NULL);
};
// -- WIDGETS LAYOUTS
void openTabBox(const char* label){}
void openHorizontalBox(const char* label){}
void openVerticalBox(const char* label){}
void closeBox(){}

// -- ACTIVE WIDGETS
void addButton(const char* label, FAUSTFLOAT* zone){}
void addCheckButton(const char* label, FAUSTFLOAT* zone){}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step){}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step){}
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step){}
// -- PASSIVE WIDGETS
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max){}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max){}

// -- METADATA DECLARATION
/**
* \fn bool parser(std::string string2parse, metadata *pmeta)
* \brief Parsing Function
*
* \param string2parse A string to parse
* \param pmeta Pointer on a metadata structure
*
* This function parses the metadata string, and puts the parameters
* in a metadata structure.
*/
bool parser(std::string string2parse, metadata *pmeta)
{
int SPACE = 32; // Parameters separator
std::vector<std::string> parameters(0);
// String analysis
for (int i = 0 ; i < string2parse.size() ; i++)
{
if (string2parse[i] == SPACE)
{
std::string oneParameter= string2parse.substr(0, i);
parameters.push_back(oneParameter);
string2parse.erase(string2parse.begin(), string2parse.begin()+i+1);
i = 0;
}
}
std::string lastParameter = string2parse;
parameters.push_back(lastParameter);
// Store Parameters in a Metadata Structure
// Parameters count must be 2
if (parameters.size() == 2)
{
/**
* \enum color
* \brief color indexes
*
* Colors are indexed
*/
if (parameters[0]=="red") /*!< red = 1 */
{
pmeta->color = 1;
}
else if (parameters[0]=="yellow") /*!< yellow = 2 */
{
pmeta->color = 2;
}
else if (parameters[0]=="green") /*!< green = 3 */
{
pmeta->color = 3;
}
else if (parameters[0]=="cyan") /*!< cyan = 4 */
{
pmeta->color = 4;
}
else if (parameters[0]=="blue") /*!< blue = 5 */
{
pmeta->color = 5;
}
else if (parameters[0]=="magenta") /*!< magenta = 6 */
{
pmeta->color = 6;
}
pmeta->param = parameters[1];
pmeta->used = false;
return true;
}
else
{
std::cout<<"Wrong count of parameters. Please check if the OpenCV"
<<"metadata is correctly defined"<<std::endl;
return false;
}
}
/**
* \fn void declare(FAUSTFLOAT* zone, const char* key, const char* val)
* \brief metadata declaration
*
* \param zone audio parameter's address
* \param key metadata key/type (here, it must be ocv)
* \param val metadata value
*
* This function gives the metadata string, which will be analysed.
*/
void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
if (key == "ocv")
{
metadata newMeta;
bool string_parsed = false;
if (zone != 0)
{
newMeta.zone = zone;
}
string_parsed = parser(val, &newMeta);
if (string_parsed)
{
parameters_storage_.push_back(newMeta);
}
}
}
// Image Processing Functions
/**
* \fn void contoursProcess(std::vector<std::vector<cv::Point>> contours, int color)
* \brief Contours processing
*
* \param contours contours of an object
* \param color color of this object
*
* This function approximates contours to rectangles,
* and stores the bigest one as a new object.
*/
void contoursProcess(std::vector<std::vector<cv::Point> > contours, int color)
{
int tempArea = 0;
cv::Rect myRect;
for (int j = 0 ; j<contours.size() ; j++)
{
std::vector<std::vector<cv::Point> > contours_poly( contours.size() );
std::vector<cv::Rect> boundRect( contours.size() );
if (contours[j].size() > 40) // Do not take care about small
// contours
{
approxPolyDP( cv::Mat(contours[j]), contours_poly[j], 3, true );// Approximate contours to
// a polygone
boundRect[j] = cv::boundingRect( cv::Mat(contours_poly[j]) ); // Bound a contour in a
// rectangle
if ((int)boundRect[j].area()>tempArea)
{
tempArea=(int)boundRect[j].area();
myRect = boundRect[j];
}
}
}
if (tempArea != 0)
{
// Create a new object structure to store the object properties
object newObject;
newObject.color = color;
newObject.centerX = myRect.x+myRect.width/2;
newObject.centerY = myRect.y+myRect.height/2;
newObject.area = 1.5*(float)tempArea/(width_*height_);
newObject.radius= (int)MIN(myRect.width/2, myRect.height/2);
// Put the new object in the objects storage.
objects_storage_.push_back(newObject);
}
}
/**
* \fn void erodeAndDilate(cv::Mat image)
* \brief Morphological Opening (Erosion and Dilatation)
*
* \param image mask produced with the "cv::inRange" function.
*
* This function improves a mask shape
* See OpenCV documentation for more informations :
* http://docs.opencv.org/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html
*/
void erodeAndDilate(cv::Mat image)
{
cv::Mat element;
element = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3, 3));
// Erase small alone pixels
// http://docs.opencv.org/modules/imgproc/doc/filtering.html#dilate
for (int i = 0; i<2 ; i++)
{
cv::erode(image, image, element);
}
// Enlarge blocks of pixels
// http://docs.opencv.org/modules/imgproc/doc/filtering.html#erode
for (int i = 0; i<10 ; i++)
{
cv::dilate(image, image, element);
}
}
/**
* \fn void drawCircle(object my_object, cv::Mat my_image)
* \brief Draws circles around chosen objects
*
* \param my_object Detected and specified object
* \param my_image image on which to draw
*
* This function draws circles around the objects specified in the metadata
* declaration and detected in the image.
* Note that the circle color depends on the object color.
*/
void drawCircle(object my_object, cv::Mat my_image)
{
cv::Scalar bgr_color;
switch (my_object.color)
{
case 1: // RED
bgr_color = cv::Scalar (0,0,255);
break;
case 2: //YELLOW
bgr_color = cv::Scalar (0, 255, 255);
break;
case 3: // GREEN
bgr_color = cv::Scalar (0, 255, 0);
break;
case 4: // CYAN
bgr_color = cv::Scalar (255, 255, 0);
break;
case 5: // BLUE
bgr_color = cv::Scalar (255,0,0);
break;
case 6: // MAGENTA
bgr_color = cv::Scalar (255, 0, 255);
break;
default: // Add a color !
break;
}
// draw circle
cv::circle(my_image, cv::Point(my_object.centerX, my_object.centerY),
my_object.radius, bgr_color, 2, 8, 0);
}
/**
* \fn imageProcessing(cv::Mat BGRImage)
* \brief Image Processing function for objects detection
*
* \param BGRImage image in BGR color scale, from camera
*
* This function processes a BGR image.
* It converts it into an HSV image, opens it (erodes and dilates), extracts contours from image
* and extracts objects from contours. The objects are stored and circled.
*/
void imageProcessing(cv::Mat BGRImage)
{
height_ = BGRImage.rows;
width_ = BGRImage.cols;
cv::Mat HsvImage;
cv::cvtColor(BGRImage, HsvImage, CV_BGR2HSV); // Convert frame to HSV format
// in order to use "inRange"
// Mask matrices (red, yellow, green, cyan, blue and magenta)
cv::Mat r_mask, y_mask, g_mask, c_mask, b_mask, m_mask;
// Objects contours
std::vector<std::vector<cv::Point> > r_contours, y_contours, g_contours,
c_contours, b_contours, m_contours;
std::vector<cv::Vec4i> hierarchy;
// Get every pixel whose value is between _min and _max
// and put it into a mask
cv::inRange(BGRImage, red_min, red_max, r_mask);
cv::inRange(BGRImage, yellow_min, yellow_max, y_mask);
cv::inRange(BGRImage, green_min, green_max, g_mask);
cv::inRange(BGRImage, cyan_min, cyan_max, c_mask);
cv::inRange(BGRImage, blue_min, blue_max, b_mask);
cv::inRange(BGRImage, magenta_min, magenta_max, m_mask);
// Improve masks shapes
erodeAndDilate(r_mask);
erodeAndDilate(y_mask);
erodeAndDilate(g_mask);
erodeAndDilate(c_mask);
erodeAndDilate(b_mask);
erodeAndDilate(m_mask);
// Get the shapes contours from masks
cv::findContours(r_mask, r_contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
cv::findContours(y_mask, y_contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
cv::findContours(g_mask, g_contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
cv::findContours(c_mask, c_contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
cv::findContours(b_mask, b_contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
cv::findContours(m_mask, m_contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
// Process every contour. Note that color is taken in account.
for (int i = 1; i <= 6; i++)
{
switch (i)
{
case 1: // RED
contoursProcess(r_contours, 1);
break;
case 2: // YELLOW
contoursProcess(y_contours, 2);
break;
case 3: // GREEN
contoursProcess(g_contours, 3);
break;
case 4: // CYAN
contoursProcess(c_contours, 4);
break;
case 5: // BLUE
contoursProcess(b_contours, 5);
break;
case 6: // MAGENTA
contoursProcess(m_contours, 6);
break;
default: // You'll have to add a new color...
break;
}
}
// Audio parameters setting
for (int i = 0; i<objects_storage_.size(); i++)
{
for (int j = 0; j < parameters_storage_.size(); j++)
{
if (objects_storage_[i].color == parameters_storage_[j].color
&& !parameters_storage_[j].used)
{
if (parameters_storage_[j].param=="color")
{
*parameters_storage_[j].zone=(float)objects_storage_[i].color;
}
else if (parameters_storage_[j].param=="x")
{
*parameters_storage_[j].zone=objects_storage_[i].centerX/width_;
}
else if (parameters_storage_[j].param=="y")
{
*parameters_storage_[j].zone=1-(objects_storage_[i].centerY/height_);
}
else if (parameters_storage_[j].param=="area")
{
*parameters_storage_[j].zone=(float)objects_storage_[i].area;
}
parameters_storage_[j].used=true;
drawCircle(objects_storage_[i], BGRImage);
}
}
}
}
/**
* \fn void empty()
* \brief Empties the object's storage
*
* This function empties the object's storage, and resets the parameters storage
*/

void empty()
{
while (objects_storage_.size() > 0)
{
objects_storage_.pop_back();
}
for (int l = 0; l<parameters_storage_.size(); l++)
{
parameters_storage_[l].used=false;
}
}
/**
* \fn bool exit()
* \brief Return the exit member parameter.
*/
bool exit()
{
return exit_;
}
/**
* \fn void exitThread()
* \brief Exit from thread
*
* \param This function exits from thread
*/
void exitThread()
{
pthread_exit(NULL);
}
/**
* \fn void run()
* \brief Creates and runs the thread
*
* This function creates the image processing thread
*/
bool run()
{
exit_ = false;
if (pthread_create(&loop_, NULL, ocvLoop, (void *)this) == 0) {
return true;
} else {
std::cerr <<"Could not create thread. Thread Creation failed." << std::endl;
return false;
}
}
////////////////////////////////////////////
//// ////
//// MEMBER VARIABLES ////
//// ////
////////////////////////////////////////////
private:
// HSV min and max values variables
// #1 : RED
static cv::Scalar red_min;
static cv::Scalar red_max;
// #2 : YELLOW
static cv::Scalar yellow_min;
static cv::Scalar yellow_max;
// #3 : GREEN
static cv::Scalar green_min;
static cv::Scalar green_max;
// #4 : CYAN
static cv::Scalar cyan_min;
static cv::Scalar cyan_max;
// #5 : BLUE
static cv::Scalar blue_min;
static cv::Scalar blue_max;
// #6 : MAGENTA
static cv::Scalar magenta_min;
static cv::Scalar magenta_max;

// Objects Storage
// Where all the objects are stored
std::vector<object> objects_storage_;
// Parameters Storage
// Where all the "ocv" metadata parameters are stored
std::vector<metadata> parameters_storage_;
// Matrix height and width
int height_, width_;
// Loop thread;
pthread_t loop_;
// Thread EXIT variable
bool exit_;
};

// HSV min and max values
// Note that H is between 0 and 180
// in openCV
// #1 = RED
cv::Scalar OCVUI::red_min = cv::Scalar (0,200,55);
cv::Scalar OCVUI::red_max = cv::Scalar (1,255,255);

// #2 = YELLOW
cv::Scalar OCVUI::yellow_min = cv::Scalar (25, 200, 55);
cv::Scalar OCVUI::yellow_max = cv::Scalar (35, 255, 255);

// #3 = GREEN
cv::Scalar OCVUI::green_min = cv::Scalar (20,155,55);
cv::Scalar OCVUI::green_max = cv::Scalar (50,255,255);

// #4 = CYAN
cv::Scalar OCVUI::cyan_min = cv::Scalar (85,200,55);
cv::Scalar OCVUI::cyan_max = cv::Scalar (95,200,55);

// #5 = BLUE
cv::Scalar OCVUI::blue_min = cv::Scalar (115,155,55);
cv::Scalar OCVUI::blue_max = cv::Scalar (125,255,255);

// #6 = MAGENTA
cv::Scalar OCVUI::magenta_min = cv::Scalar (145,200,55);
cv::Scalar OCVUI::magenta_max = cv::Scalar (155,255,255);

// OpenCV Main Loop Function Implementation
// This function is a loop that gets every frame from a camera
// and calls the image processing functions.
// This is the OCVUI.h main function.
/**
* \fn void* ocvLoop(void* ocv_object)
* \brief Loop function for image processing
*/
void* ocvLoop(void* ocv_object)
{
// The camera index allows to select the camera.
// 0 stands for the default camera.
int camIndex=1;
//std::cout<<"camera index ?"<<std::endl;
//std::cin>>camIndex;

cv::Mat frame, hsv;
OCVUI* ocv = (OCVUI*) ocv_object;
cv::VideoCapture cap(camIndex);
std::cout<<"Video Capture from camera n°"<<camIndex<<std::endl;
if (!cap.isOpened()) // check if we succeeded to read frames
// from camera
{
std::cout<<"Could not open camera n°"<<camIndex<<" !"<<std::endl;
}
cap.set(CV_CAP_PROP_FPS, 60); // Set frames rate
cv::namedWindow("Tracking", 1); // Create a window

while (!ocv->exit())
{
cap >> frame; // Get frame from camera
ocv->imageProcessing(frame); // Objects Detection function

/*** Show image ***/
cv::imshow("Tracking", frame);
ocv->empty(); // Empty the objects and parameters storages
}
ocv->exitThread();
}

#endif

+ 118
- 0
ports/temper/source/faust/gui/OSCControler.h View File

@@ -0,0 +1,118 @@
/*

Faust Project

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __OSCControler__
#define __OSCControler__

#include <string>
#include "faust/osc/FaustFactory.h"

class GUI;

typedef void (*ErrorCallback)(void*);

namespace oscfaust
{

class OSCIO;
class OSCSetup;
class OSCRegexp;
//--------------------------------------------------------------------------
/*!
\brief the main Faust OSC Lib API
The OSCControler is essentially a glue between the memory representation (in charge of the FaustFactory),
and the network services (in charge of OSCSetup).
*/
class OSCControler
{
int fUDPPort, fUDPOut, fUPDErr; // the udp ports numbers
std::string fDestAddress; // the osc messages destination address, used at initialization only
// to collect the address from the command line
OSCSetup* fOsc; // the network manager (handles the udp sockets)
OSCIO* fIO; // hack for OSC IO support (actually only relayed to the factory)
FaustFactory * fFactory; // a factory to build the memory represetnatin

bool fInit;
public:
/*
base udp port is chosen in an unassigned range from IANA PORT NUMBERS (last updated 2011-01-24)
see at http://www.iana.org/assignments/port-numbers
5507-5552 Unassigned
*/
enum { kUDPBasePort = 5510};
OSCControler(int argc, char *argv[], GUI* ui, OSCIO* io = 0, ErrorCallback errCallback = NULL, void* arg = NULL, bool init = true);

virtual ~OSCControler();
//--------------------------------------------------------------------------
// addnode, opengroup and closegroup are simply relayed to the factory
//--------------------------------------------------------------------------
// Add a node in the current group (top of the group stack)
template <typename T> void addnode(const char* label, T* zone, T init, T min, T max, bool input = true)
{ fFactory->addnode(label, zone, init, min, max, fInit, input); }
//--------------------------------------------------------------------------
// This method is used for alias messages. The arguments imin and imax allow
// to map incomming values from the alias input range to the actual range
template <typename T> void addAlias(const std::string& fullpath, T* zone, T imin, T imax, T init, T min, T max, const char* label)
{ fFactory->addAlias(fullpath, zone, imin, imax, init, min, max, label); }

void opengroup(const char* label) { fFactory->opengroup(label); }
void closegroup() { fFactory->closegroup(); }
//--------------------------------------------------------------------------
void run(); // starts the network services
void stop(); // stop the network services
int getUDPPort() const { return fUDPPort; }
int getUDPOut() const { return fUDPOut; }
int getUDPErr() const { return fUPDErr; }
const char* getDestAddress() const { return fDestAddress.c_str(); }
const char* getRootName() const; // probably useless, introduced for UI extension experiments

// By default, an osc interface emits all parameters. You can filter specific params dynamically.
static std::vector<OSCRegexp*> fFilteredPaths; // filtered paths will not be emitted
static void addFilteredPath(std::string path);
static bool isPathFiltered(std::string path);
static void resetFilteredPaths();
static float version(); // the Faust OSC library version number
static const char* versionstr(); // the Faust OSC library version number as a string
static int gXmit; // a static variable to control the transmission of values
// i.e. the use of the interface as a controler
};

#define kNoXmit 0
#define kAll 1
#define kAlias 2

}

#endif

+ 179
- 0
ports/temper/source/faust/gui/OSCUI.h View File

@@ -0,0 +1,179 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

/*
Copyright (C) 2011 Grame - Lyon
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted.
*/

#ifndef __OSCUI__
#define __OSCUI__

#include "faust/gui/OSCControler.h"
#include "faust/gui/GUI.h"
#include <vector>

#ifdef _WIN32
#define strcasecmp _stricmp
#endif

/******************************************************************************
*******************************************************************************

OSC (Open Sound Control) USER INTERFACE

*******************************************************************************
*******************************************************************************/
/*

Note about the OSC addresses and the Faust UI names:
----------------------------------------------------
There are potential conflicts between the Faust UI objects naming scheme and
the OSC address space. An OSC symbolic names is an ASCII string consisting of
printable characters other than the following:
space
# number sign
* asterisk
, comma
/ forward
? question mark
[ open bracket
] close bracket
{ open curly brace
} close curly brace

a simple solution to address the problem consists in replacing
space or tabulation with '_' (underscore)
all the other osc excluded characters with '-' (hyphen)

This solution is implemented in the proposed OSC UI;
*/

class OSCUI : public GUI
{
oscfaust::OSCControler* fCtrl;
std::vector<const char*> fAlias;
const char* tr(const char* label) const
{
static char buffer[1024];
char * ptr = buffer; int n=1;
while (*label && (n++ < 1024)) {
switch (*label) {
case ' ': case ' ':
*ptr++ = '_';
break;
case '#': case '*': case ',': case '/': case '?':
case '[': case ']': case '{': case '}': case '(': case ')':
*ptr++ = '_';
break;
default:
*ptr++ = *label;
}
label++;
}
*ptr = 0;
return buffer;
}
// add all accumulated alias
void addalias(FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, const char* label)
{
for (unsigned int i = 0; i < fAlias.size(); i++) {
fCtrl->addAlias(fAlias[i], zone, FAUSTFLOAT(0), FAUSTFLOAT(1), init, min, max, label);
}
fAlias.clear();
}
public:

OSCUI(const char* /*applicationname*/, int argc, char *argv[], oscfaust::OSCIO* io = 0, ErrorCallback errCallback = NULL, void* arg = NULL, bool init = true) : GUI()
{
fCtrl = new oscfaust::OSCControler(argc, argv, this, io, errCallback, arg, init);
// fCtrl->opengroup(applicationname);
}
virtual ~OSCUI() { delete fCtrl; }
// -- widget's layouts
virtual void openTabBox(const char* label) { fCtrl->opengroup(tr(label)); }
virtual void openHorizontalBox(const char* label) { fCtrl->opengroup(tr(label)); }
virtual void openVerticalBox(const char* label) { fCtrl->opengroup(tr(label)); }
virtual void closeBox() { fCtrl->closegroup(); }
// -- active widgets
virtual void addButton(const char* label, FAUSTFLOAT* zone) { const char* l = tr(label); addalias(zone, 0, 0, 1, l); fCtrl->addnode(l, zone, FAUSTFLOAT(0), FAUSTFLOAT(0), FAUSTFLOAT(1)); }
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) { const char* l = tr(label); addalias(zone, 0, 0, 1, l); fCtrl->addnode(l, zone, FAUSTFLOAT(0), FAUSTFLOAT(0), FAUSTFLOAT(1)); }
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT /*step*/)
{ const char* l = tr(label); addalias(zone, init, min, max, l); fCtrl->addnode(l, zone, init, min, max); }
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT /*step*/)
{ const char* l = tr(label); addalias(zone, init, min, max, l); fCtrl->addnode(l, zone, init, min, max); }
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT /*step*/)
{ const char* l = tr(label); addalias(zone, init, min, max, l); fCtrl->addnode(l, zone, init, min, max); }
// -- passive widgets
virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
const char* l = tr(label); addalias(zone, 0, min, max, l); fCtrl->addnode(l, zone, FAUSTFLOAT(0), min, max, false);
}
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
const char* l = tr(label); addalias(zone, 0, min, max, l); fCtrl->addnode(l, zone, FAUSTFLOAT(0), min, max, false);
}
// -- metadata declarations
virtual void declare(FAUSTFLOAT* , const char* key , const char* alias)
{
if (strcasecmp(key,"OSC") == 0) fAlias.push_back(alias);
}

virtual void show() {}

bool run()
{
fCtrl->run();
return true;
}
void stop()
{
fCtrl->stop();
}
const char* getRootName() { return fCtrl->getRootName(); }
int getUDPPort() { return fCtrl->getUDPPort(); }
int getUDPOut() { return fCtrl->getUDPOut(); }
int getUDPErr() { return fCtrl->getUDPErr(); }
const char* getDestAddress() { return fCtrl->getDestAddress(); }
};

#endif // __OSCUI__

+ 65
- 0
ports/temper/source/faust/gui/PathBuilder.h View File

@@ -0,0 +1,65 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef FAUST_PATHBUILDER_H
#define FAUST_PATHBUILDER_H

#include <vector>
#include <string>
#include <algorithm>

/*******************************************************************************
* PathBuilder : Faust User Interface
* Helper class to build complete hierarchical path for UI items.
******************************************************************************/

class PathBuilder
{

protected:
std::vector<std::string> fControlsLevel;
public:
PathBuilder() {}
virtual ~PathBuilder() {}
std::string buildPath(const std::string& label)
{
std::string res = "/";
for (size_t i = 0; i < fControlsLevel.size(); i++) {
res += fControlsLevel[i];
res += "/";
}
res += label;
replace(res.begin(), res.end(), ' ', '_');
return res;
}
};

#endif // FAUST_PATHBUILDER_H

+ 119
- 0
ports/temper/source/faust/gui/PrintUI.h View File

@@ -0,0 +1,119 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef FAUST_PRINTUI_H
#define FAUST_PRINTUI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include "faust/gui/UI.h"
#include "faust/gui/PathBuilder.h"
#include <vector>
#include <string>

/*******************************************************************************
* PrintUI : Faust User Interface
* This class print arguments given to calls to UI methods and build complete path for labels.
******************************************************************************/

class PrintUI : public PathBuilder, public UI
{

public:

PrintUI() {}

virtual ~PrintUI() {}

// -- widget's layouts

virtual void openTabBox(const char* label)
{
fControlsLevel.push_back(label);
std::cout << "openTabBox label : " << label << std::endl;
}
virtual void openHorizontalBox(const char* label)
{
fControlsLevel.push_back(label);
std::cout << "openHorizontalBox label : " << label << std::endl;
}
virtual void openVerticalBox(const char* label)
{
fControlsLevel.push_back(label);
std::cout << "openVerticalBox label : " << label << std::endl;
}
virtual void closeBox()
{
fControlsLevel.pop_back();
std::cout << "closeBox" << std::endl;
}

// -- active widgets

virtual void addButton(const char* label, FAUSTFLOAT* zone)
{
std::cout << "addButton label : " << buildPath(label) << std::endl;
}
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
std::cout << "addCheckButton label : " << buildPath(label) << std::endl;
}
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
std::cout << "addVerticalSlider label : " << buildPath(label) << " init : " << init << " min : " << min << " max : " << max << " step : " << step << std::endl;
}
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
std::cout << "addHorizontalSlider label : " << buildPath(label) << " init : " << init << " min : " << min << " max : " << max << " step : " << step << std::endl;
}
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
std::cout << "addNumEntry label : " << buildPath(label) << " init : " << init << " min : " << min << " max : " << max << " step : " << step << std::endl;
}

// -- passive widgets

virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
std::cout << "addHorizontalBargraph label : " << buildPath(label) << " min : " << min << " max : " << max << std::endl;
}
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
std::cout << "addVerticalBargraph label : " << buildPath(label) << " min : " << min << " max : " << max << std::endl;
}

// -- metadata declarations

virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
std::cout << "declare key : " << key << " val : " << val << std::endl;
}
};

#endif // FAUST_PRINTUI_H

+ 471
- 0
ports/temper/source/faust/gui/RosCI.h View File

@@ -0,0 +1,471 @@
/**********************************************
* ROS Callbacks Interface
*
* This interface allows the user to use ROS
* metadata
* It handles ROS metadata, and writes the
* callbacks directly in the .cpp file.
*
**********************************************/

#ifndef FAUST_RosCI_H
#define FAUST_RosCI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include "faust/gui/UI.h"

#include <algorithm>
#include <vector>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>

class RosCI : public UI
{
public:
RosCI(): count_(0), use_slider_values_(false), meta_(false)
{};
virtual ~RosCI() {}
// String processing function
std::string strProcess(std::string label)
{
int count = label.size();
bool ok = false;
int FORWARD_SLASH = 47;
int TILDE = 126;
int UNDERSCORE = 95;
int SPACE = 32;
int LEFT_BRACKET = 40;
int RIGHT_BRACKET = 41;
do
{
if ((label[0]<65) // before "A" in ASCII
|| (label[0] <= 96 && label[0] >= 91) // After "Z" and before "a" in ASCII
|| (label[0] > 122) // After "z" in ASCII
&& (label[0] != FORWARD_SLASH) // not "/"
&& (label[0] != TILDE) // not "~"
)
{
label.erase(0,1);
count = label.size();
}
else if(count < 1)
{
label = "/topic";
count = label.size();
ok = true;
}
else
{
ok = true;
}
}
while (!ok);

for (int i = 0; i < count; i++)
{
if ((label[i] <= 90 && label[i] >= 65) // A-Z
|| (label[i] <= 122 && label[i] >= 97) // a-z
|| (label[i] <= 57 && label[i] >= 47) // 0-9
|| label[i] == UNDERSCORE
)
{
}
else if (label[i] == SPACE)
{
if (label[i-1] == UNDERSCORE)
{
label.erase(i,1);
i = i-1;
count = label.size();
}
else
label[i]='_';
}

else if(label[i]== LEFT_BRACKET) // in case of '('
{
if (label[i-1] == 95)
{
label.erase(i,1);
i = i-1;
count = label.size();
}
else
label[i]='_';
}
else if (label[i] == RIGHT_BRACKET) // in case of ')'
{
label.erase(i,1);
i = i-1;
count = label.size();
}
else
{
label.erase(i, 1);
i = i-1;
count = label.size();
}

}
return (label);
}
// -- widget's layouts

void openTabBox(const char* label)
{}
void openHorizontalBox(const char* label)
{}
void openVerticalBox(const char* label)
{}
void closeBox()
{}

// -- active widgets

void addButton(const char* label, FAUSTFLOAT* zone)
{}
void addCheckButton(const char* label, FAUSTFLOAT* zone)
{}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step)
{
*zone = init;
if (meta_)
{
if (use_slider_values_)
{
callbacks_parameters_[count_-1].min_value = min;
callbacks_parameters_[count_-1].max_value = max;
use_slider_values_ = false;
}
callbacks_parameters_[count_-1].slider_min = min;
callbacks_parameters_[count_-1].slider_max = max;
meta_ = false;
}
}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step)
{
*zone = init;
if (meta_)
{
if (use_slider_values_)
{
callbacks_parameters_[count_-1].min_value = min;
callbacks_parameters_[count_-1].max_value = max;
use_slider_values_ = false;
}
callbacks_parameters_[count_-1].slider_min = min;
callbacks_parameters_[count_-1].slider_max = max;
meta_ = false;
}
}
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step)
{
*zone=init;
if (meta_)
{
if (use_slider_values_)
{
callbacks_parameters_[count_-1].min_value = min;
callbacks_parameters_[count_-1].max_value = max;
use_slider_values_ = false;
}
callbacks_parameters_[count_-1].slider_min = min;
callbacks_parameters_[count_-1].slider_max = max;
meta_ = false;
}
}
// -- passive widgets

void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{}

// -- metadata declarations

// Structure containing a callback parameters
struct CallbackParams
{
std::string topic_name;
std::string msg_type;
std::string msg_name;
std::string field_name;
FAUSTFLOAT min_value;
FAUSTFLOAT max_value;
FAUSTFLOAT slider_min;
FAUSTFLOAT slider_max;
};
// Callback writing the callbacks filekeyboard's arrows
// num is the number of ROS declared metadata
// param_vector is a callbacks parameters structure container
// name is the application name
void callbacksWriter(int num, std::vector<RosCI::CallbackParams> param_vector, std::string name)
{
// Get file name
name = name + ".cpp";
const char* file_name = name.c_str();
std::fstream file (file_name);
if (!file.is_open())
{
std::cout<<"unable to open"<<file_name<<std::endl;
return;
}
std::string line, test_line;
bool search_RosUI = true;
std::streampos begin = 0;
std::streampos end=0;
int block_size;
char * memblock;
test_line = "class RosUI : public UI"; // This is the line we look for
// in the file so that we can
// write callbacks before this line
while( search_RosUI )
{
std::getline(file,line);
if(line == test_line)
{
search_RosUI=false;
}
else
{
// Get the searched line position
begin += (std::streampos)line.size() +(std::streampos)1;
}
}
// Get the end of file position
file.seekp(0,std::ios::end);
end = file.tellp();
block_size = end-begin;
memblock = new char[block_size];

// puts the end of the file in a memory block
// in order to overwrite without deleting information
file.seekp(begin, std::ios::beg);
file.read(memblock, block_size);
file.seekp(begin,std::ios::beg);

file <<"/*****************************"<<std::endl
<<"* Code generated automatically"<<std::endl
<<"* "<<std::endl
<<"* See the RosCI.h file"<<std::endl
<<"* \tCallbacksWriter function"<<std::endl
<<"* \tfor more informations"<<std::endl
<<"* "<<std::endl
<<"*****************************/\n"<<std::endl;
// Include messages files if they are different
bool include = true;
for (int i = 0; i < num ; i++)
{
RosCI::CallbackParams parameters = param_vector[i];
if (i != 0)
{
for (int j = 0; j < i; j++)
{
if (parameters.msg_type == param_vector[j].msg_type)
{
if (parameters.msg_name == param_vector[j].msg_name)
{
include = false;
}
}
}
}
if (include)
{
file << "#include \""<< parameters.msg_type<<"/"
<< parameters.msg_name<<".h\""<<std::endl;
}
}
// New class
file << "class RosCallbacks"<< std::endl
<< "{" << std::endl
<< "\tpublic : \n" << std::endl
<< "\tRosCallbacks(ros::NodeHandle n) : nh_(n)"<<std::endl
<< "\t{};\n"<<std::endl;
// Ranging Function
file << "\tfloat rangeAndConvert(FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT slider_min, "<< std::endl
<< "\t\tFAUSTFLOAT slider_max, float value)" << std::endl
<< "\t{" << std::endl
<< "\t\tif (value < min)" << std::endl
<< "\t\t{" << std::endl
<< "\t\t\tvalue = min;" << std::endl
<< "\t\t}" << std::endl
<< "\t\telse if (value > max)" << std::endl
<< "\t\t{" << std::endl
<< "\t\t\tvalue = max ;" << std::endl
<< "\t\t}" << std::endl
<< "\t\tfloat a = (slider_max - slider_min)/(max-min);" << std::endl
<< "\t\tfloat b = (slider_max + slider_min - a*(max+min))/2;" << std::endl
<< "\t\tvalue = a*value + b;\n" << std::endl
<< "\t\treturn value;" << std::endl
<< "\t}" << std::endl;
// ROS specific callbacks
for (int i = 0; i < num; i++)
{
RosCI::CallbackParams parameters = param_vector[i];
file << "\tvoid callback"<<i<<"(const "<< parameters.msg_type<<"::"
<< parameters.msg_name<<"ConstPtr& msg, FAUSTFLOAT* zone)"<<std::endl
<< "\t{"<<std::endl
<< "\t\t FAUSTFLOAT min"<<i<<" = "<<parameters.min_value<<";"<<std::endl
<< "\t\t FAUSTFLOAT max"<<i<<" = "<<parameters.max_value<<";"<<std::endl
<< "\t\t FAUSTFLOAT smin"<<i<<" = "<<parameters.slider_min<<";"<<std::endl
<< "\t\t FAUSTFLOAT smax"<<i<<" = "<<parameters.slider_max<<";\n"<<std::endl
<< "\t\t *zone = rangeAndConvert(min"<<i<<", max"<<i<<", smin"<<i<<", smax"<<i
<< ", (float) msg->"<<parameters.field_name<<");"<<std::endl
<< "\t}\n"<<std::endl;
}
// RosCallbacks class main function :
// When called, it subscribes to all the predefined callbacks
file << "\n\tvoid subscribe(std::vector<FAUSTFLOAT*> zones)\n"<<std::endl
<< "\t{" <<std::endl;
// Declaring subscribers and subscribing
for (int i = 0; i < num; i++)
{
RosCI::CallbackParams parameters = param_vector[i];
file << "\t\tros::Subscriber* my_sub"<<i<<" = new ros::Subscriber();"<<std::endl
<< "\t\t*my_sub"<<i<<" = nh_.subscribe<"<<parameters.msg_type<<"::"<<parameters.msg_name
<< ">(\"" <<parameters.topic_name
<< "\", 1,"<<std::endl
<< "\t\t\tboost::bind(&RosCallbacks::callback"<<i
<< ", this, _1, zones["<<i<<"]));\n"<<std::endl;
}
file << "\t}\n"<<std::endl;
// RosCallbacks class private parameter
file << "\tprivate :\n"<<std::endl
<< "\tros::NodeHandle nh_;"<<std::endl;
file << "};\n" << std::endl;
file << memblock;
file.close();
}
// String parsing function, which detects every callback parameter
// Separators must be spaces, and there must be 4 or 6 arguments
void stringParser(std::string string2parse)
{
int SPACE = 32;
for (int i = 0; i < string2parse.size(); i++)
{
if (string2parse[i] == SPACE)
{
std::string param= string2parse.substr(0,i);
topic_params_.push_back(param);
string2parse.erase(string2parse.begin(), string2parse.begin()+i+1);
i = -1;
}
}
topic_params_.push_back(string2parse);
}
// Function declaring metadata
void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
if (key == "ros") // We do not care if key is not "ros" here
{
stringParser(val); // Parsing the string corresponding to a callback parameters
CallbackParams params;
if (topic_params_.size() == 4
||
topic_params_.size() == 6)
{
// Storing the parameters in a structure...
params.topic_name=strProcess(topic_params_[0]);
params.msg_type=topic_params_[1];
params.msg_name=topic_params_[2];
params.field_name=topic_params_[3];
if (topic_params_.size() == 6)
{
std::stringstream smin, smax;
smin.str(topic_params_[4]);
smin >> params.min_value;
smax.str(topic_params_[5]);
smax >> params.max_value;
}
else
{
use_slider_values_ = true;
}
// ... and the structure in a vector
callbacks_parameters_.push_back(params);
count_++;
meta_ = true;
}
else
{
std::cout<<"Wrong number of parameters in ros metadata declaration !"<<std::endl;
std::cout<<"It should look like : [ros:/my/topic/name msg_type msg_name"
<<" field_name]"<<std::endl;
std::cout<<"Example : [ros:/topic/level std_msgs Float32 data]"<<std::endl;
}
do
{
topic_params_.pop_back();
}
while ( !topic_params_.empty());
}
}
// Function returning the number of metadata declared,
//which means the number of callbacks to call
int getParamsCount()
{
return count_;
}
// Function returning a vector containing ROS Callbacks parameters structures
std::vector<CallbackParams> getCallbacksParameters()
{
return callbacks_parameters_;
}
private:
int count_;
bool use_slider_values_;
bool meta_;
std::vector<std::string> topic_params_;
std::vector<CallbackParams> callbacks_parameters_;
};

#endif

+ 463
- 0
ports/temper/source/faust/gui/RosUI.h View File

@@ -0,0 +1,463 @@
/**********************************************
* ROS User Interface
*
* This interface creates default callbacks
* with default messages types
* It also returns parameters for specific ROS
* callbacks, defined in the RosCallbacks class
* thanks to the RosCI.h and ros-callbacks.cpp
* architecture files
**********************************************/
#ifndef FAUST_RosUI_H
#define FAUST_RosUI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

#include "faust/gui/UI.h"
#include "ros/ros.h"
#include "std_msgs/Bool.h"
#include "std_msgs/Float32.h"

#include <algorithm>
#include <vector>

class RosUI : public UI
{
public:
RosUI(ros::NodeHandle nh, std::string nspace) : nh_(nh), queue_(10), count_(0), meta_(false), box_names_(0), zones_(0)
{
// Get the namespace's name for default topics
box_names_.push_back(nspace);
};
virtual ~RosUI() {}
// String processing function for topics names
std::string strProcess(std::string label)
{
int count = label.size();
bool ok = false;
int FORWARD_SLASH = 47;
int TILDE = 126;
int UNDERSCORE = 95;
int SPACE = 32;
int LEFT_BRACKET = 40;
int RIGHT_BRACKET = 41;
do
{
if ((label[0] < 65) // before "A" in ASCII
|| (label[0] <= 96 && label[0] >= 91) // After "Z" and before "a" in ASCII
|| (label[0] > 122) // After "z" in ASCII
&& (label[0] != FORWARD_SLASH) // not "/"
&& (label[0] != TILDE) // not "~"
)
{
label.erase(0,1);
count = label.size();
}
else if(count <= 1)
{
label = "/topic";
count = label.size();
ok=true;
}
else
{
ok=true;
}
}
while (!ok);

for (int i=0; i < count; i++)
{
if ((label[i] <= 90 && label[i] >= 65) // A-Z
|| (label[i] <= 122 && label[i] >= 97) // a-z
|| (label[i] <= 57 && label[i] >= 47) // 0-9
|| label[i] == UNDERSCORE
)
{
}
else if (label[i] == SPACE)
{
if(label[i-1] == UNDERSCORE)
{
label.erase(i,1);
i=i-1;
count = label.size();
}
else
label[i] = '_';
}

else if(label[i] == LEFT_BRACKET) // in case of '('
{
if(label[i-1] == 95)
{
label.erase(i,1);
i=i-1;
count = label.size();
}
else
label[i] = '_';
}
else if (label[i] == RIGHT_BRACKET) // in case of ')'
{
label.erase(i,1);
i=i-1;
count = label.size();
}
else
{
label.erase(i, 1);
i=i-1;
count = label.size();
}

}
return (label);
}
// -- default callbacks
// Default Callbacks :
// Buttons widgets use the std_msgs/Bool message type
// Sliders and Numerical entries use the std_msgs/Float32 message type
void buttonCallback(const std_msgs::BoolConstPtr& msg, FAUSTFLOAT* zone)
{
*zone = msg->data;
}
void cButtonCallback(const std_msgs::BoolConstPtr& msg, FAUSTFLOAT* zone)
{
*zone = msg->data;
}
void sliderCallback(const std_msgs::Float32ConstPtr& msg, FAUSTFLOAT* zone)
{
*zone = msg->data;
}
void numEntryCallback(const std_msgs::Float32ConstPtr& msg, FAUSTFLOAT* zone)
{
*zone = msg->data;
}
// -- widget's layouts
// Boxes names are stored in a vector so that the default topics names
// fit to the graphic interface

void openTabBox(const char* label)
{
std::string L = (std::string)label;
if (L == "0x00") // no box name
{
L = "";
}
box_names_.push_back(L);
}
void openHorizontalBox(const char* label)
{
std::string L = (std::string)label;
if (L == "0x00") // no box name
{
L = "";
}
box_names_.push_back(L);
}
void openVerticalBox(const char* label)
{
std::string L = (std::string)label;
if (L == "0x00") // no box name
{
L = "";
}
box_names_.push_back(L);
}
void closeBox()
{
box_names_.pop_back();
}

// -- active widgets
// Adding a widget is translated into subscribing to a topic
// For each widget, we use default messages types
// Buttons : std_msgs/Bool
// Sliders and Numerical Entries : std_msgs/Float32

void addButton(const char* label, FAUSTFLOAT* zone)
{
// Gets the button name and processes it to fit to ROS naming conventions
std::string str = (std::string)label;
std::string my_string = strProcess(str);
// Builds the topic name from boxes and button names
if (! box_names_.empty())
{
std::string my_name = "";
for (int i = 0; i<box_names_.size(); i++)
{
if (box_names_[i] != "")
{
my_name += "/" + strProcess(box_names_[i]);
}
else
{
box_names_.erase(box_names_.begin()+i);
}
}
my_string = my_name + "/" + my_string;
}
else
{
ROS_ERROR("RosUI.h - function addButton : No box name to use ! ");
ROS_INFO("Button's callback will not be subscribed");
return;
}
// Subscription to buttons callback
ros::Subscriber* button_sub = new ros::Subscriber();
*button_sub = nh_.subscribe<std_msgs::Bool>(my_string, queue_,
boost::bind(&RosUI::buttonCallback, this, _1, zone));
count_++;
}
void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
// Gets the check button name and processes it to fit to ROS naming conventions
std::string str = (std::string)label;
std::string my_string = strProcess(str);
// Builds the topic name from boxes and check button names
if (! box_names_.empty())
{
std::string my_name = "";
for (int i = 0; i<box_names_.size(); i++)
{
if (box_names_[i] != "")
{
my_name += "/" + strProcess(box_names_[i]);
}
else
{
box_names_.erase(box_names_.begin()+i);
}
}
my_string = my_name + "/" + my_string;
}
else
{
ROS_ERROR("RosUI.h - function addCheckButton : No box name to use ! ");
ROS_INFO("Check button's callback will not be subscribed");
return;
}
// Subscription to check buttons callback
ros::Subscriber* c_button_sub = new ros::Subscriber();
*c_button_sub = nh_.subscribe<std_msgs::Bool>(my_string, queue_,
boost::bind(&RosUI::cButtonCallback, this, _1, zone));
count_++;
}
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step)
{
// Gets the vertical slider name and processes it to fit to ROS naming conventions
std::string str = (std::string)label;
std::string my_string = strProcess(str);
// Builds the topic name from boxes and vertical slider names

if (! box_names_.empty())
{
std::string my_name = "";
for (int i = 0; i<box_names_.size(); i++)
{
if (box_names_[i] != "")
{
my_name += "/" + strProcess(box_names_[i]);
}
else
{
box_names_.erase(box_names_.begin()+i);
}
}
my_string = my_name + "/" + my_string;
}
else
{
ROS_ERROR("RosUI.h - function addVerticalSlider : No box name to use ! ");
ROS_INFO("Vertical slider's callback will not be subscribed");
return;
}
// Subscription to sliders callback
ros::Subscriber* v_slider = new ros::Subscriber();
*v_slider = nh_.subscribe<std_msgs::Float32>(my_string, queue_,
boost::bind(&RosUI::sliderCallback, this, _1, zone));
count_++;
}
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step)
{
// Gets the horizontal slider name and processes it to fit to ROS naming conventions
std::string str = (std::string)label;
std::string my_string = strProcess(str);
// Builds the topic name from boxes and horizontal slider names
if (!box_names_.empty())
{
std::string my_name = "";
for (int i = 0 ; i<box_names_.size() ; i++)
{
if (box_names_[i] != "")
{
my_name += "/" + strProcess(box_names_[i]);
}
else
{
box_names_.erase(box_names_.begin()+i);
}
}
my_string = my_name + "/" + my_string;
}
else
{
ROS_ERROR("RosUI.h - function addVerticalSlider : No box name to use ! ");
ROS_INFO("Vertical slider's callback will not be subscribed");
return;
}
// Subscription to sliders callback
ros::Subscriber* h_slider = new ros::Subscriber();
*h_slider = nh_.subscribe<std_msgs::Float32>
(my_string, queue_, boost::bind(&RosUI::sliderCallback, this, _1, zone));
count_++;
}
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min,
FAUSTFLOAT max, FAUSTFLOAT step)
{
// Gets the numerical entry name and processes it to fit to ROS naming conventions
std::string str = (std::string)label;
std::string my_string = strProcess(str);
// Builds the topic name from boxes and numerical entry names
if (! box_names_.empty())
{
std::string my_name = "";
for (int i = 0; i<box_names_.size(); i++)
{
if (box_names_[i] != "")
{
my_name += "/" + strProcess(box_names_[i]);
}
else
{
box_names_.erase(box_names_.begin()+i);
}
}
my_string = my_name + "/" + my_string;
}
else
{
ROS_ERROR("RosUI.h - function addVerticalSlider : No box name to use ! ");
ROS_INFO("Vertical slider's callback will not be subscribed");
return;
}
// Subscription to numerical entries callback
ros::Subscriber* num_entry = new ros::Subscriber();
*num_entry = nh_.subscribe<std_msgs::Float32>(my_string, queue_,
boost::bind(&RosUI::numEntryCallback, this, _1, zone));
count_++;
}
// -- passive widgets
// Nothing to say - not used

void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{}
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{}

// -- metadata declarations

void declare(FAUSTFLOAT* zone, const char* key, const char* val)
{
if (key=="ros") // We do not care if key is not "ros" here
{
// Adds the Faust parameter's address (zone) to a zone vector
// if a ros metadata has been declared
zones_.push_back(zone);
}
}
// Function returning the number of widgets added
int getParamsCount()
{
return count_;
}
// Function saying if, yes or no, there is any ROS metadata declared
bool isTrue()
{
if (!zones_.empty())
{
return true; // yes
}
else
{
return false; // no
}
}
// Function returning the Faust parameters addresses (zones)
// if these zones correspond to metadata declared topics
std::vector<FAUSTFLOAT*> getZones()
{
return zones_;
}
private:
ros::NodeHandle nh_;
int queue_;
int count_;
bool meta_;
std::vector<std::string> box_names_;
std::vector<FAUSTFLOAT*> zones_;
};

#endif

+ 460
- 0
ports/temper/source/faust/gui/SimpleParser.h View File

@@ -0,0 +1,460 @@
/************************************************************************
************************************************************************
FAUST compiler
Copyright (C) 2003-2015 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
************************************************************************
************************************************************************/

#ifndef SIMPLEPARSER_H
#define SIMPLEPARSER_H

// ---------------------------------------------------------------------
// Simple Parser
// A parser returns true if it was able to parse what it is
// supposed to parse and advance the pointer. Otherwise it returns false
// and the pointer is not advanced so that another parser can be tried.
// ---------------------------------------------------------------------

#include <vector>
#include <map>
#include <string>
#include <fstream>
#include <iostream>
#include <ctype.h>

using namespace std;

struct itemInfo {
std::string type;
std::string label;
std::string address;
std::string init;
std::string min;
std::string max;
std::string step;
std::vector<std::pair<std::string, std::string> > meta;
};

bool parseMenuList(const char*& p, vector<string>& names, vector<double>& values);
bool parseMenuItem(const char*& p, string& name, double& value);

void skipBlank(const char*& p);
bool parseChar(const char*& p, char x);
bool parseWord(const char*& p, const char* w);
bool parseString(const char*& p, char quote, string& s);
bool parseSQString(const char*& p, string& s);
bool parseDQString(const char*& p, string& s);
bool parseDouble(const char*& p, double& x);

// ---------------------------------------------------------------------
//
// IMPLEMENTATION
//
// ---------------------------------------------------------------------

/**
* @brief parseMenuList, parse a menu list {'low' : 440.0; 'mid' : 880.0; 'hi' : 1760.0}...
* @param p the string to parse, then the remaining string
* @param names the vector of names found
* @param values the vector of values found
* @return true if a menu list was found
*/
inline bool parseMenuList(const char*& p, vector<string>& names, vector<double>& values)
{
vector<string> tmpnames;
vector<double> tmpvalues;

const char* saved = p;

if (parseChar(p, '{')) {
do {
string n;
double v;
if (parseMenuItem(p, n, v)) {
tmpnames.push_back(n);
tmpvalues.push_back(v);
} else {
p = saved;
return false;
}
} while (parseChar(p, ';'));
if (parseChar(p, '}')) {
// we suceeded
names = tmpnames;
values = tmpvalues;
return true;
}
}
p = saved;
return false;
}

/**
* @brief parseMenuItem, parse a menu item ...'low':440.0...
* @param p the string to parse, then the remaining string
* @param name the name found
* @param value the value found
* @return true if a nemu item was found
*/
inline bool parseMenuItem(const char*& p, string& name, double& value)
{
const char* saved = p;
if (parseSQString(p, name) && parseChar(p, ':') && parseDouble(p, value)) {
return true;
} else {
p = saved;
return false;
}
}

// ---------------------------------------------------------------------
// Elementary parsers
// ---------------------------------------------------------------------

// Report a parsing error
static bool parseError(const char*& p, const char* errmsg)
{
std::cerr << "Parse error : " << errmsg << " here : " << p << std::endl;
return true;
}

// Parse character x, but don't report error if fails
static bool tryChar(const char*& p, char x)
{
skipBlank(p);
if (x == *p) {
p++;
return true;
} else {
return false;
}
}

/**
* @brief skipBlank : advance pointer p to the first non blank character
* @param p the string to parse, then the remaining string
*/
inline void skipBlank(const char*& p)
{
while (isspace(*p)) { p++; }
}

/**
* @brief parseChar : parse a specific character x
* @param p the string to parse, then the remaining string
* @param x the character to recognize
* @return true if x was found at the begin of p
*/
inline bool parseChar(const char*& p, char x)
{
skipBlank(p);
if (x == *p) {
p++;
return true;
} else {
return false;
}
}

/**
* @brief parseWord : parse a specific string w
* @param p the string to parse, then the remaining string
* @param w the string to recognize
* @return true if string w was found at the begin of p
*/
inline bool parseWord(const char*& p, const char* w)
{
skipBlank(p);
const char* saved = p;
while ((*w == *p) && (*w)) {++w; ++p;}
if (*w) {
p = saved;
return false;
} else {
return true;
}
}

/**
* @brief parseDouble : parse number [s]dddd[.dddd] and store the result in x
* @param p the string to parse, then the remaining string
* @param x the float number found if any
* @return true if a float number was found at the begin of p
*/
inline bool parseDouble(const char*& p, double& x)
{
double sign = +1.0; // sign of the number
double ipart = 0; // integral part of the number
double dpart = 0; // decimal part of the number before division
double dcoef = 1.0; // division factor for the decimal part

bool valid = false; // true if the number contains at least one digit
skipBlank(p);
const char* saved = p; // to restore position if we fail

if (parseChar(p, '+')) {
sign = 1.0;
} else if (parseChar(p, '-')) {
sign = -1.0;
}
while (isdigit(*p)) {
valid = true;
ipart = ipart*10 + (*p - '0');
p++;
}
if (parseChar(p, '.')) {
while (isdigit(*p)) {
valid = true;
dpart = dpart*10 + (*p - '0');
dcoef *= 10.0;
p++;
}
}
if (valid) {
x = sign*(ipart + dpart/dcoef);
} else {
p = saved;
}
return valid;
}

/**
* @brief parseString, parse an arbitrary quoted string q...q and store the result in s
* @param p the string to parse, then the remaining string
* @param quote the character used to quote the string
* @param s the (unquoted) string found if any
* @return true if a string was found at the begin of p
*/
inline bool parseString(const char*& p, char quote, string& s)
{
string str;
skipBlank(p);
const char* saved = p;
if (*p++ == quote) {
while ((*p != 0) && (*p != quote)) {
str += *p++;
}
if (*p++ == quote) {
s = str;
return true;
}
}
p = saved;
return false;
}

/**
* @brief parseSQString, parse a single quoted string '...' and store the result in s
* @param p the string to parse, then the remaining string
* @param s the (unquoted) string found if any
* @return true if a string was found at the begin of p
*/
inline bool parseSQString(const char*& p, string& s)
{
return parseString(p, '\'', s);
}

/**
* @brief parseDQString, parse a double quoted string "..." and store the result in s
* @param p the string to parse, then the remaining string
* @param s the (unquoted) string found if any
* @return true if a string was found at the begin of p
*/
inline bool parseDQString(const char*& p, string& s)
{
return parseString(p, '"', s);
}

static bool parseMetaData(const char*& p, std::map<std::string, std::string>& metadatas)
{
std::string metaKey, metaValue;
if (parseChar(p, ':') && parseChar(p, '[')) {
do {
if (parseChar(p, '{') && parseDQString(p, metaKey) && parseChar(p, ':') && parseDQString(p, metaValue) && parseChar(p, '}')) {
metadatas[metaKey] = metaValue;
}
} while (tryChar(p, ','));
return parseChar(p, ']');
} else {
return false;
}
}

static bool parseItemMetaData(const char*& p, std::vector<std::pair<std::string, std::string> >& metadatas)
{
std::string metaKey, metaValue;
if (parseChar(p, ':') && parseChar(p, '[')) {
do {
if (parseChar(p, '{') && parseDQString(p, metaKey) && parseChar(p, ':') && parseDQString(p, metaValue) && parseChar(p, '}')) {
metadatas.push_back(std::make_pair(metaKey, metaValue));
}
} while (tryChar(p, ','));
return parseChar(p, ']');
} else {
return false;
}
}

// ---------------------------------------------------------------------
// Parse metadatas of the interface:
// "name" : "...", "inputs" : "...", "outputs" : "...", ...
// and store the result as key/value
//
static bool parseGlobalMetaData(const char*& p, std::string& key, std::string& value, std::map<std::string, std::string>& metadatas)
{
if (parseDQString(p, key)) {
if (key == "meta") {
return parseMetaData(p, metadatas);
} else {
return parseChar(p, ':') && parseDQString(p, value);
}
} else {
return false;
}
}

// ---------------------------------------------------------------------
// Parse gui:
// "type" : "...", "label" : "...", "address" : "...", ...
// and store the result in uiItems Vector
//
static bool parseUI(const char*& p, std::vector<itemInfo*>& uiItems, int& numItems)
{
if (parseChar(p, '{')) {
std::string label;
std::string value;
do {
if (parseDQString(p, label)) {
if (label == "type") {
if (uiItems.size() != 0) {
numItems++;
}
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = new itemInfo;
item->type = value;
uiItems.push_back(item);
}
}
else if (label == "label") {
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = uiItems[numItems];
item->label = value;
}
}
else if (label == "address") {
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = uiItems[numItems];
item->address = value;
}
}
else if (label == "meta") {
itemInfo* item = uiItems[numItems];
if (!parseItemMetaData(p, item->meta)) {
return false;
}
}
else if (label == "init") {
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = uiItems[numItems];
item->init = value;
}
}
else if (label == "min") {
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = uiItems[numItems];
item->min = value;
}
}
else if (label == "max") {
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = uiItems[numItems];
item->max = value;
}
}
else if (label == "step"){
if (parseChar(p, ':') && parseDQString(p, value)) {
itemInfo* item = uiItems[numItems];
item->step = value;
}
}
else if (label == "items") {
if (parseChar(p, ':') && parseChar(p, '[')) {
do {
if (!parseUI(p, uiItems, numItems)) {
return false;
}
} while (tryChar(p, ','));
if (parseChar(p, ']')) {
itemInfo* item = new itemInfo;
item->type = "close";
uiItems.push_back(item);
numItems++;
}
}
}
} else {
return false;
}
} while (tryChar(p, ','));
return parseChar(p, '}');
} else {
return false;
}
}

// ---------------------------------------------------------------------
// Parse full JSON record describing a JSON/Faust interface :
// {"metadatas": "...", "ui": [{ "type": "...", "label": "...", "items": [...], "address": "...","init": "...", "min": "...", "max": "...","step": "..."}]}
//
// and store the result in map Metadatas and vector containing the items of the interface. Returns true if parsing was successfull.
//

inline bool parseJson(const char*& p, std::map<std::string, std::string>& metadatas, std::vector<itemInfo*>& uiItems)
{
parseChar(p, '{');
do {
std::string key;
std::string value;
if (parseGlobalMetaData(p, key, value, metadatas)) {
if (key != "meta") {
// keep "name", "inputs", "outputs" key/value pairs
metadatas[key] = value;
}
} else if (key == "ui") {
int numItems = 0;
parseChar(p, '[') && parseUI(p, uiItems, numItems);
}
} while (tryChar(p, ','));
return parseChar(p, '}');
}

#endif // SIMPLEPARSER_H

+ 5
- 0
ports/temper/source/faust/gui/Styles/Blue.qrc View File

@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>Blue.qss</file>
</qresource>
</RCC>

+ 177
- 0
ports/temper/source/faust/gui/Styles/Blue.qss View File

@@ -0,0 +1,177 @@
QPushButton{
min-width : 80px;
border: 2px solid grey;
border-radius: 6px;
margin-top: 1ex;
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #811453, stop: 1 #702963);
color: white;
}

QPushButton:hover{
border: 2px solid orange;
}

QPushButton:pressed{
background-color: orange;
border-color: grey;
}

QGroupBox{
subcontrol: .QGroupBox;
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #003366, stop: 1 #22427C);
margin-top: 3ex;
border-radius: 5px;
font-size: 10pt;
font-weight: bold;
color: white;
}

QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 0 5px;
color: white;
}

QMainWindow, QDialog{
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #003366, stop: 1 #22427C);
border-radius: 5px;
margin-top: 3ex;
font-size:10pt;
font-weight:bold;
color: white;
}

QPlainTextEdit, QTextEdit{
background-color: transparent;
border: 2px solid #702963;
border-radius: 5px;
top: 3px;
margin-top: 3ex;
font-size:12pt;
font-weight:bold;
color: white;
}

QTextBrowser {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #003366, stop: 1 #22427C);
color: white;
}
QTextBrowser:document{
text-decoration: underline;
color: white;
font: Menlo;
font-size: 14px
}

QLabel{
color : white;
background: transparent;
}

QSlider::groove:vertical {
background: red;
position: absolute;
left: 13px; right: 13px;
}

QSlider::handle:vertical {
height: 40px;
width: 30px;
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);
margin: 0 -5px;
border-radius: 5px;
}

QSlider::add-page:vertical {
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 yellow, stop : 0.5 orange);
}

QSlider::sub-page:vertical {
background: grey;
}

QSlider::groove:horizontal {
background: red;
position: absolute;
top: 14px; bottom: 14px;
}

QSlider::handle:horizontal {
width: 40px;
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #6A455D, stop : 0.05 #811453, stop: 0.3 #811453, stop : 0.90 #6A455D, stop: 0.91 #702963);
margin: -5px 0;
border-radius: 5px;
}
QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 yellow, stop : 0.5 orange);
}

QSlider::add-page:horizontal {
background: grey;
}

QTabWidget::pane {
color : white;
border-top: 2px #702963;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #003366, stop: 1.0 #22427C);
}
QTabWidget::tab-bar {
left: 5px;
}
QTabBar::tab {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #003366, stop: 0.4 #22427C, stop: 0.5 #003366, stop: 1.0 #22427C);
border: 2px solid #808080;
color : white;
border-bottom-color: #702963;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
min-width: 8ex;
padding: 2px;
}
QTabBar::tab:selected, QTabBar::tab:hover {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #003366, stop: 0.4 #22427C, stop: 0.5 #003366, stop: 1.0 #22427C);
color : white;
}
QTabBar::tab:selected {
color : white;
border-color: #702963;
border-bottom-color: #22427C;
}
QTabBar::tab:!selected {
margin-top: 2px;
}

QListWidget{
background-color: transparent;
}

QListWidget::item{
color: white;
}

QStatusBar{
background-color: transparent;
border: 0px;
padding:0px 0px 0px 0px;
margin:0px;
}

QScrollArea > QWidget > QWidget{
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #003366, stop: 0.4 #22427C, stop: 0.5 #003366, stop: 1.0 #22427C);
}

QScrollArea > QWidget {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #003366, stop: 0.4 #22427C, stop: 0.5 #003366, stop: 1.0 #22427C);
}

QScrollArea {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #003366, stop: 0.4 #22427C, stop: 0.5 #003366, stop: 1.0 #22427C);
}

+ 5
- 0
ports/temper/source/faust/gui/Styles/Default.qrc View File

@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>Default.qss</file>
</qresource>
</RCC>

+ 117
- 0
ports/temper/source/faust/gui/Styles/Default.qss View File

@@ -0,0 +1,117 @@
QPushButton{
min-width : 80px;
border: 2px solid grey;
border-radius: 6px;
margin-top: 1ex;
border-color: #811453;
background-color: transparent;
}

QPushButton:hover{
border: 2px;
border-radius: 6px;
border-color: #811453;
background-color: #6A455D;
}

QPushButton:pressed{
background-color: #6A455D;
border-radius: 6px;
border-color: #811453;
}

QGroupBox{
subcontrol: .QGroupBox;
margin-top: 3ex;
font-size: 10pt;
font-weight: bold;
color: black;
}

QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 0 5px;
color: black;
}

QMainWindow {
margin-top: 3ex;
font-size:10pt;
font-weight:bold;
color: black;
}

QPlainTextEdit, QTextEdit{
background-color: transparent;
border: 2px solid gray;
border-radius: 5px;
top: 3px;
margin-top: 3ex;
font-size:12pt;
font-weight:bold;
color: black;
}

QTextBrowser {
color: black;
}
QTextBrowser:document{
text-decoration: underline;
color: black;
font: Menlo;
font-size: 14px
}

QLabel{
color : black;
background: transparent;
}

QSlider::groove:vertical {
background: red;
position: absolute;
left: 13px; right: 13px;
}

QSlider::handle:vertical {
height: 40px;
width: 30px;
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #E67E30, stop : 0.05 #AD4F09, stop: 0.3 #E67E30, stop : 0.90 #AD4F09, stop: 0.91 #AD4F09);
margin: 0 -5px;
border-radius: 5px;
}

QSlider::add-page:vertical {
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,
stop: 0 #6A455D, stop : 0.5 #6A455D);
}

QSlider::sub-page:vertical {
background: grey;
}

QSlider::groove:horizontal {
background: red;
position: absolute;
top: 14px; bottom: 14px;
}

QSlider::handle:horizontal {
width: 40px;
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #E67E30, stop : 0.05 #AD4F09, stop: 0.3 #E67E30, stop : 0.90 #AD4F09, stop: 0.91 #AD4F09);
margin: -5px 0;
border-radius: 5px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #6A455D, stop : 0.5 #6A455D);
}

QSlider::add-page:horizontal {
background: grey;
}

QListWidget{
background-color: transparent;
}

+ 5
- 0
ports/temper/source/faust/gui/Styles/Grey.qrc View File

@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>Grey.qss</file>
</qresource>
</RCC>

+ 174
- 0
ports/temper/source/faust/gui/Styles/Grey.qss View File

@@ -0,0 +1,174 @@
QPushButton {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0.8, y2: 0.8,
stop: 0 #B0B0B0, stop: 1 #404040);
min-width : 80px;
border: 2px solid grey;
border-radius: 6px;
margin-top: 1ex;
color:white
}
QPushButton:hover {
border: 2px solid orange;
}
QPushButton:pressed {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #404040, stop: 1 #B0B0B0);
}
QGroupBox {
subcontrol: .QGroupBox
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #A0A0A0, stop: 1 #202020);
margin-top: 3ex;
border-radius: 5px;
font-size:10pt;
font-weight:bold;
color: white;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 0 5px;
color : white;
}

QMainWindow, QDialog {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #A0A0A0, stop: 1 #202020);
border-radius: 5px;
margin-top: 3ex;
font-size:10pt;
font-weight:bold;
color: white;
}
QPlainTextEdit, QTextEdit{
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #A0A0A0, stop: 1 #202020);
border-color: yellow;
border-radius: 5px;
top: 3px;
margin-top: 3ex;
font-size:12pt;
font-weight:bold;
color: white;
}
QTextBrowser {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0.8, y2: 0.8, stop: 0 #A0A0A0, stop: 1 #202020);
color: white;
}
QTextDocument{
text-decoration: underline;
color: white;
font: Menlo;
font-size: 14px
}

QLabel{
color : white;
background: transparent;
}
QSlider::groove:vertical {
background: red;
position: absolute;
left: 13px; right: 13px;
}
QSlider::handle:vertical {
height: 40px;
width: 30px;
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);
margin: 0 -5px;
border-radius: 5px;
}

QSlider::add-page:vertical {
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 yellow, stop : 0.5 orange);
}

QSlider::sub-page:vertical {
background: grey;
}
QSlider::groove:horizontal {
background: red;
position: absolute;
top: 14px; bottom: 14px;
}

QSlider::handle:horizontal {
width: 40px;
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);
margin: -5px 0;
border-radius: 5px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 yellow, stop : 0.5 orange);
}
QSlider::add-page:horizontal {
background: grey;
}
QTabWidget::pane {
border-top: 2px solid orange;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #A0A0A0, stop: 1 #202020);
}

QTabWidget::tab-bar {
left: 5px;
}
QTabBar::tab {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #909090, stop: 0.4 #888888, stop: 0.5 #808080, stop: 1.0 #909090);
border: 2px solid #808080;
border-bottom-color: orange;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
min-width: 8ex;
padding: 2px;
}

QTabBar::tab:selected, QTabBar::tab:hover {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #D0D0D0, stop: 0.4 #A0A0A0, stop: 0.5 #808080, stop: 1.0 #A0A0A0);
}

QTabBar::tab:selected {
border-color: orange;
border-bottom-color: #A0A0A0;
}
QTabBar::tab:!selected {
margin-top: 2px;
}
QListWidget{
background-color: transparent;
}


QListWidget::item{
color: white;
}

QStatusBar{
background-color: transparent;
border: 0px;
padding:0px 0px 0px 0px;
margin:0px;
}

QScrollArea > QWidget > QWidget{
background-color: qlineargradient(x1: 0, y1: 0, x2: 0.8, y2: 0.8, stop: 0 #A0A0A0, stop: 1 #202020);
}

QScrollArea > QWidget {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0.8, y2: 0.8, stop: 0 #A0A0A0, stop: 1 #202020);
}

QScrollArea {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0.8, y2: 0.8, stop: 0 #A0A0A0, stop: 1 #202020);
}

+ 5
- 0
ports/temper/source/faust/gui/Styles/Salmon.qrc View File

@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>Salmon.qss</file>
</qresource>
</RCC>

+ 171
- 0
ports/temper/source/faust/gui/Styles/Salmon.qss View File

@@ -0,0 +1,171 @@
QPushButton{
background-color:#FF5E4D;
min-width : 80px;
border: 2px solid grey;
border-radius: 6px;
margin-top: 1ex;
}
QPushButton:hover{
border: 2px ;
}
QPushButton:pressed{
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FFE4C4, stop: 1 #FEC3AC);
}

QGroupBox{
subcontrol: .QGroupBox
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4, stop: 1 #FEC3AC);
border-radius: 5px;
margin-top: 3ex;
font-size:10pt;
font-weight:bold;
color: dark grey;
color: white;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding: 0 5px;
color: black;
}
QMainWindow, QDialog {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
border-radius: 5px;
margin-top: 3ex;
font-size:10pt;
font-weight:bold;
color: dark grey;
color: white;
}
QPlainTextEdit, QTextEdit {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
border: 2px solid gray;
border-radius: 5px;
top: 3px;
margin-top: 3ex;
font-size:12pt;
font-weight:bold;
color: black;
}

QTextBrowser {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
color: black;
}
QTextBrowser:document{
text-decoration: underline;
color: white;
font: Menlo;
font-size: 14px
}
QLabel{
color : black;
background: transparent;
}
QSlider::groove:vertical {
background: red;
position: absolute;
left: 13px; right: 13px;
}
QSlider::handle:vertical {
height: 40px;
width: 30px;
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #4E3D28, stop : 0.05 #856D4D, stop: 0.1 #4E3D28, stop : 0.15 #856D4D, stop: 0.2 #4E3D28, stop : 0.25 #856D4D, stop: 0.3 #4E3D28, stop : 0.35 #856D4D, stop: 0.4 #4E3D28, stop : 0.45 #856D4D, stop: 0.5 #4E3D28, stop : 0.55 #856D4D, stop: 0.6 #4E3D28, stop : 0.65 #856D4D, stop: 0.7 #4E3D28, stop : 0.75 #856D4D, stop: 0.8 #4E3D28, stop : 0.85 #856D4D, stop: 0.95 #4E3D28);
margin: 0 -5px;
border-radius: 5px;
}
QSlider::add-page:vertical {
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #FF5E4D, stop : 0.5 #FF5E4D);
}
QSlider::sub-page:vertical {
background: #CECECE;
}

QSlider::groove:horizontal {
background: red;
position: absolute;
top: 14px; bottom: 14px;
}
QSlider::handle:horizontal {
width: 40px;
background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 #4E3D28, stop : 0.05 #856D4D, stop: 0.1 #4E3D28, stop : 0.15 #856D4D, stop: 0.2 #4E3D28, stop : 0.25 #856D4D, stop: 0.3 #4E3D28, stop : 0.35 #856D4D, stop: 0.4 #4E3D28, stop : 0.45 #856D4D, stop: 0.5 #4E3D28, stop : 0.55 #856D4D, stop: 0.6 #4E3D28, stop : 0.65 #856D4D, stop: 0.7 #4E3D28, stop : 0.75 #856D4D, stop: 0.8 #4E3D28, stop : 0.85 #856D4D, stop: 0.95 #4E3D28);
margin: -5px 0;
border-radius: 5px;
}

QSlider::sub-page:horizontal {
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FF5E4D stop : 0.5 #FF5E4D);
}

QSlider::add-page:horizontal {
background: #CECECE;
}
QTabWidget::pane {
color : black;
border-top: 2px #FF5E4D;
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
}

QTabWidget::tab-bar {
left: 5px;
}
QTabBar::tab {
background: #FFE4C4;
border: 2px solid #FF5E4D;
color : black;
border-bottom-color: #FF5E4D;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
min-width: 8ex;
padding: 2px;
}

QTabBar::tab:selected, QTabBar::tab:hover {
background: #FEC3AC;
color : white;
}

QTabBar::tab:!selected {
margin-top: 2px;
}
QListWidget{
background-color: transparent;
}

QListWidget::item{
color: color;
}

QStatusBar{
background-color: transparent;
border: 0px;
padding:0px 0px 0px 0px;
margin:0px;
}

QScrollArea > QWidget > QWidget{
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
}

QScrollArea > QWidget {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
}

QScrollArea {
background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, stop: 0 #FFE4C4,stop: 1 #FEC3AC);
}

+ 117
- 0
ports/temper/source/faust/gui/UI.h View File

@@ -0,0 +1,117 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef FAUST_UI_H
#define FAUST_UI_H

#ifndef FAUSTFLOAT
#define FAUSTFLOAT float
#endif

/*******************************************************************************
* UI : Faust User Interface
* This abstract class contains only the method that the faust compiler can
* generate to describe a DSP interface.
******************************************************************************/

class UI
{

public:

UI() {}

virtual ~UI() {}

// -- widget's layouts

virtual void openTabBox(const char* label) = 0;
virtual void openHorizontalBox(const char* label) = 0;
virtual void openVerticalBox(const char* label) = 0;
virtual void closeBox() = 0;

// -- active widgets

virtual void addButton(const char* label, FAUSTFLOAT* zone) = 0;
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) = 0;
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) = 0;
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) = 0;
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step) = 0;

// -- passive widgets

virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) = 0;
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) = 0;

// -- metadata declarations

virtual void declare(FAUSTFLOAT*, const char*, const char*) {}
};

//----------------------------------------------------------------
// Generic decorator
//----------------------------------------------------------------

class DecoratorUI : public UI
{
protected:
UI* fUI;

public:
DecoratorUI(UI* ui = 0):fUI(ui)
{}

virtual ~DecoratorUI() { delete fUI; }

// -- widget's layouts
virtual void openTabBox(const char* label) { fUI->openTabBox(label); }
virtual void openHorizontalBox(const char* label) { fUI->openHorizontalBox(label); }
virtual void openVerticalBox(const char* label) { fUI->openVerticalBox(label); }
virtual void closeBox() { fUI->closeBox(); }

// -- active widgets
virtual void addButton(const char* label, FAUSTFLOAT* zone) { fUI->addButton(label, zone); }
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) { fUI->addCheckButton(label, zone); }
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{ fUI->addVerticalSlider(label, zone, init, min, max, step); }
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{ fUI->addHorizontalSlider(label, zone, init, min, max, step); }
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{ fUI->addNumEntry(label, zone, init, min, max, step); }

// -- passive widgets
virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{ fUI->addHorizontalBargraph(label, zone, min, max); }
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{ fUI->addVerticalBargraph(label, zone, min, max); }

virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val) { fUI->declare(zone, key, val); }

};

#endif

+ 527
- 0
ports/temper/source/faust/gui/ValueConverter.h View File

@@ -0,0 +1,527 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef __ValueConverter__
#define __ValueConverter__

/***************************************************************************************
ValueConverter.h
(GRAME, © 2015)

Set of conversion objects used to map user interface values (for example a gui slider
delivering values between 0 and 1) to faust values (for example a vslider between
20 and 20000) using a log scale.

-- Utilities

Range(lo,hi) : clip a value x between lo and hi
Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2

-- Value Converters

ValueConverter::ui2faust(x)
ValueConverter::faust2ui(x)

-- ValueConverters used for sliders depending of the scale

LinearValueConverter(umin, umax, fmin, fmax)
LogValueConverter(umin, umax, fmin, fmax)
ExpValueConverter(umin, umax, fmin, fmax)

-- ValueConverters used for accelerometers based on 3 points

AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3

-- lists of ZoneControl are used to implement accelerometers metadata for each axes

ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter

-- ZoneReader are used to implement screencolor metadata

ZoneReader(zone, valueConverter) : a zone with a data converter

****************************************************************************************/

#include <float.h>
#include <algorithm> // std::max
#include <cmath>
#include <vector>

//--------------------------------------------------------------------------------------
// Interpolator(lo,hi,v1,v2)
// Maps a value x between lo and hi to a value y between v1 and v2
// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
// y = v1 + x*coef - lo*coef
// y = v1 - lo*coef + x*coef
// y = offset + x*coef with offset = v1 - lo*coef
//--------------------------------------------------------------------------------------
class Interpolator
{
private:

//--------------------------------------------------------------------------------------
// Range(lo,hi) clip a value between lo and hi
//--------------------------------------------------------------------------------------
struct Range
{
double fLo;
double fHi;

Range(double x, double y) : fLo(std::min(x,y)), fHi(std::max(x,y)) {}
double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
};


Range fRange;
double fCoef;
double fOffset;

public:

Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
{
if (hi != lo) {
// regular case
fCoef = (v2-v1)/(hi-lo);
fOffset = v1 - lo*fCoef;
} else {
// degenerate case, avoids division by zero
fCoef = 0;
fOffset = (v1+v2)/2;
}
}
double operator()(double v)
{
double x = fRange(v);
return fOffset + x*fCoef;
}

void getLowHigh(double& amin, double& amax)
{
amin = fRange.fLo;
amax = fRange.fHi;
}
};

//--------------------------------------------------------------------------------------
// Interpolator3pt(lo,mi,hi,v1,vm,v2)
// Map values between lo mid hi to values between v1 vm v2
//--------------------------------------------------------------------------------------
class Interpolator3pt
{

private:

Interpolator fSegment1;
Interpolator fSegment2;
double fMid;

public:

Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
fSegment1(lo, mi, v1, vm),
fSegment2(mi, hi, vm, v2),
fMid(mi) {}
double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }

void getMappingValues(double& amin, double& amid, double& amax)
{
fSegment1.getLowHigh(amin, amid);
fSegment2.getLowHigh(amid, amax);
}
};

//--------------------------------------------------------------------------------------
// Abstract ValueConverter class. Converts values between UI and Faust representations
//--------------------------------------------------------------------------------------
class ValueConverter
{

public:

virtual ~ValueConverter() {}
virtual double ui2faust(double x) = 0;
virtual double faust2ui(double x) = 0;
};

//--------------------------------------------------------------------------------------
// Linear conversion between ui and faust values
//--------------------------------------------------------------------------------------
class LinearValueConverter : public ValueConverter
{

private:

Interpolator fUI2F;
Interpolator fF2UI;

public:

LinearValueConverter(double umin, double umax, double fmin, double fmax) :
fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
{}

LinearValueConverter() :
fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
{}
virtual double ui2faust(double x) { return fUI2F(x); }
virtual double faust2ui(double x) { return fF2UI(x); }

};

//--------------------------------------------------------------------------------------
// Logarithmic conversion between ui and faust values
//--------------------------------------------------------------------------------------
class LogValueConverter : public LinearValueConverter
{

public:

LogValueConverter(double umin, double umax, double fmin, double fmax) :
LinearValueConverter(umin, umax, log(std::max(DBL_MIN,fmin)), log(std::max(DBL_MIN,fmax)))
{}

virtual double ui2faust(double x) { return exp(LinearValueConverter::ui2faust(x)); }
virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(log(std::max(x, DBL_MIN))); }

};

//--------------------------------------------------------------------------------------
// Exponential conversion between ui and Faust values
//--------------------------------------------------------------------------------------
class ExpValueConverter : public LinearValueConverter
{

public:

ExpValueConverter(double umin, double umax, double fmin, double fmax) :
LinearValueConverter(umin, umax, exp(fmin), exp(fmax))
{}

virtual double ui2faust(double x) { return log(LinearValueConverter::ui2faust(x)); }
virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(exp(x)); }

};

//--------------------------------------------------------------------------------------
// A converter than can be updated
//--------------------------------------------------------------------------------------

class UpdatableValueConverter : public ValueConverter {

protected:

bool fActive;

public:

UpdatableValueConverter():fActive(true)
{}
virtual ~UpdatableValueConverter()
{}

virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;

void setActive(bool on_off) { fActive = on_off; }
bool getActive() { return fActive; }

};

//--------------------------------------------------------------------------------------
// Convert accelerometer or gyroscope values to Faust values
// Using an Up curve (curve 0)
//--------------------------------------------------------------------------------------
class AccUpConverter : public UpdatableValueConverter
{

private:

Interpolator3pt fA2F;
Interpolator3pt fF2A;

public:

AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
fA2F(amin,amid,amax,fmin,fmid,fmax),
fF2A(fmin,fmid,fmax,amin,amid,amax)
{}

virtual double ui2faust(double x) { return fA2F(x); }
virtual double faust2ui(double x) { return fF2A(x); }

virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
{
//__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
fA2F = Interpolator3pt(amin,amid,amax,fmin,fmid,fmax);
fF2A = Interpolator3pt(fmin,fmid,fmax,amin,amid,amax);
}

virtual void getMappingValues(double& amin, double& amid, double& amax)
{
fA2F.getMappingValues(amin, amid, amax);
}

};

//--------------------------------------------------------------------------------------
// Convert accelerometer or gyroscope values to Faust values
// Using a Down curve (curve 1)
//--------------------------------------------------------------------------------------
class AccDownConverter : public UpdatableValueConverter
{

private:

Interpolator3pt fA2F;
Interpolator3pt fF2A;

public:

AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
fA2F(amin,amid,amax,fmax,fmid,fmin),
fF2A(fmin,fmid,fmax,amax,amid,amin)
{}

virtual double ui2faust(double x) { return fA2F(x); }
virtual double faust2ui(double x) { return fF2A(x); }

virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
{
//__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
fA2F = Interpolator3pt(amin,amid,amax,fmax,fmid,fmin);
fF2A = Interpolator3pt(fmin,fmid,fmax,amax,amid,amin);
}

virtual void getMappingValues(double& amin, double& amid, double& amax)
{
fA2F.getMappingValues(amin, amid, amax);
}
};

//--------------------------------------------------------------------------------------
// Convert accelerometer or gyroscope values to Faust values
// Using an Up-Down curve (curve 2)
//--------------------------------------------------------------------------------------
class AccUpDownConverter : public UpdatableValueConverter
{

private:

Interpolator3pt fA2F;
Interpolator fF2A;

public:

AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
fA2F(amin,amid,amax,fmin,fmax,fmin),
fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotone function
{}

virtual double ui2faust(double x) { return fA2F(x); }
virtual double faust2ui(double x) { return fF2A(x); }

virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
{
//__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
fA2F = Interpolator3pt(amin,amid,amax,fmin,fmax,fmin);
fF2A = Interpolator(fmin,fmax,amin,amax);
}

virtual void getMappingValues(double& amin, double& amid, double& amax)
{
fA2F.getMappingValues(amin, amid, amax);
}
};

//--------------------------------------------------------------------------------------
// Convert accelerometer or gyroscope values to Faust values
// Using a Down-Up curve (curve 3)
//--------------------------------------------------------------------------------------
class AccDownUpConverter : public UpdatableValueConverter
{

private:

Interpolator3pt fA2F;
Interpolator fF2A;

public:

AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
fA2F(amin,amid,amax,fmax,fmin,fmax),
fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotone function
{}

virtual double ui2faust(double x) { return fA2F(x); }
virtual double faust2ui(double x) { return fF2A(x); }

virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
{
//__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
fA2F = Interpolator3pt(amin,amid,amax,fmax,fmin,fmax);
fF2A = Interpolator(fmin,fmax,amin,amax);
}

virtual void getMappingValues(double& amin, double& amid, double& amax)
{
fA2F.getMappingValues(amin, amid, amax);
}
};

//--------------------------------------------------------------------------------------
// Base class for ZoneControl
//--------------------------------------------------------------------------------------
class ZoneControl
{

protected:

FAUSTFLOAT* fZone;

public:

ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
virtual ~ZoneControl() {}

virtual void update(double v) {}

virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
virtual void getMappingValues(double& amin, double& amid, double& amax) {}

FAUSTFLOAT* getZone() { return fZone; }

virtual void setActive(bool on_off) {}
virtual bool getActive() { return false; }

virtual int getCurve() { return -1; }

};

//--------------------------------------------------------------------------------------
// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
//--------------------------------------------------------------------------------------
class ConverterZoneControl : public ZoneControl
{

private:

ValueConverter* fValueConverter;

public:

ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* valueConverter) : ZoneControl(zone), fValueConverter(valueConverter) {}
virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...

void update(double v) { *fZone = fValueConverter->ui2faust(v); }

ValueConverter* getConverter() { return fValueConverter; }

};

//--------------------------------------------------------------------------------------
// Association of a zone and a four value converter, each one for each possible curve.
// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
//--------------------------------------------------------------------------------------
class CurveZoneControl : public ZoneControl
{

private:

std::vector<UpdatableValueConverter*> fValueConverters;
int fCurve;

public:

CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
{
fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
fCurve = curve;
}
virtual ~CurveZoneControl()
{
std::vector<UpdatableValueConverter*>::iterator it;
for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
delete(*it);
}
}
void update(double v) { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }

void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
{
fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
fCurve = curve;
}

void getMappingValues(double& amin, double& amid, double& amax)
{
fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
}

void setActive(bool on_off)
{
std::vector<UpdatableValueConverter*>::iterator it;
for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
(*it)->setActive(on_off);
}
}

int getCurve() { return fCurve; }
};

class ZoneReader
{

private:

FAUSTFLOAT* fZone;
Interpolator fInterpolator;

public:

ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}

virtual ~ZoneReader() {}

int getValue() {
if (fZone != 0) {
return (int)fInterpolator(*fZone);
} else {
return 127;
}
}

};

#endif

+ 287
- 0
ports/temper/source/faust/gui/console.h View File

@@ -0,0 +1,287 @@
/************************************************************************

IMPORTANT NOTE : this file contains two clearly delimited sections :
the ARCHITECTURE section (in two parts) and the USER section. Each section
is governed by its own copyright and license. Please check individually
each section for license and copyright information.
*************************************************************************/

/*******************BEGIN ARCHITECTURE SECTION (part 1/2)****************/

/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/
#ifndef __faustconsole__
#define __faustconsole__

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stack>
#include <string>
#include <map>
#include <vector>
#include <iostream>

#include "faust/gui/UI.h"

/******************************************************************************
*******************************************************************************

USER INTERFACE

*******************************************************************************
*******************************************************************************/

struct param {
FAUSTFLOAT* fZone; FAUSTFLOAT fMin; FAUSTFLOAT fMax;
param(FAUSTFLOAT* z, FAUSTFLOAT init, FAUSTFLOAT a, FAUSTFLOAT b) : fZone(z), fMin(a), fMax(b) { *z = init; }
};

class CMDUI : public UI
{
int fArgc;
char** fArgv;
std::vector<char*> fFiles;
std::stack<std::string> fPrefix;
std::map<std::string, param> fKeyParam;

void openAnyBox(const char* label)
{
std::string prefix;

if (label && label[0]) {
prefix = fPrefix.top() + "-" + label;
} else {
prefix = fPrefix.top();
}
fPrefix.push(prefix);
}

std::string simplify(const std::string& src)
{
int i = 0;
int level = 0;
std::string dst;

while (src[i] ) {

switch (level) {

case 0 :
case 1 :
case 2 :
// Skip the begin of the label "--foo-"
// until 3 '-' have been read
if (src[i]=='-') { level++; }
break;

case 3 :
// copy the content, but skip non alphnum
// and content in parenthesis
switch (src[i]) {
case '(' :
case '[' :
level++;
break;

case '-' :
dst += '-';
break;

default :
if (isalnum(src[i])) {
dst+= tolower(src[i]);
}
}
break;

default :
// here we are inside parenthesis and
// we skip the content until we are back to
// level 3
switch (src[i]) {

case '(' :
case '[' :
level++;
break;

case ')' :
case ']' :
level--;
break;

default :
break;
}

}
i++;
}
return dst;
}

public:

CMDUI(int argc, char *argv[]) : UI(), fArgc(argc), fArgv(argv) { fPrefix.push("-"); }
virtual ~CMDUI() {}

void addOption(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max)
{
std::string fullname = "-" + simplify(fPrefix.top() + "-" + label);
fKeyParam.insert(make_pair(fullname, param(zone, init, min, max)));
}

virtual void addButton(const char* label, FAUSTFLOAT* zone)
{
addOption(label,zone,0,0,1);
}

virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
addOption(label,zone,0,0,1);
}

virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addOption(label,zone,init,min,max);
}

virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addOption(label,zone,init,min,max);
}

virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addOption(label,zone,init,min,max);
}

// -- passive widgets

virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) {}
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max) {}

virtual void openTabBox(const char* label) { openAnyBox(label); }
virtual void openHorizontalBox(const char* label) { openAnyBox(label); }
virtual void openVerticalBox(const char* label) { openAnyBox(label); }

virtual void closeBox() { fPrefix.pop(); }

virtual void show() {}
virtual bool run()
{
char c;
printf("Type 'q' to quit\n");
while ((c = getchar()) != 'q') {
sleep(1);
}
return true;
}

void printhelp_command()
{
std::map<std::string, param>::iterator i;
std::cout << fArgc << "\n";
std::cout << fArgv[0] << " option list : ";
for (i = fKeyParam.begin(); i != fKeyParam.end(); i++) {
std::cout << "[ " << i->first << " " << i->second.fMin << ".." << i->second.fMax <<" ] ";
}
std::cout << " infile outfile\n";
}
void printhelp_init()
{
std::map<std::string, param>::iterator i;
std::cout << fArgc << "\n";
std::cout << fArgv[0] << " option list : ";
for (i = fKeyParam.begin(); i != fKeyParam.end(); i++) {
std::cout << "[ " << i->first << " " << i->second.fMin << ".." << i->second.fMax <<" ] ";
}
std::cout << std::endl;
}

void process_command()
{
std::map<std::string, param>::iterator p;
for (int i = 1; i < fArgc; i++) {
if (fArgv[i][0] == '-') {
if ((strcmp(fArgv[i], "-help") == 0)
|| (strcmp(fArgv[i], "-h") == 0)
|| (strcmp(fArgv[i], "--help") == 0)) {
printhelp_command();
exit(1);
}
p = fKeyParam.find(fArgv[i]);
if (p == fKeyParam.end()) {
std::cout << fArgv[0] << " : unrecognized option " << fArgv[i] << "\n";
printhelp_command();
exit(1);
}
char* end;
*(p->second.fZone) = FAUSTFLOAT(strtod(fArgv[i+1], &end));
i++;
} else {
fFiles.push_back(fArgv[i]);
}
}
}

unsigned long files() { return fFiles.size(); }
char* file (int n) { return fFiles[n]; }

char* input_file () { std::cout << "input file " << fFiles[0] << "\n"; return fFiles[0]; }
char* output_file() { std::cout << "output file " << fFiles[1] << "\n"; return fFiles[1]; }

void process_init()
{
std::map<std::string, param>::iterator p;
for (int i = 1; i < fArgc; i++) {
if (fArgv[i][0] == '-') {
if ((strcmp(fArgv[i], "-help") == 0)
|| (strcmp(fArgv[i], "-h") == 0)
|| (strcmp(fArgv[i], "--help") == 0)) {
printhelp_init();
exit(1);
}
p = fKeyParam.find(fArgv[i]);
if (p == fKeyParam.end()) {
std::cout << fArgv[0] << " : unrecognized option " << fArgv[i] << "\n";
printhelp_init();
exit(1);
}
char* end;
*(p->second.fZone) = FAUSTFLOAT(strtod(fArgv[i+1], &end));
i++;
}
}
}
};

#endif

/********************END ARCHITECTURE SECTION (part 2/2)****************/

+ 1380
- 0
ports/temper/source/faust/gui/faustgtk.h
File diff suppressed because it is too large
View File


+ 1838
- 0
ports/temper/source/faust/gui/faustqt.h
File diff suppressed because it is too large
View File


+ 366
- 0
ports/temper/source/faust/gui/httpdUI.h View File

@@ -0,0 +1,366 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef __httpdUI__
#define __httpdUI__

#include <iostream>
#include <sstream>

#include "faust/gui/HTTPDControler.h"
#include "faust/gui/UI.h"
#include "faust/gui/PathBuilder.h"
#include "faust/misc.h"

#ifndef _WIN32
#include <unistd.h>
#include <pthread.h>
#endif

/******************************************************************************
*******************************************************************************

HTTPD USER INTERFACE

*******************************************************************************
*******************************************************************************/

class httpdUIAux
{
public:
virtual bool run() = 0;
virtual void stop() = 0;
virtual int getTCPPort() = 0;
virtual std::string getJSON() = 0;
};

/*

Note about URLs and the Faust UI names:
----------------------------------------------------
Characters in a url could be:
1. Reserved: ; / ? : @ & = + $ ,
These characters delimit URL parts.
2. Unreserved: alphanum - _ . ! ~ * ' ( )
These characters have no special meaning and can be used as is.
3. Excluded: control characters, space, < > # % ", { } | \ ^ [ ] `

To solve potential conflicts between the Faust UI objects naming scheme and
the URL allowed characters, the reserved and excluded characters are replaced
with '-' (hyphen).
Space or tabulation are replaced with '_' (underscore)
*/

class httpdServerUI : public UI, public httpdUIAux
{
private:

httpdfaust::HTTPDControler* fCtrl;
const char* tr(const char* label) const
{
static char buffer[1024];
char * ptr = buffer; int n = 1;
while (*label && (n++ < 1024)) {
switch (*label) {
case ' ': case ' ':
*ptr++ = '_';
break;
case ';': case '/': case '?': case ':': case '@':
case '&': case '=': case '+': case '$': case ',':
case '<': case '>': case '#': case '%': case '"':
case '{': case '}': case '|': case '\\': case '^':
case '[': case ']': case '`':
*ptr++ = '_';
break;
default:
*ptr++ = *label;
}
label++;
}
*ptr = 0;
return buffer;
}

public:
httpdServerUI(const char* applicationname, int inputs, int outputs, int argc, char* argv[], bool init = true)
{
fCtrl = new httpdfaust::HTTPDControler(argc, argv, applicationname, init);
fCtrl->setInputs(inputs);
fCtrl->setOutputs(outputs);
}

virtual ~httpdServerUI() { delete fCtrl; }
// -- widget's layouts
virtual void openTabBox(const char* label) { fCtrl->opengroup("tgroup", tr(label)); }
virtual void openHorizontalBox(const char* label) { fCtrl->opengroup("hgroup", tr(label)); }
virtual void openVerticalBox(const char* label) { fCtrl->opengroup("vgroup", tr(label)); }
virtual void closeBox() { fCtrl->closegroup(); }

// -- active widgets
virtual void addButton(const char* label, FAUSTFLOAT* zone) { fCtrl->addnode("button", tr(label), zone); }
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone) { fCtrl->addnode("checkbox", tr(label), zone); }
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{ fCtrl->addnode("vslider", tr(label), zone, init, min, max, step); }
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{ fCtrl->addnode("hslider", tr(label), zone, init, min, max, step); }
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{ fCtrl->addnode("nentry", tr(label), zone, init, min, max, step); }

// -- passive widgets
virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{ fCtrl->addnode("hbargraph", tr(label), zone, min, max); }
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{ fCtrl->addnode("vbargraph", tr(label), zone, min, max); }

virtual void declare(FAUSTFLOAT*, const char* key, const char* val) { fCtrl->declare(key, val); }

bool run() { fCtrl->run(); return true; }
void stop() { fCtrl->stop(); }
int getTCPPort() { return fCtrl->getTCPPort(); }

std::string getJSON() { return fCtrl->getJSON(); }

};

// API from sourcefetcher.hh and compiled in libHTTPDFaust library.
int http_fetch(const char *url, char **fileBuf);


/*
Use to control a running Faust DSP wrapped with "httpdServerUI".
*/

#ifndef _WIN32
class httpdClientUI : public GUI, public PathBuilder, public httpdUIAux
{

private:
class uiUrlValue : public uiItem
{

private:
std::string fPathURL;
public:
uiUrlValue(const std::string& path_url, GUI* ui, FAUSTFLOAT* zone)
:uiItem(ui, zone),fPathURL(path_url)
{}
virtual ~uiUrlValue()
{}
virtual void reflectZone()
{
FAUSTFLOAT v = *fZone;
fCache = v;
std::stringstream str;
str << fPathURL << "?value=" << v;
std::string path = str.str();
http_fetch(path.c_str(), NULL);
}
};
std::string fServerURL;
std::string fJSON;
std::map<std::string, FAUSTFLOAT*> fZoneMap;
pthread_t fThread;
int fTCPPort;
bool fRunning;
void insertMap(std::string label, FAUSTFLOAT* zone)
{
fZoneMap[label] = zone;
}
static void* UpdateUI(void* arg)
{
httpdClientUI* ui = static_cast<httpdClientUI*>(arg);
std::map<std::string, FAUSTFLOAT*>::iterator it;
while (ui->fRunning) {
for (it = ui->fZoneMap.begin(); it != ui->fZoneMap.end(); it++) {
char* answer;
std::string path = (*it).first;
http_fetch(path.c_str(), &answer);
std::string answer_str = answer;
(*(*it).second) = (FAUSTFLOAT)strtod(answer_str.substr(answer_str.find(' ')).c_str(), NULL);
// 'http_fetch' result must be deallocated
free(answer);
}
usleep(100000);
}
return 0;
}
virtual void addGeneric(const char* label, FAUSTFLOAT* zone)
{
std::string url = fServerURL + buildPath(label);
insertMap(url, zone);
new uiUrlValue(url, this, zone);
}
public:
httpdClientUI(const std::string& server_url):fServerURL(server_url), fRunning(false)
{
char* json_buffer = 0;
std::string json_url = std::string(server_url) + "/JSON";
http_fetch(json_url.c_str(), &json_buffer);
if (json_buffer) {
fJSON = json_buffer;
fTCPPort = atoi(server_url.substr(server_url.find_last_of(':') + 1).c_str());
// 'http_fetch' result must be deallocated
free(json_buffer);
std::cout << "Faust httpd client controling server '" << server_url << "'" << std::endl;
} else {
fJSON = "";
fTCPPort = -1;
}
}
virtual ~httpdClientUI()
{
stop();
}
// -- widget's layouts
void openTabBox(const char* label)
{
fControlsLevel.push_back(label);
}
void openHorizontalBox(const char* label)
{
fControlsLevel.push_back(label);
}
void openVerticalBox(const char* label)
{
fControlsLevel.push_back(label);
}
void closeBox()
{
fControlsLevel.pop_back();
}
// -- active widgets
virtual void addButton(const char* label, FAUSTFLOAT* zone)
{
// addGeneric(label, zone);
// Do not update button state with received messages (otherwise on/off messages may be lost...)
std::string url = fServerURL + buildPath(label);
new uiUrlValue(url, this, zone);
}
virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
{
addGeneric(label, zone);
}
virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGeneric(label, zone);
}
virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGeneric(label, zone);
}
virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
{
addGeneric(label, zone);
}
// -- passive widgets
virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addGeneric(label, zone);
}
virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
{
addGeneric(label, zone);
}
virtual void declare(FAUSTFLOAT*, const char* key, const char* val) {}
bool run()
{
if (fTCPPort > 0) {
fRunning = true;
return (pthread_create(&fThread, NULL, UpdateUI, this) == 0);
} else {
return false;
}
}
void stop()
{
if (fRunning) {
fRunning = false;
pthread_join(fThread, NULL);
}
}
int getTCPPort()
{
return fTCPPort;
}

std::string getJSON() { return fJSON; }

};
#endif

/*
Creates a httpdServerUI or httpdClientUI depending of the presence of '-server URL' parameter.
*/

class httpdUI : public DecoratorUI
{
public:
httpdUI(const char* applicationname, int inputs, int outputs, int argc, char* argv[], bool init = true)
{
if (argv && isopt(argv, "-server")) {
#ifndef _WIN32
fUI = new httpdClientUI(lopts(argv, "-server", "http://localhost:5510"));
#endif
} else {
fUI = new httpdServerUI(applicationname, inputs, outputs, argc, argv, init);
}
}

bool run() { return dynamic_cast<httpdUIAux*>(fUI)->run(); }
void stop() { dynamic_cast<httpdUIAux*>(fUI)->stop(); }
int getTCPPort() { return dynamic_cast<httpdUIAux*>(fUI)->getTCPPort(); }

std::string getJSON() { return dynamic_cast<httpdUIAux*>(fUI)->getJSON(); }

};

#endif

+ 82
- 0
ports/temper/source/faust/gui/jsonfaustui.h View File

@@ -0,0 +1,82 @@
/*

Copyright (C) 2012 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __jsonfaustui__
#define __jsonfaustui__

#include "faust/gui/meta.h"
#include "faust/gui/UI.h"
#include <string>

namespace httpdfaust
{

template <typename C> class jsonui;
class jsonfaustui : public UI, public Meta
{
jsonui<FAUSTFLOAT>* fJSON;
public:

jsonfaustui(const char *name, const char* address, int port);
virtual ~jsonfaustui();

//--------------------------------------------
// UI methods
//--------------------------------------------
// -- widget's layouts
virtual void openTabBox(const char* label);
virtual void openHorizontalBox(const char* label);
virtual void openVerticalBox(const char* label);
virtual void closeBox();

// -- active widgets
void addButton(const char* label, FAUSTFLOAT* zone);
void addCheckButton(const char* label, FAUSTFLOAT* zone);
void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);
void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step);

// -- passive widgets
void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max);
void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, float min, float max);

// -- metadata declarations
void declare(FAUSTFLOAT*, const char*, const char*);

//--------------------------------------------
// additionnal methods (not part of UI)
//--------------------------------------------
void numInput(int n); // should be called with the inputs number
void numOutput(int n); // should be called with the outputs number
void declare(const char* , const char*); // global metadata declaration

//--------------------------------------------
// and eventually how to get the json as a string
//--------------------------------------------
std::string json(bool flatten);
};

} //end namespace

#endif

+ 31
- 0
ports/temper/source/faust/gui/meta.h View File

@@ -0,0 +1,31 @@
/************************************************************************
************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

************************************************************************
************************************************************************/
#ifndef __meta__
#define __meta__

struct Meta
{
virtual void declare(const char* key, const char* value) = 0;
virtual ~Meta() {};
};

#endif

+ 406
- 0
ports/temper/source/faust/gui/ring-buffer.h View File

@@ -0,0 +1,406 @@
/*
Copyright (C) 2000 Paul Davis
Copyright (C) 2003 Rohan Drape
Copyright (C) 2016 GRAME (renaming for internal use)

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

ISO/POSIX C version of Paul Davis's lock free ringbuffer C++ code.
This is safe for the case of one read thread and one write thread.
*/

#ifndef __ring_buffer__
#define __ring_buffer__

#include <stdlib.h>
#include <string.h>

typedef struct {
char *buf;
size_t len;
}
ringbuffer_data_t;

typedef struct {
char *buf;
volatile size_t write_ptr;
volatile size_t read_ptr;
size_t size;
size_t size_mask;
int mlocked;
}
ringbuffer_t;

ringbuffer_t *ringbuffer_create(size_t sz);
void ringbuffer_free(ringbuffer_t *rb);
void ringbuffer_get_read_vector(const ringbuffer_t *rb,
ringbuffer_data_t *vec);
void ringbuffer_get_write_vector(const ringbuffer_t *rb,
ringbuffer_data_t *vec);
size_t ringbuffer_read(ringbuffer_t *rb, char *dest, size_t cnt);
size_t ringbuffer_peek(ringbuffer_t *rb, char *dest, size_t cnt);
void ringbuffer_read_advance(ringbuffer_t *rb, size_t cnt);
size_t ringbuffer_read_space(const ringbuffer_t *rb);
int ringbuffer_mlock(ringbuffer_t *rb);
void ringbuffer_reset(ringbuffer_t *rb);
void ringbuffer_reset_size (ringbuffer_t * rb, size_t sz);
size_t ringbuffer_write(ringbuffer_t *rb, const char *src,
size_t cnt);
void ringbuffer_write_advance(ringbuffer_t *rb, size_t cnt);
size_t ringbuffer_write_space(const ringbuffer_t *rb);

/* Create a new ringbuffer to hold at least `sz' bytes of data. The
actual buffer size is rounded up to the next power of two. */

inline ringbuffer_t *
ringbuffer_create (size_t sz)
{
size_t power_of_two;
ringbuffer_t *rb;

if ((rb = (ringbuffer_t *) malloc (sizeof (ringbuffer_t))) == NULL) {
return NULL;
}

for (power_of_two = 1u; 1u << power_of_two < sz; power_of_two++);

rb->size = 1u << power_of_two;
rb->size_mask = rb->size;
rb->size_mask -= 1;
rb->write_ptr = 0;
rb->read_ptr = 0;
if ((rb->buf = (char *) malloc (rb->size)) == NULL) {
free (rb);
return NULL;
}
rb->mlocked = 0;

return rb;
}

/* Free all data associated with the ringbuffer `rb'. */

inline void
ringbuffer_free (ringbuffer_t * rb)
{
#ifdef USE_MLOCK
if (rb->mlocked) {
munlock (rb->buf, rb->size);
}
#endif /* USE_MLOCK */
free (rb->buf);
free (rb);
}

/* Lock the data block of `rb' using the system call 'mlock'. */

inline int
ringbuffer_mlock (ringbuffer_t * rb)
{
#ifdef USE_MLOCK
if (mlock (rb->buf, rb->size)) {
return -1;
}
#endif /* USE_MLOCK */
rb->mlocked = 1;
return 0;
}

/* Reset the read and write pointers to zero. This is not thread
safe. */

inline void
ringbuffer_reset (ringbuffer_t * rb)
{
rb->read_ptr = 0;
rb->write_ptr = 0;
memset(rb->buf, 0, rb->size);
}

/* Reset the read and write pointers to zero. This is not thread
safe. */

inline void
ringbuffer_reset_size (ringbuffer_t * rb, size_t sz)
{
rb->size = sz;
rb->size_mask = rb->size;
rb->size_mask -= 1;
rb->read_ptr = 0;
rb->write_ptr = 0;
}

/* Return the number of bytes available for reading. This is the
number of bytes in front of the read pointer and behind the write
pointer. */

inline size_t
ringbuffer_read_space (const ringbuffer_t * rb)
{
size_t w, r;

w = rb->write_ptr;
r = rb->read_ptr;

if (w > r) {
return w - r;
} else {
return (w - r + rb->size) & rb->size_mask;
}
}

/* Return the number of bytes available for writing. This is the
number of bytes in front of the write pointer and behind the read
pointer. */

inline size_t
ringbuffer_write_space (const ringbuffer_t * rb)
{
size_t w, r;

w = rb->write_ptr;
r = rb->read_ptr;

if (w > r) {
return ((r - w + rb->size) & rb->size_mask) - 1;
} else if (w < r) {
return (r - w) - 1;
} else {
return rb->size - 1;
}
}

/* The copying data reader. Copy at most `cnt' bytes from `rb' to
`dest'. Returns the actual number of bytes copied. */

inline size_t
ringbuffer_read (ringbuffer_t * rb, char *dest, size_t cnt)
{
size_t free_cnt;
size_t cnt2;
size_t to_read;
size_t n1, n2;

if ((free_cnt = ringbuffer_read_space (rb)) == 0) {
return 0;
}

to_read = cnt > free_cnt ? free_cnt : cnt;

cnt2 = rb->read_ptr + to_read;

if (cnt2 > rb->size) {
n1 = rb->size - rb->read_ptr;
n2 = cnt2 & rb->size_mask;
} else {
n1 = to_read;
n2 = 0;
}

memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;

if (n2) {
memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
}

return to_read;
}

/* The copying data reader w/o read pointer advance. Copy at most
`cnt' bytes from `rb' to `dest'. Returns the actual number of bytes
copied. */

inline size_t
ringbuffer_peek (ringbuffer_t * rb, char *dest, size_t cnt)
{
size_t free_cnt;
size_t cnt2;
size_t to_read;
size_t n1, n2;
size_t tmp_read_ptr;

tmp_read_ptr = rb->read_ptr;

if ((free_cnt = ringbuffer_read_space (rb)) == 0) {
return 0;
}

to_read = cnt > free_cnt ? free_cnt : cnt;

cnt2 = tmp_read_ptr + to_read;

if (cnt2 > rb->size) {
n1 = rb->size - tmp_read_ptr;
n2 = cnt2 & rb->size_mask;
} else {
n1 = to_read;
n2 = 0;
}

memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;

if (n2) {
memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
}

return to_read;
}

/* The copying data writer. Copy at most `cnt' bytes to `rb' from
`src'. Returns the actual number of bytes copied. */

inline size_t
ringbuffer_write (ringbuffer_t * rb, const char *src, size_t cnt)
{
size_t free_cnt;
size_t cnt2;
size_t to_write;
size_t n1, n2;

if ((free_cnt = ringbuffer_write_space (rb)) == 0) {
return 0;
}

to_write = cnt > free_cnt ? free_cnt : cnt;

cnt2 = rb->write_ptr + to_write;

if (cnt2 > rb->size) {
n1 = rb->size - rb->write_ptr;
n2 = cnt2 & rb->size_mask;
} else {
n1 = to_write;
n2 = 0;
}

memcpy (&(rb->buf[rb->write_ptr]), src, n1);
rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;

if (n2) {
memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
}

return to_write;
}

/* Advance the read pointer `cnt' places. */

inline void
ringbuffer_read_advance (ringbuffer_t * rb, size_t cnt)
{
size_t tmp = (rb->read_ptr + cnt) & rb->size_mask;
rb->read_ptr = tmp;
}

/* Advance the write pointer `cnt' places. */

inline void
ringbuffer_write_advance (ringbuffer_t * rb, size_t cnt)
{
size_t tmp = (rb->write_ptr + cnt) & rb->size_mask;
rb->write_ptr = tmp;
}

/* The non-copying data reader. `vec' is an array of two places. Set
the values at `vec' to hold the current readable data at `rb'. If
the readable data is in one segment the second segment has zero
length. */

inline void
ringbuffer_get_read_vector (const ringbuffer_t * rb,
ringbuffer_data_t * vec)
{
size_t free_cnt;
size_t cnt2;
size_t w, r;

w = rb->write_ptr;
r = rb->read_ptr;

if (w > r) {
free_cnt = w - r;
} else {
free_cnt = (w - r + rb->size) & rb->size_mask;
}

cnt2 = r + free_cnt;

if (cnt2 > rb->size) {

/* Two part vector: the rest of the buffer after the current write
ptr, plus some from the start of the buffer. */

vec[0].buf = &(rb->buf[r]);
vec[0].len = rb->size - r;
vec[1].buf = rb->buf;
vec[1].len = cnt2 & rb->size_mask;

} else {

/* Single part vector: just the rest of the buffer */

vec[0].buf = &(rb->buf[r]);
vec[0].len = free_cnt;
vec[1].len = 0;
}
}

/* The non-copying data writer. `vec' is an array of two places. Set
the values at `vec' to hold the current writeable data at `rb'. If
the writeable data is in one segment the second segment has zero
length. */

inline void
ringbuffer_get_write_vector (const ringbuffer_t * rb,
ringbuffer_data_t * vec)
{
size_t free_cnt;
size_t cnt2;
size_t w, r;

w = rb->write_ptr;
r = rb->read_ptr;

if (w > r) {
free_cnt = ((r - w + rb->size) & rb->size_mask) - 1;
} else if (w < r) {
free_cnt = (r - w) - 1;
} else {
free_cnt = rb->size - 1;
}

cnt2 = w + free_cnt;

if (cnt2 > rb->size) {

/* Two part vector: the rest of the buffer after the current write
ptr, plus some from the start of the buffer. */

vec[0].buf = &(rb->buf[w]);
vec[0].len = rb->size - w;
vec[1].buf = rb->buf;
vec[1].len = cnt2 & rb->size_mask;
} else {
vec[0].buf = &(rb->buf[w]);
vec[0].len = free_cnt;
vec[1].len = 0;
}
}

#endif // __ring_buffer__

+ 2948
- 0
ports/temper/source/faust/midi/RtMidi.cpp
File diff suppressed because it is too large
View File


+ 998
- 0
ports/temper/source/faust/midi/RtMidi.h
File diff suppressed because it is too large
View File


+ 238
- 0
ports/temper/source/faust/midi/bela-midi.h View File

@@ -0,0 +1,238 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/
#ifndef __bela_midi__
#define __bela_midi__
#include <iostream>
#include <cstdlib>
#include "Midi.h"
#include "faust/midi/midi.h"

class MapUI;

class bela_midi : public midi_handler {

private:
Midi fBelaMidi;
static void midiCallback(MidiChannelMessage message, void* arg)
{
bela_midi* midi = static_cast<bela_midi*>(arg);
switch (message.getType()) {
case kmmNoteOff:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
midi->fMidiInputs[i]->keyOff(0, message.getChannel(), message.getDataByte(0), message.getDataByte(1));
}
break;
case kmmNoteOn:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
if (message.getDataByte(1) != 0) {
midi->fMidiInputs[i]->keyOn(0, message.getChannel(), message.getDataByte(0), message.getDataByte(1));
} else {
midi->fMidiInputs[i]->keyOff(0, message.getChannel(), message.getDataByte(0), message.getDataByte(1));
}
}
break;
case kmmPolyphonicKeyPressure:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
midi->fMidiInputs[i]->keyPress(0, message.getChannel(), message.getDataByte(0), message.getDataByte(1));
}
break;
case kmmControlChange:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
midi->fMidiInputs[i]->ctrlChange(0, message.getChannel(), message.getDataByte(0), message.getDataByte(1));
}
break;
case kmmProgramChange:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
midi->fMidiInputs[i]->progChange(0, message.getChannel(), message.getDataByte(0));
}
break;
case kmmChannelPressure:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
midi->fMidiInputs[i]->chanPress(0, message.getChannel(), message.getDataByte(0));
}
break;
case kmmPitchBend:
for (unsigned int i = 0; i < midi->fMidiInputs.size(); i++) {
midi->fMidiInputs[i]->pitchWheel(0, message.getChannel(), ((message.getDataByte(1) * 128.0 + message.getDataByte(0)) - 8192) / 8192.0);
}
break;
case kmmNone:
case kmmAny:
default:
break;
}
}
public:
bela_midi()
:midi_handler("bela")
{}
virtual ~bela_midi()
{
stop_midi();
}
bool start_midi()
{
if (fBelaMidi.readFrom(0) < 0) {
return false;
}
if (fBelaMidi.writeTo(0) < 0) {
return false;
}
fBelaMidi.enableParser(true);
fBelaMidi.setParserCallback(midiCallback, this);
return true;
}
void stop_midi()
{
// Nothing todo?
}
MapUI* keyOn(int channel, int pitch, int velocity)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_NOTE_ON + channel),
static_cast<unsigned char>(pitch),
static_cast<unsigned char>(velocity) };
fBelaMidi.writeOutput(buffer, 3);
return 0;
}
void keyOff(int channel, int pitch, int velocity)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_NOTE_OFF + channel),
static_cast<unsigned char>(pitch),
static_cast<unsigned char>(velocity) };
fBelaMidi.writeOutput(buffer, 3);
}
void ctrlChange(int channel, int ctrl, int val)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_CONTROL_CHANGE + channel),
static_cast<unsigned char>(ctrl),
static_cast<unsigned char>(val) };
fBelaMidi.writeOutput(buffer, 3);
}
void chanPress(int channel, int press)
{
unsigned char buffer[2]
= { static_cast<unsigned char>(MIDI_AFTERTOUCH + channel),
static_cast<unsigned char>(press) };
fBelaMidi.writeOutput(buffer, 2);
}
void progChange(int channel, int pgm)
{
unsigned char buffer[2]
= { static_cast<unsigned char>(MIDI_PROGRAM_CHANGE + channel),
static_cast<unsigned char>(pgm) };
fBelaMidi.writeOutput(buffer, 2);
}
void keyPress(int channel, int pitch, int press)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_POLY_AFTERTOUCH + channel),
static_cast<unsigned char>(pitch),
static_cast<unsigned char>(press) };
fBelaMidi.writeOutput(buffer, 3);
}
void pitchWheel(int channel, int wheel)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_PITCH_BEND + channel),
static_cast<unsigned char>(wheel & 0x7F),
static_cast<unsigned char>((wheel >> 7) & 0x7F) };
fBelaMidi.writeOutput(buffer, 3);
}
void ctrlChange14bits(int channel, int ctrl, int value) {}
void start_sync(double date)
{
unsigned char buffer[1] = { MIDI_START };
fBelaMidi.writeOutput(buffer, 1);
}
void stop_sync(double date)
{
unsigned char buffer[1] = { MIDI_STOP };
fBelaMidi.writeOutput(buffer, 1);
}
void clock(double date)
{
unsigned char buffer[1] = { MIDI_CLOCK };
fBelaMidi.writeOutput(buffer, 1);
}
};

#endif // __bela_midi__

/*
// Use case example

#include "faust/gui/MidiUI.h"
#include "faust/midi/bela-midi.h"

bela_midi fMIDI;
MidiUI* fMidiUI;

bool setup(BeagleRTContext *context, void *userData)
{
....
// Setup a generic MidiUI to use bela_midi MIDI handler
fMidiUI = new MidiUI(&fMIDI);
// Add MidiUI control interface to DSP
fDSP.buildUserInterface(fMidiUI);
// And run it...
fMidiUI->run();
....
}

void cleanup(BeagleRTContext *context, void *userData)
{
....
delete fMidiUI;
}
*/

+ 203
- 0
ports/temper/source/faust/midi/jack-midi.h View File

@@ -0,0 +1,203 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef __jack_midi__
#define __jack_midi__

#include <iostream>
#include <cstdlib>
#include <jack/midiport.h>
#include "faust/midi/midi.h"
#include "faust/gui/ring-buffer.h"

class MapUI;

class jack_midi_handler : public midi_handler {

protected:

ringbuffer_t* fOutBuffer;

void writeMessage(unsigned char* buffer, size_t size)
{
if (fOutBuffer) {
size_t res;
// Write size of message
if ((res = ringbuffer_write(fOutBuffer, (const char*)&size, sizeof(size_t))) != sizeof(size_t)) {
std::cerr << "writeMessage size : error size = " << size << " res = " << res << std::endl;
}
// Write message content
if ((res = ringbuffer_write(fOutBuffer, (const char*)buffer, size)) != size) {
std::cerr << "writeMessage size : error size = " << size << " res = " << res << std::endl;
}
}
}

void processMidiInBuffer(void* port_buf_in)
{
for (int i = 0; i < jack_midi_get_event_count(port_buf_in); ++i) {
jack_midi_event_t event;
if (jack_midi_event_get(&event, port_buf_in, i) == 0) {

size_t nBytes = event.size;
int type = (int)event.buffer[0] & 0xf0;
int channel = (int)event.buffer[0] & 0x0f;
double time = event.time; // Timestamp in frames

// MIDI sync
if (nBytes == 1) {
handleSync(time, (int)event.buffer[0]);
} else if (nBytes == 2) {
handleData1(time, type, channel, (int)event.buffer[1]);
} else if (nBytes == 3) {
handleData2(time, type, channel, (int)event.buffer[1], (int)event.buffer[2]);
}
}
}
}

void processMidiOutBuffer(void* port_buf_out_aux, bool reset = false)
{
// MIDI output
unsigned char* port_buf_out = (unsigned char*)port_buf_out_aux;
if (reset) {
jack_midi_reset_buffer(port_buf_out);
} else {
jack_midi_clear_buffer(port_buf_out);
}
size_t res, message_size;
// Write each message one by one
while (ringbuffer_read(fOutBuffer, (char*)&message_size, sizeof(message_size)) == sizeof(message_size)) {
// Reserve MIDI event with the correct size
jack_midi_data_t* data = jack_midi_event_reserve(port_buf_out, 0, message_size);
if (data) {
// Write its content
if ((res = ringbuffer_read(fOutBuffer, (char*)data, message_size)) != message_size) {
std::cerr << "processMidiOut incorrect message : res = " << res << std::endl;
}
} else {
std::cerr << "jack_midi_event_reserve error" << std::endl;
}
}
}

public:

jack_midi_handler(const std::string& name = "JACKHandler")
:midi_handler(name)
{
fOutBuffer = ringbuffer_create(8192);
}
virtual ~jack_midi_handler()
{
ringbuffer_free(fOutBuffer);
}

MapUI* keyOn(int channel, int pitch, int velocity)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_NOTE_ON + channel),
static_cast<unsigned char>(pitch),
static_cast<unsigned char>(velocity) };
writeMessage(buffer, 3);
return 0;
}

void keyOff(int channel, int pitch, int velocity)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_NOTE_OFF + channel),
static_cast<unsigned char>(pitch),
static_cast<unsigned char>(velocity) };
writeMessage(buffer, 3);
}

void ctrlChange(int channel, int ctrl, int val)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_CONTROL_CHANGE + channel),
static_cast<unsigned char>(ctrl),
static_cast<unsigned char>(val) };
writeMessage(buffer, 3);
}

void chanPress(int channel, int press)
{
unsigned char buffer[2]
= { static_cast<unsigned char>(MIDI_AFTERTOUCH + channel),
static_cast<unsigned char>(press) };
writeMessage(buffer, 2);
}

void progChange(int channel, int pgm)
{
unsigned char buffer[2]
= { static_cast<unsigned char>(MIDI_PROGRAM_CHANGE + channel),
static_cast<unsigned char>(pgm) };
writeMessage(buffer, 2);
}

void keyPress(int channel, int pitch, int press)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_POLY_AFTERTOUCH + channel),
static_cast<unsigned char>(pitch),
static_cast<unsigned char>(press) };
writeMessage(buffer, 3);
}

void pitchWheel(int channel, int wheel)
{
unsigned char buffer[3]
= { static_cast<unsigned char>(MIDI_PITCH_BEND + channel),
static_cast<unsigned char>(wheel & 0x7F),
static_cast<unsigned char>((wheel >> 7) & 0x7F) };
writeMessage(buffer, 3);
}

void ctrlChange14bits(int channel, int ctrl, int value) {}

void start_sync(double date)
{
unsigned char buffer[1] = { MIDI_START };
writeMessage(buffer, 1);
}

void stop_sync(double date)
{
unsigned char buffer[1] = { MIDI_STOP };
writeMessage(buffer, 1);
}

void clock(double date)
{
unsigned char buffer[1] = { MIDI_CLOCK };
writeMessage(buffer, 1);
}

};

#endif

+ 199
- 0
ports/temper/source/faust/midi/juce-midi.h View File

@@ -0,0 +1,199 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/
#ifndef __juce_midi__
#define __juce_midi__
#include "juce_MidiMessage.h"
#include "faust/midi/midi.h"

class MapUI;

struct juce_midi_handler : public midi_handler {
juce_midi_handler():midi_handler("JUCE")
{}
void decodeBuffer(MidiBuffer& midiMessages)
{
MidiMessage msg;
int ignore;

for (MidiBuffer::Iterator it(midiMessages); it.getNextEvent(msg, ignore);) {
decodeMessage(msg);
}
}
void decodeMessage(const MidiMessage& message)
{
const uint8* data = message.getRawData();
if (message.isNoteOff()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->keyOff(0, message.getChannel(), data[1], data[2]);
}
} else if (message.isNoteOn()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
if (data[1] != 0) {
fMidiInputs[i]->keyOn(0, message.getChannel(), data[1], data[2]);
} else {
fMidiInputs[i]->keyOff(0, message.getChannel(), data[1], data[2]);
}
}
} else if (message.isAftertouch()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->keyPress(0, message.getChannel(), data[1], data[2]);
}
} else if (message.isController()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->ctrlChange(0, message.getChannel(), data[1], data[2]);
}
} else if (message.isProgramChange()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->progChange(0, message.getChannel(), data[1]);
}
} else if (message.isChannelPressure()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->chanPress(0, message.getChannel(), data[1]);
}
} else if (message.isPitchWheel()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->pitchWheel(0, message.getChannel(), ((data[1] * 128.0 + data[2]) - 8192) / 8192.0);
}
} else if (message.isMidiClock()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->clock(message.getTimeStamp());
}
} else if (message.isMidiStart()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->start_sync(message.getTimeStamp());
}
} else if (message.isMidiStop()) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->stop_sync(message.getTimeStamp());
}
} else {
std::cerr << "Unused MIDI message" << std::endl;
}
}

};

class juce_midi : public juce_midi_handler, public MidiInputCallback {

private:
MidiInput* fMidiIn;
MidiOutput* fMidiOut;
void handleIncomingMidiMessage(MidiInput*, const MidiMessage& message)
{
decodeMessage(message);
}
public:
virtual ~juce_midi()
{
stop_midi();
}
bool start_midi()
{
if ((fMidiIn = MidiInput::openDevice(MidiInput::getDefaultDeviceIndex(), this)) == nullptr) {
return false;
}
if ((fMidiOut = MidiOutput::openDevice(MidiOutput::getDefaultDeviceIndex())) == nullptr) {
return false;
}
fMidiIn->start();
return true;
}
void stop_midi()
{
fMidiIn->stop();
delete fMidiIn;
delete fMidiOut;
}
MapUI* keyOn(int channel, int pitch, int velocity)
{
fMidiOut->sendMessageNow(MidiMessage::noteOn(channel + 1, pitch, uint8(velocity)));
return 0;
}
void keyOff(int channel, int pitch, int velocity)
{
fMidiOut->sendMessageNow(MidiMessage::noteOff(channel + 1, pitch, uint8(velocity)));
}
void ctrlChange(int channel, int ctrl, int val)
{
fMidiOut->sendMessageNow(MidiMessage::controllerEvent(channel + 1, ctrl, uint8(val)));
}
void chanPress(int channel, int press)
{
fMidiOut->sendMessageNow(MidiMessage::channelPressureChange(channel + 1, press));
}
void progChange(int channel, int pgm)
{
fMidiOut->sendMessageNow(MidiMessage::programChange(channel + 1, pgm));
}
void keyPress(int channel, int pitch, int press)
{
fMidiOut->sendMessageNow(MidiMessage::aftertouchChange(channel + 1, pitch, press));
}
void pitchWheel(int channel, int wheel)
{
fMidiOut->sendMessageNow(MidiMessage::pitchWheel(channel + 1, wheel));
}
void ctrlChange14bits(int channel, int ctrl, int value) {}
void start_sync(double date)
{
fMidiOut->sendMessageNow(MidiMessage::midiStart());
}
void stop_sync(double date)
{
fMidiOut->sendMessageNow(MidiMessage::midiStop());
}
void clock(double date)
{
fMidiOut->sendMessageNow(MidiMessage::midiClock());
}
};

#endif // __juce_midi__


+ 212
- 0
ports/temper/source/faust/midi/midi.h View File

@@ -0,0 +1,212 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/

#ifndef __midi__
#define __midi__

#include <vector>
#include <string>
#include <algorithm>

class MapUI;

//----------------------------------------------------------------
// MIDI processor definition
//----------------------------------------------------------------

class midi {

public:

midi() {}
virtual ~midi() {}

// Additional time-stamped API for MIDI input
virtual MapUI* keyOn(double, int channel, int pitch, int velocity)
{
return keyOn(channel, pitch, velocity);
}
virtual void keyOff(double, int channel, int pitch, int velocity = 127)
{
keyOff(channel, pitch, velocity);
}
virtual void pitchWheel(double, int channel, int wheel)
{
pitchWheel(channel, wheel);
}
virtual void ctrlChange(double, int channel, int ctrl, int value)
{
ctrlChange(channel, ctrl, value);
}
virtual void progChange(double, int channel, int pgm)
{
progChange(channel, pgm);
}
virtual void keyPress(double, int channel, int pitch, int press)
{
keyPress(channel, pitch, press);
}
virtual void chanPress(double date, int channel, int press)
{
chanPress(channel, press);
}
virtual void ctrlChange14bits(double, int channel, int ctrl, int value)
{
ctrlChange14bits(channel, ctrl, value);
}

// MIDI sync
virtual void start_sync(double date) {}
virtual void stop_sync(double date) {}
virtual void clock(double date) {}

// Standard MIDI API
virtual MapUI* keyOn(int channel, int pitch, int velocity) { return 0; }
virtual void keyOff(int channel, int pitch, int velocity) {}
virtual void keyPress(int channel, int pitch, int press) {}
virtual void chanPress(int channel, int press) {}
virtual void ctrlChange(int channel, int ctrl, int value) {}
virtual void ctrlChange14bits(int channel, int ctrl, int value) {}
virtual void pitchWheel(int channel, int wheel) {}
virtual void progChange(int channel, int pgm) {}

enum MidiStatus {

// channel voice messages
MIDI_NOTE_OFF = 0x80,
MIDI_NOTE_ON = 0x90,
MIDI_CONTROL_CHANGE = 0xB0,
MIDI_PROGRAM_CHANGE = 0xC0,
MIDI_PITCH_BEND = 0xE0,
MIDI_AFTERTOUCH = 0xD0, // aka channel pressure
MIDI_POLY_AFTERTOUCH = 0xA0, // aka key pressure
MIDI_CLOCK = 0xF8,
MIDI_START = 0xFA,
MIDI_STOP = 0xFC

};

enum MidiCtrl {

ALL_NOTES_OFF = 123,
ALL_SOUND_OFF = 120

};
};

//----------------------------------------------------------------
// Base class for MIDI API handling
//----------------------------------------------------------------

class midi_handler : public midi {

protected:

std::vector<midi*> fMidiInputs;
std::string fName;

public:

midi_handler(const std::string& name = "MIDIHandler"):fName(name) {}
virtual ~midi_handler() {}

virtual void addMidiIn(midi* midi_dsp) { fMidiInputs.push_back(midi_dsp); }
virtual void removeMidiIn(midi* midi_dsp)
{
std::vector<midi*>::iterator it = std::find(fMidiInputs.begin(), fMidiInputs.end(), midi_dsp);
if (it != fMidiInputs.end()) {
fMidiInputs.erase(it);
}
}

virtual bool start_midi() { return false; }
virtual void stop_midi() {}
void handleSync(double time, int type)
{
if (type == MIDI_CLOCK) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->clock(time);
}
} else if (type == MIDI_START) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->start_sync(time);
}
} else if (type == MIDI_STOP) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->stop_sync(time);
}
}
}

void handleData1(double time, int type, int channel, int data1)
{
if (type == MIDI_PROGRAM_CHANGE) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->progChange(time, channel, data1);
}
} else if (type == MIDI_AFTERTOUCH) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->chanPress(time, channel, data1);
}
}
}

void handleData2(double time, int type, int channel, int data1, int data2)
{
if (type == MIDI_NOTE_OFF || ((type == MIDI_NOTE_ON) && (data2 == 0))) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->keyOff(time, channel, data1, data2);
}
} else if (type == MIDI_NOTE_ON) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->keyOn(time, channel, data1, data2);
}
} else if (type == MIDI_CONTROL_CHANGE) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->ctrlChange(time, channel, data1, data2);
}
} else if (type == MIDI_PITCH_BEND) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->pitchWheel(time, channel, (data2 * 128.0) + data1);
}
} else if (type == MIDI_POLY_AFTERTOUCH) {
for (unsigned int i = 0; i < fMidiInputs.size(); i++) {
fMidiInputs[i]->keyPress(time, channel, data1, data2);
}
}
}


};

#endif // __midi__

+ 260
- 0
ports/temper/source/faust/midi/rt-midi.h View File

@@ -0,0 +1,260 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.

************************************************************************
************************************************************************/
#ifndef __rt_midi__
#define __rt_midi__
#include <iostream>
#include <cstdlib>
#include "faust/midi/RtMidi.h"
#include "faust/midi/midi.h"

class MapUI;

class rt_midi : public midi_handler {

private:
std::vector<RtMidiIn*> fInput;
std::vector<RtMidiOut*> fOutput;
static void midiCallback(double time, std::vector<unsigned char>* message, void* arg)
{
rt_midi* midi = static_cast<rt_midi*>(arg);
unsigned int nBytes = message->size();
int type = (int)message->at(0) & 0xf0;
int channel = (int)message->at(0) & 0x0f;
// MIDI sync
if (nBytes == 1) {
midi->handleSync(time, (int)message->at(0));
} else if (nBytes == 2) {
midi->handleData1(time, type, channel, (int)message->at(1));
} else if (nBytes == 3) {
midi->handleData2(time, type, channel, (int)message->at(1), (int)message->at(2));
}
}
bool openMidiInputPorts()
{
// Get number of input ports
RtMidiIn midi_in;
unsigned nInPorts = midi_in.getPortCount();
if (nInPorts == 0) {
std::cout << "No input ports available!" << std::endl;
return false;
}
// Then open all of them
for (unsigned int i = 0; i < nInPorts; i++) {
RtMidiIn* midi_in = new RtMidiIn();
midi_in->ignoreTypes(true, false, true);
fInput.push_back(midi_in);
midi_in->openPort(i);
midi_in->setCallback(&midiCallback, this);
std::string portName = midi_in->getPortName(i);
std::cout << "Input port #" << i << ": " << portName << '\n';
}
return true;
}
bool openMidiOutputPorts()
{
// Get number of output ports
RtMidiOut midi_out;
unsigned nOutPorts = midi_out.getPortCount();
if (nOutPorts == 0) {
std::cout << "No output ports available!" << std::endl;
return false;
}
// Then open all of them
for (unsigned int i = 0; i < nOutPorts; i++) {
RtMidiOut* midi_out = new RtMidiOut();
fOutput.push_back(midi_out);
midi_out->openPort(i);
std::string portName = midi_out->getPortName(i);
std::cout << "Output port #" << i << ": " << portName << '\n';
}
return true;
}
void chooseMidiInputPort(const std::string& name)
{
RtMidiIn* midi_in = new RtMidiIn();
midi_in->ignoreTypes(true, false, true);
fInput.push_back(midi_in);
midi_in->setCallback(&midiCallback, this);
midi_in->openVirtualPort(name);
}
void chooseMidiOutPort(const std::string& name)
{
RtMidiOut* midi_out = new RtMidiOut();
fOutput.push_back(midi_out);
midi_out->openVirtualPort(name);
}
void sendMessage(std::vector<unsigned char>& message)
{
std::vector<RtMidiOut*>::iterator it;
for (it = fOutput.begin(); it != fOutput.end(); it++) {
(*it)->sendMessage(&message);
}
}
public:
rt_midi(const std::string& name = "RtMidi"):midi_handler(name)
{}
virtual ~rt_midi()
{
stop_midi();
}
bool start_midi()
{
try {
#if TARGET_OS_IPHONE
if (!openMidiInputPorts()) { stop_midi(); return false; }
if (!openMidiOutputPorts()) { stop_midi(); return false; }
#else
chooseMidiInputPort(fName);
chooseMidiOutPort(fName);
#endif
return true;
} catch (RtMidiError &error) {
error.printMessage();
stop_midi();
return false;
}
}
void stop_midi()
{
std::vector<RtMidiIn*>::iterator it1;
for (it1 = fInput.begin(); it1 != fInput.end(); it1++) {
delete (*it1);
}
fInput.clear();
std::vector<RtMidiOut*>::iterator it2;
for (it2 = fOutput.begin(); it2 != fOutput.end(); it2++) {
delete (*it2);
}
fOutput.clear();
}
MapUI* keyOn(int channel, int pitch, int velocity)
{
std::vector<unsigned char> message;
message.push_back(MIDI_NOTE_ON + channel);
message.push_back(pitch);
message.push_back(velocity);
sendMessage(message);
return 0;
}
void keyOff(int channel, int pitch, int velocity)
{
std::vector<unsigned char> message;
message.push_back(MIDI_NOTE_OFF + channel);
message.push_back(pitch);
message.push_back(velocity);
sendMessage(message);
}
void ctrlChange(int channel, int ctrl, int val)
{
std::vector<unsigned char> message;
message.push_back(MIDI_CONTROL_CHANGE + channel);
message.push_back(ctrl);
message.push_back(val);
sendMessage(message);
}
void chanPress(int channel, int press)
{
std::vector<unsigned char> message;
message.push_back(MIDI_AFTERTOUCH + channel);
message.push_back(press);
sendMessage(message);
}
void progChange(int channel, int pgm)
{
std::vector<unsigned char> message;
message.push_back(MIDI_PROGRAM_CHANGE + channel);
message.push_back(pgm);
sendMessage(message);
}
void keyPress(int channel, int pitch, int press)
{
std::vector<unsigned char> message;
message.push_back(MIDI_POLY_AFTERTOUCH + channel);
message.push_back(pitch);
message.push_back(press);
sendMessage(message);
}
void pitchWheel(int channel, int wheel)
{
std::vector<unsigned char> message;
message.push_back(MIDI_PITCH_BEND + channel);
message.push_back(wheel & 0x7F); // lsb 7bit
message.push_back((wheel >> 7) & 0x7F); // msb 7bit
sendMessage(message);
}
void ctrlChange14bits(int channel, int ctrl, int value) {}
void start_sync(double date)
{
std::vector<unsigned char> message;
message.push_back(MIDI_START);
sendMessage(message);
}
void stop_sync(double date)
{
std::vector<unsigned char> message;
message.push_back(MIDI_STOP);
sendMessage(message);
}
void clock(double date)
{
std::vector<unsigned char> message;
message.push_back(MIDI_CLOCK);
sendMessage(message);
}
};

#endif // __rt_midi__

+ 71
- 0
ports/temper/source/faust/misc.h View File

@@ -0,0 +1,71 @@
/************************************************************************
************************************************************************
FAUST Architecture File
Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

************************************************************************
************************************************************************/
#ifndef __misc__
#define __misc__

#include <algorithm>
#include <map>
#include <string.h>
#include <stdlib.h>

#include "faust/gui/meta.h"

using std::max;
using std::min;

struct XXXX_Meta : std::map<const char*, const char*>
{
void declare(const char* key, const char* value) { (*this)[key]=value; }
};

struct MY_Meta : Meta, std::map<const char*, const char*>
{
void declare(const char* key, const char* value) { (*this)[key]=value; }
};

inline int lsr(int x, int n) { return int(((unsigned int)x) >> n); }

inline int int2pow2(int x) { int r = 0; while ((1<<r) < x) r++; return r; }

inline long lopt(char* argv[], const char* name, long def)
{
int i;
for (i = 0; argv[i]; i++) if (!strcmp(argv[i], name)) return atoi(argv[i+1]);
return def;
}

inline bool isopt(char* argv[], const char* name)
{
int i;
for (i = 0; argv[i]; i++) if (!strcmp(argv[i], name)) return true;
return false;
}

inline const char* lopts(char* argv[], const char* name, const char* def)
{
int i;
for (i = 0; argv[i]; i++) if (!strcmp(argv[i], name)) return argv[i+1];
return def;
}

#endif


+ 107
- 0
ports/temper/source/faust/osc/FaustFactory.h View File

@@ -0,0 +1,107 @@
/*

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __FaustFactory__
#define __FaustFactory__

#include <stack>
#include <string>
#include <sstream>

#include "faust/osc/FaustNode.h"
#include "faust/osc/smartpointer.h"

class GUI;
namespace oscfaust
{

class OSCIO;
class RootNode;
typedef class SMARTP<RootNode> SRootNode;
class MessageDriven;
typedef class SMARTP<MessageDriven> SMessageDriven;

//--------------------------------------------------------------------------
/*!
\brief a factory to build a OSC UI hierarchy
Actually, makes use of a stack to build the UI hierarchy.
It includes a pointer to a OSCIO controler, but just to give it to the root node.
*/
class FaustFactory
{
std::stack<SMessageDriven> fNodes; ///< maintains the current hierarchy level
SRootNode fRoot; ///< keep track of the root node
OSCIO* fIO; ///< hack to support audio IO via OSC, actually the field is given to the root node
GUI* fGUI; ///< a GUI pointer to support updateAllGuis(), required for bi-directionnal OSC

private:
std::string addressFirst(const std::string& address) const;
std::string addressTail(const std::string& address) const;

public:
FaustFactory(GUI* ui, OSCIO * io = 0);
virtual ~FaustFactory();

template <typename C> void addnode(const char* label, C* zone, C init, C min, C max, bool initZone, bool input);
template <typename C> void addAlias(const std::string& fullpath, C* zone, C imin, C imax, C init, C min, C max, const char* label);
void addAlias(const char* alias, const char* address, float imin, float imax, float omin, float omax);
void opengroup(const char* label);
void closegroup();

SRootNode root() const;
};

/**
* Add a node to the OSC UI tree in the current group at the top of the stack
*/
template <typename C> void FaustFactory::addnode(const char* label, C* zone, C init, C min, C max, bool initZone, bool input)
{
SMessageDriven top;
if (fNodes.size()) top = fNodes.top();
if (top) {
std::string prefix = top->getOSCAddress();
top->add(FaustNode<C>::create(root(), label, zone, init, min, max, prefix.c_str(), fGUI, initZone, input));
}
}

/**
* Add an alias (actually stored and handled at root node level
*/
template <typename C> void FaustFactory::addAlias(const std::string& fullpath, C* zone, C imin, C imax, C init, C min, C max, const char* label)
{
std::istringstream ss(fullpath);
std::string realpath;
ss >> realpath >> imin >> imax;
SMessageDriven top = fNodes.top();
if (top) {
std::string target = top->getOSCAddress() + "/" + label;
addAlias(realpath.c_str(), target.c_str(), float(imin), float(imax), float(min), float(max));
}
}

} // end namespoace

#endif

+ 96
- 0
ports/temper/source/faust/osc/FaustNode.h View File

@@ -0,0 +1,96 @@
/*

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __FaustNode__
#define __FaustNode__

#include <string>
#include <vector>

#include "faust/osc/MessageDriven.h"
#include "faust/osc/Message.h"
#include "faust/gui/GUI.h"
#include "faust/osc/smartpointer.h"
#include "faust/osc/RootNode.h"

class GUI;

namespace oscfaust
{

/**
* map (rescale) input values to output values
*/
template <typename C> struct mapping
{
const C fMinOut;
const C fMaxOut;
mapping(C omin, C omax) : fMinOut(omin), fMaxOut(omax) {}
C clip (C x) { return (x < fMinOut) ? fMinOut : (x > fMaxOut) ? fMaxOut : x; }
};

//--------------------------------------------------------------------------
/*!
\brief a faust node is a terminal node and represents a faust parameter controler
*/
template <typename C> class FaustNode : public MessageDriven, public uiItem
{
mapping<C> fMapping;
RootNode* fRoot;
bool fInput; // true for input nodes (slider, button...)
bool store(C val) { *fZone = fMapping.clip(val); return true; }
void sendOSC() const;

protected:
FaustNode(RootNode* root, const char *name, C* zone, C init, C min, C max, const char* prefix, GUI* ui, bool initZone, bool input)
: MessageDriven(name, prefix), uiItem(ui, zone), fRoot(root), fMapping(min, max), fInput(input)
{
if (initZone) {
*zone = init;
}
}
virtual ~FaustNode() {}

public:
typedef SMARTP<FaustNode<C> > SFaustNode;
static SFaustNode create(RootNode* root, const char* name, C* zone, C init, C min, C max, const char* prefix, GUI* ui, bool initZone, bool input)
{
SFaustNode node = new FaustNode(root, name, zone, init, min, max, prefix, ui, initZone, input);
/*
Since FaustNode is a subclass of uiItem, the pointer will also be kept in the GUI class, and it's desallocation will be done there.
So we don't want to have smartpointer logic desallocate it and we increment the refcount.
*/
node->addReference();
return node;
}

bool accept(const Message* msg);
void get(unsigned long ipdest) const; ///< handler for the 'get' message
virtual void reflectZone() { sendOSC(); fCache = *fZone; }
};

} // end namespace

#endif

+ 263
- 0
ports/temper/source/faust/osc/Message.h View File

@@ -0,0 +1,263 @@
/*

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/


#ifndef __Message__
#define __Message__

#include <string>
#include <vector>
#include "faust/osc/smartpointer.h"

namespace oscfaust
{

class OSCStream;
template <typename T> class MsgParam;
class baseparam;
typedef SMARTP<baseparam> Sbaseparam;

//--------------------------------------------------------------------------
/*!
\brief base class of a message parameters
*/
class baseparam : public smartable
{
public:
virtual ~baseparam() {}

/*!
\brief utility for parameter type checking
*/
template<typename X> bool isType() const { return dynamic_cast<const MsgParam<X>*> (this) != 0; }
/*!
\brief utility for parameter convertion
\param errvalue the returned value when no conversion applies
\return the parameter value when the type matches
*/
template<typename X> X value(X errvalue) const
{ const MsgParam<X>* o = dynamic_cast<const MsgParam<X>*> (this); return o ? o->getValue() : errvalue; }
/*!
\brief utility for parameter comparison
*/
template<typename X> bool equal(const baseparam& p) const
{
const MsgParam<X>* a = dynamic_cast<const MsgParam<X>*> (this);
const MsgParam<X>* b = dynamic_cast<const MsgParam<X>*> (&p);
return a && b && (a->getValue() == b->getValue());
}
/*!
\brief utility for parameter comparison
*/
bool operator==(const baseparam& p) const
{
return equal<float>(p) || equal<int>(p) || equal<std::string>(p);
}
bool operator!=(const baseparam& p) const
{
return !equal<float>(p) && !equal<int>(p) && !equal<std::string>(p);
}
virtual SMARTP<baseparam> copy() const = 0;
};

//--------------------------------------------------------------------------
/*!
\brief template for a message parameter
*/
template <typename T> class MsgParam : public baseparam
{
T fParam;
public:
MsgParam(T val) : fParam(val) {}
virtual ~MsgParam() {}
T getValue() const { return fParam; }
virtual Sbaseparam copy() const { return new MsgParam<T>(fParam); }
};

//--------------------------------------------------------------------------
/*!
\brief a message description
A message is composed of an address (actually an OSC address),
a message string that may be viewed as a method name
and a list of message parameters.
*/
class Message
{
public:
typedef SMARTP<baseparam> argPtr; ///< a message argument ptr type
typedef std::vector<argPtr> argslist; ///< args list type

private:
unsigned long fSrcIP; ///< the message source IP number
std::string fAddress; ///< the message osc destination address
std::string fAlias; ///< the message alias osc destination address
argslist fArguments; ///< the message arguments

public:
/*!
\brief an empty message constructor
*/
Message() {}
/*!
\brief a message constructor
\param address the message destination address
*/
Message(const std::string& address) : fAddress(address), fAlias("") {}
Message(const std::string& address, const std::string& alias) : fAddress(address), fAlias(alias) {}
/*!
\brief a message constructor
\param address the message destination address
\param args the message parameters
*/
Message(const std::string& address, const argslist& args)
: fAddress(address), fArguments(args) {}
/*!
\brief a message constructor
\param msg a message
*/
Message(const Message& msg);
virtual ~Message() {} //{ freed++; std::cout << "running messages: " << (allocated - freed) << std::endl; }

/*!
\brief adds a parameter to the message
\param val the parameter
*/
template <typename T> void add(T val) { fArguments.push_back(new MsgParam<T>(val)); }
/*!
\brief adds a float parameter to the message
\param val the parameter value
*/
void add(float val) { add<float>(val); }
/*!
\brief adds an int parameter to the message
\param val the parameter value
*/
void add(int val) { add<int>(val); }
/*!
\brief adds a string parameter to the message
\param val the parameter value
*/
void add(const std::string& val) { add<std::string>(val); }

/*!
\brief adds a parameter to the message
\param val the parameter
*/
void add(argPtr val) { fArguments.push_back( val ); }

/*!
\brief sets the message address
\param addr the address
*/
void setSrcIP(unsigned long addr) { fSrcIP = addr; }

/*!
\brief sets the message address
\param addr the address
*/
void setAddress(const std::string& addr) { fAddress = addr; }
/*!
\brief print the message
\param out the output stream
*/
void print(std::ostream& out) const;
/*!
\brief send the message to OSC
\param out the OSC output stream
*/
void print(OSCStream& out) const;
/*!
\brief print message arguments
\param out the OSC output stream
*/
void printArgs(OSCStream& out) const;

/// \brief gives the message address
const std::string& address() const { return fAddress; }
/// \brief gives the message alias
const std::string& alias() const { return fAlias; }
/// \brief gives the message parameters list
const argslist& params() const { return fArguments; }
/// \brief gives the message parameters list
argslist& params() { return fArguments; }
/// \brief gives the message source IP
unsigned long src() const { return fSrcIP; }
/// \brief gives the message parameters count
int size() const { return fArguments.size(); }

bool operator == (const Message& other) const;

/*!
\brief gives a message float parameter
\param i the parameter index (0 <= i < size())
\param val on output: the parameter value when the parameter type matches
\return false when types don't match
*/
bool param(int i, float& val) const { val = params()[i]->value<float>(val); return params()[i]->isType<float>(); }
/*!
\brief gives a message int parameter
\param i the parameter index (0 <= i < size())
\param val on output: the parameter value when the parameter type matches
\return false when types don't match
*/
bool param(int i, int& val) const { val = params()[i]->value<int>(val); return params()[i]->isType<int>(); }
/*!
\brief gives a message int parameter
\param i the parameter index (0 <= i < size())
\param val on output: the parameter value when the parameter type matches
\return false when types don't match
*/
bool param(int i, unsigned int& val) const { val = params()[i]->value<int>(val); return params()[i]->isType<int>(); }
/*!
\brief gives a message int parameter
\param i the parameter index (0 <= i < size())
\param val on output: the parameter value when the parameter type matches
\return false when types don't match
\note a boolean value is handled as integer
*/
bool param(int i, bool& val) const { int ival = 0; ival = params()[i]->value<int>(ival); val = ival!=0; return params()[i]->isType<int>(); }
/*!
\brief gives a message int parameter
\param i the parameter index (0 <= i < size())
\param val on output: the parameter value when the parameter type matches
\return false when types don't match
*/
bool param(int i, long int& val) const { val = long(params()[i]->value<int>(val)); return params()[i]->isType<int>(); }
/*!
\brief gives a message string parameter
\param i the parameter index (0 <= i < size())
\param val on output: the parameter value when the parameter type matches
\return false when types don't match
*/
bool param(int i, std::string& val) const { val = params()[i]->value<std::string>(val); return params()[i]->isType<std::string>(); }
};


} // end namespoace

#endif

+ 131
- 0
ports/temper/source/faust/osc/MessageDriven.h View File

@@ -0,0 +1,131 @@
/*

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __MessageDriven__
#define __MessageDriven__

#include <string>
#include <vector>

#include "faust/osc/MessageProcessor.h"
#include "faust/osc/smartpointer.h"

namespace oscfaust
{

class Message;
class OSCRegexp;
class MessageDriven;
typedef class SMARTP<MessageDriven> SMessageDriven;

//--------------------------------------------------------------------------
/*!
\brief a base class for objects accepting OSC messages
Message driven objects are hierarchically organized in a tree.
They provides the necessary to dispatch an OSC message to its destination
node, according to the message OSC address.
The principle of the dispatch is the following:
- first the processMessage() method should be called on the top level node
- next processMessage call propose
*/
class MessageDriven : public MessageProcessor, public smartable
{
std::string fName; ///< the node name
std::string fOSCPrefix; ///< the node OSC address prefix (OSCAddress = fOSCPrefix + '/' + fName)
std::vector<SMessageDriven> fSubNodes; ///< the subnodes of the current node

protected:
MessageDriven(const char *name, const char *oscprefix) : fName (name), fOSCPrefix(oscprefix) {}
virtual ~MessageDriven() {}

public:
static SMessageDriven create(const char* name, const char *oscprefix) { return new MessageDriven(name, oscprefix); }

/*!
\brief OSC message processing method.
\param msg the osc message to be processed
The method should be called on the top level node.
*/
virtual void processMessage(const Message* msg);

/*!
\brief propose an OSc message at a given hierarchy level.
\param msg the osc message currently processed
\param regexp a regular expression based on the osc address head
\param addrTail the osc address tail
The method first tries to match the regular expression with the object name.
When it matches:
- it calls \c accept when \c addrTail is empty
- or it \c propose the message to its subnodes when \c addrTail is not empty.
In this case a new \c regexp is computed with the head of \c addrTail and a new \c addrTail as well.
*/
virtual void propose(const Message* msg, const OSCRegexp* regexp, const std::string addrTail);

/*!
\brief accept an OSC message.
\param msg the osc message currently processed
\return true when the message is processed by the node
The method is called only for the destination nodes. The real message acceptance is the node
responsability and may depend on the message content.
*/
virtual bool accept(const Message* msg);

/*!
\brief handler for the \c 'get' message
\param ipdest the output message destination IP
The \c 'get' message is supported by every node:
- it is propagated to the subnodes until it reaches terminal nodes
- a terminal node send its state on \c 'get' request to the IP address given as parameter.
The \c get method is basically called by the accept method.
*/
virtual void get(unsigned long ipdest) const;

/*!
\brief handler for the \c 'get' 'attribute' message
\param ipdest the output message destination IP
\param what the requested attribute
The \c 'get' message is supported by every node:
- it is propagated to the subnodes until it reaches terminal nodes
- a terminal node send its state on \c 'get' request to the IP address given as parameter.
The \c get method is basically called by the accept method.
*/
virtual void get (unsigned long ipdest, const std::string & what) const {}

void add(SMessageDriven node) { fSubNodes.push_back (node); }
const char* getName() const { return fName.c_str(); }
std::string getOSCAddress() const;
int size() const { return fSubNodes.size (); }
const std::string& name() const { return fName; }
SMessageDriven subnode(int i) { return fSubNodes[i]; }
};

} // end namespoace

#endif

+ 44
- 0
ports/temper/source/faust/osc/MessageProcessor.h View File

@@ -0,0 +1,44 @@
/*

Copyright (C) 2010 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __MessageProcessor__
#define __MessageProcessor__

namespace oscfaust
{

class Message;
//--------------------------------------------------------------------------
/*!
\brief an abstract class for objects able to process OSC messages
*/
class MessageProcessor
{
public:
virtual ~MessageProcessor() {}
virtual void processMessage( const Message* msg ) = 0;
};

} // end namespoace

#endif

+ 115
- 0
ports/temper/source/faust/osc/RootNode.h View File

@@ -0,0 +1,115 @@
/*

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __RootNode__
#define __RootNode__

#include <map>
#include <string>
#include <vector>

#include "faust/osc/MessageDriven.h"

namespace oscfaust
{

class OSCIO;
class RootNode;
typedef class SMARTP<RootNode> SRootNode;

/**
* an alias target includes a map to rescale input values to output values
* and a target osc address. The input values can be given in reversed order
* to reverse the control
*/
struct aliastarget
{
float fMinIn;
float fMaxIn;
float fMinOut;
float fMaxOut;
std::string fTarget; // the real osc address

aliastarget(const char* address, float imin, float imax, float omin, float omax)
: fMinIn(imin), fMaxIn(imax), fMinOut(omin), fMaxOut(omax), fTarget(address) {}

aliastarget(const aliastarget& t)
: fMinIn(t.fMinIn), fMaxIn(t.fMaxIn), fMinOut(t.fMinOut), fMaxOut(t.fMaxOut), fTarget(t.fTarget) {}

float scale(float x) const
{
if (fMinIn < fMaxIn) {
// increasing control
float z = (x < fMinIn) ? fMinIn : (x > fMaxIn) ? fMaxIn : x;
return fMinOut + (z-fMinIn)*(fMaxOut-fMinOut)/(fMaxIn-fMinIn);
} else if (fMinIn > fMaxIn) {
// reversed control
float z = (x < fMaxIn) ? fMaxIn : (x > fMinIn) ? fMinIn : x;
return fMinOut + (fMinIn-z)*(fMaxOut-fMinOut)/(fMinIn-fMaxIn);
} else {
// no control !
return (fMinOut+fMaxOut)/2.0;
}
}
};

//--------------------------------------------------------------------------
/*!
\brief a faust root node

A Faust root node handles the \c 'hello' message and provides support
for incoming osc signal data.
*/
class RootNode : public MessageDriven
{
int *fUPDIn, *fUDPOut, *fUDPErr; // the osc port numbers (required by the hello method)
OSCIO* fIO; // an OSC IO controler
std::map<std::string, std::vector<aliastarget> > fAliases;

void processAlias(const std::string& address, float val);
protected:
RootNode(const char *name, OSCIO* io = 0) : MessageDriven(name, ""), fUPDIn(0), fUDPOut(0), fUDPErr(0), fIO(io) {}
virtual ~RootNode() {}

public:
static SRootNode create(const char* name, OSCIO* io = 0) { return new RootNode(name, io); }

virtual void processMessage(const Message* msg);
virtual bool accept(const Message* msg);
virtual void get(unsigned long ipdest) const;
virtual void get(unsigned long ipdest, const std::string& what) const;

void addAlias(const char* alias, const char* address, float imin, float imax, float omin, float omax);
bool acceptSignal(const Message* msg); ///< handler for signal data
void hello(unsigned long ipdest) const; ///< handler for the 'hello' message
void setPorts(int* in, int* out, int* err);
std::vector<std::string> getAliases(const std::string& address);
};

} // end namespoace

#endif

+ 139
- 0
ports/temper/source/faust/osc/smartpointer.h View File

@@ -0,0 +1,139 @@
/*

Copyright (C) 2011 Grame

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

Grame Research Laboratory, 9 rue du Garet, 69001 Lyon - France
research@grame.fr

*/

#ifndef __smartpointer__
#define __smartpointer__

#include <cassert>

namespace oscfaust
{

/*!
\brief the base class for smart pointers implementation

Any object that want to support smart pointers should
inherit from the smartable class which provides reference counting
and automatic delete when the reference count drops to zero.
*/
class smartable {
private:
unsigned refCount;
public:
//! gives the reference count of the object
unsigned refs() const { return refCount; }
//! addReference increments the ref count and checks for refCount overflow
void addReference() { refCount++; assert(refCount != 0); }
//! removeReference delete the object when refCount is zero
void removeReference() { if (--refCount == 0) delete this; }
protected:
smartable() : refCount(0) {}
smartable(const smartable&): refCount(0) {}
//! destructor checks for non-zero refCount
virtual ~smartable()
{
/*
See "Static SFaustNode create (const char* name, C* zone, C init, C min, C max, const char* prefix, GUI* ui)" comment.
assert (refCount == 0);
*/
}
smartable& operator=(const smartable&) { return *this; }
};

/*!
\brief the smart pointer implementation

A smart pointer is in charge of maintaining the objects reference count
by the way of pointers operators overloading. It supports class
inheritance and conversion whenever possible.
\n Instances of the SMARTP class are supposed to use \e smartable types (or at least
objects that implements the \e addReference and \e removeReference
methods in a consistent way).
*/
template<class T> class SMARTP {
private:
//! the actual pointer to the class
T* fSmartPtr;

public:
//! an empty constructor - points to null
SMARTP() : fSmartPtr(0) {}
//! build a smart pointer from a class pointer
SMARTP(T* rawptr) : fSmartPtr(rawptr) { if (fSmartPtr) fSmartPtr->addReference(); }
//! build a smart pointer from an convertible class reference
template<class T2>
SMARTP(const SMARTP<T2>& ptr) : fSmartPtr((T*)ptr) { if (fSmartPtr) fSmartPtr->addReference(); }
//! build a smart pointer from another smart pointer reference
SMARTP(const SMARTP& ptr) : fSmartPtr((T*)ptr) { if (fSmartPtr) fSmartPtr->addReference(); }

//! the smart pointer destructor: simply removes one reference count
~SMARTP() { if (fSmartPtr) fSmartPtr->removeReference(); }
//! cast operator to retrieve the actual class pointer
operator T*() const { return fSmartPtr; }

//! '*' operator to access the actual class pointer
T& operator*() const {
// checks for null dereference
assert (fSmartPtr != 0);
return *fSmartPtr;
}

//! operator -> overloading to access the actual class pointer
T* operator->() const {
// checks for null dereference
assert (fSmartPtr != 0);
return fSmartPtr;
}

//! operator = that moves the actual class pointer
template <class T2>
SMARTP& operator=(T2 p1_) { *this=(T*)p1_; return *this; }

//! operator = that moves the actual class pointer
SMARTP& operator=(T* p_) {
// check first that pointers differ
if (fSmartPtr != p_) {
// increments the ref count of the new pointer if not null
if (p_ != 0) p_->addReference();
// decrements the ref count of the old pointer if not null
if (fSmartPtr != 0) fSmartPtr->removeReference();
// and finally stores the new actual pointer
fSmartPtr = p_;
}
return *this;
}
//! operator < to support SMARTP map with Visual C++
bool operator<(const SMARTP<T>& p_) const { return fSmartPtr < ((T *) p_); }
//! operator = to support inherited class reference
SMARTP& operator=(const SMARTP<T>& p_) { return operator=((T *) p_); }
//! dynamic cast support
template<class T2> SMARTP& cast(T2* p_) { return operator=(dynamic_cast<T*>(p_)); }
//! dynamic cast support
template<class T2> SMARTP& cast(const SMARTP<T2>& p_) { return operator=(dynamic_cast<T*>(p_)); }
};

}

#endif

+ 133
- 0
ports/temper/source/faust/sound-file.h View File

@@ -0,0 +1,133 @@
/************************************************************************
FAUST Architecture File
Copyright (C) 2003-2016 GRAME, Centre National de Creation Musicale
---------------------------------------------------------------------
This Architecture section is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; If not, see <http://www.gnu.org/licenses/>.

EXCEPTION : As a special exception, you may create a larger work
that contains this FAUST architecture section and distribute
that work under terms of your choice, so long as this FAUST
architecture section is not modified.


************************************************************************
************************************************************************/

#ifndef __SoundFileReader__
#define __SoundFileReader__

#include <sndfile.h>
#include <stdlib.h>

#define BUFFER_SIZE 1024

#ifndef FAUSTFLOAT
#define READ_SAMPLE sf_readf_float
#define FAUSTFLOAT float
#else
#define READ_SAMPLE sf_readf_double
#define FAUSTFLOAT double
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct SoundFileReader {
FAUSTFLOAT** fBuffer;
SNDFILE* fSoundFile;
int fChannels;
int fFramesNum;
} SoundFileReader;
inline static SoundFileReader* createSFR(const char* name)
{
SoundFileReader* reader = (SoundFileReader*)calloc(1, sizeof(SoundFileReader));
if (!reader) return NULL;

{
SF_INFO snd_info;
snd_info.format = 0;
reader->fSoundFile = sf_open(name, SFM_READ, &snd_info);
if (!reader->fSoundFile) {
printf("soundfile '%s' cannot be opened\n", name);
goto error;
}
reader->fChannels = snd_info.channels;
reader->fFramesNum = snd_info.frames;

reader->fBuffer = (FAUSTFLOAT**)malloc(reader->fChannels * sizeof(FAUSTFLOAT*));
if (!reader) goto error;
for (int i = 0; i < reader->fChannels; i++) {
reader->fBuffer[i] = (FAUSTFLOAT*)malloc(reader->fFramesNum * sizeof(FAUSTFLOAT));
if (!reader->fBuffer[i]) goto error;
}
// Read file in memory
int nbf, cur_index = 0;
FAUSTFLOAT buffer[BUFFER_SIZE * reader->fChannels];
do {
nbf = READ_SAMPLE(reader->fSoundFile, buffer, BUFFER_SIZE);
for (int sample = 0; sample < nbf; sample++) {
for (int chan = 0; chan < reader->fChannels; chan++) {
reader->fBuffer[chan][cur_index + sample] = buffer[sample * reader->fChannels + chan];
}
}
cur_index += nbf;
} while (nbf == BUFFER_SIZE);
return reader;
}
error:
if (reader->fBuffer) free(reader->fBuffer);
if (reader) free(reader);
return NULL;
}

inline static void destroySFR(SoundFileReader* reader)
{
if (reader) {
sf_close(reader->fSoundFile);
for (int i = 0; i < reader->fChannels; i++) {
free(reader->fBuffer[i]);
}
free(reader->fBuffer);
free(reader);
}
}

inline static int sizeSFR(SoundFileReader* reader)
{
return (reader) ? reader->fFramesNum : 1;
}

inline static int channelsSFR(SoundFileReader* reader)
{
return (reader) ? reader->fChannels : 1;
}

inline static FAUSTFLOAT sampleSFR(SoundFileReader* reader, int channel, int index)
{
return (reader) ? reader->fBuffer[channel][index] : 0.f;
}

#ifdef __cplusplus
}
#endif

#endif

+ 116
- 0
ports/temper/source/faust/vst/faust.h View File

@@ -0,0 +1,116 @@
#ifndef __VST_FAUST_H__
#define __VST_FAUST_H__

#include <list>
#include <map>
#include <vector>

#include "audioeffectx.h"
//#include "../audio/dsp.h"

const int MAX_POLYPHONY = 10;

const int INITIAL_TEMP_OUTPUT_SIZE = 1024;

//////////////////////////////////////////////////////////////////
// Faust class definition
// This class implements the abstract methods of AudioEffectX
// that define the VST instrument behavior.
//////////////////////////////////////////////////////////////////
class Faust : public AudioEffectX {
public:
// Constructor
Faust(audioMasterCallback audioMaster, dsp* dspi, vstUI* dspUIi);

// Destructor
virtual ~Faust();

virtual void processReplacing (FAUSTFLOAT** inputs, FAUSTFLOAT** outputs, VstInt32 sampleFrames);
virtual VstInt32 processEvents (VstEvents* events);

virtual void setProgram (VstInt32 program);
virtual void setProgramName (const char *name);
virtual void getProgramName (char *name);
virtual bool getProgramNameIndexed (VstInt32 category, VstInt32 index, char *text);

virtual void setParameter (VstInt32 index, float value);
virtual float getParameter (VstInt32 index);
virtual void getParameterLabel (VstInt32 index, char *label);
virtual void getParameterDisplay (VstInt32 index, char *text);
virtual void getParameterName (VstInt32 index, char *text);
virtual bool getParameterProperties(VstInt32 index, VstParameterProperties* properties);

virtual void setSampleRate (float sampleRate);

virtual bool getInputProperties (VstInt32 index, VstPinProperties *properties);
virtual bool getOutputProperties (VstInt32 index, VstPinProperties *properties);

virtual bool getEffectName (char *name);
virtual bool getVendorString (char *text);
virtual bool getProductString (char *text);
virtual VstInt32 getVendorVersion ();
virtual VstInt32 canDo (const char *text);

virtual VstInt32 getNumMidiInputChannels ();
virtual VstInt32 getNumMidiOutputChannels ();

virtual VstInt32 getMidiProgramName (VstInt32 channel, MidiProgramName *midiProgramName);
virtual VstInt32 getCurrentMidiProgram (VstInt32 channel, MidiProgramName *currentProgram);
virtual VstInt32 getMidiProgramCategory (VstInt32 channel, MidiProgramCategory *category);

private:
// Get metadata supplied by Faust compiler
const char* getMetadata(const char* key, const char* defaultString);

void initProcess ();
void noteOn (VstInt32 note, VstInt32 velocity, VstInt32 delta);
void noteOff (VstInt32 note, VstInt32 delta);
void allNotesOff( void );
void fillProgram (VstInt32 channel, VstInt32 prg, MidiProgramName* mpn);

void synthProcessReplacing(float **inputs, float **outputs,
VstInt32 sampleFrames);

void compute(float** inputs, float** outputs, VstInt32 sampleFrames);
void bendPitch(float bend);

dsp* m_dsp;
vstUI* m_dspUI;

// For synths:
bool noteIsOn;
VstInt32 currentNote;
VstInt32 currentVelocity;
VstInt32 currentDelta;

std::list<VstInt32> m_currentNotes;
std::list<VstInt32> m_currentVelocities;
std::list<VstInt32> m_currentDeltas;

char programName[kVstMaxProgNameLen + 1];

// Polyphony
std::vector<Voice*> m_voices;

// Occupied voices - map note to voice index
struct voice_node {
VstInt32 note;
int voice;
};

std::list<voice_node*> m_playingVoices;

// key off but still sounding
std :: vector< int > m_releasedVoices;

// Free voices - currently rot playing
std :: list< int > m_freeVoices;

// Previously played voice
int m_prevVoice;

FAUSTFLOAT** m_tempOutputs;
size_t m_tempOutputSize; // in float frames
}; // end of Faust class

#endif

+ 22
- 0
ports/temper/source/faust/vst/voice.h View File

@@ -0,0 +1,22 @@
//////////////////////////////////////////////////////
// Faust VST Voice
//////////////////////////////////////////////////////

#ifndef __VST_VOICE_H__
#define __VST_VOICE_H__

//#include "../audio/dsp.h"

class Voice : public vstUI {
public:
Voice(int samplingRate)
: vstUI(), m_dsp()
{
m_dsp.init(samplingRate);
m_dsp.buildUserInterface(this);
}

mydsp m_dsp;
}; //end of Voice vlass

#endif

+ 455
- 0
ports/temper/source/faust/vst/vstui.h View File

@@ -0,0 +1,455 @@
#ifndef __VST_UI_H__
#define __VST_UI_H__

#include <audioeffectx.h>
#include <faust/gui/UI.h>

#ifdef DEBUG
#define TRACE(x) x
#else
#define TRACE(x)
#endif

//////////////////////////// VST UI ////////////////////////

class vstUIObject { /* superclass of all VST UI widgets */
protected:
string fLabel;
float* fZone;
Meta metadata;
float clip(float min, float max, float val)
{
return (val < min) ? min : (val > max) ? max : val;
}
float normalize(float min, float max, float val)
{ // VST parameters are normalized to the range [0;1] on the host
val = min + val * (max - min);
return (val < min) ? min : (val > max) ? max : val;
}
public:
vstUIObject(const char* label, float* zone)
: fLabel(label), fZone(zone), metadata()
{}
virtual ~vstUIObject()
{}
virtual void GetName(char *text) {
std::strcpy(text,fLabel.c_str());
}
virtual void SetValue(double f) {
*fZone = normalize(0.0f,1.0f,(float)f);
}
virtual void SetValueNoNormalization(double f) {
*fZone = clip(0.0f,1.0f,(float)f);
}
virtual float GetValue() {
return *fZone;
}
virtual float GetValueNoNormalization() {
return *fZone;
}
virtual void GetDisplay(char *text){
std::sprintf(text,"%f",*fZone);
}
virtual long GetID() {
/* returns the sum of all the ASCII characters contained in the
parameter's label */
unsigned int i;
long acc;
for(i=0,acc = 0; i < fLabel.length(); i++) {
acc += (fLabel.c_str())[i];
}
return acc;
}
const float* getZone() const {
return fZone;
}
}; // end of vstUIObject class

/*-------------------------------------------------------------------------*/
class vstToggleButton : public vstUIObject {
public:
vstToggleButton(const char* label, float* zone)
: vstUIObject(label,zone)
{}
virtual ~vstToggleButton() {}
virtual float GetValue() {
return *fZone;
}
virtual void SetValue(double f) {
*fZone = (f>0.5f) ? 1.0f : 0.0f;
}
virtual void GetDisplay(char *text) {
(*fZone > 0.5f) ? std::strcpy(text,"ON") : std::strcpy(text,"OFF");
}
};

/*--------------------------------------------------------------------------*/
class vstCheckButton : public vstUIObject {
public:
vstCheckButton(const char* label, float* zone):vstUIObject(label,zone) {}
virtual ~vstCheckButton() {}
virtual float GetValue() {
return *fZone;
}
virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;}
virtual void GetDisplay(char *text) {
(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");
}
};

/*--------------------------------------------------------------------------*/
class vstButton : public vstUIObject {
public:
vstButton(const char* label, float* zone)
: vstUIObject(label,zone)
{}
virtual ~vstButton() {}
virtual float GetValue() {return *fZone;}
virtual void SetValue(double f) {*fZone = (f>0.5f)?1.0f:0.0f;}
virtual void GetDisplay(char *text){(*fZone>0.5f)? std::strcpy(text,"ON"): std::strcpy(text,"OFF");}
};

#define MAX_PARAM_DISPLAY_PRECISION 6
/*--------------------------------------------------------------------------*/
class vstSlider : public vstUIObject{
private:
float fInit;
float fMin;
float fMax;
float fStep;
int fPrecision;
public:
vstSlider(const char* label, float* zone, float init, float min, float max, float step)
:vstUIObject(label,zone), fInit(init), fMin(min), fMax(max), fStep(step), fPrecision(0) {
for (fPrecision = 0; fPrecision < MAX_PARAM_DISPLAY_PRECISION && step != floor(step); ++fPrecision, step *= 10.0) {;}
}
virtual ~vstSlider() {}
// The VST host calls GetValue() and expects a result in [0,1].
// The VST host calls SetValue(f) with f in [0,1]. We convert to real units.
// When we process MIDI controls, we call SetValueNoNormalization(f) with f in real units.
virtual float GetValue() {
return (*fZone-fMin)/(fMax-fMin); // normalize
}
virtual void SetValue(double f) {
*fZone = normalize(fMin,fMax,(float)f); // denormalize
}
virtual void SetValueNoNormalization(double f) {
*fZone = clip(fMin,fMax,(float)f); // raw
}
int getMinValue() const {
return fMin;
}
int getMaxValue() const {
return fMax;
}
int getStep() const {
return fStep;
}
void GetDisplay(char *text) {
if(fPrecision == 0) {
std::sprintf(text, "%d", int(*fZone));
} else {
std::sprintf(text,"%.*f", fPrecision, *fZone);
}
}
};

/*--------------------------------------------------------------------------*/
class vstUI : public UI
{
private:
bool fStopped;
vector<vstUIObject*> fUITable;
map<const float*, Meta*> m_controlMetadataMap;
public:
int freqIndex; // note frequency
int gainIndex; // note velocity
int gateIndex; // note on/off
// can be used for effects such as portamento where
// we have to know the previous note
int prevFreqIndex;
// pitchbend wheel
int pitchbendIndex;
// Constructor
vstUI()
: fStopped(false), freqIndex(-1), gainIndex(-1), gateIndex(-1)
{ }
// Destructor
virtual ~vstUI()
{
for (vector<vstUIObject*>::iterator iter = fUITable.begin();
iter != fUITable.end(); iter++) {
delete *iter;
}
for (map<const float*, Meta*>::iterator iter = m_controlMetadataMap.begin();
iter != m_controlMetadataMap.end(); ++iter)
{
delete iter->second;
}
} // end of destructor
void stop() { fStopped = true; }
bool stopped() { return fStopped; }
virtual void declare(FAUSTFLOAT* zone, const char* key, const char* value) {
map<const float*, Meta*>::iterator iter = m_controlMetadataMap.find(zone);
if (iter == m_controlMetadataMap.end()) {
// if Meta for zone doesn't exist, create it now
pair<const float*, Meta*> entry(zone, new Meta());
pair< map<const float*, Meta*>::iterator, bool> result = m_controlMetadataMap.insert(entry);
if (!result.second) {
TRACE(fprintf(stderr, "Failed adding metadata %s:%s\n", key, value));
return;
}
iter = result.first;
}
iter->second->declare(key, value);
} // end of declare
/*
Return metadata for control (such as style, unit, etc...).
*/
const char* getControlMetadata(int index, const char* key, const char* defaultString)
{
if (index < 0 || index > (int)fUITable.size()) {
TRACE(fprintf(stderr, "Illegal index (%d) accessed by getControlMetadata\n",
index));
return defaultString;
}
const float* zone = fUITable[index]->getZone();
map<const float*, Meta*>::iterator iter = m_controlMetadataMap.find(zone);
if (iter == m_controlMetadataMap.end()) {
TRACE(fprintf(stderr, "Metadata for control %d not found\n", index));
return defaultString;
}
return iter->second->get(key, defaultString);
} // end of getControlMetadata
void setAny(int anyIndex, float val, const char *str) {
if (anyIndex < 0) {
// On the Receptor, and perhaps other hosts, output to stderr is
// logged in a file.
TRACE(fprintf(stderr,"*** Faust vsti: %sIndex = %d never set!\n",
str,anyIndex) );
return;
}
if (anyIndex >= (int)fUITable.size()) {
TRACE(fprintf(stderr,"*** Faust vsti: %sIndex = %d too large!\n",
str,anyIndex));
return;
}
TRACE(fprintf(stderr,"*** Faust vsti: Setting %sIndex = %d to %f\n",
str,anyIndex,val));
fUITable[anyIndex]->SetValueNoNormalization(val);
} // end of setAny
float getAny(int anyIndex, const char* str) {
if (anyIndex < 0) {
TRACE(fprintf(stderr, "=== Faust VSTi: %sIndex = %d never set!\n",
str, anyIndex));
return -1;
}
return fUITable[anyIndex]->GetValueNoNormalization();
} // end of getAny
void setFreq(float val) {
setAny(freqIndex, val, "freq");
}
float getFreq( void ) {
return getAny(freqIndex, "freq");
}
void setGate(float val) {
setAny(gateIndex, val, "gate");
}
void setGain(float val) {
setAny(gainIndex, val, "gain");
}
void setPrevFreq(float val) {
setAny(prevFreqIndex, val, "prevfreq");
}
void setPitchBend(float val) {
setAny(pitchbendIndex, val, "pitchbend");
}
bool ckAnyMatch(const char* label, const char* indexName, int *index) {
if (0 == strcmp(label,indexName)) {
TRACE( fprintf(stderr,"=== Faust vsti: label '%s' matches '%s'\n",label,indexName) );
*index = fUITable.size() - 1;
return true;
}
return false;
}
void ckAllMatches(const char* label) {
ckAnyMatch(label,"gain",&gainIndex);
ckAnyMatch(label,"gate",&gateIndex);
ckAnyMatch(label,"freq",&freqIndex);
ckAnyMatch(label,"prevfreq", &prevFreqIndex);
ckAnyMatch(label,"pitchbend", &pitchbendIndex);
}
void addButton(const char* label, float* zone) {
vstButton* theButton = new vstButton(label, zone);
fUITable.push_back(theButton);
TRACE( fprintf(stderr,"=== Faust vsti: Adding Button with label '%s'\n",label) );
ckAnyMatch(label,"gate",&gateIndex);
}
void addToggleButton(const char* label, float* zone) {
fUITable.push_back(new vstToggleButton(label, zone));
}
void addCheckButton(const char* label, float* zone) {
fUITable.push_back(new vstCheckButton(label, zone));
}
void addVerticalSlider(const char* label, float* zone, float init,
float min, float max, float step)
{
vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step);
fUITable.push_back(theSlider);
TRACE( fprintf(stderr,"=== Faust vsti: Adding VSlider (HSlider) "
"with label '%s'\n",label) );
ckAllMatches(label);
}
void addHorizontalSlider(const char* label, float* zone, float init,
float min, float max, float step)
{
vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step);
fUITable.push_back(theSlider);
TRACE( fprintf(stderr,"=== Faust vsti: Adding HSlider with label '%s'\n",label) );
ckAllMatches(label);
}
void addNumEntry(const char* label, float* zone, float init, float min,
float max, float step)
{
/* Number entries converted to horizontal sliders */
vstSlider* theSlider = new vstSlider(label, zone, init, min, max, step);
fUITable.push_back(theSlider);
TRACE( fprintf(stderr,"=== Faust vsti: Adding NumEntry (HSlider) with "
"label '%s'\n",label) );
ckAllMatches(label);
}
void openFrameBox(const char* label) {}
void openTabBox(const char* label) {}
void openHorizontalBox(const char* label) {}
void openVerticalBox(const char* label) {}
void closeBox() {}
void SetValue(VstInt32 index, double f) {
assert(index < (VstInt32)fUITable.size());
fUITable[index]->SetValue(f);
}
float GetValue(VstInt32 index) {
assert(index < (VstInt32)fUITable.size());
return fUITable[index]->GetValue();
}
void GetDisplay(VstInt32 index, char *text) {
assert(index < (VstInt32)fUITable.size());
fUITable[index]->GetDisplay(text);
}
void GetName(VstInt32 index, char *text) {
assert(index < (VstInt32)fUITable.size());
fUITable[index]->GetName(text);
}
long GetNumParams() {
return fUITable.size();
}
/* Creates a (unique?)id by summing all the parameter's labels,
* then wrapping it in the range [0;maxNumberOfId] and adding
* this number to the offset made by the Four Character ID: 'FAUS'
*/
long makeID() {
const long maxNumberOfId = 128;
long baseid = 'FAUS';
long id=0;
for(int i=0;i<(int)fUITable.size();i++) {
id += fUITable[i]->GetID();
}
return baseid + id % maxNumberOfId;
}
// To be implemented
void addNumDisplay(const char* label, float* zone, int precision) {}
void addTextDisplay(const char* label, float* zone, char* names[],
float min, float max){}
void addHorizontalBargraph(const char* label, float* zone, float min,
float max){}
void addVerticalBargraph(const char* label, float* zone, float min,
float max){}
}; // end of vstUI class

#endif

Loading…
Cancel
Save