Engin resolution + am implementation

pull/1/head
asb2m10 10 years ago
parent 77fa26a066
commit 05cd3aeba9
  1. 4742
      Builds/MacOSX/Dexed.xcodeproj/project.pbxproj
  2. BIN
      Builds/MacOSX/Dexed.xcodeproj/project.xcworkspace/xcuserdata/asb2m10.xcuserdatad/UserInterfaceState.xcuserstate
  3. 12
      Builds/VisualStudio2012/Dexed.sln
  4. 1081
      Builds/VisualStudio2012/Dexed.vcxproj
  5. 119
      Builds/VisualStudio2012/Dexed.vcxproj.filters
  6. 38
      README.md
  7. 4
      Source/Dexed.h
  8. 82
      Source/ParamDialog.cpp
  9. 5
      Source/ParamDialog.h
  10. 9
      Source/PluginEditor.cpp
  11. 5
      Source/PluginParam.cpp
  12. 40
      Source/PluginProcessor.cpp
  13. 10
      Source/PluginProcessor.h
  14. 5
      Source/msfa/controllers.h
  15. 529
      Source/msfa/dx7note.cc
  16. 147
      Source/msfa/dx7note.h
  17. 303
      Source/msfa/fm_core.cc
  18. 78
      Source/msfa/fm_core.h
  19. 573
      Source/msfa/fm_op_kernel.cc
  20. 77
      Source/msfa/fm_op_kernel.h

File diff suppressed because it is too large Load Diff

@ -1,23 +1,17 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio Express 2012 for Windows Desktop # Visual Studio 2012
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Dexed", "Dexed.vcxproj", "{1A9EF105-5BF5-9FB6-9634-A91A6D840866}" Project("{BD26B4C3-163D-4785-A63F-D3E66858BFF3}") = "Dexed", "Dexed.vcxproj", "{1A9EF105-5BF5-9FB6-9634-A91A6D840866}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
Debug|x64 = Debug|x64
Release|Win32 = Release|Win32 Release|Win32 = Release|Win32
Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Debug|Win32.ActiveCfg = Debug|Win32 {1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Debug|Win32.ActiveCfg = Debug|Win32
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Debug|Win32.Build.0 = Debug|Win32 {1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Debug|Win32.Build.0 = Debug|Win32
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Debug|x64.ActiveCfg = Debug|x64
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Debug|x64.Build.0 = Debug|x64
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Release|Win32.ActiveCfg = Release|Win32 {1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Release|Win32.ActiveCfg = Release|Win32
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Release|Win32.Build.0 = Release|Win32 {1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Release|Win32.Build.0 = Release|Win32
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Release|x64.ActiveCfg = Release|x64
{1A9EF105-5BF5-9FB6-9634-A91A6D840866}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

File diff suppressed because it is too large Load Diff

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup> <ItemGroup>
<Filter Include="Dexed"> <Filter Include="Dexed">
@ -384,6 +385,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\synthesisers\juce_Synthesiser.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_basics\synthesisers\juce_Synthesiser.cpp">
<Filter>Juce Modules\juce_audio_basics\synthesisers</Filter> <Filter>Juce Modules\juce_audio_basics\synthesisers</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AU\juce_AU_Wrapper.mm">
<Filter>Juce Modules\juce_audio_plugin_client\AU</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode1.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode1.cpp">
<Filter>Juce Modules\juce_audio_plugin_client\RTAS</Filter> <Filter>Juce Modules\juce_audio_plugin_client\RTAS</Filter>
</ClCompile> </ClCompile>
@ -399,15 +403,27 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_Wrapper.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_Wrapper.cpp">
<Filter>Juce Modules\juce_audio_plugin_client\RTAS</Filter> <Filter>Juce Modules\juce_audio_plugin_client\RTAS</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_MacUtilities.mm">
<Filter>Juce Modules\juce_audio_plugin_client\RTAS</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp">
<Filter>Juce Modules\juce_audio_plugin_client\VST</Filter> <Filter>Juce Modules\juce_audio_plugin_client\VST</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.mm">
<Filter>Juce Modules\juce_audio_plugin_client\VST</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.cpp">
<Filter>Juce Modules\juce_audio_plugin_client\VST3</Filter> <Filter>Juce Modules\juce_audio_plugin_client\VST3</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.mm">
<Filter>Juce Modules\juce_audio_plugin_client\VST3</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.cpp">
<Filter>Juce Modules\juce_audio_plugin_client\AAX</Filter> <Filter>Juce Modules\juce_audio_plugin_client\AAX</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.mm">
<Filter>Juce Modules\juce_audio_plugin_client\AAX</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\utility\juce_PluginUtilities.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\utility\juce_PluginUtilities.cpp">
<Filter>Juce Modules\juce_audio_plugin_client\utility</Filter> <Filter>Juce Modules\juce_audio_plugin_client\utility</Filter>
</ClCompile> </ClCompile>
@ -432,6 +448,9 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\format\juce_AudioPluginFormatManager.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\format\juce_AudioPluginFormatManager.cpp">
<Filter>Juce Modules\juce_audio_processors\format</Filter> <Filter>Juce Modules\juce_audio_processors\format</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\juce_AudioUnitPluginFormat.mm">
<Filter>Juce Modules\juce_audio_processors\format_types</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\juce_LADSPAPluginFormat.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_processors\format_types\juce_LADSPAPluginFormat.cpp">
<Filter>Juce Modules\juce_audio_processors\format_types</Filter> <Filter>Juce Modules\juce_audio_processors\format_types</Filter>
</ClCompile> </ClCompile>
@ -672,6 +691,21 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_linux_Threads.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_linux_Threads.cpp">
<Filter>Juce Modules\juce_core\native</Filter> <Filter>Juce Modules\juce_core\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_mac_Files.mm">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_mac_Network.mm">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_mac_Strings.mm">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_mac_SystemStats.mm">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_mac_Threads.mm">
<Filter>Juce Modules\juce_core\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_posix_NamedPipe.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_core\native\juce_posix_NamedPipe.cpp">
<Filter>Juce Modules\juce_core\native</Filter> <Filter>Juce Modules\juce_core\native</Filter>
</ClCompile> </ClCompile>
@ -744,9 +778,15 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_android_Messaging.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_android_Messaging.cpp">
<Filter>Juce Modules\juce_events\native</Filter> <Filter>Juce Modules\juce_events\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_ios_MessageManager.mm">
<Filter>Juce Modules\juce_events\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_linux_Messaging.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_linux_Messaging.cpp">
<Filter>Juce Modules\juce_events\native</Filter> <Filter>Juce Modules\juce_events\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_mac_MessageManager.mm">
<Filter>Juce Modules\juce_events\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_win32_Messaging.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_events\native\juce_win32_Messaging.cpp">
<Filter>Juce Modules\juce_events\native</Filter> <Filter>Juce Modules\juce_events\native</Filter>
</ClCompile> </ClCompile>
@ -846,6 +886,12 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_graphics\native\juce_linux_Fonts.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_graphics\native\juce_linux_Fonts.cpp">
<Filter>Juce Modules\juce_graphics\native</Filter> <Filter>Juce Modules\juce_graphics\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_graphics\native\juce_mac_CoreGraphicsContext.mm">
<Filter>Juce Modules\juce_graphics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_graphics\native\juce_mac_Fonts.mm">
<Filter>Juce Modules\juce_graphics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_graphics\native\juce_win32_Direct2DGraphicsContext.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_graphics\native\juce_win32_Direct2DGraphicsContext.cpp">
<Filter>Juce Modules\juce_graphics\native</Filter> <Filter>Juce Modules\juce_graphics\native</Filter>
</ClCompile> </ClCompile>
@ -1194,6 +1240,12 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_android_Windowing.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_android_Windowing.cpp">
<Filter>Juce Modules\juce_gui_basics\native</Filter> <Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_ios_UIViewComponentPeer.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_ios_Windowing.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_linux_Clipboard.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_linux_Clipboard.cpp">
<Filter>Juce Modules\juce_gui_basics\native</Filter> <Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile> </ClCompile>
@ -1203,6 +1255,21 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_linux_Windowing.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_linux_Windowing.cpp">
<Filter>Juce Modules\juce_gui_basics\native</Filter> <Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_mac_FileChooser.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_mac_MainMenu.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_mac_MouseCursor.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_mac_NSViewComponentPeer.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_mac_Windowing.mm">
<Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_win32_DragAndDrop.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_basics\native\juce_win32_DragAndDrop.cpp">
<Filter>Juce Modules\juce_gui_basics\native</Filter> <Filter>Juce Modules\juce_gui_basics\native</Filter>
</ClCompile> </ClCompile>
@ -1257,15 +1324,27 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_android_WebBrowserComponent.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_android_WebBrowserComponent.cpp">
<Filter>Juce Modules\juce_gui_extra\native</Filter> <Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_ios_UIViewComponent.mm">
<Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_linux_SystemTrayIcon.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_linux_SystemTrayIcon.cpp">
<Filter>Juce Modules\juce_gui_extra\native</Filter> <Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_linux_WebBrowserComponent.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_linux_WebBrowserComponent.cpp">
<Filter>Juce Modules\juce_gui_extra\native</Filter> <Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_mac_AppleRemote.mm">
<Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_mac_NSViewComponent.mm">
<Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_mac_SystemTrayIcon.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_mac_SystemTrayIcon.cpp">
<Filter>Juce Modules\juce_gui_extra\native</Filter> <Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_mac_WebBrowserComponent.mm">
<Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_win32_ActiveXComponent.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_gui_extra\native\juce_win32_ActiveXComponent.cpp">
<Filter>Juce Modules\juce_gui_extra\native</Filter> <Filter>Juce Modules\juce_gui_extra\native</Filter>
</ClCompile> </ClCompile>
@ -1338,42 +1417,6 @@
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp"> <ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp">
<Filter>Juce Library Code</Filter> <Filter>Juce Library Code</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\utility\juce_PluginUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode1.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode2.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode3.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_WinUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\utility\juce_PluginUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode1.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode2.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode3.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_WinUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\utility\juce_PluginUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode1.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode2.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode3.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_WinUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\AAX\juce_AAX_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\utility\juce_PluginUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode1.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode2.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_DigiCode3.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_WinUtilities.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\RTAS\juce_RTAS_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST3\juce_VST3_Wrapper.cpp" />
<ClCompile Include="..\..\JuceLibraryCode\modules\juce_audio_plugin_client\VST\juce_VST_Wrapper.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\Source\Dexed.h"> <ClInclude Include="..\..\Source\Dexed.h">
@ -2671,4 +2714,4 @@
<Filter>Juce Library Code</Filter> <Filter>Juce Library Code</Filter>
</ResourceCompile> </ResourceCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -33,11 +33,13 @@ new version here but you see it in the change log, it's because this version is
* Version 0.6.0 [vst win32/x64](http://le-son666.com/software/dexed/dexed-0.6.0-win.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.6.0-osx.vst.zip) * Version 0.6.0 [vst win32/x64](http://le-son666.com/software/dexed/dexed-0.6.0-win.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.6.0-osx.vst.zip)
* Version 0.5.1 [vst win32](http://le-son666.com/software/dexed/dexed-0.5.1-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.5.1-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.5.1-osx.vst.zip) * Version 0.5.1 [vst win32](http://le-son666.com/software/dexed/dexed-0.5.1-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.5.1-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.5.1-osx.vst.zip)
* Version 0.5.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.5.0a-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.5.0a-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.5.0-osx.vst.zip) * Version 0.5.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.5.0a-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.5.0a-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.5.0-osx.vst.zip)
* Version 0.4.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.4.0-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.4.0-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.4.0-osx.vst.zip)
* Version 0.3.0 [vst win32](http://le-son666.com/software/dexed/dexed-0.3.0-win32.zip) - [vst win64](http://le-son666.com/software/dexed/dexed-0.3.0-win64.zip) - [vst os x](http://le-son666.com/software/dexed/dexed-0.3.0-osx.vst.zip)
Changelog Changelog
--------- ---------
#### Version 0.7.0 (current sprint)
* DX Engine customizable bitrate engine
* DX Engine AM implementation
#### Version 0.6.1 #### Version 0.6.1
* Mouse over + LFO type fix + pitch eg values * Mouse over + LFO type fix + pitch eg values
@ -49,20 +51,6 @@ Changelog
* Knobs now works with vertical mouse drags * Knobs now works with vertical mouse drags
* User DX7 zip cartridges * User DX7 zip cartridges
#### Version 0.5.1
* Fix distortion issue with FL (DAW blocksize not multiple of 64)
* OS X 64bit build (the VST package contains both 32bit and 64bit)
#### Version 0.5.0
* Linux support
* Fix large DAW blocksize with midi events
#### Version 0.4.0
* Modulation wheel support
* Now using the [Obxd](https://obxd.wordpress.com) 4-pole lowpass filter implementation
* Pitchbend range / step
* Output/Volume VU status
User DX7 zip cartridges User DX7 zip cartridges
----------------------- -----------------------
It is possible to enjoy your DX7 sysex collection from one single zip file. Simply move your zipped It is possible to enjoy your DX7 sysex collection from one single zip file. Simply move your zipped
@ -71,6 +59,23 @@ sysex content to where you have installed Dexed (VST plugins dir). Then rename t
file is changed. Directories in the zip file will be transformed into submenu when you hit the file is changed. Directories in the zip file will be transformed into submenu when you hit the
[CART] button. Watch out; Windows hides the .zip extension by default ! [CART] button. Watch out; Windows hides the .zip extension by default !
Engine resolutions
------------------
Dexed can be configured to try to use the original math limitation of a DX synthesizer. And when I say
math limitation, I'm not only talking about the DAC, it is also about the sin LUT lookup table, multiply
resolution and original DX sampling rate. This is a work in progress and this might take time to be able
to perfect.
If you look at the original DX7 and implementation a DX engine with 10-bit sin lookup and 12 mul possibility,
you get something "not quite there". Yamaha did a lot of hacks to be able to squeeze this into something
musical and expressive. It is those 'hacks' that we need to recreate to be able to find that original
DX sound.
Dexed comes with 3 engine resolution.
* Modern : this is the original 24-bit music-synthesizer-for-android implementation.
* Mark I : this is a pale implementation of the limitation of a Yamaha DX7 Mark I with the 12-bit (with the 4-bit attenuator hack) DAC.
* OPL Series : this is a experimental implementation of Yamaha 4-ops that used the YM2151 chip. These chips were supposed to be even more limited to the DX7 but gave a very interesting distinctive sound.
Using as a DX7 editor Using as a DX7 editor
--------------------- ---------------------
You can use this plugin to edit your real DX7 patchs. Since midi sysex send/receive are quirky for the You can use this plugin to edit your real DX7 patchs. Since midi sysex send/receive are quirky for the
@ -142,5 +147,4 @@ TODO - msfa
----------- -----------
* The sample rate should not change the response of the envelopes * The sample rate should not change the response of the envelopes
* Portamento implementation * Portamento implementation
* LFO/Mod-wheel amplitude
* Algo 4 & 6 feedback * Algo 4 & 6 feedback

@ -24,14 +24,14 @@
void dexed_trace(const char *source, const char *fmt, ...); void dexed_trace(const char *source, const char *fmt, ...);
#ifdef DEBUG #ifdef DEBUG
#define DEXED_VERSION "0.6.1 DEBUG" #define DEXED_VERSION "0.7.0 BETA DEBUG"
#ifdef _MSC_VER #ifdef _MSC_VER
#define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__) #define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__)
#else #else
#define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__) #define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__)
#endif #endif
#else #else
#define DEXED_VERSION "0.6.1" #define DEXED_VERSION "0.7.0 BETA"
#define TRACE(fmt, ...) #define TRACE(fmt, ...)
#endif #endif

@ -62,11 +62,21 @@ ParamDialog::ParamDialog ()
sysexChl->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20); sysexChl->setTextBoxStyle (Slider::TextBoxLeft, false, 80, 20);
sysexChl->addListener (this); sysexChl->addListener (this);
addAndMakeVisible (engineReso = new ComboBox ("new combo box"));
engineReso->setEditableText (false);
engineReso->setJustificationType (Justification::centredLeft);
engineReso->setTextWhenNothingSelected (String::empty);
engineReso->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
engineReso->addItem (TRANS("Modern (Direct)"), 1);
engineReso->addItem (TRANS("Mark I"), 2);
engineReso->addItem (TRANS("OPL Series"), 3);
engineReso->addListener (this);
//[UserPreSize] //[UserPreSize]
//[/UserPreSize] //[/UserPreSize]
setSize (330, 300); setSize (350, 350);
//[Constructor] You can add your own custom stuff here.. //[Constructor] You can add your own custom stuff here..
@ -95,6 +105,7 @@ ParamDialog::~ParamDialog()
sysexIn = nullptr; sysexIn = nullptr;
sysexOut = nullptr; sysexOut = nullptr;
sysexChl = nullptr; sysexChl = nullptr;
engineReso = nullptr;
//[Destructor]. You can add your own custom destruction code here.. //[Destructor]. You can add your own custom destruction code here..
@ -124,32 +135,45 @@ void ParamDialog::paint (Graphics& g)
g.setColour (Colours::white); g.setColour (Colours::white);
g.setFont (Font (15.00f, Font::plain)); g.setFont (Font (15.00f, Font::plain));
g.drawText (TRANS("DX7 In"), g.drawText (TRANS("DX7 In"),
20, 178, 131, 23, 28, 226, 131, 23,
Justification::centredLeft, true); Justification::centredLeft, true);
g.setColour (Colours::white); g.setColour (Colours::white);
g.setFont (Font (15.00f, Font::plain)); g.setFont (Font (15.00f, Font::plain));
g.drawText (TRANS("DX7 Out"), g.drawText (TRANS("DX7 Out"),
19, 218, 131, 23, 30, 267, 131, 23,
Justification::centredLeft, true); Justification::centredLeft, true);
g.setColour (Colours::white); g.setColour (Colours::white);
g.setFont (Font (15.00f, Font::plain)); g.setFont (Font (15.00f, Font::plain));
g.drawText (TRANS("DX7 Channel"), g.drawText (TRANS("DX7 Channel"),
19, 258, 245, 23, 27, 306, 245, 23,
Justification::centredLeft, true);
g.setColour (Colours::white);
g.setFont (Font (15.00f, Font::plain));
g.drawText (TRANS("Engine Resolution"),
22, 154, 276, 23,
Justification::centredLeft, true); Justification::centredLeft, true);
g.setColour (Colours::black);
g.fillRect (22, 138, 306, 1);
g.setColour (Colours::black);
g.fillRect (22, 194, 306, 1);
//[UserPaint] Add your own custom painting code here.. //[UserPaint] Add your own custom painting code here..
//[/UserPaint] //[/UserPaint]
} }
void ParamDialog::resized() void ParamDialog::resized()
{ {
pitchRange->setBounds (240, 16, 72, 24); pitchRange->setBounds (264, 16, 72, 24);
pitchStep->setBounds (240, 56, 72, 24); pitchStep->setBounds (264, 56, 72, 24);
sysexIn->setBounds (96, 176, 208, 24); sysexIn->setBounds (104, 224, 224, 24);
sysexOut->setBounds (96, 216, 208, 24); sysexOut->setBounds (104, 264, 224, 24);
sysexChl->setBounds (240, 256, 72, 24); sysexChl->setBounds (264, 304, 72, 24);
engineReso->setBounds (160, 152, 168, 24);
//[UserResized] Add your own custom resize handling here.. //[UserResized] Add your own custom resize handling here..
//[/UserResized] //[/UserResized]
} }
@ -195,6 +219,11 @@ void ParamDialog::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
//[UserComboBoxCode_sysexOut] -- add your combo box handling code here.. //[UserComboBoxCode_sysexOut] -- add your combo box handling code here..
//[/UserComboBoxCode_sysexOut] //[/UserComboBoxCode_sysexOut]
} }
else if (comboBoxThatHasChanged == engineReso)
{
//[UserComboBoxCode_engineReso] -- add your combo box handling code here..
//[/UserComboBoxCode_engineReso]
}
//[UsercomboBoxChanged_Post] //[UsercomboBoxChanged_Post]
//[/UsercomboBoxChanged_Post] //[/UsercomboBoxChanged_Post]
@ -204,7 +233,7 @@ void ParamDialog::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
//[MiscUserCode] You can add your own definitions of your custom methods or any other code here... //[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void ParamDialog::setDialogValues(Controllers &c, SysexComm &mgr) { void ParamDialog::setDialogValues(Controllers &c, SysexComm &mgr, int reso) {
pitchRange->setValue(c.values_[kControllerPitchRange]); pitchRange->setValue(c.values_[kControllerPitchRange]);
pitchStep->setValue(c.values_[kControllerPitchStep]); pitchStep->setValue(c.values_[kControllerPitchStep]);
sysexChl->setValue(mgr.getChl() + 1); sysexChl->setValue(mgr.getChl() + 1);
@ -216,12 +245,13 @@ void ParamDialog::setDialogValues(Controllers &c, SysexComm &mgr) {
StringArray outputs = MidiOutput::getDevices(); StringArray outputs = MidiOutput::getDevices();
idx = outputs.indexOf(mgr.getOutput()); idx = outputs.indexOf(mgr.getOutput());
TRACE("output idx %d output %s", idx, mgr.getOutput().toRawUTF8());
idx = idx == -1 ? 0 : idx + 1; idx = idx == -1 ? 0 : idx + 1;
sysexOut->setSelectedItemIndex(idx); sysexOut->setSelectedItemIndex(idx);
engineReso->setSelectedItemIndex(reso);
} }
bool ParamDialog::getDialogValues(Controllers &c, SysexComm &mgr) { bool ParamDialog::getDialogValues(Controllers &c, SysexComm &mgr, int *reso) {
bool ret = true; bool ret = true;
c.values_[kControllerPitchRange] = pitchRange->getValue(); c.values_[kControllerPitchRange] = pitchRange->getValue();
@ -230,6 +260,8 @@ bool ParamDialog::getDialogValues(Controllers &c, SysexComm &mgr) {
ret &= mgr.setOutput(sysexOut->getItemText(sysexOut->getSelectedItemIndex())); ret &= mgr.setOutput(sysexOut->getItemText(sysexOut->getSelectedItemIndex()));
mgr.setChl(sysexChl->getValue() - 1); mgr.setChl(sysexChl->getValue() - 1);
*reso = engineReso->getSelectedItemIndex();
return ret; return ret;
} }
@ -248,37 +280,45 @@ BEGIN_JUCER_METADATA
<JUCER_COMPONENT documentType="Component" className="ParamDialog" componentName="" <JUCER_COMPONENT documentType="Component" className="ParamDialog" componentName=""
parentClasses="public Component" constructorParams="" variableInitialisers="" parentClasses="public Component" constructorParams="" variableInitialisers=""
snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330" snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
fixedSize="1" initialWidth="330" initialHeight="300"> fixedSize="1" initialWidth="350" initialHeight="350">
<BACKGROUND backgroundColour="ff4e270d"> <BACKGROUND backgroundColour="ff4e270d">
<TEXT pos="20 18 276 23" fill="solid: ffffffff" hasStroke="0" text="Pitch Bend Range" <TEXT pos="20 18 276 23" fill="solid: ffffffff" hasStroke="0" text="Pitch Bend Range"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/> fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>
<TEXT pos="20 58 276 23" fill="solid: ffffffff" hasStroke="0" text="Pitch Bend Step" <TEXT pos="20 58 276 23" fill="solid: ffffffff" hasStroke="0" text="Pitch Bend Step"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/> fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>
<TEXT pos="20 178 131 23" fill="solid: ffffffff" hasStroke="0" text="DX7 In" <TEXT pos="28 226 131 23" fill="solid: ffffffff" hasStroke="0" text="DX7 In"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>
<TEXT pos="30 267 131 23" fill="solid: ffffffff" hasStroke="0" text="DX7 Out"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/> fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>
<TEXT pos="19 218 131 23" fill="solid: ffffffff" hasStroke="0" text="DX7 Out" <TEXT pos="27 306 245 23" fill="solid: ffffffff" hasStroke="0" text="DX7 Channel"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/> fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>
<TEXT pos="19 258 245 23" fill="solid: ffffffff" hasStroke="0" text="DX7 Channel" <TEXT pos="22 154 276 23" fill="solid: ffffffff" hasStroke="0" text="Engine Resolution"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/> fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>
<RECT pos="22 138 306 1" fill="solid: ff000000" hasStroke="0"/>
<RECT pos="22 194 306 1" fill="solid: ff000000" hasStroke="0"/>
</BACKGROUND> </BACKGROUND>
<SLIDER name="pitchRange" id="7409be5a8dfaa91" memberName="pitchRange" <SLIDER name="pitchRange" id="7409be5a8dfaa91" memberName="pitchRange"
virtualName="" explicitFocusOrder="0" pos="240 16 72 24" min="0" virtualName="" explicitFocusOrder="0" pos="264 16 72 24" min="0"
max="12" int="1" style="RotaryVerticalDrag" textBoxPos="TextBoxLeft" max="12" int="1" style="RotaryVerticalDrag" textBoxPos="TextBoxLeft"
textBoxEditable="1" textBoxWidth="80" textBoxHeight="20" skewFactor="1"/> textBoxEditable="1" textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
<SLIDER name="pitchStep" id="b86af4b792e768ca" memberName="pitchStep" <SLIDER name="pitchStep" id="b86af4b792e768ca" memberName="pitchStep"
virtualName="" explicitFocusOrder="0" pos="240 56 72 24" min="0" virtualName="" explicitFocusOrder="0" pos="264 56 72 24" min="0"
max="12" int="1" style="RotaryVerticalDrag" textBoxPos="TextBoxLeft" max="12" int="1" style="RotaryVerticalDrag" textBoxPos="TextBoxLeft"
textBoxEditable="1" textBoxWidth="80" textBoxHeight="20" skewFactor="1"/> textBoxEditable="1" textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
<COMBOBOX name="sysexIn" id="3750642d8b5be11" memberName="sysexIn" virtualName="" <COMBOBOX name="sysexIn" id="3750642d8b5be11" memberName="sysexIn" virtualName=""
explicitFocusOrder="0" pos="96 176 208 24" editable="0" layout="33" explicitFocusOrder="0" pos="104 224 224 24" editable="0" layout="33"
items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
<COMBOBOX name="sysexOut" id="44730115841c2214" memberName="sysexOut" virtualName="" <COMBOBOX name="sysexOut" id="44730115841c2214" memberName="sysexOut" virtualName=""
explicitFocusOrder="0" pos="96 216 208 24" editable="0" layout="33" explicitFocusOrder="0" pos="104 264 224 24" editable="0" layout="33"
items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/> items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
<SLIDER name="sysexChl" id="7fdc8830f90a7c86" memberName="sysexChl" virtualName="" <SLIDER name="sysexChl" id="7fdc8830f90a7c86" memberName="sysexChl" virtualName=""
explicitFocusOrder="0" pos="240 256 72 24" min="1" max="16" int="1" explicitFocusOrder="0" pos="264 304 72 24" min="1" max="16" int="1"
style="RotaryVerticalDrag" textBoxPos="TextBoxLeft" textBoxEditable="1" style="RotaryVerticalDrag" textBoxPos="TextBoxLeft" textBoxEditable="1"
textBoxWidth="80" textBoxHeight="20" skewFactor="1"/> textBoxWidth="80" textBoxHeight="20" skewFactor="1"/>
<COMBOBOX name="new combo box" id="4087ff978c3d9e8d" memberName="engineReso"
virtualName="" explicitFocusOrder="0" pos="160 152 168 24" editable="0"
layout="33" items="Modern (Direct)&#10;Mark I&#10;OPL Series"
textWhenNonSelected="" textWhenNoItems="(no choices)"/>
</JUCER_COMPONENT> </JUCER_COMPONENT>
END_JUCER_METADATA END_JUCER_METADATA

@ -47,8 +47,8 @@ public:
//============================================================================== //==============================================================================
//[UserMethods] -- You can add your own custom methods in this section. //[UserMethods] -- You can add your own custom methods in this section.
void setDialogValues(Controllers &c, SysexComm &mgr); void setDialogValues(Controllers &c, SysexComm &mgr, int reso);
bool getDialogValues(Controllers &c, SysexComm &mgr); bool getDialogValues(Controllers &c, SysexComm &mgr, int *reso);
//[/UserMethods] //[/UserMethods]
void paint (Graphics& g); void paint (Graphics& g);
@ -68,6 +68,7 @@ private:
ScopedPointer<ComboBox> sysexIn; ScopedPointer<ComboBox> sysexIn;
ScopedPointer<ComboBox> sysexOut; ScopedPointer<ComboBox> sysexOut;
ScopedPointer<Slider> sysexChl; ScopedPointer<Slider> sysexChl;
ScopedPointer<ComboBox> engineReso;
//============================================================================== //==============================================================================

@ -27,6 +27,8 @@
#include "math.h" #include "math.h"
#include <fstream> #include <fstream>
#include "msfa/fm_op_kernel.h"
using namespace ::std; using namespace ::std;
class AboutBox : public DialogWindow { class AboutBox : public DialogWindow {
@ -316,10 +318,12 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
} }
if (buttonThatWasClicked == settingsButton) { if (buttonThatWasClicked == settingsButton) {
int reso = processor->getEngineResolution();
AlertWindow window("","", AlertWindow::NoIcon, this); AlertWindow window("","", AlertWindow::NoIcon, this);
ParamDialog param; ParamDialog param;
param.setColour(AlertWindow::backgroundColourId, Colour(0x32FFFFFF)); param.setColour(AlertWindow::backgroundColourId, Colour(0x32FFFFFF));
param.setDialogValues(processor->controllers, processor->sysexComm); param.setDialogValues(processor->controllers, processor->sysexComm, reso);
window.addCustomComponent(&param); window.addCustomComponent(&param);
window.addButton("OK", 0); window.addButton("OK", 0);
@ -327,7 +331,8 @@ void DexedAudioProcessorEditor::buttonClicked(Button *buttonThatWasClicked) {
if ( window.runModalLoop() != 0 ) if ( window.runModalLoop() != 0 )
return; return;
bool ret = param.getDialogValues(processor->controllers, processor->sysexComm); bool ret = param.getDialogValues(processor->controllers, processor->sysexComm, &reso);
processor->setEngineResolution(reso);
processor->savePreference(); processor->savePreference();
if ( ret == false ) { if ( ret == false ) {

@ -523,6 +523,9 @@ void DexedAudioProcessor::loadPreference() {
sysexComm.setChl( prop.getIntValue( String("sysexChl") ) ); sysexComm.setChl( prop.getIntValue( String("sysexChl") ) );
} }
if ( prop.containsKey( String("engineResolution" ) ) ) {
engineResolution = prop.getIntValue( String(engineResolution) );
}
} }
void DexedAudioProcessor::savePreference() { void DexedAudioProcessor::savePreference() {
@ -536,6 +539,8 @@ void DexedAudioProcessor::savePreference() {
prop.setValue(String("sysexOut"), sysexComm.getOutput()); prop.setValue(String("sysexOut"), sysexComm.getOutput());
prop.setValue(String("sysexChl"), sysexComm.getChl()); prop.setValue(String("sysexChl"), sysexComm.getChl());
//prop.setValue(String("engineResolution"), engineResolution);
prop.save(); prop.save();
} }

@ -28,6 +28,7 @@
#include "msfa/exp2.h" #include "msfa/exp2.h"
#include "msfa/pitchenv.h" #include "msfa/pitchenv.h"
#include "msfa/aligned_buf.h" #include "msfa/aligned_buf.h"
#include "msfa/fm_op_kernel.h"
//============================================================================== //==============================================================================
@ -54,6 +55,7 @@ DexedAudioProcessor::DexedAudioProcessor() {
normalizeDxVelocity = false; normalizeDxVelocity = false;
sysexComm.listener = this; sysexComm.listener = this;
keyboardState.addListener(&sysexComm); keyboardState.addListener(&sysexComm);
engineResolution = -1;
memset(&voiceStatus, 0, sizeof(VoiceStatus)); memset(&voiceStatus, 0, sizeof(VoiceStatus));
@ -66,11 +68,14 @@ DexedAudioProcessor::DexedAudioProcessor() {
controllers.values_[kControllerPitchStep] = 0; controllers.values_[kControllerPitchStep] = 0;
loadPreference(); loadPreference();
setEngineResolution(DEXED_RESO_MODERN);
for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) {
voices[note].dx7_note = NULL; voices[note].dx7_note = NULL;
} }
nextMidi = NULL; nextMidi = NULL;
midiMsg = NULL; midiMsg = NULL;
} }
DexedAudioProcessor::~DexedAudioProcessor() { DexedAudioProcessor::~DexedAudioProcessor() {
@ -184,9 +189,14 @@ void DexedAudioProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& mi
for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) { for (int note = 0; note < MAX_ACTIVE_NOTES; ++note) {
if (voices[note].live) { if (voices[note].live) {
voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers); voices[note].dx7_note->compute(audiobuf.get(), lfovalue, lfodelay, &controllers);
uint32_t state = 0;
for (int j=0; j < N; ++j) { for (int j=0; j < N; ++j) {
int32_t val = audiobuf.get()[j] >> 4; int32 r = rand() & 0xFFFF;
int32_t val = audiobuf.get()[j]; //& 0xFFFFF000);// + r - state;
state = r;
val = val >> 4;
int clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; 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) 32768;
if( f > 1 ) f = 1; if( f > 1 ) f = 1;
@ -411,6 +421,32 @@ void DexedAudioProcessor::handleIncomingMidiMessage(MidiInput* source, const Mid
forceRefreshUI = true; forceRefreshUI = true;
} }
int DexedAudioProcessor::getEngineResolution() {
return engineResolution;
}
void DexedAudioProcessor::setEngineResolution(int rs) {
switch (rs) {
case DEXED_RESO_MODERN :
controllers.sinBitFilter = -1;
controllers.dacBitFilter = -1;
controllers.mulBitFilter = -1;
break;
case DEXED_RESO_MARKI:
controllers.sinBitFilter = 0xFFFFC000; // 10 bit
controllers.dacBitFilter = 0xFFFFF000; // semi 14 bit
break;
case DEXED_RESO_OPL:
controllers.sinBitFilter = 0xFFFF8000; // 9 bit
controllers.dacBitFilter = 0xFFFF0000;
break;
}
engineResolution = rs;
}
// ==================================================================== // ====================================================================
bool DexedAudioProcessor::peekVoiceStatus() { bool DexedAudioProcessor::peekVoiceStatus() {
if ( currentNote == -1 ) if ( currentNote == -1 )
@ -507,7 +543,7 @@ AudioProcessorEditor* DexedAudioProcessor::createEditor() {
} }
void DexedAudioProcessor::handleAsyncUpdate() { void DexedAudioProcessor::handleAsyncUpdate() {
updateUI(); updateUI();
} }
void dexed_trace(const char *source, const char *fmt, ...) { void dexed_trace(const char *source, const char *fmt, ...) {

@ -40,6 +40,12 @@ struct ProcessorVoice {
Dx7Note *dx7_note; Dx7Note *dx7_note;
}; };
enum DexedEngineResolution {
DEXED_RESO_MODERN,
DEXED_RESO_MARKI,
DEXED_RESO_OPL
};
//============================================================================== //==============================================================================
/** /**
*/ */
@ -98,6 +104,7 @@ class DexedAudioProcessor : public AudioProcessor, public AsyncUpdater, public
bool getNextEvent(MidiBuffer::Iterator* iter,const int samplePos); bool getNextEvent(MidiBuffer::Iterator* iter,const int samplePos);
void handleIncomingMidiMessage(MidiInput* source, const MidiMessage& message); void handleIncomingMidiMessage(MidiInput* source, const MidiMessage& message);
uint32_t engineResolution;
public : public :
// in MIDI units (0x4000 is neutral) // in MIDI units (0x4000 is neutral)
@ -114,6 +121,9 @@ public :
bool forceRefreshUI; bool forceRefreshUI;
float vuSignal; float vuSignal;
int getEngineResolution();
void setEngineResolution(int rs);
Array<Ctrl*> ctrl; Array<Ctrl*> ctrl;

@ -26,6 +26,11 @@ const int kControllerPitchStep = 130;
class Controllers { class Controllers {
public: public:
int values_[131]; int values_[131];
// engine bit filters
uint32_t sinBitFilter; // bit filter based upon sin LUT lookup
uint32_t dacBitFilter; // bit filter based upon DAC resolution
uint32_t mulBitFilter; // bit filter based upon multipliers (?????)
}; };
#endif // __CONTROLLERS_H #endif // __CONTROLLERS_H

@ -1,257 +1,272 @@
/* /*
* Copyright 2012 Google Inc. * Copyright 2012 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifdef VERBOSE #ifdef VERBOSE
#include <iostream> #include <iostream>
#endif using namespace std;
#include <math.h> #endif
#include "synth.h" #include <math.h>
#include "freqlut.h" #include "synth.h"
#include "exp2.h" #include "freqlut.h"
#include "controllers.h" #include "exp2.h"
#include "dx7note.h" #include "controllers.h"
#include "dx7note.h"
using namespace std;
void dexed_trace(const char *source, const char *fmt, ...);
void dexed_trace(const char *source, const char *fmt, ...);
#ifdef _MSC_VER
#ifdef _MSC_VER #define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__)
#define TRACE(fmt, ...) dexed_trace(__FUNCTION__,fmt,##__VA_ARGS__) #else
#else #define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__)
#define TRACE(fmt, ...) dexed_trace(__PRETTY_FUNCTION__,fmt,##__VA_ARGS__) #endif
#endif
int32_t midinote_to_logfreq(int midinote) {
int32_t midinote_to_logfreq(int midinote) { const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12) const int step = (1 << 24) / 12;
const int step = (1 << 24) / 12; return base + step * midinote;
return base + step * midinote; }
}
const int32_t coarsemul[] = {
const int32_t coarsemul[] = { -16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600,
-16777216, 0, 16777216, 26591258, 33554432, 38955489, 43368474, 47099600, 50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816,
50331648, 53182516, 55732705, 58039632, 60145690, 62083076, 63876816, 65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858,
65546747, 67108864, 68576247, 69959732, 71268397, 72509921, 73690858, 74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032,
74816848, 75892776, 76922906, 77910978, 78860292, 79773775, 80654032, 81503396, 82323963, 83117622
81503396, 82323963, 83117622 };
};
int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) {
int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) { // TODO: pitch randomization
// TODO: pitch randomization int32_t logfreq;
int32_t logfreq; if (mode == 0) {
if (mode == 0) { logfreq = midinote_to_logfreq(midinote);
logfreq = midinote_to_logfreq(midinote); logfreq += coarsemul[coarse & 31];
logfreq += coarsemul[coarse & 31]; if (fine) {
if (fine) { // (1 << 24) / log(2)
// (1 << 24) / log(2) logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5);
logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5); }
} // This was measured at 7.213Hz per count at 9600Hz, but the exact
// This was measured at 7.213Hz per count at 9600Hz, but the exact // value is somewhat dependent on midinote. Close enough for now.
// value is somewhat dependent on midinote. Close enough for now. logfreq += 12606 * (detune - 7);
logfreq += 12606 * (detune - 7); } else {
} else { // ((1 << 24) * log(10) / log(2) * .01) << 3
// ((1 << 24) * log(10) / log(2) * .01) << 3 logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3;
logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; logfreq += detune > 7 ? 13457 * (detune - 7) : 0;
logfreq += detune > 7 ? 13457 * (detune - 7) : 0; }
} return logfreq;
return logfreq; }
}
const uint8_t velocity_data[64] = {
const uint8_t velocity_data[64] = { 0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163,
0, 70, 86, 97, 106, 114, 121, 126, 132, 138, 142, 148, 152, 156, 160, 163, 166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202,
166, 170, 173, 174, 178, 181, 184, 186, 189, 190, 194, 196, 198, 200, 202, 205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232,
205, 206, 209, 211, 214, 216, 218, 220, 222, 224, 225, 227, 229, 230, 232, 233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251,
233, 235, 237, 238, 240, 241, 242, 243, 244, 246, 246, 248, 249, 250, 251, 252, 253, 254
252, 253, 254 };
};
// See "velocity" section of notes. Returns velocity delta in microsteps.
// See "velocity" section of notes. Returns velocity delta in microsteps. int ScaleVelocity(int velocity, int sensitivity) {
int ScaleVelocity(int velocity, int sensitivity) { int clamped_vel = max(0, min(127, velocity));
int clamped_vel = max(0, min(127, velocity)); int vel_value = velocity_data[clamped_vel >> 1] - 239;
int vel_value = velocity_data[clamped_vel >> 1] - 239; int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4;
int scaled_vel = ((sensitivity * vel_value + 7) >> 3) << 4; return scaled_vel;
return scaled_vel; }
}
int ScaleRate(int midinote, int sensitivity) {
int ScaleRate(int midinote, int sensitivity) { int x = min(31, max(0, midinote / 3 - 7));
int x = min(31, max(0, midinote / 3 - 7)); int qratedelta = (sensitivity * x) >> 3;
int qratedelta = (sensitivity * x) >> 3; #ifdef SUPER_PRECISE
#ifdef SUPER_PRECISE int rem = x & 7;
int rem = x & 7; if (sensitivity == 3 && rem == 3) {
if (sensitivity == 3 && rem == 3) { qratedelta -= 1;
qratedelta -= 1; } else if (sensitivity == 7 && rem > 0 && rem < 4) {
} else if (sensitivity == 7 && rem > 0 && rem < 4) { qratedelta += 1;
qratedelta += 1; }
} #endif
#endif return qratedelta;
return qratedelta; }
}
const uint8_t exp_scale_data[] = {
const uint8_t exp_scale_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 14, 16, 19, 23, 27, 33, 39, 47, 56, 66, 80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250
80, 94, 110, 126, 142, 158, 174, 190, 206, 222, 238, 250 };
};
int ScaleCurve(int group, int depth, int curve) {
int ScaleCurve(int group, int depth, int curve) { int scale;
int scale; if (curve == 0 || curve == 3) {
if (curve == 0 || curve == 3) { // linear
// linear scale = (group * depth * 329) >> 12;
scale = (group * depth * 329) >> 12; } else {
} else { // exponential
// exponential int n_scale_data = sizeof(exp_scale_data);
int n_scale_data = sizeof(exp_scale_data); int raw_exp = exp_scale_data[min(group, n_scale_data - 1)];
int raw_exp = exp_scale_data[min(group, n_scale_data - 1)]; scale = (raw_exp * depth * 329) >> 15;
scale = (raw_exp * depth * 329) >> 15; }
} if (curve < 2) {
if (curve < 2) { scale = -scale;
scale = -scale; }
} return scale;
return scale; }
}
int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth,
int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth, int left_curve, int right_curve) {
int left_curve, int right_curve) { int offset = midinote - break_pt - 17;
int offset = midinote - break_pt - 17; if (offset >= 0) {
if (offset >= 0) { return ScaleCurve(offset / 3, right_depth, right_curve);
return ScaleCurve(offset / 3, right_depth, right_curve); } else {
} else { return ScaleCurve((-offset) / 3, left_depth, left_curve);
return ScaleCurve((-offset) / 3, left_depth, left_curve); }
} }
}
static const uint8_t pitchmodsenstab[] = {
static const uint8_t pitchmodsenstab[] = { 0, 10, 20, 33, 55, 92, 153, 255
0, 10, 20, 33, 55, 92, 153, 255 };
};
// PG: we need to find the real values
void Dx7Note::init(const char patch[156], int midinote, int velocity) { static const uint8_t ampmodsenstab[] = {
int rates[4]; 0, 33, 153, 255
int levels[4]; };
for (int op = 0; op < 6; op++) {
int off = op * 21; void Dx7Note::init(const char patch[156], int midinote, int velocity) {
for (int i = 0; i < 4; i++) { int rates[4];
rates[i] = patch[off + i]; int levels[4];
levels[i] = patch[off + 4 + i]; for (int op = 0; op < 6; op++) {
} int off = op * 21;
int outlevel = patch[off + 16]; for (int i = 0; i < 4; i++) {
outlevel = Env::scaleoutlevel(outlevel); rates[i] = patch[off + i];
#ifdef VERBOSE levels[i] = patch[off + 4 + i];
for (int j = 8; j < 12; j++) { }
cout << (int)patch[off + j] << " "; int outlevel = patch[off + 16];
} outlevel = Env::scaleoutlevel(outlevel);
#endif #ifdef VERBOSE
int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9], for (int j = 8; j < 12; j++) {
patch[off + 10], patch[off + 11], patch[off + 12]); cout << (int)patch[off + j] << " ";
outlevel += level_scaling; }
outlevel = min(127, outlevel); #endif
#ifdef VERBOSE int level_scaling = ScaleLevel(midinote, patch[off + 8], patch[off + 9],
cout << op << ": " << level_scaling << " " << outlevel << endl; patch[off + 10], patch[off + 11], patch[off + 12]);
#endif outlevel += level_scaling;
outlevel = outlevel << 5; outlevel = min(127, outlevel);
outlevel += ScaleVelocity(velocity, patch[off + 15]); #ifdef VERBOSE
outlevel = max(0, outlevel); cout << op << ": " << level_scaling << " " << outlevel << endl;
int rate_scaling = ScaleRate(midinote, patch[off + 13]); #endif
env_[op].init(rates, levels, outlevel, rate_scaling); outlevel = outlevel << 5;
outlevel += ScaleVelocity(velocity, patch[off + 15]);
int mode = patch[off + 17]; outlevel = max(0, outlevel);
int coarse = patch[off + 18]; int rate_scaling = ScaleRate(midinote, patch[off + 13]);
int fine = patch[off + 19]; env_[op].init(rates, levels, outlevel, rate_scaling);
int detune = patch[off + 20];
int32_t freq = osc_freq(midinote, mode, coarse, fine, detune); int mode = patch[off + 17];
basepitch_[op] = freq; int coarse = patch[off + 18];
// cout << op << " freq: " << freq << endl; int fine = patch[off + 19];
params_[op].phase = 0; int detune = patch[off + 20];
params_[op].gain[1] = 0; int32_t freq = osc_freq(midinote, mode, coarse, fine, detune);
} basepitch_[op] = freq;
for (int i = 0; i < 4; i++) { // cout << op << " freq: " << freq << endl;
rates[i] = patch[126 + i]; params_[op].phase = 0;
levels[i] = patch[130 + i]; params_[op].gain[1] = 0;
} ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3];
pitchenv_.set(rates, levels);
algorithm_ = patch[134]; TRACE("operator set: %d %d", op, ampmodsens_[op]);
int feedback = patch[135]; }
fb_shift_ = feedback != 0 ? 8 - feedback : 16; for (int i = 0; i < 4; i++) {
pitchmoddepth_ = (patch[139] * 165) >> 6; rates[i] = patch[126 + i];
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; levels[i] = patch[130 + i];
ampmoddepth_ = (patch[140] * 165) >> 6; }
} pitchenv_.set(rates, levels);
algorithm_ = patch[134];
void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, int feedback = patch[135];
const Controllers *ctrls) { fb_shift_ = feedback != 0 ? 8 - feedback : 16;
int32_t pitchmod = pitchenv_.getsample(); pitchmoddepth_ = (patch[139] * 165) >> 6;
uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32 pitchmodsens_ = pitchmodsenstab[patch[143] & 7];
// TODO: add modulation sources (mod wheel, etc) ampmoddepth_ = (patch[140] * 165) >> 6;
uint32_t pwmd = (ctrls->values_[kControllerModWheel] * 0.7874) * (1 << 24); }
int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23));
void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay,
pitchmod += (((int64_t)pwmd) * (int64_t)senslfo) >> 39; const Controllers *ctrls) {
pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39; int32_t pitchmod = pitchenv_.getsample();
uint32_t pmd = pitchmoddepth_ * lfo_delay; // Q32
int pitchbend = ctrls->values_[kControllerPitch]; // TODO(PG) : make this integer friendly
int32_t pb = (pitchbend - 0x2000); uint32_t pwmd = (ctrls->values_[kControllerModWheel] * 0.7874) * (1 << 24);
int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23));
if ( pb != 0 ) { uint32_t amd = ampmoddepth_ * lfo_delay; // Q32 :D
if ( ctrls->values_[kControllerPitchStep] == 0 ) {
pb = ((float)(pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0; pitchmod += (((int64_t)pwmd) * (int64_t)senslfo) >> 39;
} else { pitchmod += (((int64_t)pmd) * (int64_t)senslfo) >> 39;
int stp = 12 / ctrls->values_[kControllerPitchStep];
pb = pb * stp / 8191; int pitchbend = ctrls->values_[kControllerPitch];
pb = (pb * (8191/stp)) << 11; int32_t pb = (pitchbend - 0x2000);
}
} if ( pb != 0 ) {
if ( ctrls->values_[kControllerPitchStep] == 0 ) {
pitchmod += pb; pb = ((float)(pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0;
for (int op = 0; op < 6; op++) { } else {
params_[op].gain[0] = params_[op].gain[1]; int stp = 12 / ctrls->values_[kControllerPitchStep];
int32_t level = env_[op].getsample(); pb = pb * stp / 8191;
int32_t gain = Exp2::lookup(level - (14 * (1 << 24))); pb = (pb * (8191/stp)) << 11;
//int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24))); }
params_[op].freq = Freqlut::lookup(basepitch_[op] + pitchmod); }
params_[op].gain[1] = gain;
} pitchmod += pb;
core_.compute(buf, params_, algorithm_, fb_buf_, fb_shift_); for (int op = 0; op < 6; op++) {
} params_[op].gain[0] = params_[op].gain[1];
void Dx7Note::keyup() { //int32_t gain = pow(2, 10 + level * (1.0 / (1 << 24)));
for (int op = 0; op < 6; op++) { params_[op].freq = Freqlut::lookup(basepitch_[op] + pitchmod);
env_[op].keydown(false);
pitchenv_.keydown(false); int32_t level = env_[op].getsample();
} if ( ampmodsens_[op] != 0 ) {
} uint32_t sensamp = ampmodsens_[op] * (lfo_val - (1 << 23));
uint32_t amd_level = (((int64_t)amd) * (int64_t)sensamp) >> 40;
void Dx7Note::update(const char patch[156], int midinote) { level -= amd_level;
for (int op = 0; op < 6; op++) { }
int off = op * 21; int32_t gain = Exp2::lookup(level - (14 * (1 << 24)));
int mode = patch[off + 17]; params_[op].gain[1] = gain;
int coarse = patch[off + 18]; }
int fine = patch[off + 19]; core_.compute(buf, params_, algorithm_, fb_buf_, fb_shift_, ctrls);
int detune = patch[off + 20]; }
basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune);
} void Dx7Note::keyup() {
algorithm_ = patch[134]; for (int op = 0; op < 6; op++) {
int feedback = patch[135]; env_[op].keydown(false);
fb_shift_ = feedback != 0 ? 8 - feedback : 16; pitchenv_.keydown(false);
pitchmoddepth_ = (patch[139] * 165) >> 6; }
pitchmodsens_ = pitchmodsenstab[patch[143] & 7]; }
}
void Dx7Note::update(const char patch[156], int midinote) {
void Dx7Note::peekVoiceStatus(VoiceStatus &status) { for (int op = 0; op < 6; op++) {
for(int i=0;i<6;i++) { int off = op * 21;
status.amp[i] = params_[i].gain[1]; int mode = patch[off + 17];
env_[i].getPosition(&status.ampStep[i]); int coarse = patch[off + 18];
} int fine = patch[off + 19];
pitchenv_.getPosition(&status.pitchStep); int detune = patch[off + 20];
} basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune);
}
algorithm_ = patch[134];
int feedback = patch[135];
fb_shift_ = feedback != 0 ? 8 - feedback : 16;
pitchmoddepth_ = (patch[139] * 165) >> 6;
pitchmodsens_ = pitchmodsenstab[patch[143] & 7];
}
void Dx7Note::peekVoiceStatus(VoiceStatus &status) {
for(int i=0;i<6;i++) {
status.amp[i] = params_[i].gain[1];
env_[i].getPosition(&status.ampStep[i]);
}
pitchenv_.getPosition(&status.pitchStep);
}

@ -1,73 +1,74 @@
/* /*
* Copyright 2012 Google Inc. * Copyright 2012 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef SYNTH_DX7NOTE_H_ #ifndef SYNTH_DX7NOTE_H_
#define SYNTH_DX7NOTE_H_ #define SYNTH_DX7NOTE_H_
// This is the logic to put together a note from the MIDI description // This is the logic to put together a note from the MIDI description
// and run the low-level modules. // and run the low-level modules.
// It will continue to evolve a bit, as note-stealing logic, scaling, // It will continue to evolve a bit, as note-stealing logic, scaling,
// and real-time control of parameters live here. // and real-time control of parameters live here.
#include "env.h" #include "env.h"
#include "pitchenv.h" #include "pitchenv.h"
#include "fm_core.h" #include "fm_core.h"
struct VoiceStatus { struct VoiceStatus {
uint32_t amp[6]; uint32_t amp[6];
char ampStep[6]; char ampStep[6];
char pitchStep; char pitchStep;
}; };
class Dx7Note { class Dx7Note {
public: public:
void init(const char patch[156], int midinote, int velocity); void init(const char patch[156], int midinote, int velocity);
// Note: this _adds_ to the buffer. Interesting question whether it's // Note: this _adds_ to the buffer. Interesting question whether it's
// worth it... // worth it...
void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, void compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay,
const Controllers *ctrls); const Controllers *ctrls);
void keyup(); void keyup();
// TODO: parameter changes // TODO: parameter changes
// TODO: some way of indicating end-of-note. Maybe should be a return // TODO: some way of indicating end-of-note. Maybe should be a return
// value from the compute method? (Having a count return from keyup // value from the compute method? (Having a count return from keyup
// is also tempting, but if there's a dynamic parameter change after // is also tempting, but if there's a dynamic parameter change after
// keyup, that won't work. // keyup, that won't work.
// PG:add the update // PG:add the update
void update(const char patch[156], int midinote); void update(const char patch[156], int midinote);
void peekVoiceStatus(VoiceStatus &status); void peekVoiceStatus(VoiceStatus &status);
private: private:
FmCore core_; FmCore core_;
Env env_[6]; Env env_[6];
FmOpParams params_[6]; FmOpParams params_[6];
PitchEnv pitchenv_; PitchEnv pitchenv_;
int32_t basepitch_[6]; int32_t basepitch_[6];
int32_t fb_buf_[2]; int32_t fb_buf_[2];
int32_t fb_shift_; int32_t fb_shift_;
int32_t ampmodsens_[6];
int ampmoddepth_;
int algorithm_; int ampmoddepth_;
int pitchmoddepth_; int algorithm_;
int pitchmodsens_; int pitchmoddepth_;
}; int pitchmodsens_;
};
#endif // SYNTH_DX7NOTE_H_
#endif // SYNTH_DX7NOTE_H_

@ -1,151 +1,152 @@
/* /*
* Copyright 2012 Google Inc. * Copyright 2012 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifdef VERBOSE #ifdef VERBOSE
#include <iostream> #include <iostream>
#endif #endif
#include "synth.h" #include "synth.h"
#include "fm_op_kernel.h" #include "fm_op_kernel.h"
#include "fm_core.h" #include "fm_core.h"
using namespace std;
using namespace std;
struct FmOperatorInfo {
int in; struct FmOperatorInfo {
int out; int in;
}; int out;
};
enum FmOperatorFlags {
OUT_BUS_ONE = 1 << 0, enum FmOperatorFlags {
OUT_BUS_TWO = 1 << 1, OUT_BUS_ONE = 1 << 0,
OUT_BUS_ADD = 1 << 2, OUT_BUS_TWO = 1 << 1,
IN_BUS_ONE = 1 << 4, OUT_BUS_ADD = 1 << 2,
IN_BUS_TWO = 1 << 5, IN_BUS_ONE = 1 << 4,
FB_IN = 1 << 6, IN_BUS_TWO = 1 << 5,
FB_OUT = 1 << 7 FB_IN = 1 << 6,
}; FB_OUT = 1 << 7
};
struct FmAlgorithm {
int ops[6]; struct FmAlgorithm {
}; int ops[6];
};
const FmAlgorithm algorithms[32] = {
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1 const FmAlgorithm algorithms[32] = {
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2 { { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3 { { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
{ { 0x41, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4 { { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5 { { 0x41, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4
{ { 0x41, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6 { { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7 { { 0x41, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8 { { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9 { { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
{ { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10 { { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9
{ { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11 { { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10
{ { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12 { { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11
{ { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13 { { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12
{ { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14 { { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13
{ { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15 { { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14
{ { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16 { { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15
{ { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17 { { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16
{ { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18 { { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17
{ { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19 { { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20 { { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19
{ { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21 { { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20
{ { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22 { { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21
{ { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23 { { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22
{ { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24 { { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23
{ { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25 { { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24
{ { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26 { { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27 { { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26
{ { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28 { { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27
{ { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29 { { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28
{ { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30 { { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29
{ { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31 { { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30
{ { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32 { { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31
}; { { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32
};
int n_out(const FmAlgorithm &alg) {
int count = 0; int n_out(const FmAlgorithm &alg) {
for (int i = 0; i < 6; i++) { int count = 0;
if ((alg.ops[i] & 7) == OUT_BUS_ADD) count++; for (int i = 0; i < 6; i++) {
} if ((alg.ops[i] & 7) == OUT_BUS_ADD) count++;
return count; }
} return count;
}
void FmCore::dump() {
#ifdef VERBOSE void FmCore::dump() {
for (int i = 0; i < 32; i++) { #ifdef VERBOSE
cout << (i + 1) << ":"; for (int i = 0; i < 32; i++) {
const FmAlgorithm &alg = algorithms[i]; cout << (i + 1) << ":";
for (int j = 0; j < 6; j++) { const FmAlgorithm &alg = algorithms[i];
int flags = alg.ops[j]; for (int j = 0; j < 6; j++) {
cout << " "; int flags = alg.ops[j];
if (flags & FB_IN) cout << "["; cout << " ";
cout << (flags & IN_BUS_ONE ? "1" : flags & IN_BUS_TWO ? "2" : "0") << "->"; if (flags & FB_IN) cout << "[";
cout << (flags & OUT_BUS_ONE ? "1" : flags & OUT_BUS_TWO ? "2" : "0"); cout << (flags & IN_BUS_ONE ? "1" : flags & IN_BUS_TWO ? "2" : "0") << "->";
if (flags & OUT_BUS_ADD) cout << "+"; cout << (flags & OUT_BUS_ONE ? "1" : flags & OUT_BUS_TWO ? "2" : "0");
//cout << alg.ops[j].in << "->" << alg.ops[j].out; if (flags & OUT_BUS_ADD) cout << "+";
if (flags & FB_OUT) cout << "]"; //cout << alg.ops[j].in << "->" << alg.ops[j].out;
} if (flags & FB_OUT) cout << "]";
cout << " " << n_out(alg); }
cout << endl; cout << " " << n_out(alg);
} cout << endl;
#endif }
} #endif
}
void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm,
int32_t *fb_buf, int feedback_shift) { void FmCore::compute(int32_t *output, FmOpParams *params, int algorithm,
const int kLevelThresh = 1120; int32_t *fb_buf, int feedback_shift, const Controllers *controllers) {
const FmAlgorithm alg = algorithms[algorithm]; const int kLevelThresh = 1120;
bool has_contents[3] = { true, false, false }; const FmAlgorithm alg = algorithms[algorithm];
for (int op = 0; op < 6; op++) { bool has_contents[3] = { true, false, false };
int flags = alg.ops[op]; for (int op = 0; op < 6; op++) {
bool add = (flags & OUT_BUS_ADD) != 0; int flags = alg.ops[op];
FmOpParams &param = params[op]; bool add = (flags & OUT_BUS_ADD) != 0;
int inbus = (flags >> 4) & 3; FmOpParams &param = params[op];
int outbus = flags & 3; int inbus = (flags >> 4) & 3;
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); int outbus = flags & 3;
int32_t gain1 = param.gain[0]; int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get();
int32_t gain2 = param.gain[1]; int32_t gain1 = param.gain[0];
if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { int32_t gain2 = param.gain[1];
if (!has_contents[outbus]) { if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) {
add = false; if (!has_contents[outbus]) {
} add = false;
if (inbus == 0 || !has_contents[inbus]) { }
// todo: more than one op in a feedback loop if (inbus == 0 || !has_contents[inbus]) {
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { // todo: more than one op in a feedback loop
// cout << op << " fb " << inbus << outbus << add << endl; if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
FmOpKernel::compute_fb(outptr, param.phase, param.freq, // cout << op << " fb " << inbus << outbus << add << endl;
gain1, gain2, FmOpKernel::compute_fb(outptr, param.phase, param.freq,
fb_buf, feedback_shift, add); gain1, gain2,
} else { fb_buf, feedback_shift, add, controllers);
// cout << op << " pure " << inbus << outbus << add << endl; } else {
FmOpKernel::compute_pure(outptr, param.phase, param.freq, // cout << op << " pure " << inbus << outbus << add << endl;
gain1, gain2, add); FmOpKernel::compute_pure(outptr, param.phase, param.freq,
} gain1, gain2, add, controllers);
} else { }
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl; } else {
FmOpKernel::compute(outptr, buf_[inbus - 1].get(), // cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
param.phase, param.freq, gain1, gain2, add); FmOpKernel::compute(outptr, buf_[inbus - 1].get(),
} param.phase, param.freq, gain1, gain2, add, controllers);
has_contents[outbus] = true; }
} else if (!add) { has_contents[outbus] = true;
has_contents[outbus] = false; } else if (!add) {
} has_contents[outbus] = false;
param.phase += param.freq << LG_N; }
} param.phase += param.freq << LG_N;
} }
}

@ -1,38 +1,40 @@
/* /*
* Copyright 2012 Google Inc. * Copyright 2012 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef __FM_CORE_H #ifndef __FM_CORE_H
#define __FM_CORE_H #define __FM_CORE_H
#include "aligned_buf.h" #include "aligned_buf.h"
#include "synth.h" #include "fm_op_kernel.h"
#include "synth.h"
struct FmOpParams { #include "controllers.h"
int32_t gain[2];
int32_t freq; struct FmOpParams {
int32_t phase; int32_t gain[2];
}; int32_t freq;
int32_t phase;
class FmCore { };
public:
static void dump(); class FmCore {
void compute(int32_t *output, FmOpParams *params, int algorithm, public:
int32_t *fb_buf, int32_t feedback_gain); static void dump();
private: void compute(int32_t *output, FmOpParams *params, int algorithm,
AlignedBuf<int32_t, N>buf_[2]; int32_t *fb_buf, int32_t feedback_gain, const Controllers *controller);
}; private:
AlignedBuf<int32_t, N>buf_[2];
#endif // __FM_CORE_H };
#endif // __FM_CORE_H

@ -1,274 +1,299 @@
/* /*
* Copyright 2012 Google Inc. * Copyright 2012 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include <math.h> #include <math.h>
#ifdef HAVE_NEON #include <cstdlib>
#include <cpu-features.h>
#endif #ifdef HAVE_NEON
#include <cpu-features.h>
#include "synth.h" #endif
#include "sin.h" #include "synth.h"
#include "fm_op_kernel.h"
#include "sin.h"
#ifdef HAVE_NEON #include "fm_op_kernel.h"
static bool hasNeon() {
return true;
return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; uint32_t restdither() {
} return rand() & 0x3FFF;
return 0;
extern "C"
void neon_fm_kernel(const int *in, const int *busin, int *out, int count, }
int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain);
#ifdef HAVE_NEONx
const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; static bool hasNeon() {
return true;
#else return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
static bool hasNeon() { }
return false;
} extern "C"
#endif void neon_fm_kernel(const int *in, const int *busin, int *out, int count,
int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain);
void FmOpKernel::compute(int32_t *output, const int32_t *input,
int32_t phase0, int32_t freq, const int32_t __attribute__ ((aligned(16))) zeros[N] = {0};
int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; #else
int32_t gain = gain1; static bool hasNeon() {
int32_t phase = phase0; return false;
if (hasNeon()) { }
#ifdef HAVE_NEON #endif
neon_fm_kernel(input, add ? output : zeros, output, N,
phase0, freq, gain, dgain); //#define BIT8 0xFFFFFF00
#endif
} else { void FmOpKernel::compute(int32_t *output, const int32_t *input,
if (add) { int32_t phase0, int32_t freq,
for (int i = 0; i < N; i++) { int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) {
gain += dgain; int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
int32_t y = Sin::lookup(phase + input[i]); int32_t gain = gain1;
output[i] += ((int64_t)y * (int64_t)gain) >> 24; int32_t phase = phase0;
phase += freq; if (hasNeon()) {
} #ifdef HAVE_NEON
} else { neon_fm_kernel(input, add ? output : zeros, output, N,
for (int i = 0; i < N; i++) { phase0, freq, gain, dgain);
gain += dgain; #endif
int32_t y = Sin::lookup(phase + input[i]); } else {
output[i] = ((int64_t)y * (int64_t)gain) >> 24; if (add) {
phase += freq; for (int i = 0; i < N; i++) {
} gain += dgain;
} int32_t y = Sin::lookup(phase + input[i]);
} y &= controllers->sinBitFilter;
} int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24;
output[i] += y1;
#if 1 phase += freq;
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, }
int32_t gain1, int32_t gain2, bool add) { } else {
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; for (int i = 0; i < N; i++) {
int32_t gain = gain1; gain += dgain;
int32_t phase = phase0; int32_t y = Sin::lookup(phase + input[i]);
if (hasNeon()) { y &= controllers->sinBitFilter;
#ifdef HAVE_NEON int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24;
neon_fm_kernel(zeros, add ? output : zeros, output, N, output[i] = y1;
phase0, freq, gain, dgain); phase += freq;
#endif }
} else { }
if (add) { }
for (int i = 0; i < N; i++) { }
gain += dgain;
int32_t y = Sin::lookup(phase); void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
output[i] += ((int64_t)y * (int64_t)gain) >> 24; int32_t gain1, int32_t gain2, bool add, const Controllers *controllers) {
phase += freq; int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
} int32_t gain = gain1;
} else { int32_t phase = phase0;
for (int i = 0; i < N; i++) { if (hasNeon()) {
gain += dgain; #ifdef HAVE_NEON
int32_t y = Sin::lookup(phase); neon_fm_kernel(zeros, add ? output : zeros, output, N,
output[i] = ((int64_t)y * (int64_t)gain) >> 24; phase0, freq, gain, dgain);
phase += freq; #endif
} } else {
} if (add) {
} for (int i = 0; i < N; i++) {
} gain += dgain;
#endif int32_t y = Sin::lookup(phase);
y &= controllers->sinBitFilter;
#define noDOUBLE_ACCURACY int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24;
#define HIGH_ACCURACY output[i] += y1;
phase += freq;
// Experimental sine wave generators below }
#if 0 } else {
// Results: accuracy 64.3 mean, 170 worst case for (int i = 0; i < N; i++) {
// high accuracy: 5.0 mean, 49 worst case gain += dgain;
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t y = Sin::lookup(phase);
int32_t gain1, int32_t gain2, bool add) { y &= controllers->sinBitFilter;
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24;
int32_t gain = gain1; output[i] = y1;
int32_t phase = phase0; phase += freq;
#ifdef HIGH_ACCURACY }
int32_t u = Sin::compute10(phase << 6); }
u = ((int64_t)u * gain) >> 30; }
int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle }
v = ((int64_t)v * gain) >> 30;
int32_t s = Sin::compute10(freq << 6); #define noDOUBLE_ACCURACY
int32_t c = Sin::compute10((freq << 6) + (1 << 28)); #define HIGH_ACCURACY
#else
int32_t u = Sin::compute(phase); void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
u = ((int64_t)u * gain) >> 24; int32_t gain1, int32_t gain2,
int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle int32_t *fb_buf, int fb_shift, bool add, const Controllers *controllers) {
v = ((int64_t)v * gain) >> 24; int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
int32_t s = Sin::compute(freq) << 6; int32_t gain = gain1;
int32_t c = Sin::compute(freq + (1 << 22)) << 6; int32_t phase = phase0;
#endif int32_t y0 = fb_buf[0];
for (int i = 0; i < N; i++) { int32_t y = fb_buf[1];
output[i] = u; if (add) {
int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30; for (int i = 0; i < N; i++) {
u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30; gain += dgain;
v = t; int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
} y0 = y;
} y = Sin::lookup(phase + scaled_fb);
#endif y &= controllers->sinBitFilter;
y = ((int64_t)y * (int64_t)gain) >> 24;
#if 0 output[i] += y;
// Results: accuracy 392.3 mean, 15190 worst case (near freq = 0.5) phase += freq;
// for freq < 0.25, 275.2 mean, 716 worst }
// high accuracy: 57.4 mean, 7559 worst } else {
// freq < 0.25: 17.9 mean, 78 worst for (int i = 0; i < N; i++) {
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, gain += dgain;
int32_t gain1, int32_t gain2, bool add) { int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; y0 = y;
int32_t gain = gain1; y = Sin::lookup(phase + scaled_fb);
int32_t phase = phase0; y &= controllers->sinBitFilter;
#ifdef HIGH_ACCURACY y = ((int64_t)y * (int64_t)gain) >> 24;
int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5); output[i] = y;
int32_t v = floor(gain * cos((phase - freq * 0.5) * (M_PI / (1 << 23))) + 0.5); phase += freq;
int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5); }
#else }
int32_t u = Sin::compute(phase); fb_buf[0] = y0;
u = ((int64_t)u * gain) >> 24; fb_buf[1] = y;
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); }
v = ((int64_t)v * gain) >> 24;
int32_t a = Sin::compute(freq >> 1) << 1; ////////////////////////////////////////////////////////////////////////////////////
#endif ////////////////////////////////////////////////////////////////////////////////////
for (int i = 0; i < N; i++) { ////////////////////////////////////////////////////////////////////////////////////
output[i] = u; ////////////////////////////////////////////////////////////////////////////////////
v -= ((int64_t)a * (int64_t)u) >> 24;
u += ((int64_t)a * (int64_t)v) >> 24; // Experimental sine wave generators below
} #if 0
} // Results: accuracy 64.3 mean, 170 worst case
#endif // high accuracy: 5.0 mean, 49 worst case
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
#if 0 int32_t gain1, int32_t gain2, bool add) {
// Results: accuracy 370.0 mean, 15480 worst case (near freq = 0.5) int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
// with double accuracy initialization: mean 1.55, worst 58 (near freq = 0) int32_t gain = gain1;
// with high accuracy: mean 4.2, worst 292 (near freq = 0.5) int32_t phase = phase0;
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, #ifdef HIGH_ACCURACY
int32_t gain1, int32_t gain2, bool add) { int32_t u = Sin::compute10(phase << 6);
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; u = ((int64_t)u * gain) >> 30;
int32_t gain = gain1; int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle
int32_t phase = phase0; v = ((int64_t)v * gain) >> 30;
#ifdef DOUBLE_ACCURACY int32_t s = Sin::compute10(freq << 6);
int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5); int32_t c = Sin::compute10((freq << 6) + (1 << 28));
double a_d = sin(freq * (M_PI / (1 << 24))); #else
int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) * int32_t u = Sin::compute(phase);
(M_PI / (1 << 23))) + 0.5); u = ((int64_t)u * gain) >> 24;
int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5); int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle
#else v = ((int64_t)v * gain) >> 24;
#ifdef HIGH_ACCURACY int32_t s = Sin::compute(freq) << 6;
int32_t u = Sin::compute10(phase << 6); int32_t c = Sin::compute(freq + (1 << 22)) << 6;
int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5)); #endif
int32_t a = Sin::compute10(freq << 5); for (int i = 0; i < N; i++) {
v = ((int64_t)v * (int64_t)a) >> 29; output[i] = u;
int32_t aa = ((int64_t)a * (int64_t)a) >> 29; int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30;
#else u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30;
int32_t u = Sin::compute(phase) << 6; v = t;
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); }
int32_t a = Sin::compute(freq >> 1); }
v = ((int64_t)v * (int64_t)a) >> 17; #endif
int32_t aa = ((int64_t)a * (int64_t)a) >> 17;
#endif #if 0
#endif // Results: accuracy 392.3 mean, 15190 worst case (near freq = 0.5)
// for freq < 0.25, 275.2 mean, 716 worst
if (aa < 0) aa = (1 << 31) - 1; // high accuracy: 57.4 mean, 7559 worst
for (int i = 0; i < N; i++) { // freq < 0.25: 17.9 mean, 78 worst
gain += dgain; void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
output[i] = ((int64_t)u * (int64_t)gain) >> 30; int32_t gain1, int32_t gain2, bool add) {
v -= ((int64_t)aa * (int64_t)u) >> 29; int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
u += v; int32_t gain = gain1;
} int32_t phase = phase0;
} #ifdef HIGH_ACCURACY
#endif int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5);
int32_t v = floor(gain * cos((phase - freq * 0.5) * (M_PI / (1 << 23))) + 0.5);
#if 0 int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5);
// Results:: accuracy 112.3 mean, 4262 worst (near freq = 0.5) #else
// high accuracy 2.9 mean, 143 worst int32_t u = Sin::compute(phase);
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, u = ((int64_t)u * gain) >> 24;
int32_t gain1, int32_t gain2, bool add) { int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1));
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; v = ((int64_t)v * gain) >> 24;
int32_t gain = gain1; int32_t a = Sin::compute(freq >> 1) << 1;
int32_t phase = phase0; #endif
#ifdef HIGH_ACCURACY for (int i = 0; i < N; i++) {
int32_t u = Sin::compute10(phase << 6); output[i] = u;
int32_t lastu = Sin::compute10((phase - freq) << 6); v -= ((int64_t)a * (int64_t)u) >> 24;
int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1; u += ((int64_t)a * (int64_t)v) >> 24;
#else }
int32_t u = Sin::compute(phase) << 6; }
int32_t lastu = Sin::compute(phase - freq) << 6; #endif
int32_t a = Sin::compute(freq + (1 << 22)) << 7;
#endif #if 0
if (a < 0 && freq < 256) a = (1 << 31) - 1; // Results: accuracy 370.0 mean, 15480 worst case (near freq = 0.5)
if (a > 0 && freq > 0x7fff00) a = -(1 << 31); // with double accuracy initialization: mean 1.55, worst 58 (near freq = 0)
for (int i = 0; i < N; i++) { // with high accuracy: mean 4.2, worst 292 (near freq = 0.5)
gain += dgain; void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
output[i] = ((int64_t)u * (int64_t)gain) >> 30; int32_t gain1, int32_t gain2, bool add) {
//output[i] = u; int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu; int32_t gain = gain1;
lastu = u; int32_t phase = phase0;
u = newu; #ifdef DOUBLE_ACCURACY
} int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5);
} double a_d = sin(freq * (M_PI / (1 << 24)));
#endif int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) *
(M_PI / (1 << 23))) + 0.5);
void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq, int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5);
int32_t gain1, int32_t gain2, #else
int32_t *fb_buf, int fb_shift, bool add) { #ifdef HIGH_ACCURACY
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; int32_t u = Sin::compute10(phase << 6);
int32_t gain = gain1; int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5));
int32_t phase = phase0; int32_t a = Sin::compute10(freq << 5);
int32_t y0 = fb_buf[0]; v = ((int64_t)v * (int64_t)a) >> 29;
int32_t y = fb_buf[1]; int32_t aa = ((int64_t)a * (int64_t)a) >> 29;
if (add) { #else
for (int i = 0; i < N; i++) { int32_t u = Sin::compute(phase) << 6;
gain += dgain; int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1));
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); int32_t a = Sin::compute(freq >> 1);
y0 = y; v = ((int64_t)v * (int64_t)a) >> 17;
y = Sin::lookup(phase + scaled_fb); int32_t aa = ((int64_t)a * (int64_t)a) >> 17;
y = ((int64_t)y * (int64_t)gain) >> 24; #endif
output[i] += y; #endif
phase += freq;
} if (aa < 0) aa = (1 << 31) - 1;
} else { for (int i = 0; i < N; i++) {
for (int i = 0; i < N; i++) { gain += dgain;
gain += dgain; output[i] = ((int64_t)u * (int64_t)gain) >> 30;
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); v -= ((int64_t)aa * (int64_t)u) >> 29;
y0 = y; u += v;
y = Sin::lookup(phase + scaled_fb); }
y = ((int64_t)y * (int64_t)gain) >> 24; }
output[i] = y; #endif
phase += freq;
} #if 0
} // Results:: accuracy 112.3 mean, 4262 worst (near freq = 0.5)
fb_buf[0] = y0; // high accuracy 2.9 mean, 143 worst
fb_buf[1] = y; void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
} int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N;
int32_t gain = gain1;
int32_t phase = phase0;
#ifdef HIGH_ACCURACY
int32_t u = Sin::compute10(phase << 6);
int32_t lastu = Sin::compute10((phase - freq) << 6);
int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1;
#else
int32_t u = Sin::compute(phase) << 6;
int32_t lastu = Sin::compute(phase - freq) << 6;
int32_t a = Sin::compute(freq + (1 << 22)) << 7;
#endif
if (a < 0 && freq < 256) a = (1 << 31) - 1;
if (a > 0 && freq > 0x7fff00) a = -(1 << 31);
for (int i = 0; i < N; i++) {
gain += dgain;
output[i] = ((int64_t)u * (int64_t)gain) >> 30;
//output[i] = u;
int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu;
lastu = u;
u = newu;
}
}
#endif

@ -1,35 +1,42 @@
/* /*
* Copyright 2012 Google Inc. * Copyright 2012 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
class FmOpKernel { #ifndef __FM_OP_KERNEL_H
public: #define __FM_OP_KERNEL_H
// gain1 and gain2 represent linear step: gain for sample i is
// gain1 + (1 + i) / 64 * (gain2 - gain1) #include "controllers.h"
// This is the basic FM operator. No feedback. class FmOpKernel {
static void compute(int32_t *output, const int32_t *input, public:
int32_t phase0, int32_t freq, // gain1 and gain2 represent linear step: gain for sample i is
int32_t gain1, int32_t gain2, bool add); // gain1 + (1 + i) / 64 * (gain2 - gain1)
// This is a sine generator, no feedback. // This is the basic FM operator. No feedback.
static void compute_pure(int32_t *output, int32_t phase0, int32_t freq, static void compute(int32_t *output, const int32_t *input,
int32_t gain1, int32_t gain2, bool add); int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add, const Controllers *controllers);
// One op with feedback, no add.
static void compute_fb(int32_t *output, int32_t phase0, int32_t freq, // This is a sine generator, no feedback.
int32_t gain1, int32_t gain2, static void compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t *fb_buf, int fb_gain, bool add); int32_t gain1, int32_t gain2, bool add, const Controllers *controllers);
};
// One op with feedback, no add.
static void compute_fb(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2,
int32_t *fb_buf, int fb_gain, bool add, const Controllers *controllers);
};
#endif

Loading…
Cancel
Save