Merge remote-tracking branch 'refs/remotes/origin/work-0.9.2'

pull/1/head 0.9.2
Pascal Gauthier 8 years ago
commit 586f5cf250
  1. 3
      Builds/MacOSX/Dexed.xcodeproj/project.pbxproj
  2. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  3. BIN
      Builds/VisualStudio2012/Dexed.v11.suo
  4. 1
      Builds/VisualStudio2012/Dexed.vcxproj
  5. 3
      Builds/VisualStudio2012/Dexed.vcxproj.filters
  6. 6
      Dexed.jucer
  7. BIN
      Documentation/TX802-SYSEX.pdf
  8. 292
      Documentation/sysex-format.txt
  9. 12
      JuceLibraryCode/AppConfig.h
  10. 1135
      JuceLibraryCode/BinaryData.cpp
  11. 9
      JuceLibraryCode/BinaryData.h
  12. 32
      README.md
  13. BIN
      Resources/ui/GlobalEditor_864x144.png
  14. BIN
      Resources/ui/OperatorEditor_287x218.png
  15. BIN
      Resources/ui/Switch_32x32.png
  16. BIN
      Resources/ui/source/Global.skin
  17. BIN
      Resources/ui/source/Operator.skin
  18. BIN
      Resources/ui/source/render_template.png
  19. 3
      Source/CartManager.cpp
  20. 32
      Source/DXComponents.cpp
  21. 3
      Source/DXComponents.h
  22. 7
      Source/DXLookNFeel.cpp
  23. 11
      Source/DXLookNFeel.h
  24. 6
      Source/Dexed.h
  25. 203
      Source/EngineMkI.cpp
  26. 2
      Source/EngineMkI.h
  27. 22
      Source/GlobalEditor.cpp
  28. 1
      Source/GlobalEditor.h
  29. 30
      Source/OperatorEditor.cpp
  30. 15
      Source/OperatorEditor.h
  31. 45
      Source/PluginData.cpp
  32. 81
      Source/PluginData.h
  33. 16
      Source/PluginEditor.cpp
  34. 8
      Source/PluginEditor.h
  35. 16
      Source/PluginFx.cpp
  36. 4
      Source/PluginFx.h
  37. 148
      Source/PluginParam.cpp
  38. 1
      Source/PluginParam.h
  39. 9
      Source/PluginProcessor.cpp
  40. 1
      Source/PluginProcessor.h
  41. 30
      Source/ProgramListBox.cpp
  42. 3
      Source/ProgramListBox.h
  43. 6
      Source/msfa/controllers.h
  44. 28
      Source/msfa/dx7note.cc
  45. 4
      Source/msfa/fm_core.cc

@ -262,6 +262,7 @@
2CA19470CA427333F8CAC0A5 /* juce_ImagePreviewComponent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_ImagePreviewComponent.cpp; path = ../../JuceLibraryCode/modules/juce_gui_basics/filebrowser/juce_ImagePreviewComponent.cpp; sourceTree = SOURCE_ROOT; };
2CA60524355CF872ADB42EA4 /* CAVectorUnit.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = CAVectorUnit.cpp; path = Extras/CoreAudio/PublicUtility/CAVectorUnit.cpp; sourceTree = DEVELOPER_DIR; };
2CB4C73C121FCDEF65CBAC79 /* juce_mac_MainMenu.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = juce_mac_MainMenu.mm; path = ../../JuceLibraryCode/modules/juce_gui_basics/native/juce_mac_MainMenu.mm; sourceTree = SOURCE_ROOT; };
2CBFFF86BDEB0B89734D6956 /* Switch_32x32.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Switch_32x32.png; path = ../../Resources/ui/Switch_32x32.png; sourceTree = SOURCE_ROOT; };
2D26E2304C0F6FC633936014 /* lfo.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = lfo.cc; path = ../../Source/msfa/lfo.cc; sourceTree = SOURCE_ROOT; };
2D8A5B5929909ADD898D7E00 /* juce_HashMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_HashMap.h; path = ../../JuceLibraryCode/modules/juce_core/containers/juce_HashMap.h; sourceTree = SOURCE_ROOT; };
2D9932D322EDA14CC872D08B /* juce_MemoryOutputStream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_MemoryOutputStream.h; path = ../../JuceLibraryCode/modules/juce_core/streams/juce_MemoryOutputStream.h; sourceTree = SOURCE_ROOT; };
@ -2581,6 +2582,7 @@
F472964B0FFEE5615B72CE3D /* Resources */ = {
isa = PBXGroup;
children = (
2CBFFF86BDEB0B89734D6956 /* Switch_32x32.png */,
0D5761BE1D2DEA319B57D740 /* Switch_48x26.png */,
E6F65C031FCBB192F3927D4C /* ButtonUnlabeled_50x30.png */,
8B19E0BEAD29F2C0D46FA89C /* Knob_34x34.png */,
@ -2881,7 +2883,6 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;

@ -1555,6 +1555,7 @@
<ClInclude Include="..\..\JuceLibraryCode\JuceHeader.h"/>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Resources\ui\Switch_32x32.png"/>
<None Include="..\..\Resources\ui\Switch_48x26.png"/>
<None Include="..\..\Resources\ui\ButtonUnlabeled_50x30.png"/>
<None Include="..\..\Resources\ui\Knob_34x34.png"/>

@ -2723,6 +2723,9 @@
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\Resources\ui\Switch_32x32.png">
<Filter>Dexed\Resources</Filter>
</None>
<None Include="..\..\Resources\ui\Switch_48x26.png">
<Filter>Dexed\Resources</Filter>
</None>

@ -12,6 +12,8 @@
buildRTAS="0" buildAAX="0" pluginManufacturerEmail="support@yourcompany.com">
<MAINGROUP id="kHXTgw" name="Dexed">
<GROUP id="{F12593AE-639A-6F59-5819-ACE25AF86F95}" name="Resources">
<FILE id="CD5ehh" name="Switch_32x32.png" compile="0" resource="1"
file="Resources/ui/Switch_32x32.png"/>
<FILE id="SXelfa" name="Switch_48x26.png" compile="0" resource="1"
file="Resources/ui/Switch_48x26.png"/>
<FILE id="AjTNZm" name="ButtonUnlabeled_50x30.png" compile="0" resource="1"
@ -191,5 +193,7 @@
<MODULES id="juce_gui_basics" showAllCode="1" useLocalCopy="1"/>
<MODULES id="juce_gui_extra" showAllCode="1" useLocalCopy="1"/>
</MODULES>
<JUCEOPTIONS JUCE_QUICKTIME="disabled"/>
<JUCEOPTIONS JUCE_QUICKTIME="disabled" JUCE_USE_FLAC="disabled" JUCE_USE_OGGVORBIS="disabled"
JUCE_USE_MP3AUDIOFORMAT="disabled" JUCE_USE_LAME_AUDIO_FORMAT="disabled"
JUCE_USE_WINDOWS_MEDIA_FORMAT="disabled" JUCE_WEB_BROWSER="disabled"/>
</JUCERPROJECT>

Binary file not shown.

@ -0,0 +1,292 @@
Sysex Documentation
===================
(Message GUS:472)
Received: from mailhub.iastate.edu by po-3.iastate.edu
id AA06806; Sat, 25 Sep 93 16:13:53 -0500
Received: from Waisman.Wisc.EDU (don.waisman.wisc.edu) by mailhub.iastate.edu
id AA23002; Sat, 25 Sep 1993 16:14:09 -0500
Received: from Waisman.Wisc.EDU by Waisman.Wisc.EDU (PMDF V4.2-10 #2484) id
<01H3DDLUXLDSBMA3H1@Waisman.Wisc.EDU>; Sat, 25 Sep 1993 16:13:40 CDT
Date: Sat, 25 Sep 1993 16:13:40 -0500 (CDT)
From: "Ewan A. Macpherson" <MACPHERSON@waisman.wisc.edu>
Subject: DX7 Data Format
To: xeno@iastate.edu
Message-Id: <01H3DDLUY4O2BMA3H1@Waisman.Wisc.EDU>
Organization: Waisman Center, University of Wisconsin-Madison
X-Vms-To: IN::"xeno@iastate.edu"
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Content-Transfer-Encoding: 7BIT
Gary:
I don't know anything about the differences between the DX7 and DX7s, but this
DX7 info may be useful. I posted this to r.m.s. before xmas.
I've seen many requests for public domain / shareware DX editors, but I've
never seen a definitive reply. They're usually along the lines of "I was
roaching around on CompuServe last month, and I think I remember seeing one..."
Anyway, hope this helps ...
=========================================================================
For those interested in unpacking the uscd.edu DX7 patch data, here is
DX7 data format information.
compiled from - the DX7 MIDI Data Format Sheet
- article by Steve DeFuria (Keyboard Jan 87)
- looking at what my DX7 spits out
I have kept the kinda weird notation used in the DX7 Data Sheet to reduce
typing errors. Where it doesn't quite make sense to me I've added comments.
(And I will not be liable for errors etc ....)
Contents: A: SYSEX Message: Bulk Data for 1 Voice
B: SYSEX Message: Bulk Data for 32 Voices
C: SYSEX Message: Parameter Change
D: Data Structure: Single Voice Dump & Voice Parameter #'s
E: Function Parameter #'s
F: Data Structure: Bulk Dump Packed Format
////////////////////////////////////////////////////////////
A:
SYSEX Message: Bulk Data for 1 Voice
------------------------------------
bits hex description
11110000 F0 Status byte - start sysex
0iiiiiii 43 ID # (i=67; Yamaha)
0sssnnnn 00 Sub-status (s=0) & channel number (n=0; ch 1)
0fffffff 00 format number (f=0; 1 voice)
0bbbbbbb 01 byte count MS byte
0bbbbbbb 1B byte count LS byte (b=155; 1 voice)
0ddddddd ** data byte 1
| | |
0ddddddd ** data byte 155
0eeeeeee ** checksum (masked 2's complement of sum of 155 bytes)
11110111 F7 Status - end sysex
///////////////////////////////////////////////////////////
B:
SYSEX Message: Bulk Data for 32 Voices
--------------------------------------
bits hex description
11110000 F0 Status byte - start sysex
0iiiiiii 43 ID # (i=67; Yamaha)
0sssnnnn 00 Sub-status (s=0) & channel number (n=0; ch 1)
0fffffff 09 format number (f=9; 32 voices)
0bbbbbbb 20 byte count MS byte
0bbbbbbb 00 byte count LS byte (b=4096; 32 voices)
0ddddddd ** data byte 1
| | |
0ddddddd ** data byte 4096 (there are 128 bytes / voice)
0eeeeeee ** checksum (masked 2's comp. of sum of 4096 bytes)
11110111 F7 Status - end sysex
/////////////////////////////////////////////////////////////
C:
SYSEX MESSAGE: Parameter Change
-------------------------------
bits hex description
11110000 F0 Status byte - start sysex
0iiiiiii 43 ID # (i=67; Yamaha)
0sssnnnn 10 Sub-status (s=1) & channel number (n=0; ch 1)
0gggggpp ** parameter group # (g=0; voice, g=2; function)
0ppppppp ** parameter # (these are listed in next section)
Note that voice parameter #'s can go over 128 so
the pp bits in the group byte are either 00 for
par# 0-127 or 01 for par# 128-155. In the latter case
you add 128 to the 0ppppppp byte to compute par#.
0ddddddd ** data byte
11110111 F7 Status - end sysex
//////////////////////////////////////////////////////////////
D:
Data Structure: Single Voice Dump & Parameter #'s (single voice format, g=0)
-------------------------------------------------------------------------
Parameter
Number Parameter Value Range
--------- --------- -----------
0 OP6 EG rate 1 0-99
1 " " rate 2 "
2 " " rate 3 "
3 " " rate 4 "
4 " " level 1 "
5 " " level 2 "
6 " " level 3 "
7 " " level 4 "
8 OP6 KBD LEV SCL BRK PT " C3= $27
9 " " " " LFT DEPTH "
10 " " " " RHT DEPTH "
11 " " " " LFT CURVE 0-3 0=-LIN, -EXP, +EXP, +LIN
12 " " " " RHT CURVE " " " " "
13 OP6 KBD RATE SCALING 0-7
14 OP6 AMP MOD SENSITIVITY 0-3
15 OP6 KEY VEL SENSITIVITY 0-7
16 OP6 OPERATOR OUTPUT LEVEL 0-99
17 OP6 OSC MODE (fixed/ratio) 0-1 0=ratio
18 OP6 OSC FREQ COARSE 0-31
19 OP6 OSC FREQ FINE 0-99
20 OP6 OSC DETUNE 0-14 0: det=-7
21 \
| > repeat above for OSC 5, OSC 4, ... OSC 1
125 /
126 PITCH EG RATE 1 0-99
127 " " RATE 2 "
128 " " RATE 3 "
129 " " RATE 4 "
130 " " LEVEL 1 "
131 " " LEVEL 2 "
132 " " LEVEL 3 "
133 " " LEVEL 4 "
134 ALGORITHM # 0-31
135 FEEDBACK 0-7
136 OSCILLATOR SYNC 0-1
137 LFO SPEED 0-99
138 " DELAY "
139 " PITCH MOD DEPTH "
140 " AMP MOD DEPTH "
141 LFO SYNC 0-1
142 " WAVEFORM 0-5, (data sheet claims 9-4 ?!?)
0:TR, 1:SD, 2:SU, 3:SQ, 4:SI, 5:SH
143 PITCH MOD SENSITIVITY 0-7
144 TRANSPOSE 0-48 12 = C2
145 VOICE NAME CHAR 1 ASCII
146 VOICE NAME CHAR 2 ASCII
147 VOICE NAME CHAR 3 ASCII
148 VOICE NAME CHAR 4 ASCII
149 VOICE NAME CHAR 5 ASCII
150 VOICE NAME CHAR 6 ASCII
151 VOICE NAME CHAR 7 ASCII
152 VOICE NAME CHAR 8 ASCII
153 VOICE NAME CHAR 9 ASCII
154 VOICE NAME CHAR 10 ASCII
155 OPERATOR ON/OFF
bit6 = 0 / bit 5: OP1 / ... / bit 0: OP6
Note that there are actually 156 parameters listed here, one more than in
a single voice dump. The OPERATOR ON/OFF parameter is not stored with the
voice, and is only transmitted or received while editing a voice. So it
only shows up in parameter change SYS-EX's.
////////////////////////////////////////////////////////
E:
Function Parameters: (g=2)
-------------------------
Parameter
Number Parameter Range
--------- ---------- ------
64 MONO/POLY MODE CHANGE 0-1 O=POLY
65 PITCH BEND RANGE 0-12
66 " " STEP 0-12
67 PORTAMENTO MODE 0-1 0=RETAIN 1=FOLLOW
68 " GLISS 0-1
69 " TIME 0-99
70 MOD WHEEL RANGE 0-99
71 " " ASSIGN 0-7 b0: pitch, b1:amp, b2: EG bias
72 FOOT CONTROL RANGE 0-99
73 " " ASSIGN 0-7 "
74 BREATH CONT RANGE 0-99
75 " " ASSIGN 0-7 "
76 AFTERTOUCH RANGE 0-99
77 " ASSIGN 0-7 "
///////////////////////////////////////////////////////////////
F:
Data Structure: Bulk Dump Packed Format
---------------------------------------
OK, now the tricky bit. For a bulk dump the 155 voice parameters for each
voice are packed into 32 consecutive 128 byte chunks as follows ...
byte bit #
# 6 5 4 3 2 1 0 param A range param B range
---- --- --- --- --- --- --- --- ------------ ----- ------------ -----
0 R1 OP6 EG R1 0-99
1 R2 OP6 EG R2 0-99
2 R3 OP6 EG R3 0-99
3 R4 OP6 EG R4 0-99
4 L1 OP6 EG L1 0-99
5 L2 OP6 EG L2 0-99
6 L3 OP6 EG L3 0-99
7 L4 OP6 EG L4 0-99
8 BP LEV SCL BRK PT 0-99
9 LD SCL LEFT DEPTH 0-99
10 RD SCL RGHT DEPTH 0-99
11 0 0 0 | RC | LC | SCL LEFT CURVE 0-3 SCL RGHT CURVE 0-3
12 | DET | RS | OSC DETUNE 0-14 OSC RATE SCALE 0-7
13 0 0 | KVS | AMS | KEY VEL SENS 0-7 AMP MOD SENS 0-3
14 OL OP6 OUTPUT LEV 0-99
15 0 | FC | M | FREQ COARSE 0-31 OSC MODE 0-1
16 FF FREQ FINE 0-99
17 \
| > these 17 bytes for OSC 5
33 /
34 \
| > these 17 bytes for OSC 4
50 /
51 \
| > these 17 bytes for OSC 3
67 /
68 \
| > these 17 bytes for OSC 2
84 /
85 \
| > these 17 bytes for OSC 1
101 /
byte bit #
# 6 5 4 3 2 1 0 param A range param B range
---- --- --- --- --- --- --- --- ------------ ----- ------------ -----
102 PR1 PITCH EG R1 0-99
103 PR2 PITCH EG R2 0-99
104 PR3 PITCH EG R3 0-99
105 PR4 PITCH EG R4 0-99
106 PL1 PITCH EG L1 0-99
107 PL2 PITCH EG L2 0-99
108 PL3 PITCH EG L3 0-99
109 PL4 PITCH EG L4 0-99
110 0 0 | ALG | ALGORITHM 0-31
111 0 0 0 |OKS| FB | OSC KEY SYNC 0-1 FEEDBACK 0-7
112 LFS LFO SPEED 0-99
113 LFD LFO DELAY 0-99
114 LPMD LF PT MOD DEP 0-99
115 LAMD LF AM MOD DEP 0-99
116 | LPMS | LFW |LKS| LF PT MOD SNS 0-7 WAVE 0-5, SYNC 0-1
117 TRNSP TRANSPOSE 0-48
118 NAME CHAR 1 VOICE NAME 1 ASCII
119 NAME CHAR 2 VOICE NAME 2 ASCII
120 NAME CHAR 3 VOICE NAME 3 ASCII
121 NAME CHAR 4 VOICE NAME 4 ASCII
122 NAME CHAR 5 VOICE NAME 5 ASCII
123 NAME CHAR 6 VOICE NAME 6 ASCII
124 NAME CHAR 7 VOICE NAME 7 ASCII
125 NAME CHAR 8 VOICE NAME 8 ASCII
126 NAME CHAR 9 VOICE NAME 9 ASCII
127 NAME CHAR 10 VOICE NAME 10 ASCII
/////////////////////////////////////////////////////////////////////
And that's it.
Hope this is useful.
ewan.

@ -83,23 +83,23 @@
// juce_audio_formats flags:
#ifndef JUCE_USE_FLAC
//#define JUCE_USE_FLAC
#define JUCE_USE_FLAC 0
#endif
#ifndef JUCE_USE_OGGVORBIS
//#define JUCE_USE_OGGVORBIS
#define JUCE_USE_OGGVORBIS 0
#endif
#ifndef JUCE_USE_MP3AUDIOFORMAT
//#define JUCE_USE_MP3AUDIOFORMAT
#define JUCE_USE_MP3AUDIOFORMAT 0
#endif
#ifndef JUCE_USE_LAME_AUDIO_FORMAT
//#define JUCE_USE_LAME_AUDIO_FORMAT
#define JUCE_USE_LAME_AUDIO_FORMAT 0
#endif
#ifndef JUCE_USE_WINDOWS_MEDIA_FORMAT
//#define JUCE_USE_WINDOWS_MEDIA_FORMAT
#define JUCE_USE_WINDOWS_MEDIA_FORMAT 0
#endif
//==============================================================================
@ -178,7 +178,7 @@
// juce_gui_extra flags:
#ifndef JUCE_WEB_BROWSER
//#define JUCE_WEB_BROWSER
#define JUCE_WEB_BROWSER 0
#endif
#ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR

File diff suppressed because it is too large Load Diff

@ -9,6 +9,9 @@
namespace BinaryData
{
extern const char* Switch_32x32_png;
const int Switch_32x32_pngSize = 841;
extern const char* Switch_48x26_png;
const int Switch_48x26_pngSize = 2261;
@ -46,16 +49,16 @@ namespace BinaryData
const int about_pngSize = 24863;
extern const char* GlobalEditor_864x144_png;
const int GlobalEditor_864x144_pngSize = 30438;
const int GlobalEditor_864x144_pngSize = 17334;
extern const char* OperatorEditor_287x218_png;
const int OperatorEditor_287x218_pngSize = 15614;
const int OperatorEditor_287x218_pngSize = 10927;
// Points to the start of a list of resource names.
extern const char* namedResourceList[];
// Number of elements in the namedResourceList array.
const int namedResourceListSize = 14;
const int namedResourceListSize = 15;
// 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).

@ -17,6 +17,15 @@ in the source folder) stays on the Apache 2.0 license to able to collaborate bet
Changelog
---------
#### Version 0.9.2
* Mark I engine is now the default engine
* Added operator mute switch
* Added Tune (MASTER TUNE ADJ) knob
* Correct feedback implementation for Algo 4 and 6
* Single click program select
* Fix sysex issue with wrong machine ID
* Fix for parameter hosts values. thanks @Sentinel77
#### Version 0.9.1
* Mark I engine now uses 10-bit sine/exp tables. Still a work in progress but we are getting there
* More accurate FM feedback on the Mark I and OPL Series engine
@ -42,28 +51,6 @@ Changelog
* Fixed some of mono mode ticks on lower frequencies
* SynprezFM preset are now in a submenu
#### Version 0.7.0
* Preliminary Algo 4 & 6 feedback support
* DX Engine 'Dirty DX' emulation, including one based on OPL chips
* DX Engine LFO amplitude. This still needs tuning.
* Monophonic mode
* Added the 'INIT' button to re-initialize a program
* Fixed stucked notes when programs where changed
* Fixed engine envelopes wrong timing if it was not 44100Khz
* Fixed only .syx are shown when we are using the Dexed_cart.zip cartridges collection
* The DX7 Sysex port are now only used for sysex messages. This is used to avoid any midi note feedback.
#### Version 0.6.1
* Mouse over + LFO type fix + pitch eg values
#### Version 0.6.0
* Added external midi interface to send / receive sysex messages
* Fix Tracktion crash upon startup
* Middle C (transpose) now works
* Identify the parameter knob/switch by simply moving the mouse over it
* Knobs now works with vertical mouse drags
* User DX7 zip cartridges
Credits & thanks
----------------
* DX Synth engine : Raph Levien and the [msfa](https://code.google.com/p/music-synthesizer-for-android) team
@ -73,6 +60,7 @@ Credits & thanks
* DX7 program compilation : Jean-Marc Desprez (author of [SynprezFM](http://www.synprez.com/SynprezFM))
* DX7 programs : Dave Benson, Frank Carvalho, Tim Conrardy, Jack Deckard, Chris Dodunski, Tim Garrett, Hitaye, Stephan Ibsen, Christian Jezreel, Narfman, Godric Wilkie
* falkTX [distrho](http://distrho.sourceforge.net/)
* Sentinel77 for parameter host value fix
TODO - Dexed
------------

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

@ -31,7 +31,7 @@ class SyxFileFilter : public FileFilter {
public:
SyxFileFilter() : FileFilter(".syx") {}
bool isFileSuitable(const File &file) const {
return file.getFileExtension().toLowerCase() == ".syx" && file.getSize() == 4104;
return file.getFileExtension().toLowerCase() == ".syx" && file.getSize() >= 4104;
}
bool isDirectorySuitable(const File &file) const {
return true;
@ -125,7 +125,6 @@ CartManager::CartManager(DexedAudioProcessorEditor *editor) : Component("CartMan
addAndMakeVisible(getDXCartButton = new TextButton("GET DX7 CART"));
getDXCartButton->setBounds(755, 545, 100, 30);
getDXCartButton->addListener(this);
*/
}

@ -1,4 +1,4 @@
/**
/**
*
* Copyright (c) 2014 Pascal Gauthier.
*
@ -408,5 +408,35 @@ void ComboBoxImage::setImage(Image image, int pos[]) {
itemPos[i] = pos[i];
}
void ProgramSelector::mouseDown(const MouseEvent &event) {
if ( event.x < getWidth() - 8) {
ComboBox::mouseDown(event);
return;
}
int cur = getSelectedItemIndex();
if ( event.y < getHeight() / 2 ) {
if ( cur == 0 )
cur = 31;
else
cur--;
} else {
if ( cur == 31 )
cur = 0;
else
cur++;
}
setSelectedItemIndex(cur);
}
void ProgramSelector::paint(Graphics &g) {
int x = getWidth();
int y = getHeight();
Path path;
path.addTriangle(x-8, y/2-1, x-4, 2, x, y/2-1);
path.addTriangle(x-8, y/2+1, x-4, y-2, x, y/2+1);
g.setColour(Colours::white);
g.fillPath(path);
}

@ -63,7 +63,7 @@ class ComboBoxImage : public ComboBox {
public:
ComboBoxImage();
virtual void paint(Graphics &g);
virtual void paint(Graphics &g) override;
virtual void showPopup() override;
void setImage(Image image);
void setImage(Image image, int pos[]);
@ -71,6 +71,7 @@ public:
class ProgramSelector : public ComboBox {
public:
void mouseDown(const MouseEvent &event) override;
virtual void paint(Graphics &g) override;
};

@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2013-2014 Pascal Gauthier.
* Copyright (c) 2013-2016 Pascal Gauthier.
*
* 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
@ -64,6 +64,7 @@ DXLookNFeel::DXLookNFeel() {
imageKnob = ImageCache::getFromMemory(BinaryData::Knob_34x34_png, BinaryData::Knob_34x34_pngSize);
imageSwitch = ImageCache::getFromMemory(BinaryData::Switch_48x26_png, BinaryData::Switch_48x26_pngSize);
imageSwitchOperator = ImageCache::getFromMemory(BinaryData::Switch_32x32_png, BinaryData::Switch_32x32_pngSize);
imageButton = ImageCache::getFromMemory(BinaryData::ButtonUnlabeled_50x30_png, BinaryData::ButtonUnlabeled_50x30_pngSize);
imageSlider = ImageCache::getFromMemory(BinaryData::Slider_26x26_png, BinaryData::Slider_26x26_pngSize);
imageScaling = ImageCache::getFromMemory(BinaryData::Scaling_36_26_png, BinaryData::Scaling_36_26_pngSize);;
@ -119,6 +120,10 @@ DXLookNFeel::DXLookNFeel() {
imageSwitch = findImage(path);
continue;
}
if ( name == "Switch_32x64.png" ) {
imageSwitchOperator = findImage(path);
continue;
}
if ( name == "ButtonUnlabeled_50x30.png" ) {
imageButton = findImage(path);
continue;

@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2013-2014 Pascal Gauthier.
* Copyright (c) 2013-2016 Pascal Gauthier.
*
* 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
@ -35,11 +35,12 @@ public:
Typeface::Ptr defaultFontBold;
Image imageKnob, imageSwitch, imageButton, imageSlider, imageScaling, imageLight, imageLFO;
Image imageSwitchOperator;
Image imageOperator, imageGlobal;
/* overriden methods */
virtual void drawRotarySlider(Graphics &g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, Slider &slider );
virtual void drawToggleButton(Graphics& g, ToggleButton& button, bool isMouseOverButton, bool isButtonDown);
virtual void drawRotarySlider(Graphics &g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, Slider &slider ) override;
virtual void drawToggleButton(Graphics& g, ToggleButton& button, bool isMouseOverButton, bool isButtonDown) override;
virtual void drawLinearSliderBackground (Graphics&, int x, int y, int width, int height,
float sliderPos, float minSliderPos, float maxSliderPos,
const Slider::SliderStyle, Slider&) override;
@ -49,8 +50,8 @@ public:
virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
bool isMouseOverButton, bool isButtonDown) override;
virtual Font getTextButtonFont(TextButton&, int buttonHeight) override;
virtual Typeface::Ptr getTypefaceForFont(const Font &);
virtual void positionComboBoxText (ComboBox& box, Label& label);
virtual Typeface::Ptr getTypefaceForFont(const Font &) override;
virtual void positionComboBoxText (ComboBox& box, Label& label) override;
static DXLookNFeel *getLookAndFeel();
static Colour fillColour;

@ -23,15 +23,17 @@
void dexed_trace(const char *source, const char *fmt, ...);
#define DEXED_ID "0.9.2"
#ifdef DEBUG
#define DEXED_VERSION "0.9.1 DEBUG"
#define DEXED_VERSION DEXED_ID " DEBUG"
#ifdef _MSC_VER
#define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__)
#else
#define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__)
#endif
#else
#define DEXED_VERSION "0.9.1"
#define DEXED_VERSION DEXED_ID
#define TRACE(fmt, ...)
#endif

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Pascal Gauthier.
* Copyright (C) 2015-2016 Pascal Gauthier.
*
* 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
@ -57,6 +57,8 @@ static const uint16_t SINEXP_BITDEPTH = 10;
static const uint16_t SINEXP_TABLESIZE = 1<<SINEXP_BITDEPTH;
static uint16_t sinExpTable[SINEXP_TABLESIZE];
const uint16_t ENV_MAX = 1<<ENV_BITDEPTH;
static inline uint16_t sinLog(uint16_t phi) {
const uint16_t SINLOG_TABLEFILTER = SINLOG_TABLESIZE-1;
const uint16_t index = (phi & SINLOG_TABLEFILTER);
@ -200,180 +202,105 @@ void EngineMkI::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
fb_buf[1] = y;
}
void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm,
int32_t *fb_buf, int feedback_shift) {
const uint16_t ENV_MAX = 1<<ENV_BITDEPTH;
const uint16_t kLevelThresh = ENV_MAX-100; // really ???? uhuhuh
const FmAlgorithm alg = algorithms[algorithm];
bool has_contents[3] = { true, false, false };
for (int op = 0; op < 6; op++) {
int flags = alg.ops[op];
bool add = (flags & OUT_BUS_ADD) != 0;
FmOpParams &param = params[op];
int inbus = (flags >> 4) & 3;
int outbus = flags & 3;
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get();
int32_t gain1 = param.gain_out == 0 ? (ENV_MAX-1) : param.gain_out;
int32_t gain2 = ENV_MAX-(param.level_in >> (28-ENV_BITDEPTH));
param.gain_out = gain2;
if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) {
if (!has_contents[outbus]) {
add = false;
}
if (inbus == 0 || !has_contents[inbus]) {
// todo: more than one op in a feedback loop
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
// cout << op << " fb " << inbus << outbus << add << endl;
compute_fb(outptr, param.phase, param.freq,
gain1, gain2,
fb_buf, feedback_shift, add);
} else {
// cout << op << " pure " << inbus << outbus << add << endl;
compute_pure(outptr, param.phase, param.freq,
gain1, gain2, add);
}
} else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
compute(outptr, buf_[inbus - 1].get(),
param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
}
param.phase += param.freq << LG_N;
}
}
const FmAlgorithm EngineMkI::algo2[32] = {
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
{ { 0xc4, 0x00, 0x00, 0x01, 0x11, 0x14 } }, // 4 ** EXCEPTION VIA CODE
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
{ { 0xc4, 0x00, 0x01, 0x14, 0x01, 0x14 } }, // 6 ** EXCEPTION VIA CODE
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9
{ { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10
{ { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11
{ { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12
{ { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13
{ { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14
{ { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15
{ { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16
{ { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17
{ { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18
{ { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20
{ { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21
{ { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22
{ { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23
{ { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24
{ { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25
{ { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27
{ { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28
{ { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29
{ { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30
{ { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31
{ { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32
};
// exclusively used for ALGO 4 with feedback
void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t dgain[3];
int32_t gain[3];
int32_t phase[3];
// exclusively used for ALGO 6 with feedback
void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t dgain[2];
int32_t gain[2];
int32_t phase[2];
int32_t y0 = fb_buf[0];
int32_t y = fb_buf[1];
phase[0] = parms[0].phase;
phase[1] = parms[1].phase;
phase[2] = parms[2].phase;
parms[1].gain_out = (ENV_MAX-(parms[1].level_in >> (28-ENV_BITDEPTH)));
gain[0] = gain01;
gain[1] = parms[1].gain_out;
gain[2] = parms[2].gain_out;
gain[1] = parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out;
dgain[0] = (gain02 - gain01 + (N >> 1)) >> LG_N;
parms[1].gain_out = Exp2::lookup(parms[1].level_in - (14 * (1 << 24)));
dgain[1] = (parms[1].gain_out - gain[1] + (N >> 1)) >> LG_N;
parms[2].gain_out = Exp2::lookup(parms[2].level_in - (14 * (1 << 24)));
dgain[2] = (parms[1].gain_out - gain[2] + (N >> 1)) >> LG_N;
dgain[1] = (parms[1].gain_out - (parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out));
for (int i = 0; i < N; i++) {
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
// op 0
gain[0] += dgain[0];
int32_t scaled_fb = (y0 + y) >> (fb_shift + 6); // tsk tsk tsk: this needs some tuning
y0 = y;
y = Sin::lookup(phase[0] + scaled_fb);
y = ((int64_t)y * (int64_t)gain[0]) >> 24;
y = mkiSin(phase[0]+scaled_fb, gain[0]);
phase[0] += parms[0].freq;
// op 1
gain[1] += dgain[1];
y = Sin::lookup(phase[1] + y);
y = ((int64_t)y * (int64_t)gain[1]) >> 24;
y = mkiSin(phase[1]+y, gain[1]);
phase[1] += parms[1].freq;
// op 2
gain[2] += dgain[2];
y = Sin::lookup(phase[2] + y);
y = ((int64_t)y * (int64_t)gain[2]) >> 24;
output[i] = y;
phase[2] += parms[2].freq;
}
fb_buf[0] = y0;
fb_buf[1] = y;
}
// exclusively used for ALGO 6 with feedback
void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t dgain[2];
int32_t gain[2];
int32_t phase[2];
// exclusively used for ALGO 4 with feedback
void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t dgain[3];
int32_t gain[3];
int32_t phase[3];
int32_t y0 = fb_buf[0];
int32_t y = fb_buf[1];
phase[0] = parms[0].phase;
phase[1] = parms[1].phase;
phase[2] = parms[2].phase;
parms[1].gain_out = (ENV_MAX-(parms[1].level_in >> (28-ENV_BITDEPTH)));
parms[2].gain_out = (ENV_MAX-(parms[2].level_in >> (28-ENV_BITDEPTH)));
gain[0] = gain01;
gain[1] = parms[1].gain_out;
gain[1] = parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out;
gain[2] = parms[2].gain_out == 0 ? (ENV_MAX-1) : parms[2].gain_out;
dgain[0] = (gain02 - gain01 + (N >> 1)) >> LG_N;
dgain[1] = (parms[1].gain_out - (parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out));
dgain[2] = (parms[2].gain_out - (parms[2].gain_out == 0 ? (ENV_MAX-1) : parms[2].gain_out));
parms[1].gain_out = Exp2::lookup(parms[1].level_in - (14 * (1 << 24)));
dgain[1] = (parms[1].gain_out - gain[1] + (N >> 1)) >> LG_N;
for (int i = 0; i < N; i++) {
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
// op 0
gain[0] += dgain[0];
int32_t scaled_fb = (y0 + y) >> (fb_shift + 2); // tsk tsk tsk: this needs some tuning
y0 = y;
y = Sin::lookup(phase[0] + scaled_fb);
y = ((int64_t)y * (int64_t)gain[0]) >> 24;
y = mkiSin(phase[0]+scaled_fb, gain[0]);
phase[0] += parms[0].freq;
// op 1
gain[1] += dgain[1];
y = Sin::lookup(phase[1] + y);
y = ((int64_t)y * (int64_t)gain[1]) >> 24;
output[i] = y;
y = mkiSin(phase[1]+y, gain[1]);
phase[1] += parms[1].freq;
// op 2
gain[2] += dgain[2];
y = mkiSin(phase[2]+y, gain[2]);
phase[2] += parms[2].freq;
output[i] = y;
}
fb_buf[0] = y0;
fb_buf[1] = y;
}
/*
void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) {
const int kLevelThresh = 507;
const FmAlgorithm alg = algo2[algorithm];
const int kLevelThresh = ENV_MAX-100;
FmAlgorithm alg = algorithms[algorithm];
bool has_contents[3] = { true, false, false };
bool fb_on = feedback_shift < 16;
switch(algorithm) {
case 3 : case 5 :
if ( fb_on )
alg.ops[0] = 0xc4;
}
for (int op = 0; op < 6; op++) {
int flags = alg.ops[op];
@ -382,11 +309,11 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32
int inbus = (flags >> 4) & 3;
int outbus = flags & 3;
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get();
int32_t gain1 = param.gain_out == 0 ? 511 : param.gain_out;
int32_t gain2 = 512-(param.level_in >> 19);
int32_t gain1 = param.gain_out == 0 ? (ENV_MAX-1) : param.gain_out;
int32_t gain2 = ENV_MAX-(param.level_in >> (28-ENV_BITDEPTH));
param.gain_out = gain2;
if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) {
if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) {
if (!has_contents[outbus]) {
add = false;
@ -394,44 +321,38 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32
if (inbus == 0 || !has_contents[inbus]) {
// PG: this is my 'dirty' implementation of FB for 2 and 3 operators...
// still needs some tuning...
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
if ((flags & 0xc0) == 0xc0 && fb_on) {
switch ( algorithm ) {
// two operator feedback, process exception for ALGO 6
case 5 :
//compute_fb2(outptr, params, gain1, gain2, fb_buf, feedback_shift, controllers);
params[1].phase += params[1].freq << LG_N; // yuk, hack, we already processed op-5
op++; // ignore next operator;
break;
// three operator feedback, process exception for ALGO 4
case 3 :
//compute_fb3(outptr, params, gain1, gain2, fb_buf, feedback_shift, controllers);
compute_fb3(outptr, params, gain1, gain2, fb_buf, feedback_shift);
params[1].phase += params[1].freq << LG_N; // hack, we already processed op-5 - op-4
params[2].phase += params[2].freq << LG_N; // yuk yuk
op += 2; // ignore the 2 other operators
break;
// two operator feedback, process exception for ALGO 6
case 5 :
compute_fb2(outptr, params, gain1, gain2, fb_buf, feedback_shift);
params[1].phase += params[1].freq << LG_N; // yuk, hack, we already processed op-5
op++; // ignore next operator;
break;
default:
// one operator feedback, normal proces
//cout << "\t" << op << " fb " << inbus << outbus << add << endl;
compute_fb(outptr, param.phase, param.freq,gain1, gain2, fb_buf, feedback_shift, add);
compute_fb(outptr, param.phase, param.freq, gain1, gain2, fb_buf, feedback_shift, add);
break;
}
} else {
// cout << op << " pure " << inbus << outbus << add << endl;
compute_pure(outptr, param.phase, param.freq, gain1, gain2, add);
}
} else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
compute(outptr, buf_[inbus - 1].get(), param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
}
param.phase += param.freq << LG_N;
}
}
*/

@ -26,8 +26,6 @@
class EngineMkI : public FmCore {
//refacter this when it is working
const static FmAlgorithm algo2[32];
public:
EngineMkI();

@ -260,6 +260,12 @@ GlobalEditor::GlobalEditor ()
Image(), 1.000f, Colour (0x00000000),
Image(), 1.000f, Colour (0x00000000),
Image(), 1.000f, Colour (0x00000000));
addAndMakeVisible (tune = new Slider ("tune"));
tune->setRange (0, 1, 0);
tune->setSliderStyle (Slider::RotaryVerticalDrag);
tune->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
tune->addListener (this);
//[UserPreSize]
//[/UserPreSize]
@ -321,6 +327,7 @@ GlobalEditor::~GlobalEditor()
lfoType = nullptr;
programSelector = nullptr;
aboutButton = nullptr;
tune = nullptr;
//[Destructor]. You can add your own custom destruction code here..
@ -379,6 +386,7 @@ void GlobalEditor::resized()
lfoType->setBounds (583, 8, 36, 26);
programSelector->setBounds (153, 115, 112, 18);
aboutButton->setBounds (8, 11, 135, 46);
tune->setBounds (190, 9, 34, 34);
//[UserResized] Add your own custom resize handling here..
//[/UserResized]
}
@ -491,6 +499,11 @@ void GlobalEditor::sliderValueChanged (Slider* sliderThatWasMoved)
//[UserSliderCode_output] -- add your slider handling code here..
//[/UserSliderCode_output]
}
else if (sliderThatWasMoved == tune)
{
//[UserSliderCode_tune] -- add your slider handling code here..
//[/UserSliderCode_tune]
}
//[UsersliderValueChanged_Post]
//[/UsersliderValueChanged_Post]
@ -584,14 +597,15 @@ void GlobalEditor::bind(DexedAudioProcessorEditor *edit) {
processor->fxCutoff->bind(cutoff);
processor->fxReso->bind(reso);
processor->output->bind(output);
processor->tune->bind(tune);
algoDisplay->algo = (char *) &(processor->data[134]);
pitchEnvDisplay->pvalues = &(processor->data[126]);
editor = edit;
midiMonitor = new MidiMonitor(&(processor->sysexComm));
addAndMakeVisible(midiMonitor);
midiMonitor->setBounds(155, 21, 80, 45);
//addAndMakeVisible(midiMonitor);
//midiMonitor->setBounds(155, 21, 80, 45);
repaint();
}
@ -759,6 +773,10 @@ BEGIN_JUCER_METADATA
resourceNormal="" opacityNormal="1" colourNormal="0" resourceOver=""
opacityOver="1" colourOver="0" resourceDown="" opacityDown="1"
colourDown="0"/>
<SLIDER name="tune" id="d22c34aa3363a28a" memberName="tune" virtualName=""
explicitFocusOrder="0" pos="190 9 34 34" min="0" max="1" int="0"
style="RotaryVerticalDrag" textBoxPos="NoTextBox" textBoxEditable="0"
textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
</JUCER_COMPONENT>
END_JUCER_METADATA

@ -113,6 +113,7 @@ private:
ScopedPointer<ComboBoxImage> lfoType;
ScopedPointer<ProgramSelector> programSelector;
ScopedPointer<ImageButton> aboutButton;
ScopedPointer<Slider> tune;
//==============================================================================

@ -7,12 +7,12 @@
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
Created with Introjucer version: 3.2.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
==============================================================================
*/
@ -27,11 +27,28 @@
#ifndef M_LN10
#define M_LN10 2.30258509299404568402
#endif
class OperatorSwitch : public ToggleButton {
Image image;
public :
OperatorSwitch() : ToggleButton("opSwitch") {
image = DXLookNFeel::getLookAndFeel()->imageSwitchOperator;
setSize(32, 32);
}
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) {
g.drawImage(image, 0, 0, 32, 32, 0, getToggleState() ? 0 : 32, 32, 32);
}
};
//[/MiscUserDefs]
//==============================================================================
OperatorEditor::OperatorEditor ()
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
addAndMakeVisible (s_egl1 = new Slider ("egl1"));
s_egl1->setRange (0, 99, 1);
s_egl1->setSliderStyle (Slider::RotaryVerticalDrag);
@ -173,6 +190,7 @@ OperatorEditor::OperatorEditor ()
//[UserPreSize]
addAndMakeVisible(opSwitch = new OperatorSwitch());
//[/UserPreSize]
setSize (287, 218);
@ -233,6 +251,7 @@ OperatorEditor::~OperatorEditor()
//[Destructor]. You can add your own custom destruction code here..
opSwitch = nullptr;
//[/Destructor]
}
@ -246,7 +265,7 @@ void OperatorEditor::paint (Graphics& g)
//[UserPaint] Add your own custom painting code here..
g.setColour (Colours::white);
g.setFont(Font (30.00f, Font::plain));
g.drawText(opNum, 242, 8, 30, 30, Justification::centred, true);
g.drawText(opNum, 250, 14, 30, 30, Justification::centred, true);
bool state = opMode->getToggleState();
@ -259,6 +278,9 @@ void OperatorEditor::paint (Graphics& g)
void OperatorEditor::resized()
{
//[UserPreResize] Add your own custom resize code here..
//[/UserPreResize]
s_egl1->setBounds (5, 128, 34, 34);
s_egl2->setBounds (33, 129, 34, 34);
s_egl3->setBounds (61, 128, 34, 34);
@ -284,6 +306,7 @@ void OperatorEditor::resized()
kbdLeftCurve->setBounds (128, 170, 36, 26);
kbdRightCurve->setBounds (240, 170, 36, 26);
//[UserResized] Add your own custom resize handling here..
opSwitch->setBounds(226, 13, 64, 32);
//[/UserResized]
}
@ -439,6 +462,7 @@ void OperatorEditor::bind(DexedAudioProcessor *parent, int op) {
parent->opCtrl[op].sclRate->bind(sclRateScaling);
parent->opCtrl[op].ampModSens->bind(ampModSens);
parent->opCtrl[op].velModSens->bind(keyVelSens);
parent->opCtrl[op].opSwitch->bind(opSwitch);
int offset = parent->opCtrl[op].egRate[0]->getOffset();
envDisplay->pvalues = &(parent->data[offset]);

@ -7,12 +7,12 @@
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
Created with Introjucer version: 3.2.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
==============================================================================
*/
@ -56,10 +56,10 @@ public:
void mouseDown(const MouseEvent& e) override;
//[/UserMethods]
void paint (Graphics& g);
void resized();
void sliderValueChanged (Slider* sliderThatWasMoved);
void buttonClicked (Button* buttonThatWasClicked);
void paint (Graphics& g) override;
void resized() override;
void sliderValueChanged (Slider* sliderThatWasMoved) override;
void buttonClicked (Button* buttonThatWasClicked) override;
@ -68,10 +68,9 @@ private:
String opNum;
int internalOp;
Image light;
DexedAudioProcessor *processor;
Image background;
ScopedPointer<ToggleButton> opSwitch;
//[/UserVariables]
//==============================================================================

@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2014-2015 Pascal Gauthier.
* Copyright (c) 2014-2016 Pascal Gauthier.
*
* 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
@ -55,7 +55,7 @@ void exportSysexPgm(uint8_t *dest, uint8_t *src) {
/**
* Pack a program into a 32 packed sysex
*/
void Cartridge::packProgram(uint8_t *src, int idx, String name) {
void Cartridge::packProgram(uint8_t *src, int idx, String name, char *opSwitch) {
uint8_t *bulk = voiceData + 6 + (idx * 128);
for(int op = 0; op < 6; op++) {
@ -70,7 +70,10 @@ void Cartridge::packProgram(uint8_t *src, int idx, String name) {
// kvs_ams
bulk[pp+13] = (src[up+14]&0x03) | ((src[up+15]&0x07) << 2);
// output lvl
bulk[pp+14] = src[up+16];
if ( opSwitch[op] == '0' )
bulk[pp+14] = 0;
else
bulk[pp+14] = src[up+16];
// fcoarse_mode
bulk[pp+15] = (src[up+17]&0x01) | ((src[up+18]&0x1f) << 1);
// fine freq
@ -158,7 +161,7 @@ void Cartridge::unpackProgram(uint8_t *unpackPgm, int idx) {
unpackPgm[142] = (lpms_lfw_lks >> 1) & 7;
unpackPgm[143] = lpms_lfw_lks >> 4;
memcpy(unpackPgm + 144, bulk + 117, 11); // transpose, name
unpackPgm[155] = 1; // operator on/off
unpackPgm[155] = 1; // operator on/off (DEPRECATED)
unpackPgm[156] = 1;
unpackPgm[157] = 1;
unpackPgm[158] = 1;
@ -173,6 +176,7 @@ void DexedAudioProcessor::loadCartridge(Cartridge &sysex) {
void DexedAudioProcessor::updateProgramFromSysex(const uint8_t *rawdata) {
memcpy(data, rawdata, 161);
lfo.reset(data + 137);
triggerAsyncUpdate();
}
@ -249,18 +253,27 @@ void DexedAudioProcessor::sendCurrentSysexCartridge() {
void DexedAudioProcessor::sendSysexCartridge(File cart) {
if ( ! sysexComm.isOutputActive() )
return;
String f = cart.getFullPathName();
uint8_t syx_data[4104];
ifstream fp_in(f.toRawUTF8(), ios::binary);
if (fp_in.fail()) {
FileInputStream *fis = cart.createInputStream();
if ( fis == NULL ) {
String f = cart.getFullPathName();
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Error",
"Unable to open: " + f);
}
uint8 syx_data[65535];
int sz = fis->read(syx_data, 65535);
delete fis;
if (syx_data[0] != 0xF0) {
String f = cart.getFullPathName();
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Error",
"File: " + f + " doesn't seems to contain any sysex data");
return;
}
fp_in.read((char *)syx_data, 4104);
fp_in.close();
sysexComm.send(MidiMessage(syx_data, 4104));
sysexComm.send(MidiMessage(syx_data, sz));
}
@ -285,6 +298,8 @@ void DexedAudioProcessor::getStateInformation(MemoryBlock& destData) {
dexedState.setAttribute("currentProgram", currentProgram);
dexedState.setAttribute("monoMode", monoMode);
dexedState.setAttribute("engineType", (int) engineType);
dexedState.setAttribute("masterTune", controllers.masterTune);
dexedState.setAttribute("opSwitch", controllers.opSwitch);
char mod_cfg[15];
controllers.wheel.setConfig(mod_cfg);
@ -324,6 +339,13 @@ void DexedAudioProcessor::setStateInformation(const void* source, int sizeInByte
fx.uiGain = root->getDoubleAttribute("gain");
currentProgram = root->getIntAttribute("currentProgram");
String opSwitchValue = root->getStringAttribute("opSwitch");
if ( opSwitchValue.length() != 6 ) {
strcpy(controllers.opSwitch, "111111");
} else {
strncpy(controllers.opSwitch, opSwitchValue.toRawUTF8(), 6);
}
controllers.wheel.parseConfig(root->getStringAttribute("wheelMod").toRawUTF8());
controllers.foot.parseConfig(root->getStringAttribute("footMod").toRawUTF8());
controllers.breath.parseConfig(root->getStringAttribute("breathMod").toRawUTF8());
@ -331,6 +353,7 @@ void DexedAudioProcessor::setStateInformation(const void* source, int sizeInByte
setEngineType(root->getIntAttribute("engineType", 1));
monoMode = root->getIntAttribute("monoMode", 0);
controllers.masterTune = root->getIntAttribute("masterTune", 0);
File possibleCartridge = File(root->getStringAttribute("activeFileCartridge"));
if ( possibleCartridge.exists() )

@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2014-2015 Pascal Gauthier.
* Copyright (c) 2014-2016 Pascal Gauthier.
*
* 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
@ -22,15 +22,16 @@
#define PLUGINDATA_H_INCLUDED
#include "../JuceLibraryCode/JuceHeader.h"
#define SYSEX_SIZE 4104
#include <stdint.h>
#include <string.h>
#include "Dexed.h"
uint8_t sysexChecksum(const uint8_t *sysex, int size);
void exportSysexPgm(uint8_t *dest, uint8_t *src);
#define SYSEX_HEADER { 0xF0, 0x43, 0x00, 0x00, 0x20, 0x00 }
#define SYSEX_HEADER { 0xF0, 0x43, 0x00, 0x09, 0x20, 0x00 }
#define SYSEX_SIZE 4104
class Cartridge {
uint8_t voiceData[SYSEX_SIZE];
@ -89,6 +90,11 @@ public:
return rc;
}
/**
* Loads sysex stream
* Returns 0 if it was parsed sucessfully
* Returns -1 if it cannot open the stream
*/
int load(InputStream &fis) {
uint8 buffer[65535];
int sz = fis.read(buffer, 65535);
@ -97,7 +103,17 @@ public:
return load(buffer, sz);
}
/**
* Loads sysex buffer
* Returns 0 if it was parsed sucessfully
* Returns 1 if sysex checksum didn't match
* Returns 2 if no sysex data found, probably random data
*/
int load(const uint8_t *stream, int size) {
const uint8 voiceHeaderBroken[] = { 0xF0, 0x43, 0x00, 0x00, 0x20, 0x00 };
// I've added a stupid bug that saved the wrong sysex data for dx7 sysex (0.9.1)
// This is there to support this version. One day we will be able to remove this. :(
uint8 voiceHeader[] = SYSEX_HEADER;
uint8 tmp[65535];
uint8 *pos = tmp;
@ -111,14 +127,14 @@ public:
while(size >= 4104) {
// random data
if ( pos[0] != 0xF0 ) {
if ( status != 0 )
if ( status != 3 )
return status;
memcpy(voiceData, pos+6, 4096);
return 2;
}
pos[3] = 0;
if ( memcmp(pos, voiceHeader, 6) == 0 ) {
if ( memcmp(pos, voiceHeader, 6) == 0 || memcmp(pos, voiceHeaderBroken, 6) == 0) {
memcpy(voiceData, pos, SYSEX_SIZE);
if ( sysexChecksum(voiceData + 6, 4096) == pos[4102] )
status = 0;
@ -139,12 +155,63 @@ public:
stream += i;
}
// nothing good has been found, map it then to random data
if ( status > 1 ) {
memcpy(voiceData, pos+6, 4096);
return 2;
}
return status;
}
int saveVoice(File f) {
setHeader();
return f.replaceWithData(voiceData, SYSEX_SIZE);
if ( ! f.existsAsFile() ) {
// file doesn't exists, create it
return f.replaceWithData(voiceData, SYSEX_SIZE);
}
FileInputStream *fis = f.createInputStream();
if ( fis == NULL )
return -1;
uint8 buffer[65535];
int sz = fis->read(buffer, 65535);
delete fis;
// if the file is smaller than 4104, it probably needs to be overriden.
if ( sz <= 4104 ) {
return f.replaceWithData(voiceData, SYSEX_SIZE);
}
// To avoid to erase the performance data, we skip the sysex stream until
// we see the header 0xF0, 0x43, 0x00, 0x09, 0x20, 0x00
int pos = 0;
bool found = 0;
while(pos < sz) {
// corrupted sysex, erase everything :
if ( buffer[pos] != 0xF0 )
return f.replaceWithData(voiceData, SYSEX_SIZE);
uint8_t header[] = SYSEX_HEADER;
if ( memcmp(buffer+pos, header, 6) ) {
found = true;
memcpy(buffer+pos, voiceData, SYSEX_SIZE);
break;
} else {
for(;pos<sz;pos++) {
if ( buffer[pos] == 0xF7 )
break;
}
}
}
if ( ! found )
return -1;
return f.replaceWithData(buffer, sz);
}
void saveVoice(uint8_t *sysex) {
@ -174,7 +241,7 @@ public:
}
void unpackProgram(uint8_t *unpackPgm, int idx);
void packProgram(uint8_t *src, int idx, String name);
void packProgram(uint8_t *src, int idx, String name, char *opSwitch);
};
#endif // PLUGINDATA_H_INCLUDED

@ -115,13 +115,23 @@ void DexedAudioProcessorEditor::cartShow() {
void DexedAudioProcessorEditor::loadCart(File file) {
Cartridge cart;
if ( cart.load(file) < 0 ) {
int rc = cart.load(file);
if ( rc < 0 ) {
AlertWindow::showMessageBoxAsync (AlertWindow::WarningIcon,
"Error",
"Unable to open: " + file.getFullPathName());
return;
}
if ( rc != 0 ) {
rc = AlertWindow::showOkCancelBox(AlertWindow::QuestionIcon, "Unable to find DX7 sysex cartridge in file",
"This sysex file is not for the DX7 or it is corrupted. "
"Do you still want to load this file as random data ?");
if ( rc == 0 )
return;
}
processor->loadCartridge(cart);
rebuildProgramCombobox();
processor->setCurrentProgram(0);
@ -297,7 +307,7 @@ void DexedAudioProcessorEditor::storeProgram() {
}
if ( externalFile == NULL ) {
processor->currentCart.packProgram((uint8_t *) processor->data, programNum, programName);
processor->currentCart.packProgram((uint8_t *) processor->data, programNum, programName, processor->controllers.opSwitch);
rebuildProgramCombobox();
processor->setCurrentProgram(programNum);
processor->updateHostDisplay();
@ -316,7 +326,7 @@ void DexedAudioProcessorEditor::storeProgram() {
processor->activeFileCartridge = destination;
}
} else {
destSysex.packProgram((uint8_t *) processor->data, programNum, programName);
destSysex.packProgram((uint8_t *) processor->data, programNum, programName, processor->controllers.opSwitch);
if ( ! destSysex.saveVoice(*externalFile)) {
AlertWindow::showMessageBoxAsync(AlertWindow::WarningIcon, "Write error", "Unable to write file");
}

@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2013-2015 Pascal Gauthier.
* Copyright (c) 2013-2016 Pascal Gauthier.
*
* 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
@ -31,11 +31,7 @@
//==============================================================================
/**
*/
class DexedAudioProcessorEditor : public AudioProcessorEditor,
public ComboBoxListener,
public Timer {
PopupMenu cartPopup;
class DexedAudioProcessorEditor : public AudioProcessorEditor, public ComboBoxListener, public Timer {
MidiKeyboardComponent midiKeyboard;
OperatorEditor operators[6];
Colour background;

@ -81,6 +81,10 @@ void PluginFx::init(int sr) {
pCutoff = -1;
pReso = -1;
dc_r = 1.0-(126.0/sr);
dc_id = 0;
dc_od = 0;
}
inline float PluginFx::NR24(float sample,float g,float lpc) {
@ -97,6 +101,18 @@ inline float PluginFx::NR(float sample, float g) {
}
void PluginFx::process(float *work, int sampleSize) {
// very basic DC filter
float t_fd = work[0];
work[0] = work[0] - dc_id + dc_r * dc_od;
dc_id = t_fd;
for (int i=1; i<sampleSize; i++) {
t_fd = work[i];
work[i] = work[i] - dc_id + dc_r * work[i-1];
dc_id = t_fd;
}
dc_od = work[sampleSize-1];
if ( uiGain != 1 ) {
for(int i=0; i < sampleSize; i++ )
work[i] *= uiGain;

@ -55,6 +55,10 @@ class PluginFx {
float rcor,rcorInv;
int R;
float dc_id;
float dc_od;
float dc_r;
public:
PluginFx();

@ -1,6 +1,6 @@
/**
*
* Copyright (c) 2013-2015 Pascal Gauthier.
* Copyright (c) 2013-2016 Pascal Gauthier.
*
* 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
@ -49,8 +49,6 @@ public:
String getValueDisplay() {
String ret;
int value = getValue();
if ( value == 48 )
value = 47;
switch(value % 12) {
case 0: ret << "C"; break;
@ -70,6 +68,76 @@ public:
}
};
class CtrlTune : public Ctrl {
public:
DexedAudioProcessor *processor;
CtrlTune(String name, DexedAudioProcessor *owner) : Ctrl(name) {
processor = owner;
}
float getValueHost() {
// meh. good enough for now
int32_t tune = processor->controllers.masterTune / (1.0/12);
tune = (tune >> 11) + 0x2000;
return (float)tune / 0x4000;
}
void setValueHost(float v) {
int32_t tune = (v * 0x4000) - 0x2000;
processor->controllers.masterTune = ((float) (tune << 11)) * (1.0/12);
}
String getValueDisplay() {
String display;
display << (getValueHost() * 2) -1;
return display;
}
void updateComponent() {
if (slider != NULL) {
slider->setValue(getValueHost(), dontSendNotification);
}
}
};
class CtrlOpSwitch : public Ctrl {
char *value;
public :
CtrlOpSwitch(String name, char *switchValue) : Ctrl(name) {
value = switchValue;
}
void setValueHost(float f) {
if ( f == 0 )
*value = '0';
else
*value = '1';
}
float getValueHost() {
if ( *value == '0' )
return 0;
else
return 1;
}
String getValueDisplay() {
String ret;
ret << label << " " << (*value == '0' ? "OFF" : "ON");
return ret;
}
void updateComponent() {
if (button != NULL) {
if (*value == '0') {
button->setToggleState(false, dontSendNotification);
} else {
button->setToggleState(true, dontSendNotification);
}
}
}
};
// ************************************************************************
//
@ -186,17 +254,11 @@ float CtrlDX::getValueHost() {
}
void CtrlDX::setValueHost(float f) {
if ( f == 1 )
f = 0.999;
setValue((f * steps));
setValue(roundToInt(f * steps));
}
void CtrlDX::setValue(int v) {
TRACE("setting value %d %d", dxOffset, v);
if (v >= steps) {
TRACE("WARNING: value too big %s : %d", label.toRawUTF8(), v);
v = steps - 1;
}
dxValue = v;
if (dxOffset >= 0) {
if (parent != NULL)
@ -288,28 +350,31 @@ void DexedAudioProcessor::initCtrl() {
output = new CtrlFloat("Output", &fx.uiGain);
ctrl.add(output);
algo = new CtrlDX("ALGORITHM", 32, 134, 1);
tune = new CtrlTune("MASTER TUNE ADJ", this);
ctrl.add(tune);
algo = new CtrlDX("ALGORITHM", 31, 134, 1);
ctrl.add(algo);
feedback = new CtrlDX("FEEDBACK", 8, 135);
feedback = new CtrlDX("FEEDBACK", 7, 135);
ctrl.add(feedback);
oscSync = new CtrlDX("OSC KEY SYNC", 2, 136);
oscSync = new CtrlDX("OSC KEY SYNC", 1, 136);
ctrl.add(oscSync);
lfoRate = new CtrlDX("LFO SPEED", 100, 137);
lfoRate = new CtrlDX("LFO SPEED", 99, 137);
ctrl.add(lfoRate);
lfoDelay = new CtrlDX("LFO DELAY", 100, 138);
lfoDelay = new CtrlDX("LFO DELAY", 99, 138);
ctrl.add(lfoDelay);
lfoPitchDepth = new CtrlDX("LFO PM DEPTH", 100, 139);
lfoPitchDepth = new CtrlDX("LFO PM DEPTH", 99, 139);
ctrl.add(lfoPitchDepth);
lfoAmpDepth = new CtrlDX("LFO AM DEPTH", 100, 140);
lfoAmpDepth = new CtrlDX("LFO AM DEPTH", 99, 140);
ctrl.add(lfoAmpDepth);
lfoSync = new CtrlDX("LFO KEY SYNC", 2, 141);
lfoSync = new CtrlDX("LFO KEY SYNC", 1, 141);
ctrl.add(lfoSync);
StringArray lbl;
@ -320,26 +385,26 @@ void DexedAudioProcessor::initCtrl() {
lbl.add("SINE");
lbl.add("S&HOLD");
lfoWaveform = new CtrlDXLabel("LFO WAVE", 6, 142, lbl);
lfoWaveform = new CtrlDXLabel("LFO WAVE", 5, 142, lbl);
ctrl.add(lfoWaveform);
transpose = new CtrlDXTranspose("MIDDLE C", 49, 144);
transpose = new CtrlDXTranspose("MIDDLE C", 48, 144);
ctrl.add(transpose);
pitchModSens = new CtrlDX("P MODE SENS.", 8, 143);
pitchModSens = new CtrlDX("P MODE SENS.", 7, 143);
ctrl.add(pitchModSens);
for (int i=0;i<4;i++) {
String rate;
rate << "PITCH EG RATE " << (i+1);
pitchEgRate[i] = new CtrlDX(rate, 100, 126+i);
pitchEgRate[i] = new CtrlDX(rate, 99, 126+i);
ctrl.add(pitchEgRate[i]);
}
for (int i=0;i<4;i++) {
String level;
level << "PITCH EG LEVEL " << (i+1);
pitchEgLevel[i] = new CtrlDX(level, 100, 130+i);
pitchEgLevel[i] = new CtrlDX(level, 99, 130+i);
ctrl.add(pitchEgLevel[i]);
}
@ -360,81 +425,86 @@ void DexedAudioProcessor::initCtrl() {
for (int j = 0; j < 4; j++) {
String opRate;
opRate << opName << " EG RATE " << (j + 1);
opCtrl[opVal].egRate[j] = new CtrlDX(opRate, 100, opTarget + j);
opCtrl[opVal].egRate[j] = new CtrlDX(opRate, 99, opTarget + j);
ctrl.add(opCtrl[opVal].egRate[j]);
}
for (int j = 0; j < 4; j++) {
String opLevel;
opLevel << opName << " EG LEVEL " << (j + 1);
opCtrl[opVal].egLevel[j] = new CtrlDX(opLevel, 100, opTarget + j + 4);
opCtrl[opVal].egLevel[j] = new CtrlDX(opLevel, 99, opTarget + j + 4);
ctrl.add(opCtrl[opVal].egLevel[j]);
}
String opVol;
opVol << opName << " OUTPUT LEVEL";
opCtrl[opVal].level = new CtrlDX(opVol, 100, opTarget + 16);
opCtrl[opVal].level = new CtrlDX(opVol, 99, opTarget + 16);
ctrl.add(opCtrl[opVal].level);
String opMode;
opMode << opName << " MODE";
opCtrl[opVal].opMode = new CtrlDX(opMode, 2, opTarget + 17);
opCtrl[opVal].opMode = new CtrlDX(opMode, 1, opTarget + 17);
ctrl.add(opCtrl[opVal].opMode);
String coarse;
coarse << opName << " F COARSE";
opCtrl[opVal].coarse = new CtrlDX(coarse, 32, opTarget + 18);
opCtrl[opVal].coarse = new CtrlDX(coarse, 31, opTarget + 18);
ctrl.add(opCtrl[opVal].coarse);
String fine;
fine << opName << " F FINE";
opCtrl[opVal].fine = new CtrlDX(fine, 100, opTarget + 19);
opCtrl[opVal].fine = new CtrlDX(fine, 99, opTarget + 19);
ctrl.add(opCtrl[opVal].fine);
String detune;
detune << opName << " OSC DETUNE";
opCtrl[opVal].detune = new CtrlDX(detune, 15, opTarget + 20, -7);
opCtrl[opVal].detune = new CtrlDX(detune, 14, opTarget + 20, -7);
ctrl.add(opCtrl[opVal].detune);
String sclBrkPt;
sclBrkPt << opName << " BREAK POINT";
opCtrl[opVal].sclBrkPt = new CtrlDX(sclBrkPt, 100, opTarget + 8);
opCtrl[opVal].sclBrkPt = new CtrlDX(sclBrkPt, 99, opTarget + 8);
ctrl.add(opCtrl[opVal].sclBrkPt);
String sclLeftDepth;
sclLeftDepth << opName << " L SCALE DEPTH";
opCtrl[opVal].sclLeftDepth = new CtrlDX(sclLeftDepth, 100, opTarget + 9);
opCtrl[opVal].sclLeftDepth = new CtrlDX(sclLeftDepth, 99, opTarget + 9);
ctrl.add(opCtrl[opVal].sclLeftDepth);
String sclRightDepth;
sclRightDepth << opName << " R SCALE DEPTH";
opCtrl[opVal].sclRightDepth = new CtrlDX(sclRightDepth, 100, opTarget + 10);
opCtrl[opVal].sclRightDepth = new CtrlDX(sclRightDepth, 99, opTarget + 10);
ctrl.add(opCtrl[opVal].sclRightDepth);
String sclLeftCurve;
sclLeftCurve << opName << " L KEY SCALE";
opCtrl[opVal].sclLeftCurve = new CtrlDXLabel(sclLeftCurve, 4, opTarget + 11, keyScaleLabels);
opCtrl[opVal].sclLeftCurve = new CtrlDXLabel(sclLeftCurve, 3, opTarget + 11, keyScaleLabels);
ctrl.add(opCtrl[opVal].sclLeftCurve);
String sclRightCurve;
sclRightCurve << opName << " R KEY SCALE";
opCtrl[opVal].sclRightCurve = new CtrlDXLabel(sclRightCurve, 4, opTarget + 12, keyScaleLabels);
opCtrl[opVal].sclRightCurve = new CtrlDXLabel(sclRightCurve, 3, opTarget + 12, keyScaleLabels);
ctrl.add(opCtrl[opVal].sclRightCurve);
String sclRate;
sclRate << opName << " RATE SCALING";
opCtrl[opVal].sclRate = new CtrlDX(sclRate, 8, opTarget + 13);
opCtrl[opVal].sclRate = new CtrlDX(sclRate, 7, opTarget + 13);
ctrl.add(opCtrl[opVal].sclRate);
String ampModSens;
ampModSens << opName << " A MOD SENS.";
opCtrl[opVal].ampModSens = new CtrlDX(ampModSens, 4, opTarget + 14);
opCtrl[opVal].ampModSens = new CtrlDX(ampModSens, 3, opTarget + 14);
ctrl.add(opCtrl[opVal].ampModSens);
String velModSens;
velModSens << opName << " KEY VELOCITY";
opCtrl[opVal].velModSens = new CtrlDX(velModSens, 8, opTarget + 15);
opCtrl[opVal].velModSens = new CtrlDX(velModSens, 7, opTarget + 15);
ctrl.add(opCtrl[opVal].velModSens);
String opSwitchLabel;
opSwitchLabel << opName << " SWITCH";
opCtrl[opVal].opSwitch = new CtrlOpSwitch(opSwitchLabel, (char *)&(controllers.opSwitch)+(5-i));
ctrl.add(opCtrl[opVal].opSwitch);
}
for (int i=0; i < ctrl.size(); i++) {
@ -513,6 +583,7 @@ void DexedAudioProcessor::setCurrentProgram(int index) {
index = index > 31 ? 31 : index;
currentCart.unpackProgram(data, index);
strcpy(controllers.opSwitch, "111111");
lfo.reset(data + 137);
currentProgram = index;
triggerAsyncUpdate();
@ -632,4 +703,3 @@ void DexedAudioProcessor::savePreference() {
prop.save();
}

@ -121,6 +121,7 @@ struct OperatorCtrl {
ScopedPointer<CtrlDX> sclRate;
ScopedPointer<CtrlDX> ampModSens;
ScopedPointer<CtrlDX> velModSens;
ScopedPointer<Ctrl> opSwitch;
};
#endif // PLUGINPARAM_H_INCLUDED

@ -54,6 +54,8 @@ DexedAudioProcessor::DexedAudioProcessor() {
resolvAppDir();
TRACE("controler %s", controllers.opSwitch);
initCtrl();
sendSysexChange = true;
normalizeDxVelocity = false;
@ -61,10 +63,12 @@ DexedAudioProcessor::DexedAudioProcessor() {
showKeyboard = true;
memset(&voiceStatus, 0, sizeof(VoiceStatus));
setEngineType(DEXED_ENGINE_MODERN);
setEngineType(DEXED_ENGINE_MARKI);
controllers.values_[kControllerPitchRange] = 3;
controllers.values_[kControllerPitchStep] = 0;
controllers.masterTune = 0;
loadPreference();
for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) {
@ -199,7 +203,7 @@ void DexedAudioProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& mi
val = val >> 4;
int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9;
float f = ((float) clip_val) / (float) 32768;
float f = ((float) clip_val) / (float) 0x8000;
if( f > 1 ) f = 1;
if( f < -1 ) f = -1;
sumbuf[j] += f;
@ -319,7 +323,6 @@ void DexedAudioProcessor::processMidiMessage(const MidiMessage *msg) {
controllers.values_[kControllerPitch] = buf[1] | (buf[2] << 7);
break;
}
}
void DexedAudioProcessor::keydown(uint8_t pitch, uint8_t velo) {

@ -155,6 +155,7 @@ public :
ScopedPointer<CtrlFloat> fxCutoff;
ScopedPointer<CtrlFloat> fxReso;
ScopedPointer<CtrlFloat> output;
ScopedPointer<Ctrl> tune;
void loadCartridge(Cartridge &cart);
void setDxValue(int offset, int v);

@ -29,6 +29,7 @@ ProgramListBox::ProgramListBox(const String name, int numCols) : Component(name)
selectedPgm = -1;
hasContent = false;
dragCandidate = -1;
pgmCandidate = -1;
readOnly = false;
programNames.clear();
}
@ -101,29 +102,36 @@ int ProgramListBox::programPosition(int x, int y) {
return (y / cellHeight) + ((x / cellWidth) * rows);
}
void ProgramListBox::mouseDoubleClick(const MouseEvent &event) {
void ProgramListBox::mouseDown(const MouseEvent &event) {
pgmCandidate = -1;
if ( ! hasContent )
return;
if ( ! event.mods.isLeftButtonDown() )
if ( event.mods.isRightButtonDown() ) {
int pos = programPosition(event.getMouseDownX(), event.getMouseDownY());
if ( listener != nullptr )
listener->programRightClicked(this, pos);
return;
}
int pos = programPosition(event.getMouseDownX(), event.getMouseDownY());
if ( listener != nullptr )
listener->programSelected(this, pos);
pgmCandidate = programPosition(event.getMouseDownX(), event.getMouseDownY());
}
void ProgramListBox::mouseDown(const MouseEvent &event) {
if ( ! hasContent )
return;
if ( ! event.mods.isRightButtonDown() )
void ProgramListBox::mouseUp(const MouseEvent &event) {
if ( pgmCandidate == -1 )
return;
int pos = programPosition(event.getMouseDownX(), event.getMouseDownY());
if ( listener != nullptr )
listener->programRightClicked(this, pos);
if ( pgmCandidate == pos) {
if ( listener != nullptr )
listener->programSelected(this, pgmCandidate);
pgmCandidate = -1;
}
}
void ProgramListBox::mouseDrag(const MouseEvent &event) {
pgmCandidate = -1;
if ( ! hasContent )
return;
if ( dragCandidate != -1 )

@ -45,6 +45,7 @@ class ProgramListBox : public Component, public DragAndDropTarget {
Cartridge cartContent;
int dragCandidate;
int pgmCandidate;
public:
StringArray programNames;
@ -54,9 +55,9 @@ public:
void addListener(ProgramListBoxListener *listener);
void paint(Graphics &g) override;
void resized() override;
void mouseDoubleClick(const MouseEvent &event) override;
void mouseDown(const MouseEvent &event) override;
void mouseDrag(const MouseEvent &event) override;
void mouseUp(const MouseEvent &event) override;
void setSelected(int idx);
Cartridge &getCurrentCart();

@ -20,6 +20,7 @@
#include "synth.h"
#include "../Dexed.h"
#include <stdio.h>
#include <string.h>
#ifdef _WIN32
#define snprintf _snprintf
@ -77,6 +78,8 @@ class Controllers {
public:
int values_[131];
char opSwitch[7];
int amp_mod;
int pitch_mod;
int eg_mod;
@ -86,6 +89,8 @@ public:
int foot_cc;
int modwheel_cc;
int masterTune;
FmMod wheel;
FmMod foot;
FmMod breath;
@ -95,6 +100,7 @@ public:
amp_mod = 0;
pitch_mod = 0;
eg_mod = 0;
strcpy(opSwitch, "111111");
}
void refresh() {

@ -202,6 +202,7 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
}
}
pitch_mod += pb;
pitch_mod += ctrls->masterTune;
// ==== AMP MOD ====
uint32_t amod_1 = ((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8; // Q24 :D
@ -215,19 +216,24 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
// ==== OP RENDER ====
for (int op = 0; op < 6; op++) {
//int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_mod);
if ( ctrls->opSwitch[op] == '0' ) {
env_[op].getsample(); // advance the envelop even if it is not playing
params_[op].level_in = 0;
} else {
//int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitch_mod);
int32_t level = env_[op].getsample();
if (ampmodsens_[op] != 0) {
uint32_t sensamp = ((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24;
int32_t level = env_[op].getsample();
if (ampmodsens_[op] != 0) {
uint32_t sensamp = ((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24;
// TODO: mehhh.. this needs some real tuning.
uint32_t pt = exp(((float)sensamp)/262144 * 0.07 + 12.2);
uint32_t ldiff = ((uint64_t)level) * (((uint64_t)pt<<4)) >> 28;
level -= ldiff;
// TODO: mehhh.. this needs some real tuning.
uint32_t pt = exp(((float)sensamp)/262144 * 0.07 + 12.2);
uint32_t ldiff = ((uint64_t)level) * (((uint64_t)pt<<4)) >> 28;
level -= ldiff;
}
params_[op].level_in = level;
}
params_[op].level_in = level;
}
ctrls->core->render(buf, params_, algorithm_, fb_buf_, fb_shift_);
}
@ -235,8 +241,8 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co
void Dx7Note::keyup() {
for (int op = 0; op < 6; op++) {
env_[op].keydown(false);
pitchenv_.keydown(false);
}
pitchenv_.keydown(false);
}
void Dx7Note::update(const uint8_t patch[156], int midinote, int fb_depth) {

@ -30,9 +30,9 @@ const FmAlgorithm FmCore::algorithms[32] = {
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
{ { 0xc1, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4 ** EXCEPTION VIA CODE
{ { 0xc1, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
{ { 0xc1, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6 ** EXCEPTION VIA CODE
{ { 0xc1, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9

Loading…
Cancel
Save