zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 9d624c66531070d11b5f9ebd19ab22f80eb8f066
Author: paulnasca <paulnasca>
Date:   Fri, 28 Nov 2003 20:44:39 +0000

Initial revision

Diffstat:
ACOPYING | 347+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AChangeLog | 502+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AExternalPrograms/Controller/Controller.C | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AExternalPrograms/Controller/Controller.h | 32++++++++++++++++++++++++++++++++
AExternalPrograms/Controller/ControllerUI.fl | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AExternalPrograms/Controller/clean.sh | 1+
AExternalPrograms/Controller/compile.sh | 10++++++++++
AExternalPrograms/Controller/main.C | 16++++++++++++++++
AExternalPrograms/Spliter/Spliter.C | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AExternalPrograms/Spliter/Spliter.h | 26++++++++++++++++++++++++++
AExternalPrograms/Spliter/SpliterUI.fl | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AExternalPrograms/Spliter/clean.sh | 1+
AExternalPrograms/Spliter/compile.sh | 8++++++++
AExternalPrograms/Spliter/main.C | 36++++++++++++++++++++++++++++++++++++
AExternalPrograms/Spliter/readme.txt | 15+++++++++++++++
AExternalPrograms/readme.txt | 3+++
AFAQ.txt | 32++++++++++++++++++++++++++++++++
AHISTORY.txt | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AREADME.txt | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AZynAddSubFX.lsm | 22++++++++++++++++++++++
Acompile.win32 | 32++++++++++++++++++++++++++++++++
Aexamples/Banks/readme.txt | 2++
Aexamples/Big_Pad.mas_zyn | 0
Aexamples/Big_Pad_2.mas_zyn | 0
Aexamples/Big_Pad_2resonance.mas_zyn | 0
Aexamples/Instruments/accomp00.ins_zyn | 0
Aexamples/Instruments/accomp01.ins_zyn | 0
Aexamples/Instruments/choir01.ins_zyn | 0
Aexamples/Instruments/fmthrumpet.ins_zyn | 0
Aexamples/Instruments/organ00.ins_zyn | 0
Aexamples/Instruments/organ01.ins_zyn | 0
Aexamples/Instruments/organ02.ins_zyn | 0
Aexamples/Instruments/organ03.ins_zyn | 0
Aexamples/Instruments/organ04.ins_zyn | 0
Aexamples/Instruments/res01.ins_zyn | 0
Aexamples/Instruments/res02.ins_zyn | 0
Aexamples/Instruments/res03.ins_zyn | 0
Aexamples/Instruments/rhodes00.ins_zyn | 0
Aexamples/Instruments/rhodes01.ins_zyn | 0
Aexamples/Instruments/rhodes02.ins_zyn | 0
Aexamples/Instruments/soft_organ.ins_zyn | 0
Aexamples/Instruments/synth_brazz.ins_zyn | 0
Aexamples/Rhodes_chorus.mas_zyn | 0
Aexamples/Rhodes_chorus2.mas_zyn | 0
Aexamples/Scales/5-24.scl_zyn | 0
Aexamples/Scales/8-11.scl_zyn | 0
Aexamples/Scales/IntenseDiatonic_mapped.scl_zyn | 0
Aexamples/Scales/Just Intonation.scl_zyn | 0
Aexamples/Scales/harrison.scl_zyn | 0
Aexamples/Scales/pyth.scl_zyn | 0
Aexamples/Split_keyboard.mas_zyn | 0
Aexamples/distortion_and_strings.mas_zyn | 0
Aexamples/examples.mas_zyn | 0
Aexamples/flanged_guitar.mas_zyn | 0
Aexamples/ins01.mas_zyn | 0
Aexamples/ins02.mas_zyn | 0
Aexamples/ins03.mas_zyn | 0
Aexamples/ins04.mas_zyn | 0
Aexamples/ins05.mas_zyn | 0
Aexamples/ins06.mas_zyn | 0
Aexamples/ins07.mas_zyn | 0
Aexamples/ins08.mas_zyn | 0
Aexamples/oops.mas_zyn | 0
Aexamples/organ1.mas_zyn | 0
Aexamples/organ_pad.mas_zyn | 0
Aexamples/organ_pad2.mas_zyn | 0
Aexamples/rezzy_synth_reverberated.mas_zyn | 0
Aexamples/string_and_rhodes.mas_zyn | 0
Aexamples/synth_reverberated.mas_zyn | 0
Aexamples/synth_reverberated2.mas_zyn | 0
Asrc/DSP/AnalogFilter.C | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/AnalogFilter.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/FFTwrapper.C | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/FFTwrapper.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/Filter.C | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/Filter.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/Filter_.h | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/FormantFilter.C | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/FormantFilter.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/Makefile | 14++++++++++++++
Asrc/DSP/SVFilter.C | 152+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/DSP/SVFilter.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Alienwah.C | 267+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Alienwah.h | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Chorus.C | 293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Chorus.h | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Distorsion.C | 290+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Distorsion.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/EQ.C | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/EQ.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Echo.C | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Echo.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Effect.C | 24++++++++++++++++++++++++
Asrc/Effects/Effect.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/EffectLFO.C | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/EffectLFO.h | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/EffectMgr.C | 240+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/EffectMgr.h | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Makefile | 16++++++++++++++++
Asrc/Effects/Phaser.C | 283+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Phaser.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Reverb.C | 458+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Effects/Reverb.h | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/ALSAMidiIn.C | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/ALSAMidiIn.h | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/Makefile | 26++++++++++++++++++++++++++
Asrc/Input/MidiIn.C | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/MidiIn.h | 42++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/NULLMidiIn.C | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/NULLMidiIn.h | 40++++++++++++++++++++++++++++++++++++++++
Asrc/Input/OSSMidiIn.C | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/OSSMidiIn.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/WINMidiIn.C | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Input/WINMidiIn.h | 34++++++++++++++++++++++++++++++++++
Asrc/Makefile | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Makefile.inc | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Bank.C | 394+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Bank.h | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Buffer.C | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Buffer.h | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Config.C | 221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Config.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Dump.C | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Dump.h | 43+++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Makefile | 14++++++++++++++
Asrc/Misc/Master.C | 685+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Master.h | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Microtonal.C | 563+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Microtonal.h | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Part.C | 915+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Part.h | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Util.C | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Misc/Util.h | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/JACKaudiooutput.C | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/JACKaudiooutput.h | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/Makefile | 30++++++++++++++++++++++++++++++
Asrc/Output/OSSaudiooutput.C | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/OSSaudiooutput.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/PAaudiooutput.C | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/PAaudiooutput.h | 34++++++++++++++++++++++++++++++++++
Asrc/Output/Recorder.C | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/Recorder.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/VSTaudiooutput.C | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Output/VSTaudiooutput.h | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/ADnoteParameters.C | 482+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/ADnoteParameters.h | 269+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/Controller.C | 306+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/Controller.h | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/EnvelopeParams.C | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/EnvelopeParams.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/FilterParams.C | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/FilterParams.h | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/LFOParams.C | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/LFOParams.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/Makefile | 15+++++++++++++++
Asrc/Params/SUBnoteParameters.C | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Params/SUBnoteParameters.h | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Seq/Makefile | 14++++++++++++++
Asrc/Seq/Sequencer.C | 204+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Seq/Sequencer.h | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/ADnote.C | 930+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/ADnote.h | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/Envelope.C | 166+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/Envelope.h | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/LFO.C | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/LFO.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/Makefile | 14++++++++++++++
Asrc/Synth/OscilGen.C | 776+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/OscilGen.h | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/Resonance.C | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/Resonance.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/SUBnote.C | 419+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Synth/SUBnote.h | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/ADnoteUI.fl | 1731+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/BankUI.fl | 299+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/ConfigUI.fl | 252+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/EffUI.fl | 1216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/EnvelopeUI.fl | 700+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/FilterUI.fl | 547+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/LFOUI.fl | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/Makefile | 36++++++++++++++++++++++++++++++++++++
Asrc/UI/MasterUI.fl | 1167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/MicrotonalUI.fl | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/PartUI.fl | 1047+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/ResonanceUI.fl | 306+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/SUBnoteUI.fl | 382+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/SeqUI.fl | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/VirKeyboard.fl | 385+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/UI/WidgetPDial.fl | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/default.bnk_zyn | 0
Asrc/globals.h | 206+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/main.C | 577+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/zynaddsubfx_gcc.def | 3+++
193 files changed, 27201 insertions(+), 0 deletions(-)

diff --git a/COPYING b/COPYING @@ -0,0 +1,347 @@ + +NOTE! The GPL below is copyrighted by the Free Software Foundation, but +the instance of code that it refers to (the ZynAddSubFX application) +is copyrighted by the author (Nasca Octavian Paul) who actually wrote it. +--------------------------------------------------------------------------- + + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog @@ -0,0 +1,501 @@ +6 Mar 2002 -(dupamasa - in jur de ora 4) Mi-a venit ideea cand ma plimbam pe strada Rolirudnap +7/8 Mar 2002 - Started to do diagrams +10 Mar 2002 - Started to write "voice" +11 Mar 2002 - Heard first sound +12 Mar 2002 - tested with 200 voices +16 Mar 2002 - made "Note" the main class + - added vibratto + - added glissando +20 Mar 2002 - started to write the Envelope class +21 Mar 2002 - Envelope written (almost) + Volume envelope almost written +23 Mar 2002 - Scris relasenote(putin) + Envelope-ul este si in dB + "glissando" este inlocuit cu "Envelope" de frecventa + started to write the LFO class +24 Mar 2002 - Corrected a bug that could crashed the synth (forgotten to disable the amp/freq envelopeenabled when killed it) +25 Mar 2002 - Started to write the Filter class (wrote only few lines) +27 Mar 2002 - Scris filtrul(putin), si FilterEnvelope +28 Mar 2002 - Adaugat la LFO si tipul "rampup" si "rampdown" + Scris filterLFO si amplitudeLFO(termollo) + redenumiti si aranjati parametrii + Adaugat LFO delay + Scris FilterEnvelope(corect) si FilterLFO(corect) +29 Mar 2002 - Adaugat RingModulation + Adaugat FM/RM Amplitude si Frequency Envelope + Corectat un bug minor la Envelope-ASRinit(); + Adaugat FM +01 Apr 2002 - Corectat un bug care facea sa se auda paraituri la sunetele care incepeau co o faza!=0 + Scris cativa dintre parametrii globali Envelop-ulire,LFO,Filter,.. +02 Apr 2002 - Curatat putin ADnote + Adaugat VelocityScale la amplitudine, la FM si la Filtru Global +03 Apr 2002 - Aranjati toti parametrii ADnote in structuri +04 Apr 2002 - Mutati multi parametrii in ADnoteParameters + Inceput sa scriu ADnoteParameters +05 Apr 2002 - Inceput sa scriu clase speciale pentru parametrii(midi) (LFO..) +06 Apr 2002 - Continuat sa scriu clasele speciale pentru parametrii + Teoretic merge sinteza multitimbrala(Adica se poate aplea ADnote(canal,note,vel)) +07 Apr 2002 - Completat(aproape) transferul de parametri midi la cei reali +08 Apr 2002 - Added FM oscil at parameters and corrected a small FM bug +09 Apr 2002 - Inceput sa-l fac real-time +10 Apr 2002 - Merge la keyboard-ul MIDI, polifonic +27 Apr 2002 - Scris interfata la OSS, la latenta scazuta + Corectat un bug care facea ca sa se execute calcule inutile, ceea ce facea ca polifonia maxima sa scada de 10 ori +29 Apr 2002 - Inceput sa scriu interfata midi(obiect) +30 Apr 2002 - Continuat putin interfata midi (dar nu am terminat) +02 Mai 2002 - Merge in timp real cu latenta scazuta, dar se mai auda niste "pacanaituri" +03 Mai 2002 - Inceput sa scriu Reverb (acum este doar ecou) + "Pacanaiturile" au fost eliminate. +09 Mai 2002 - Reverb-ul suna a reverberatie +11 Mai 2002 - Adaugat cativa parametrii midi la Reverb +18 Mai 2002 - Adaugat filtrul AllPass la Reverb si adaugat parametrul Plohidamp +19 Mai 2002 - Adaugat InitialDelay (idelay) la Reverb +24 Iun 2002 - Clasa Filtru nu mai este dependenta de FilterParams(pot sa-l folosesc in alte scopuri) + Corectat un bug la filtru care facea ca la rezomante scazute sa amplifice f. mult basii + Adaugat High Pass Filter + Rezonanta filtrului este exponentiala + Adauga LPF+HPF la Reverb + Inceput sa scriu Generatorul de Functii (OscilGen) +25 Iun 2002 - Scris cateva forme de unda (functii) + Reverb-ul are volumul in dB si daca este zero(ca parametru) atunci se dezactiveaza +02 Iul 2002 - Adaugat inca o functie la generatorul de functii +03 Iul 2002 - Inceput sa scriu generarea de functii la OscilGen pe baza de FFT + Inlaturat DC-ul de la OscilGen +04 Iul 2002 - Adaugat ANTI-ALIASING la ADnote si insumarea armonicelor se face in domeniul frecventa + Corectat un bug care facea sa sune rau dac OSCIL_SIZE!=512 (era declarat de 2 ori) +12 Iul 2002 - Adaugat posibilitatea de a folosi ca modulator alta voce + Adaugat parametrii MIDI la OscilGen +13 Iul 2002 - Adaugat Randomness la clasa OscilGen +15 Iul 2002 - Adaugat si Panning(incl. Randomness) => instrumentul este acum stereo +16 Iul 2002 - Adaugat Randomness la LFO (faza 0 => random) + Inlaturat o eroare care facea ca amplitudinea sa nu fie interpolata +17 Iul 2002 - Volumul FM-ului este exponential + Adaugat atenuare la volumul FM-ului la note inalte +23 Iul 2002 - Adaugat EnvelopeStretch + Corectata o eroare care facea ca uneori sunetul sa se auda foarte tare la inceput + Adaugat fade-in (f. scurt) si fade out in caz ca envelop-ul are A=0 sau R=0, a.i. sa nu se auda pacanaituri +24 Iul 2002 - Corectat Relase-ul la Envelope si adaugat ForcedRelase +25 Iul 2002 - Adaugat posibilitatea de a nu folosi AntiAliasing-ul + Adaugat Frequency Modulation (nu phase modulation) + Adaugat Delay la fiecare voce + Adaugat Morphing la modulatie +26 Iul 2002 - Inceput sa scriu clasa Part +27 Iul 2002 - Se face controlul Midi folosind clasa Part si nu ADnote +28 Iul 2002 - Corectata o eroare care facea sa se instantieze clasa ADnoteParameters pt. fiecare nota => memoria era ocupata excesiv si "manca" din procesor. Cauza erorii este ca trimiteam obiectul ADnoteParameters ca parametru si nu referinta lui. Asta era cauza pacanaiturilor ce se auzeau daca apasam multe clape simultan. +29 Iul 2002 - Adaugat clasa Master (Permite acum mai multe instr. simultan => multitimbral) + Observat o eroare la Envelope +30 Iul 2002 - Adaugat EnvelopeStretch si Forcedrelase la instantierea unui obiect EnvelopeParams + Durata Sustainul-ui fortat este acceeasi indiferent de paramentrul EnvelopeStretch + Adaugat Ecou +31 Iul 2002 - Daca VelocityScaleFunction=127 atunci orice vel. va face amplitudinea maxima (ca si cand vel.=127) + Inceput sa scriu Interfata Utilizator +01 Aug 2002 - Toti parametrii sunt convertiti in REALTYPE direct de ADnote,de LFO + Inlataurate mici probleme de AntiAliasing daca detune-ul era prea sus si la unele moduri FM + Programul incepe sa fie controlabil de Interfata +02 Aug 2002 - Inlaturat o eroare stupida care facea ca sa se seteze valorile EnvelopeParams la -1 (scria din Master:: prea mult) +03 Aug 2002 - Terminata interfata pentru ADnoteParameters.GlobalPars + Adaugat inca un parametru la lfo (continous LFO) care faca ca LFO-ul sa nu inceapa la fiecare NoteOn + Corectat doua erori la ...[nvoice].AmpEnvelope si ...[nvoice].FreqEnvelope + Scrisa interfata pentru ADnoteParameters.VoicePars (fara FM+OSCIL...) +04 Aug 2002 - Scrisa interfata cu FM (fara Oscil) + Corectate doua erori cu provire la FMampenv si FMfreqenv + Inlaturat aliasing-ul la vocea FM + Modificata interfata (Voice si FM-ul sunt intr-o singura fereastra) + Inceput sa scriu schimbare voce curenta. +05 Aug 2002 - Adaugat interfata pentru cei mai importanti parametrii ai ADnote_VoicePar[nvoice] + Inceput sa scriu interfata pentru OscilGen +06 Aug 2002 - Este mult mai usoara schimbarea vocii curente. + Inceput sa scriu OscilEditor + Nu mai este necesara changebasefunc() la oscil pentru a schimba basefunction, se apeleaza automat. + OscilEditor este (aproape) complet + Toti parametrii ADnoteParameters au UI + Corectate cateva erori (cauzate de faptul ca nu am verificat daca ADnote::...Enabled!=0) +07 Aug 2002 - Corectata o eroare la envelope + Adaugat afisaj spectrum la OscilEdit + Adaugat parametrii noi: extenal oscillator (voice si FM) si oscilphase(si FM) si interfata pentru ei + Gasite mai multe erori care apar daca misc widget-urile in timp ce cant la clape (probabil este vorba de thread-uri care trebuie sa fie sincronizate sau ceva cam asa sau memory leaks) + Inceput sa scriu interfata pentru Part + Adaugat bypass la filtrul global + Adaugat conversia oscil-ului in basefunction + Corectata o mica eroare la calcularea oscil-ului referitor la faze +08 Aug 2002 - In VoiceList valorile sunt actualizate la fiecare apasare a butonului "ShowVoiceList" si formele de unda sunt afisate corect. + Corectate niste mici erori la FM + Daca se foloseste ca modulator o alta voce, interfata dezativeaza unii parametrii FM daca sunt inutili + Inceput sa scriu interfata si parametrii Master/Part + Schimbat putin Master si Part (atentie sa nu se instantieza ADnoteParameters la fiecare apasare de tasta) + Inceput sa scriu control-ul pentru Master/Parts +09 Aug 2002 - Scris parametrii Part si Master + Inceput sa scriu sincronizarea intre thread-uri +10 Aug 2002 - Adaugat o noua forma de unda la OscilGen + Adaugat sincronizarea intre thread-uri=>programul nu mai crapa daca in timp ce apas clapele, modific forma de unda + Adaugat enable/disable ADnote + Inceput sa scriu SUBnote/SUBnoteParameters + Se poate canta si la SUBnote(inceput sa scriu UI pt. el) +11 Aug 2002 - Scris controlul armonicelor + Adugati cativa parametrii la SUBnote + Adaugat AmpEnvelope la SUBnote(si UI) +12 Aug 2002 - Adaugat Detune la SUBnote si schimbat Detune-ul la ADnote + Adaugat FreqEnvelope la SUBnote +16 Aug 2002 - Corectata o eroare care facea ca VoiceOut sa fie inlaturat chiar daca era inca folosit(de alte voci) + Daca "Forced Relase" este off atunci se face relase-ul liniar + Adaugat BandWidth Envelope +17 Aug 2002 - Inceput sa pregatesc pentru EffectManager +18 Aug 2002 - Adaugat inca un parametru la Reverb: initial delay fb + Scris efectele de insertie + Inceput sa scriu efectele de sistem +19 Aug 2002 - Continuat sa scriu efectele de sistem + Inceput sa scriu interfata la Efecte (Reverb - terminat, aproape) +22 Aug 2002 - Corectata o eroare la Echo + Se poate schimba efectul de insertie + Gasita o eroare care "crapa" programul daca schimb efectul de le Reverb (rezolvata temporar, dar cu "memory leak") +23 Aug 2002 - Corectata eroarea la Reverb (a fost din cauza ca am pus ">" in loc de ">=" :-p ) + Terminat efectele de insertie(si interfata) + Adaugat Effect cleanup + Scrisa interfata pentru efectele sistem (cu exceptia sendto another sys eff) +24 Aug 2002 - Adaugate doua noi efecte: Chorus si Phaser +25 Aug 2002 - Nu se mai aude tacanit la Chorus daca schimb Delay/Depth + Corectat o mica eroare care facea ca sa nu se afiseze Pinsparts corect + Adaugat un nou efect: AlienWah + Nu se mai aude tacanit la Phaser si la AlienWah la frecvente LFO f. mari +27 Aug 2002 - Adaugata o noua forma de unda: Chirp + Adaugat Waveshaping la OscilGen + Se poate compila si fara UI + Inceput sa scriu Salvarea/Incarcarea Parametrilor +28 Aug 2002 - In ADnoteVoiceListUI se afisaza corect daca vocea este activata/dezactivata + Scrisa Salvarea/Incarcarea parametrilor (cu exceptia la OSCIL::UseAsBaseFunction) + Adaugat File Save/Open +29 Aug 2002 - Se poate salva si oscil::useasbase + Se afiseaza corect valorile dupa incarcare +01 Sep 2002 - Adaugat "codul de intrare" sa saveload 0xfe pt. a sti de unde incepe o noua "ramura" + "Codul de intrare" este folosit pentru a nu incarca "ramurile" care nu se potrivesc cu specificatiile (ex. nr. de voce sau nr. part prea mare) + Adaugat header la fisier + Imbunatatit OscilUI::useasbase +03 Sep 2002 - Modificat codurile de parmetrii: indicele par. sunt >= 0x80, parametrii <0x80 , controlerii speciali(urcare/coborare creanga) >=0xf0; Este util la versiunile viitoare, la forward/reverse compatibility. + Inceput sa scriu clasa Microtonal si interfata pt. Microtonal +04 Sep 2002 - Adaugat Pfilterbypass la salvare (am uitat sa o pun pana acum) + Aproape terminat Microtonal-ul (cu exceptia importului din fisiere .scl) +05 Sep 2002 - Facut cateva mici modificari la Microtonal si Echo + Adaugat un nou parametru la ADnote: PVolumeminus + Adaudat parametrii noi de Detune: Pcoarsedetune(coarse+octave) si Pdetunetype + Adaugat cateva tipuri de detune +06 Sep 2002 - Adaugat posibilitatea de a folosi ADnotepars:Globalpars.Pdetudetype in loc de Pdetunetype (0 = default detunetype), asa ca nu mai trebuie sa mai modific la fiecare voce detunetype: setez la 0 si modific global-ul + Facut mici modificari la MidiInput(OSS) +07 Sep 2002 - Corectata o eroare cu privire la detune si daca freq. > Nyquist + Modificat driver-ul OSSmidiin + Adaugat driver Alsa cu port virtual + Se poate salva doar instrumentele/microtonal. + Adaugata un nou fel de waveshaping(Zigzag) +08 Sep 2002 - Psysefxvol[][] sunt scalate in dB + Nu mai este periculos sa inchid fereastra principala +09 Sep 2002 - Se actualizeaza corect la incarcare la Master:Psysefxvol[][],Pvolume,Pkeyshift; si alti parametrii la Part + Adaugat nume la Part + Panic-ul (Shut-up-ul) se aplica si la efecte + Part->Penable controleaza de fapt daca Part-ul este activat/complet dezactivat. Daca se dezactiveaza un part toate notele+ efectele insertion sunt oprite. Nu mai consuma CPU daca folosesc multe part-uri. + Adaugat un nou parametru la part: Pnoteon care controleaza daca part-ul primeste mesaje NoteOn + Adaugarea extensiei se face automat. + Adaugat LFO exp_up 1 si 2 + Curatat putin de memory leaks (mai am de curatat si interfata) +10 Sep 2002 - Adaugat filtrul HPF cu un pol + Interfata se inchide corect. + Adaugat textul cu Copyright in interfata + Traduse toate comentariile in limba engleza + Adaugat licenta in fiecare fisier +11 Sep 2002 - Adaugat descriere la fiecare fisier + Corectata o eroare care facea ca SUBnote sa aiba amplitudini f. mari la freq. f. inalte + Adaugat cateva macro-uri la interpolarea amplitudinii +12 Sep 2002 - Modificat extensiile (*.mas.zyn ---> *.mas_zyn, la fel si celelalte) pentru a nu aparea fisiere *.mas.mas.zyn +13 Sep 2002 - Am decis numele programului: "ZynAddSubFX" (Zyn de la synthetizer (inlocuit S cu Z), Add de la additive, Sub de la substractive, FX de la effects) +14 Sep 2002 - Volumul din ADvoicelist se afiseaza corect +15 Sep 2002 - Adaugat inca 3 moduri de waveshaping Limiter, UpperLimiter, LowerLimiter +16 Sep 2002 - Adaugat Makefile +17 Sep 2002 - Corectata o mica eroare care facea ca sa nu se incarce fisierele cu data intotdeauna + Nu se amplifica freq. f. inalte daca freq. filtrului este mare. + Inceput sa scriu documentatia. +18 Sep 2002 - Adaugat functia de resetare a tuturor parametrilor(master si instrument) +23 Sep 2002 - Adaugat posibilitatea de a conecta efectele de insertie la iesire Master + Lfo-ul la frecventa incepe de la 0 pt. startphase=0 +24 Sep 2002 - Corectate niste mici erori la Chorus/Phaser + Adaugat si "substract" la Chorus si Phaser + Limitat tipul detune-ului la valoarea maxima +25 Sep 2002 - LANSAT PE INTERNET - PRIMA VERSIUNE (1.0.0) +-------------------------------------------------------------------------------------------------- +01 Dec 2002 - Corectat niste comentarii + - Inlaturat o eroare care facea ca ZynAddSubFX sa crape daca dezactivez un part utilizat + - Inceput sa scriu Rezonanta +02 Dec 2002 - Terminat de scris Rezonante + - Adaugat filtru trecer-banda (BPF) + - Scris Recording +03 Dec 2002 - Adaugat Gain la Resonance + - Adaugat "New Instrument" la meniu +06 Dec 2002 - LANSAT PE INTERNET - VERSIUNEA (1.0.1) +-------------------------------------------------------------------------------------------------- +08 Dec 2002 - Inceput sa scriu Bank si interfata pentru Bank +09 Dec 2002 - adaugat si "make debug" + - Continuat sa scriu Bank/UI; acum se poate folosi (dar nu salva pe HDD) +10 Dec 2002 - Terminat Bank (mai trebuie scris un "config" file pentru a alege automat ultima banka folosita) +11 Dec 2002 - Am mai lucrat ceva la Bank si am adaugat "config file" +12 Dec 2002 - Filtrul BPF suna mai tare + - Nu mai ar trebui sa fie probleme la compilarea FFTwrapper.h (fftw.h) +13 Dec 2002 - LANSAT PE INTERNET - VERSIUNEA (1.0.2) +-------------------------------------------------------------------------------------------------- + - Corectat o eroare care facea ca programul sa crape daca salvam parametrii in timp ce cantam + - LANSAT PE INTERNET - VERSIUNEA (1.0.2-1) - de acasa +-------------------------------------------------------------------------------------------------- +21 Dec 2002 - Corectate mici erori (nu mai dispare "Bypass Global Filter", inlaturat zgomotul de mica amplitudine - cauzat de reverb,nu mai apare intarzierea foarte lunga de la inceput a notelor muzicale daca conectam la aseqview) + - Adaugat filtru de rejectie banda (Notch) + - adugat randomize la Resonance + - Inceput sa scriu VU-meter-ul +22 Dec 2002 - Terminat VU-meter-ul + - Schimbat modul in care efectele de insertie se calculeaza (suna mai tare un pic) + - Adaugata o noua functie la OscilGen +23 Dec 2002 - LANSAT PE INTERNET - VERSIUNEA (1.0.3) +-------------------------------------------------------------------------------------------------- +24 Dec 2002 - Adaugata posibilitatea de a incarca fisiere ".scl" (la Microtonal) +26 Dec 2002 - Adaugata optiunea de a folosi numai OSS-ul (fara ALSA) +27 Dec 2002 - Corectate cateva erori si modificate cateva lucruri marunte la Microtonal +28 Dec 2002 - Mici modificari la Microtonal + - Panic-ul la Reverb functioneaza OK + - Inceput sa scriu Scale Degree Mapping la Microtonal +29 Dec 2002 - Continuat Scale Degree Mapping la Microtonal (dar nu am terminat) +30 Dec 2002 - Corectat lucrul cu ScaleShift-ul + - schimbat modul in care se face keyshift-ul (nu se mai schimba armonia, indiferent de sistem) +31 Dec 2002 - Terminat Mapping-ul la Microtonal(incl. incarcarea/salvarea) + Corectat eroarea care facea ca la Microtonal sa nu se incarce de fiecare data din scl_zyn unele date + +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +01 Ian 2003 - Corectata o eroare la Microtonal (erau probleme la InvertKeys daca era folosit key mapping) + - Adaugata un nou tip de waveshaping (Inverse Limiter) +02 Ian 2003 - Adaugat afisaj al acordului fin (cents) + - Butoanele arata f. frumos (am adaugat un nou widget in loc de Fl_Dial) +03 Ian 2003 - Schimbate butoanele (putin) + - Nu se mai aude un tacanit la ShutUp sau AllNotesOff + - Corectat putin waveshaper-quantisize si butoanele + - Inlaturata o eroare care facea ca programul sa crape daca schimbam unii parametri ale efectelor +07 Ian 2003 - LANSAT PE INTERNET - VERSIUNEA (1.0.4) +-------------------------------------------------------------------------------------------------- +08 Ian 2003 - Am inlaturat de-a binelea eroarea (cu efectele - 3 Ian) +11 Ian 2003 - Corectate o mica eroare care facea ca volumul sa fie negativ la ADnote::voice[].PVolume <64 +13 Ian 2003 - Corectata o mica eroare la VU-Meter + - Corectata o mica eroare cu privire la panning la Reverb +15 Ian 2003 - Adaugat min/max keyresponse limits la Part + - Adaugat Filtru si FiltreEnvelope la SubNote +16 Ian 2003 - Curatat codul sursa (ADnote) prin inlaturarea unor variabile + - Durata fadein-ul este aleasa automat (a.i. sa nu rezulte click-uri la notele joase si nici fadein-ul audibil la notele inalte sau cu freqcvente inalte) + - Corectata o mica eroare care faca ca uneori instrumentul sa nu fie salvat/sters la Bank slot-ul cerut + - Imbunatatita putin interfata: La ADnote si SUBnote, butoanele care controleaza amplitudinea armonicelor sunt colorate diferit daca au amplitudinea 0 +17 Ian 2003 - Corectate erori la Chorus si la Phaser care faceau ca sa sune prea 'sec' (din cauza ca wet-ul era la 50% din volum) +18 Ian 2003 - Inceput sa scriu Preset-uri la efecte +19 Ian 2003 - Adaugat Preset-urile la efecte +20 Ian 2003 - Schimbat putin HPF-ul la Reverb +21 Ian 2003 - Adaugat tuning-ul la Reverb (si Freeverb) si Roomsize + - Schimata putin interfata si modificat putin widgetul Pdial +22 Ian 2003 - Amplificat volumul Reverb-ului cu 6 dB + - Buffer-ul foloseste liste simplu-inlantuite, asa ca nu-i mai problema la "configuratii mari" (multe part-uri) +24 Ian 2003 - LANSAT PE INTERNET - VERSIUNEA (1.0.5) +-------------------------------------------------------------------------------------------------- +26 Ian 2003 - Inceput sa scriu GetAudioOutSamples, care ar putea fi apelat in modul callback +27 Ian 2003 - Adaugat o noua fuctie la waveshaping (clip) + - Adaugat suportul pentru Jack (adica programul poate rula in modul call-back ;-) ) + - Inlaturata o eroare care facea ca npart sa fie foarte mare si ca programul sa crape +29 Ian 2003 - Schimbari foarte minore la OscilGen::waveshape (la clip) + - Daca dau "clear" la OscilEdit, butoanele care au amplitudinea zero, sunt colorate corect +30 Ian 2003 - LANSAT PE INTERNET - VERSIUNEA (1.0.6) +-------------------------------------------------------------------------------------------------- +31 Ian 2003 - Inceput sa adaug optiuni la linia de comanda + - Rata de esantionare (SAMPLE_RATE) este setata la rulare si nu la compilare +01 Feb 2003 - Inca 2 variabile sunt setate la rulare (SOUND_BUFFER_SIZE si OSCIL_SIZE) + - Volumul la Part se aplica doar dupa efecte de insertie + - Inceput sa scriu Distorsionarea (fara filtre) +02 Feb 2003 - Schimbate modurile de distorsionare (exp -> asym1 si pow -> pow ( altul ) ) + - Terminat Distorsionarea +03 Feb 2003 - Adaugata inca o functie la waveshape (asym2) + - Inceput sa scriu Controller-ii + - Adaugat controller-i PitchWheel,Expression,Panning,Filter Cutoff, Filter Q, BandWidth, Modulation Wheel + - Panning-ul si volumul sunt interpolate + - Inceput sa scriu un nou program (Controller) care timite mesaje midi (controller) catre un port ALSA + - Panning-ul la Part se aplica doar dupa efecte de insertie + - Panning-ul la efecte se aplica inainte de procesare +04 Feb 2003 - Adaugat posibilitatea de a seta intensitatea/dezactiva la controlleri(incl. UI) + - Adaugat controler-ul FMmodulationAmplitude + - Corectat o eroare la Buffer (care facea ca Buffer-ul sa nu se reseteze :-P ) +05 Feb 2003 - Corectata o eroare care facea ca programul sa consume mult din procesor (denormalisation) + - Nu mai este permisa o valoare a lui OSCIL_SIZE care sa nu fie putere a lui 2 (este ajustata automat) + - Adaugat controller-i Volume si Sustain Pedal, AllNotesOff, AllSoundOff, ResetAllControllers + - Adaugat NRPN, adica toti parametrii efectelor pot fi controlati prin controlleri +06 Feb 2003 - Pus limite la parametrii efectelor a.i. sa nu se seteze (datorita controllerilor) la valori nevalide + - Inlaturata o mica eroare la controller-ul BandWidth + - Schimbat putin EffectLFO::updateparams + - Controler-ul BandWidth afecteaza doar FineDetune-ul + - Schimbat putin identificare controlerilor si adaugat controlleri la OSS + - Schimbat putin interfata utilizator la controlleri +07 Feb 2003 - LANSAT PE INTERNET - VERSIUNEA (1.0.7) +-------------------------------------------------------------------------------------------------- +08 Feb 2003 - Adaugat modul "mono"(monofonic) la part + - Inceput sa scriu portamento-ul +09 Feb 2003 - Terminat portamento-ul +10 Feb 2003 - Inceput sa scriu Equaliser-ul + - Inlaturata o eroare care facea ca la parametrii efectelor care sunt 0 sa nu fie incarcati +11 Feb 2003 - Terminat Equaliser-ul (adica adaugat vizualizator freq response) + - Corectata o mica eroare care facea ca part-ul 0 sa fie activ chiar daca cel salvat era inactiv +12 Feb 2003 - Mici modificari la EQ (UI) + - Adaugata posibilitatea de swap (stanga <--> dreapta) + - Adaugat Q la filtrele shelf +13 Feb 2003 - Adaugat inca un parametru la Phaser (phase) + - Curatit putin codul sursa la efecte + - Adaugat system effect send to next systems effects +14 Feb 2003 - LANSAT PE INTERNET - VERSIUNEA (1.0.8) +-------------------------------------------------------------------------------------------------- + - cateva mici modificari (de la un patch primit de pe Internet) + - adaugat keylimit la Part (si first note priority) +15 Feb 2003 - Corectata o foarte mica eroare la Part +16 Feb 2003 - Se poate aplica filtrul inainte de distorsion + - Adaugat filter stages (adica filtrul se poate aplica de mai multe ori) +17 Feb 2003 - Corectata o mica eroare la Reverb si modificat putin filter-ul si UI +18 Feb 2003 - Corectata o eroare care facea ca semnalul la voice sa fie intre [-4.0..4.0] si sa faca probleme la RingModulation + - Adaugat modul Noise la ADsynth(voice) pentru a putea produce si tobe + - Adaugat parametrul fixed frequency la 440Hz +19 Feb 2003 - Corectata o mica eroare la ADnote (aparea un fadein nedorit) + - Facute inca cateva mici modificari la ADnoteUI +20 Feb 2003 - Imbunatatit foarte mult Controller-ul si adaugat la ZynAddSubFX ca program extern + - Modificat putin Waveshaper-ul (fct. L/U limit) + - Corectata o eroare la SUBnote (care facea probleme la glissando) + - Adaugat un nou parametru Punch la ADnote care face ca sa sune ca si cum ar fi o lovitura (f. util la Rhodes) +21 Feb 2003 - Adaugata inca o functie de distorsionare x(1-x) +23 Feb 2003 - Corectata o eroare (cu mutex) care facea ca sunetul sa fie extrem de tare, daca in timp ce cantam, modificam unii parametrii de sunet la ADnote +24 Feb 2003 - LANSAT PE INTERNET - VERSIUNEA (1.0.9) +-------------------------------------------------------------------------------------------------- + - Adaugata posibilitatea de a tipari notele si timpul in care au fost produse (optiunea -D) +26 Feb 2003 - Adaugat inca 2 controlleri (Resonance Center Freq. (relative) si Resonace Bandwidth(relative)) +27 Feb 2003 - Adaugata posibilitatea de a modifica parametrii (in mod direct) al oscilatorului extern +07 Mar 2003 - Portat partial(doar interfata) programul sub Windows +08 Mar 2003 - Adaugat Virtual Keyboard + - Cateva mici modificari in vederea portarii pt. windows + - Adaugat si controller la Virtual Keyboard +09 Mar 2003 - Adaugat pitch wheel la Virtual Keyboard si modificat putin controller-ul la VK +10 Mar 2003 - Adaugat Filter Frequency Tracking (adica modificarea frecventei filtrului in functie de frecventa notei) + - Marite eficienta la LFOparams - update lfotime + - Adaugat mod de normalize prin RMS + - Corectate doua erori la Distorsion (negate si mono+prefiltering) +11 Mar 2003 - In Windows, nu mai este necesar functiile getopt (scrisa o functie proprie) +12 Mar 2003 - Adaugat filtru la OscilGen +13 Mar 2003 - Adaugat mai multe filtre la OscilGen + - Facute optimzari la ADnote (adaugarea unui element la oscilsmp si fmsmp,etc.) si curatat putin codul sursa + - Corectata o eroare care amplifica fm-ul la rate de esantionare inalte + - Optimizat si curatat reverb-ul +16 Mar 2003 - Modificate optiunile de compilare in Makefile.inc si coduri sursa a.i. sa se realizeze portarea pe windows mai usor +17 Mar 2003 - Inregistrarea se face in formatul WAV si nu RAW + - Adaugat trigger la recorder (se incepe inregistrarea doar cand este apasata o nota) + - Adaugat interfata PortAudio + - Corectata eroarea care facea ca UI sa nu ruleze pt. Windows (trebuia dat show() la UI in thread-ul 3) si corectate alte erori din windows + - Si audio-ul functioneaza sub Windows + - Corectata o eroare care se manifesta foarte rar(Resonance, i era de la 0 si nu de la 1) +18 Mar 2003 - Adaugat interpolare la filtru (nu se mai aud tacanaituri, daca frecventa filtrului se schimba foarte rapid si semnalul contine putine armonice) + - Adaugat interfata Midi in Windows => consider ca programul este portat in Windows +19 Mar 2003 - Adaugat interfata de configurare + - Corectata o eroare la OscilGen care facea ca in loc ca amplitudinile sa fie reduse la -40,..,-100dB, sa fie setate la 1 si unde era intensitate mare sa file amplificate +20 Mar 2003 - Corectata o mica eroare la interfata (uneori disparea butonul ON de la ADvoice) +21 Mar 2003 - LANSAT PE INTERNET - VERSIUNEA (1.2.0) +-------------------------------------------------------------------------------------------------- + - Se interpoleaza filtrul si cand se trece peste pragul Nyquist (in sus sau in jos) +22 Mar 2003 - Corectata o eroare care facea ca nr. de esantioane scrise in headerul fisierului WAV sa nu fie initializat +26 Mar 2003 - Nu mai este permisa alegerea unui fisier wav in timpul pauzei de la record + - Gasita si corectata o eroare stupida (am pus la NRPN 0x98 in loc de 98 zecimal) +28 Mar 2003 - Inceput sa portez programul sub VST +29 Mar 2003 - Adaugat Master fine detune (-64.0 .. 63.0 cents) +01 Apr 2003 - Functioneaza portarea sub VST, dar mai este de lucru... +02 Apr 2003 - Modificat synth-ul a.i. sa se poate apela in mai multe instante in VST + - Continuata portarea in VST +03 Apr 2003 - Continuata portarea in VST (este limitat la o singura instanta) +05 Apr 2003 - Adaugata posibilitatea de a interschimba/copia parametrii efectelor + - Mici modificari la Makefile (ignora headerele inexistente la deps) +06 Apr 2003 - Adaugat posibilitatea de protectie impotriva atenuarii a notei fundamentale la rezonanta + - Pitch bend-ul merge bine in Windows +07 Apr 2003 - LANSAT PE INTERNET - VERSIUNEA (1.2.1) +-------------------------------------------------------------------------------------------------- + - Adaugat efect la part (adica efect care face parte din instrument ;-) ) +08 Apr 2003 - Adaugata interpolare la Resonance (peak-urile le interpoleaza) +09 Apr 2003 - Interfata la Envelope este o singura clasa + - Adaugat Envelope free mode (adica de orice forma) + - Adaugata posibilitatea de a copia de la o voce la alta la ADnote + - Release-ul este liniar (in loc de dB) +10 Apr 2003 - Adaugata afisarea ultimului fisier master salvat/incarcat + - Adaugata setarea notei minime/maxime la ultima nota + - Pot alege daca release-ul sa fie liniar + - Facute cateva corecturi la envelope +11 Apr 2003 - Curatat codul sursa la UI si impartit in mai multe fisiere .fl + - Corectate niste erori la Envelope si adaugat modul liniar/logaritmic la amplitudine +12 Apr 2003 - Inceput sa scriu kit-ul la part +13 Apr 2003 - Terminat de scris kit-ul la part+UI +14 Apr 2003 - Copierea vocilor este sub forma de clipboard + - ADsyn su SUBsyn check-urile de la PartUI sunt actualizate +15 Apr 2003 - LANSAT PE INTERNET - VERSIUNEA (1.4.0) +-------------------------------------------------------------------------------------------------- +16 Apr 2003 - Adaugat modul "Single" la instrument kit, care face ca sa sune doar primul instrument din kit disponibil +21 Apr 2003 - Adaugat realtime priority, care seteaza prioritatea mare la sintetizator, daca are posibilitate; merge numai pe Linux + - Gasite multe erori mici(dar potential periculoase) cu ajutorul programului Valgrind +30 Apr 2003 - Adaugat "Spectrum adjust" la OscilGen, care ajusteaza intensitatile armonicelor +03 Mai 2003 - Normalizat spectrul inaintea adjust-ului la OscilGen +04 Mai 2003 - Adaugat mod "egal temperat" la fixed frequency (440Hz), util la tobe +05 Mai 2003 - Adaugat modul "Drum mode", unde sistemul este intotdeauna temperat (12tET), toate notele sunt mapate si transpose-ul este ignorat +08 Mai 2003 - LANSAT PE INTERNET - VERSIUNEA (1.4.1) +-------------------------------------------------------------------------------------------------- +09 Iun 2003 - Am schimbat <FL/... .h> in .H in fisierele .fl (ca sa se poate compila si pe Debian) +10 Iun 2003 - Inceput sa modific interfata la filtru a.i. sa pot adauga filtrul formantic usor + - Interfata pentru filtru este o singura clasa +12 Iun 2003 - Inceput sa scriu panoul de part-uri (care afiseaza parametrii importanti ale part-urilor) + - VU-meter-ul poate afisa si intensitatea part-ului dorit (folosit la panou de part-uri) +13 Iun 2003 - Terminat panoul de part-uri + - Adaugat posibilitatea de a inchide automat fereastra bancii de instrumente, cand se incarca un instrument +19 Iun 2003 - Modificat modul cum se calculeaza frecventa filtrului (se fac doar adunari si doar la urma se ridica la putere) +22 Iun 2003 - Aproape terminat filtrul formantic (fara UI) +24 Iun 2003 - Merge mai multe instante in jack (alege porturi diferite) +26 Iun 2003 - Continuat de scris filtrul formantic +29 Iun 2003 - Adaugat vu-meter fals la Panel (in caz ca partul este dezactivat si primeste note on). De asemenea se arata daca in partul dezactivat s-a cantat ceva (apare o liniuta). +09 Iul 2003 - Inceput sa scriu interfata pentru filtrul formantic +10 Iul 2003 - Continuat filtrul formantic (interfata) +11 Iul 2003 - Eroarea vine de la Makefile pt. ca nu recompileaza si clasele care folosesc o anumita clasa, daca aceasta din urma se schimba + - Continuat filtrul formantic (interfata+adaugarea interpolarii la Q) +12 Iul 2003 - Adaugat la filtrul formantic setarile de amplitudine formanti si interpolarea acestora + - Adaugat grafic la UI-ul filtrului formantic si alti paramatrii la filtrul formantic +13 Iul 2003 - Corectata eroarea la FormantFilter care facea ca sa nu se interpoleze intre vocale + - Adaugat parametrul VowelClearness la FormantFilter care face ca sa se evite vocalele mixte +14 Iul 2003 - Inlaturat parametrul Psequence[].pos, pt. ca era confuz => fiecare vocala are zona egala + - Adaugat parametrii Psequencestretch si Psequencereversed la FormantFilter + - Adaugat parametrul Pgain la filtru (-30...30 dB) + - Terminat de scris Filtrul Formantic + - Corectata o eroare care facea ca sa nu se salveze oscilatorul la o ADnote_voce, daca vocea este dezactivata, chiar daca era folosita de o alta voce + - Prima data se cauta fisierul "default.bnk_zyn" si in dir "/usr/share/zynaddsubfx" sau "/usr/local/share/zynaddsubfx" +15 Iul 2003 - Setat Pkeylimit prestabilit la 15 la Part + - Activarea unui Part din interfata Panel schimba automat part-ul curent la acela + - Se poate alege ca un instrument din Kit sa fie procesat incepand cu un anumit efect; si se mai poate alege ca un efect din Part sa fie trimis in afara +17 Iul 2003 - LANSAT PE INTERNET - VERSIUNEA (1.4.2) +-------------------------------------------------------------------------------------------------- +21 Iul 2003 - Corectata o eroare la FilterUI care facea ca la fiecare afisare sa se initializeze FilterParames::Pgain la 64 +25 Iul 2003 - Corectata o eroare care facea ca modulatia in faza/frecventa sa sune diferit la diferite rate de esantionare/oscilsize +26 Iul 2003 - Afisat corect - valoarea OSCIL_SIZE ajustata (in caz ca a fost data optiunea "-o" incorect) + - In windows arata si numele la midi_in_device +04 Aug 2003 - Adaugat filtrele Peak,LowShelf,HighSelf la filtru si foloseste parametrul Gain de la interfata filtrelor +30 Aug 2003 - Adaugat un nou tip de filtru: State Variable Filter +31 Aug 2003 - LANSAT PE INTERNET - VERSIUNEA (1.4.3) +-------------------------------------------------------------------------------------------------- +02 Sep 2003 - Adaugata posibilitatea de a incarca de la inceput un fisier .mas_zyn "-l" + - Se poate lansa programul fara interfata utilizator ("-U") +17 Sep 2003 - Adaugat niste simple patch-uri de Frank Neumann +02 Oct 2003 - Corectata o eroare la SUBsynth care facea ca la freq inalte si Q foarte mici sa se produca filtre instabile +30 Oct 2003 - Adaugate posibilitatea (+interfata in config) de Dump (avansat) + - Adaugat ModWheel liniar si facut prestabilit (si posibilitatea de a alege in interfata modul de modwheel) +04 Nov 2003 - Modificat putin interfata la ResonanceUI +05 Nov 2003 - Marita viteza prin inlocuirea de (int) cu cod de asamblare (cu.10-50% la FM,chorus,etc.) +10 Nov 2003 - Inceput sa adaug posibilitatea de a adauga comentarii la instrumente +11 Nov 2003 - Terminat de adaugat comentariile/autor/tipuri la instrumente +12 Nov 2003 - Adaugat intefata pentru FFTW3 la fftwrapper +18 Nov 2003 - Inceput sa scriu Sequencer-ul +19 Nov 2003 - Adaugat un buton "i" pt. instrument info si facut ca instrument info sa se afiseze automat daca se schimba partul (sau se incarca instrumente,etc) +20 Nov 2003 - Continuat de scris Sequencer-ul si inceput sa ii scriu interfata + - Mici modificari la preset-urile de la Echo +26 Nov 2003 - Continuat de scris sequencerul - inceput sa scriu inregistrarea (fara timer) +27 Nov 2003 - Se poate inregistra (dar nu rula) - adaugat timerul de inregistrat + - Frecventa maxima al filtrelor este de Nyquist-500.0 pentru a evita instabilitatea filtrelor +28 Nov 2003 - Adaugata favorizarea portamento-ului in sus sau un jos; ex. se poate face ca portamento-ul sa fie doar in sus, sa portamento-ul in jos sa fie mai scurt decat cel in jos + - Inceput sa pun pe cvs la cvs.sourceforge.net +\ No newline at end of file diff --git a/ExternalPrograms/Controller/Controller.C b/ExternalPrograms/Controller/Controller.C @@ -0,0 +1,74 @@ +#include "Controller.h" +#include <stdio.h> +#include <stdlib.h> +#include <math.h> + +pthread_mutex_t mutex; +int Pexitprogram; + +Controller::Controller(){ + //init + for (int i=0;i<6;i++){ + pars[i].mode=1; + pars[i].val1=0; + pars[i].val2=127; + pars[i].nrpn.cpar=8; + pars[i].nrpn.fpar=0; + pars[i].nrpn.cval=0; + }; + pars[0].ctl.par=71; + pars[1].ctl.par=74; + pars[2].ctl.par=10; + pars[3].ctl.par=11; + pars[4].ctl.par=1; + pars[5].ctl.par=75; + + //ALSA init + snd_seq_open(&midi_out,"default",SND_SEQ_OPEN_OUTPUT,0); + + char portname[50];sprintf(portname,"Controller"); + int alsaport = snd_seq_create_simple_port(midi_out,portname + ,SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ + ,SND_SEQ_PORT_TYPE_SYNTH); +}; + +Controller::~Controller(){ + snd_seq_close(midi_out); +}; + +void Controller::sendcontroller(int par,unsigned char val){ + snd_seq_event_t midievent; + snd_seq_ev_clear(&midievent); + + snd_seq_ev_set_controller(&midievent,Pchout,par,val); + + snd_seq_ev_set_subs(&midievent); + snd_seq_ev_set_direct(&midievent); + snd_seq_event_output_direct(midi_out,&midievent); + +// fprintf(stderr,"Controller: %d %d\n",par,val); +}; + +void Controller::sendnrpn(int npar,unsigned char val){ +// fprintf(stderr,"NRPN: %d %d %d %d\n",pars[npar].nrpn.cpar,pars[npar].nrpn.fpar,pars[npar].nrpn.cval,val); + + sendcontroller(0x99,pars[npar].nrpn.cpar); + sendcontroller(0x98,pars[npar].nrpn.fpar); + sendcontroller(0x06,pars[npar].nrpn.cval); + sendcontroller(0x26,val); +// fprintf(stderr,"------------\n\n"); +}; + +void Controller::send(int npar,float xval){ + if (pars[npar].mode==0) return; + int val; + if (pars[npar].val1<=pars[npar].val2) + val=(int) (xval*(pars[npar].val2-pars[npar].val1+1.0)*0.9999+pars[npar].val1); + else val=(int) (xval*(pars[npar].val2-pars[npar].val1-1.0)*0.9999+pars[npar].val1+1.0); + switch (pars[npar].mode){ + case 1:sendcontroller(pars[npar].ctl.par,val);break; + //case 2:break; + case 3:sendnrpn(npar,val);break; + }; +}; + diff --git a/ExternalPrograms/Controller/Controller.h b/ExternalPrograms/Controller/Controller.h @@ -0,0 +1,32 @@ +#ifndef CONTROLLER_H +#define CONTROLLER_H +#include <alsa/asoundlib.h> + +extern pthread_mutex_t mutex; +extern int Pexitprogram; + +class Controller{ + public: + Controller(); + ~Controller(); + void send(int npar,float xval); + //parameters + unsigned char Pchout; + struct{ + unsigned char mode;//0=off,1=ctl,2=RPN,3=NRPN + unsigned char val1,val2; + struct { + unsigned char par; + } ctl; + struct { + unsigned char cpar,fpar,cval; + } nrpn; + }pars[6]; + private: + void sendcontroller(int par,unsigned char val); + void sendnrpn(int npar,unsigned char val); + + snd_seq_t *midi_out; +}; + +#endif diff --git a/ExternalPrograms/Controller/ControllerUI.fl b/ExternalPrograms/Controller/ControllerUI.fl @@ -0,0 +1,218 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0103 +header_name {.h} +code_name {.cxx} +decl {\#include <FL/Fl_Box.h>} {public +} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include "Controller.h"} {public +} + +decl {Controller *controller;} {} + +class Pad {: {public Fl_Box} +} { + Function {Pad(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {} {} + } + Function {temp_draw()} {} { + code {/*int ox=x(),oy=y(),lx=w(),ly=h(),i,ix,iy,oiy; +REALTYPE freqx; + +fl_color(FL_BLACK); +fl_rectf(ox,oy,lx,ly); + + + +fl_color(FL_GRAY); + +fl_line_style(FL_SOLID); +fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); +*/} {} + } + Function {sendmidi(int button,float datax,float datay)} {} { + code {controller->send(button,datax); +controller->send(button+1,datay);} {} + } + Function {handle(int event)} {return_type int + } { + code {int x_=Fl::event_x()-x(); +int y_=Fl::event_y()-y(); + +if ((event==FL_PUSH)||(event==FL_DRAG)){ + if (x_<0) x_=0;if (y_<0) y_=0; + if (x_>=w()) x_=w();if (y_>=h()-1) y_=h()-1; + + float tmpx=(float) x_/(w()); + float tmpy=1.0-(float) y_/h(); + + int b=Fl::event_buttons()>>24; + + if (b&1) sendmidi(0,tmpx,tmpy); + if (b&2) sendmidi(2,tmpx,tmpy); + if (b&4) sendmidi(4,tmpx,tmpy); + +}; + +return(1);} {} + } + decl {int oldx,oldy;} {} +} + +class ControllerUI {} { + Function {make_window()} {} { + Fl_Window controlleruiwindow { + label {Midi Controller} + callback {o->hide(); +exit(0);} + xywh {210 213 340 410} hide + } { + Fl_Counter {} { + label {Output Channel} + callback {controller->Pchout=(int) o->value();} + xywh {10 13 75 22} type Simple labelsize 10 align 5 minimum 0 maximum 15 step 1 textfont 1 + code0 {o->value(controller->Pchout);} + } + Fl_Box {} { + xywh {10 80 320 320} box ENGRAVED_BOX color 176 + class Pad + } + Fl_Choice {} { + callback {nbut=(int) o->value(); +refreshvalues();} + xywh {10 50 75 20} down_box BORDER_BOX + } { + menuitem {} { + label {But.1 X} + xywh {0 0 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {But.1 Y} + xywh {10 10 100 20} labelfont 1 labelsize 12 divider + } + menuitem {} { + label {But.2 X} + xywh {10 10 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {But.2 Y} + xywh {20 20 100 20} labelfont 1 labelsize 12 divider + } + menuitem {} { + label {But.3 X} + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {But.3 Y} + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + } + Fl_Group ctlgroup { + xywh {95 35 60 40} box ENGRAVED_BOX + } { + Fl_Counter ctlcounter { + label Controller + callback {controller->pars[nbut].ctl.par=(int) o->value();} + xywh {100 50 50 15} type Simple labelsize 10 align 1 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + } + } + Fl_Choice modechoice { + label Mode + callback {controller->pars[nbut].mode=(int) o->value(); +refreshvalues();} + xywh {95 13 60 20} down_box BORDER_BOX labelsize 10 align 5 + } { + menuitem {} { + label OFF + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Ctl.} + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label RPN + xywh {30 30 100 20} labelfont 1 labelsize 12 deactivate + } + menuitem {} { + label NRPN + xywh {40 40 100 20} labelfont 1 labelsize 12 + } + } + Fl_Group nrpngroup { + xywh {160 35 170 40} box ENGRAVED_BOX + } { + Fl_Counter cparcounter { + label {CoarseP.} + callback {controller->pars[nbut].nrpn.cpar=(int) o->value();} + xywh {165 50 50 15} type Simple labelsize 10 align 1 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + } + Fl_Counter fparcounter { + label {FineP.} + callback {controller->pars[nbut].nrpn.fpar=(int) o->value();} + xywh {220 50 50 15} type Simple labelsize 10 align 1 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + } + Fl_Counter cvalcounter { + label {CoarseV.} + callback {controller->pars[nbut].nrpn.cval=(int) o->value();} + xywh {275 50 50 15} type Simple labelsize 10 align 1 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + } + } + Fl_Counter val1counter { + label {Val.1} + callback {controller->pars[nbut].val1=(int) o->value();} + xywh {190 15 50 15} type Simple labelsize 10 align 5 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + } + Fl_Counter val2counter { + label {Val.2} + callback {controller->pars[nbut].val2=(int) o->value();} + xywh {275 15 50 15} type Simple labelsize 10 align 5 minimum 0 maximum 127 step 1 value 127 textfont 1 textsize 12 + } + Fl_Button exchangebutton { + label {<->} + callback {unsigned char tmp=controller->pars[nbut].val2; +controller->pars[nbut].val2=controller->pars[nbut].val1; +controller->pars[nbut].val1=tmp; +refreshvalues();} + xywh {245 15 25 15} box THIN_UP_BOX + } + } + } + Function {refreshvalues()} {} { + code {modechoice->value(controller->pars[nbut].mode); +val1counter->value(controller->pars[nbut].val1); +val2counter->value(controller->pars[nbut].val2); +ctlcounter->value(controller->pars[nbut].ctl.par); +cparcounter->value(controller->pars[nbut].nrpn.cpar); +fparcounter->value(controller->pars[nbut].nrpn.fpar); +cvalcounter->value(controller->pars[nbut].nrpn.cval); + +if (controller->pars[nbut].mode!=0){ + val1counter->activate(); + val2counter->activate(); + exchangebutton->activate(); +}else{ + val1counter->deactivate(); + val2counter->deactivate(); + exchangebutton->deactivate(); +}; + +if (controller->pars[nbut].mode==1) ctlgroup->activate(); + else ctlgroup->deactivate(); + +if (controller->pars[nbut].mode==3) nrpngroup->activate(); + else nrpngroup->deactivate();} {selected + } + } + Function {ControllerUI(Controller *controller_)} {} { + code {nbut=0; +controller=controller_; +make_window(); +refreshvalues(); +controlleruiwindow->show();} {} + } + decl {int nbut;} {} +} diff --git a/ExternalPrograms/Controller/clean.sh b/ExternalPrograms/Controller/clean.sh @@ -0,0 +1 @@ +rm -f *.o controller ControllerUI.cxx ControllerUI.h diff --git a/ExternalPrograms/Controller/compile.sh b/ExternalPrograms/Controller/compile.sh @@ -0,0 +1,10 @@ +clean.sh +fluid -c ControllerUI.fl +gcc -c ControllerUI.cxx -o ControllerUI.o +gcc -c Controller.C -o Controller.o +gcc -c main.C -o main.o + + + +gcc -o controller *.o `fltk-config --ldflags` -lasound -lpthread -lm + diff --git a/ExternalPrograms/Controller/main.C b/ExternalPrograms/Controller/main.C @@ -0,0 +1,16 @@ +#include "Controller.h" +#include "ControllerUI.h" + +pthread_t thr1,thr2; +Controller controller; + + + +main(){ + ControllerUI *controllerUI=new ControllerUI(&controller); + + Fl::run(); + + delete controllerUI; +}; + diff --git a/ExternalPrograms/Spliter/Spliter.C b/ExternalPrograms/Spliter/Spliter.C @@ -0,0 +1,72 @@ +//Copyright (c) 2002-2003 Nasca Octavian Paul +//License: GNU GPL 2 + +#include "Spliter.h" +#include <stdio.h> + +pthread_mutex_t mutex; +int Pexitprogram; + +Spliter::Spliter(){ + //init + Psplitpoint=60; + Pchin=0; + Pchout1=0; + Pchout2=1; + Poct1=0; + Poct2=0; + //ALSA init + snd_seq_open(&midi_in,"default",SND_SEQ_OPEN_INPUT,0); + snd_seq_open(&midi_out,"default",SND_SEQ_OPEN_OUTPUT,0); + + char portname[50];sprintf(portname,"Spliter IN"); + int alsaport = snd_seq_create_simple_port(midi_in,portname + ,SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE + ,SND_SEQ_PORT_TYPE_SYNTH); + sprintf(portname,"Spliter OUT"); + alsaport = snd_seq_create_simple_port(midi_out,portname + ,SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ + ,SND_SEQ_PORT_TYPE_SYNTH); + + +}; + +Spliter::~Spliter(){ + snd_seq_close(midi_in); + snd_seq_close(midi_out); +}; + +// This splits the Midi events from one channel to another two channels +void Spliter::midievents(){ + snd_seq_event_t *midievent; + midievent=NULL; + snd_seq_event_input(midi_in,&midievent); + + if (midievent==NULL) return; + if ((midievent->type==SND_SEQ_EVENT_NOTEON)||(midievent->type==SND_SEQ_EVENT_NOTEOFF)){ + int cmdchan=midievent->data.note.channel; + if (cmdchan==Pchin){ + snd_seq_ev_set_subs(midievent); + snd_seq_ev_set_direct(midievent); + if (midievent->data.note.note<Psplitpoint) { + midievent->data.note.channel=Pchout1; + int tmp=midievent->data.note.note; + tmp+=Poct1*12;if (tmp>127) tmp=127;if (tmp<0) tmp=0; + midievent->data.note.note=tmp; + } else { + midievent->data.note.channel=Pchout2; + int tmp=midievent->data.note.note; + tmp+=Poct2*12;if (tmp>127) tmp=127;if (tmp<0) tmp=0; + midievent->data.note.note=tmp; + }; + snd_seq_event_output_direct(midi_out,midievent); + } else { + snd_seq_ev_set_subs(midievent); + snd_seq_ev_set_direct(midievent); + snd_seq_event_output_direct(midi_out,midievent); + }; + + }; + snd_seq_free_event(midievent); +}; + diff --git a/ExternalPrograms/Spliter/Spliter.h b/ExternalPrograms/Spliter/Spliter.h @@ -0,0 +1,26 @@ +//Copyright (c) 2002-2003 Nasca Octavian Paul +//License: GNU GPL 2 + +#ifndef SPLITER_H +#define SPLITER_H +#include <pthread.h> +#include <alsa/asoundlib.h> + +extern pthread_mutex_t mutex; +extern int Pexitprogram; + +class Spliter{ + public: + Spliter(); + ~Spliter(); + void midievents(); + + //parameters + unsigned char Psplitpoint; + unsigned char Pchin,Pchout1,Pchout2; + signed char Poct1,Poct2; + private: + snd_seq_t *midi_in,*midi_out; +}; + +#endif diff --git a/ExternalPrograms/Spliter/SpliterUI.fl b/ExternalPrograms/Spliter/SpliterUI.fl @@ -0,0 +1,70 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0102 +header_name {.h} +code_name {.cxx} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {selected +} + +decl {//License: GNU GPL 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include "Spliter.h"} {public +} + +class SpliterUI {} { + Function {make_window()} {open + } { + Fl_Window spliteruiwindow { + label {Midi Spliter} + callback {o->hide(); +exit(0);} + xywh {225 187 375 72} hide + } { + Fl_Counter {} { + label {Split note} + callback {spliter->Psplitpoint=(int) o->value();} + xywh {93 27 114 24} labelsize 12 align 5 minimum 0 maximum 127 step 1 value 60 textfont 1 textsize 16 + code0 {o->value(spliter->Psplitpoint);} + code1 {o->lstep(12);} + } + Fl_Counter {} { + label {Input Channel} + callback {spliter->Pchin=(int) o->value();} + xywh {6 30 69 18} type Simple labelsize 10 align 5 minimum 0 maximum 15 step 1 textfont 1 + code0 {o->value(spliter->Pchin);} + } + Fl_Counter {} { + label {Output Channel 1} + callback {spliter->Pchout1=(int) o->value();} + xywh {285 18 69 18} type Simple labelsize 10 align 5 minimum 0 maximum 15 step 1 textfont 1 + code0 {o->value(spliter->Pchout1);} + } + Fl_Counter {} { + label {Output Channel 2} + callback {spliter->Pchout2=(int) o->value();} + xywh {285 36 69 18} type Simple labelsize 10 align 6 minimum 0 maximum 15 step 1 textfont 1 + code0 {o->value(spliter->Pchout2);} + } + Fl_Counter {} { + label {Tr.1(oct.)} + callback {spliter->Poct1=(int) o->value();} + tooltip {Transpose (octaves)} xywh {225 18 48 18} type Simple labelsize 10 align 5 minimum -8 maximum 8 step 1 textfont 1 + code0 {o->value(spliter->Poct1);} + } + Fl_Counter {} { + label {Tr.2(oct.)} + callback {spliter->Poct2=(int) o->value();} + tooltip {Transpose (octaves)} xywh {225 36 48 18} type Simple labelsize 10 align 6 minimum -8 maximum 8 step 1 textfont 1 + code0 {o->value(spliter->Poct2);} + } + } + } + Function {SpliterUI(Spliter *spliter_)} {} { + code {spliter=spliter_; +make_window(); +spliteruiwindow->show();} {} + } + decl {Spliter *spliter;} {} +} diff --git a/ExternalPrograms/Spliter/clean.sh b/ExternalPrograms/Spliter/clean.sh @@ -0,0 +1 @@ +rm -f *.o spliter SpliterUI.cxx SpliterUI.h diff --git a/ExternalPrograms/Spliter/compile.sh b/ExternalPrograms/Spliter/compile.sh @@ -0,0 +1,8 @@ +clean.sh +fluid -c SpliterUI.fl +gcc -c SpliterUI.cxx -o SpliterUI.o +gcc -c Spliter.C -o Spliter.o +gcc -c main.C -o main.o + +gcc -o spliter *.o `fltk-config --ldflags` -lasound + diff --git a/ExternalPrograms/Spliter/main.C b/ExternalPrograms/Spliter/main.C @@ -0,0 +1,36 @@ +//Copyright (c) 2002-2003 Nasca Octavian Paul +//License: GNU GPL 2 + +#include <pthread.h> +#include "Spliter.h" +#include "SpliterUI.h" + +pthread_t thr1,thr2; +Spliter spliter; + +void *thread1(void *arg){ + Fl::run(); + return(0); +}; +void *thread2(void *arg){ + while (Pexitprogram==0) spliter.midievents(); + return(0); +}; + + +main(){ + Pexitprogram=0; + SpliterUI *spliterUI=new SpliterUI(&spliter); + + pthread_mutex_init(&mutex,NULL); + pthread_create(&thr1,NULL,thread1,NULL); + pthread_create(&thr2,NULL,thread2,NULL); + + while (Pexitprogram==0){ + usleep(100000); + }; + + pthread_mutex_destroy(&mutex); + delete spliterUI; +}; + diff --git a/ExternalPrograms/Spliter/readme.txt b/ExternalPrograms/Spliter/readme.txt @@ -0,0 +1,15 @@ +Spliter +------ + +This program splits the keyboard and alows you to play two instruments same time. You can use this program with ZynAddSubFX or any other synthesizer. +This requires ALSA 0.9.x. + +To compile it, run the file "compile.sh". There is no Makefile, yet. +If you want to use with ZynAddSubFX send the midi events thru Spliter with aconnect like this: + + - connect the keyboard port to "Spliter IN" port + - connect the "Spliter OUT" to ZynAddSubFX + - change the midi channels that you want to play. Be sure that the both output channels are enabled and receive NoteOn in ZynAddSubFX. + +If you change some settings from Spliter while you are playing to keyboard you may ecounter "stucked keys". To clear all theese press to "Panic" button from ZynAddSubFX. + diff --git a/ExternalPrograms/readme.txt b/ExternalPrograms/readme.txt @@ -0,0 +1,2 @@ +Theese are external programs, which can use with ZynAddSubFX or any other midi device. More information is in the documentation (html - webpages). +There is no Makefile for theese, yet. +\ No newline at end of file diff --git a/FAQ.txt b/FAQ.txt @@ -0,0 +1,32 @@ + Frequently Asked Questions + -------------------------- + +Q1) What means "ZynAddSubFX" ? +A1) The name of the program comes from 4 words: + 1) Synthesizer ('S'->'Z') --> Zyn + ^^^ + 2) Additive Synthesis ------> Add + ^^^ + 3) Subtractive Synthesis ---> Sub + ^^^ + 4) Effects ----------------> FX + + So, ZynAddSubFX is a SYNthesizer with ADDitive, SUBtractive engines and effects. + + + +Q2) How can I change the number of parts, voices to ADSynth, effects, etc. ? +A2) Look in src/globals.h and change there theese values. You don't have to change anything else, just recompile all. But most settings must be below 128. As the rule of the thumb if a setting is 128 or below 128, please don't make it bigger than 128. Anyway, I don't belive that you'll need more than 128 for theese settings; for example you don't need 128(or more) effects same time? That's why I put the limit of 128 (using 7 bits of char). + + + +Q3) How do I enable Jack support on ZynAddSubFX ? +A3) Look in "Makefile.inc" from "src/" directory for more information. If you want *really* small latencies, you can decrease "SOUND_BUFFER_SIZE" from "src/globals.h". It is highly recomanded that the Jack samplerate to be equal to ZynAddSubFX samplerate (SAMPLE_RATE from globals.h), otherwise the resampling will be done and this will decrease the quality a bit. + + +Q4) Why is licensed only under version 2 of the GNU GPL? +A4) I licensed under GNU GPL v.2 only, because I don't know what the next versions of GPL will say. For example what if they tell that a GPL licensed program can be a part of a proprietary software? This may blow up the entire opensource comunity (well, only 'GPL v.2 or any later version' programs - but they are the most). +To 'be similar in spirit to the present version [of GPL]' (what is said in the section 9 of GNU GPL) is too ambigous for me. +Anyway, ZynAddSubFX is free (as speech) even is licensed only to GPL v.2 ;-) . + + diff --git a/HISTORY.txt b/HISTORY.txt @@ -0,0 +1,122 @@ +1.4.3 (31 Aug 2003) + - added state variable filters and other types to analog filters + - small user interface improvememnts + - small bugfixes + +1.4.2 (17 Iul 2003) + - added full-featured, advanced formantic filters + - added mixer panel which lets you to see/change most important part settings, and shows a vu-meters for each part + - you can choose to process the instrument's kit items only with one Part effect (eg. you can make a instrument kit that contains a reverberated piano and flanged strings) + - enabled to launch more instances in Jack + - when is launched first time, it searches for default.bnk_zyn file into /usr/share/zynaddsubfx and /usr/local/share/zynaddsubfx directories (useful for binary packages for Linux distributions) + - bugfixes + +1.4.1 (8 May 2003) + - added single mode to the instrument kit who alows only one item to be played same time + - added "Spectrum Adjust" to the ADsynth oscillator + - added "drum mode" to the instrument, where all midi keys are mapped to 12tET + - added a parameter to the "440Hz" which make the freq to varies a bit according to the key pressed (very usefull to toms and other drums) + - (for OSS audio out) if it is launched with root privileges, the synth will gain realtime scheduling priority + - bugfixes + +1.4.0 (15 Apr 2003) + - added instrument's own effect (effects that are loaded/saved with the instrument) + - FreeMode Envelopes: all Envelopes can have any shape (not only ADSR) + - Added instrument kits: It is possible to use more than one instruments into one part (used for layered synths or drum kits) + - Amplitude envelopes can be linear or logarithmic + - added interpolation on the Resonance user interface + - user interface improvements and cleanups of it's code + - initiated a mailing list to allow users to share patches for ZynAddSubFX. Please share your ZynAddSubFX patches; look at http://lists.sourceforge.net/mailman/listinfo/zynaddsubfx-user for more information about the mailing list. + +1.2.1 (6 Apr 2003) + - improved filter interpolation + - bugfix: wav header is written correctly + - bugfix: NRPN works correctly (eg:the controller was 0x98 instead of 98), now you can controll all effects parametrer realtime via MIDI + - bugfix: pitch bend works OK in windows + - added master fine detune (-64..63 cents) + - it is possible to swap effects or copy them + - started to port ZynAddSubFX to VST (not functional, yet) + - the resonace can protect the fundamental freq. against damping + +1.2.0 (21 Mar 2003) + - ZynAddSubFX is ported to Windows ;-) + - added internal Virtual Keyboard + - added Configuration window + - added frequency tracking to filter + - improved the OscilGen (harmonic filter, RMS normalisation, etc..) + - improved the recorder (uses the WAV file format and it starts only when a key is pressed) + - added filter interpolation if the frequency is changed very fast (it removes some annoying clicks) + - other improovements, bugfixes, speedups and cleanups of the code + +1.0.9 (24 Feb 2003) + - added keylimit to Part + - you can use multiple filter stages in order to make very steep filter rolloffs (eg. 48 dB/octave) + - ADsynth - added noise mode and you can make fixed frequencies; added the "Punch" parameter + - added an external program "Controller" which enables you to use the mouse for MIDI controllers + - other improvements and bugfixes + +1.0.8 (14 Feb 2003) + - added mono mode and portamento + - added the EQ effect + - the output of a system effect can be sent to others system effects + - minor bugfixes and improvements + +1.0.7 (7 Feb 2003) + - some settings (like samplerate) are set at runtime (by comand line) + - added Distorsion effect + - added controllers, and NRPNs for changing all effects parameters by midi + - bugs removed and other improvements + +1.0.6 (30 Jan 2003) + - Added JACK output ;-) + - Minor improvements and bugfixes + +1.0.5 (24 Jan 2003) + - The bug that crashed ZynAddSubFX if you change some effect parameters, it is realy removed (I forgot to update the file before upload) + - Other bugfixes and code cleanups + - Added a Global Filter to SubSynth + - Added keyresponse limits to Part + - Added presets to Effects + - The fade is smaller on high frequecy content and larger on low frequecies; so you'll don't hear starting clicks on basses and audible fadeins on higher pitched sounds + - Added tunnings to Reverb: you can choose Random of Freeverb + +1.0.4 (7 Jan 2003) + - It is possible to load Scala (.scl and .kbm) files + - Added mapping from note number to scale degree is possible to load Scala kbm files + - Corrected small bugs related to Microtonal + - If you want to use ZynAddSubFX with OSS (or you don't have ALSA) you can modify the Makefile.inc file to compile with OSS only. + - It is shown the real detune (in cents) + - Made a new widget that replaces the Dial widget + - Removed a bug that crashed ZynAddSubFX if you change some effect parameters + +1.0.3 (23 Dec 2002) + - small bugfixes: "Bypass Global Filter" from ADnoteUI dissapears sometimes ; + removed the low amplitude noise produced by the reverb; + if you "acconect" zynaddsubfx with aseqview no note was processed a long time. + - added Notch Filter + - added the option to randomize the ressonance function + - added VU-Meter + - Change the Insertion effect modes behaves (it sounds a bit louder) + - Added to the project an external program called Spliter that splits the + keyboard and alows you to play two instruments same time. You can use this + program with ZynAddSubFX or any other synthesizer. + - Added a new function to OscilGen + +1.0.2-1 (13 Dec 2002) + - bug found and removed: sometimes when Master/Instrument is saved, the synth crashed + +1.0.2 (13 Dec 2002) + - Added instrument banks + - the BandPass Filter's output amplitude was increased + - few fixes of FFTwrapper. See the documentation from "FFTwrapper.h" if you got error messages. + +1.0.1 (6 Dec 2002) + - corrected a bug that made ZynAddSubFX to crash(sometimes) if you disable a part + - wrote Resonance + - added the BandPass filter + - added the recording feature + - added "New instrument" menuitem + +1.0.0 (25 Sep 2002) + - first release, done a lot before it :-) + diff --git a/README.txt b/README.txt @@ -0,0 +1,93 @@ +ZynAddSubFX +----------- +It is a realtime software synthesizer for Linux and Windows with many features. Please see the docs for details. +Copyright (c) 2002-2003 Nasca Octavian Paul +e-mail: zynaddsubfx AT yahoo D0T com +ZynAddSubFX is free program and is distribuited WITH NO WARRANTY. It is licensed under GNU General Public License version 2 (and only version 2) - see the file COPYING. + + --==## PLEASE SHARE YOUR INSTRUMENTS/MASTER SETTINGS ##==-- + --==## MADE WITH ZynAddSubFX ##==-- + Here is the mailing list where you can share your patches with others: + http://lists.sourceforge.net/mailman/listinfo/zynaddsubfx-user + + +The project page is + http://sourceforge.net/projects/zynaddsubfx + or + http://zynaddsubfx.sourceforge.net + +ZynAddSubFX is also available on many Internet sites like: + http://www-ccrma.stanford.edu/planetccrma/software/soundapps.html (Planet CCRMA) + http://www.hitsquad.com/smm/programs/ZynAddSubFX/ + http://freshmeat.net/projects/zynaddsubfx/ + http://ibiblio.org/pub/Linux/apps/sound/midi/ + or search "ZynAddSubFX" on a search engine (like www.google.com). + + +Requirements: +------------- + - a fast computer + - Linux (tested with RedHat 7.2,7.3,etc.) or Windows + - FLTK 1.x.x (tested with fltk 1.1.0, 1.1.1, 1.1.2,etc.) + - FFTW 2.x.x (tested with fftw 2.0.5, 2.1.3) - necesary for + Fast Fourier computations + - (for Linux) OpenSoundSystem (OSS) (if you don't have ALSA, only) + - (for Windows) pthreads, portaudio + +Not requred, but recomanded: +--------------------------- + + - ALSA 0.9.x (with OSS emulation, if you don't use JACK) + - JACKit - if you want to use it you must enable compilation for JACK in Makefile.inc + + +Compilation: +------------ + If you want to compile on Windows, please read compile.win32 file. + If you don't know how to compile, you may download binaries from Planet CCRMA (see above, on sites). + First set what should sound input/ouput should use in Makefile.inc in src/ directory. + Then "make" from the "src/" directory. Hope all goes right. If the compiler complains something about FFTwrapper.h and FFTW library headers(rfftw.h or fftw.h) please read the docs from DSP/FFTwrapper.h . + To compile the Spliter, run "compile.sh" from the "Spliter" directory. + To compile the Controller, run "compile.sh" from the "Controller" directory. + +Running on LINUX +---------------- + *AUDIO OUTPUT + A) OSS (Open Sound System) + B) JACK (JACK Audio Connection Kit) + + *MIDI INPUT* + There are 2 possibilites of midi inputs (depends on what you have chosen in Makefile.inc to use - OSS or ALSA). + A) ALSA (Advenced Linux Sound Architecture) + 1) Launch zynaddsubfx + 2) ZynAddSubFX will make a virtual MIDI port. + You can connect other midi devices (like a real MIDI keyboard, midi sequencers which supports ALSA or virtual keyboard - like vkeybd). + To connect, use "aconnect" or "alsa-patch-bay"; usualy the port of ZynAddSubFX is 128:0 or 129:0. + 3) You are ready to play + + It is possible to use midi sequencer/other software that doesn't supports ALSA with ZynAddSubFX, but this is a bit more complicated. + Search on Internet for "HOWTO Use MIDI Sequencers With Softsynths" by Frank Barknecht, if you want to do this. + + + B) OSS (Open Sound System) + 1) Launch zynaddsubfx + 2) Connect the midi keyboard + + As you have seen the OSS option needs a real midi keyboard. If you don't have it, you can download/install ALSA from www.alsa-project.org + +Running on WINDOWS +------------------ + If you launch zynaddsubfx.exe and nothing happens, you need pthreadGC.dll and portaudio.dll in the same directory (or windows directory). The dll files are distribuited with zynaddsubfx windows binaries. + It might be possible that the latency will be very high. If this happens, you have to set the environment variable PA_MIN_LATENCY_MSEC to a value that represents the latency in miliseconds. + Eg: (in autoexec.bat or launched before running zynaddsubfx) "set PA_MIN_LATENCY_MSEC=50" + Warning: if the value is too low, you might ecounter severe dropouts on zynaddsubfx. You'll have to set to a higher value and turn off automated background tasks (like virus scanners, email clients, etc.). + If you have more cards, you can select the desired card where you can play audio with the evironment variable "PA_RECOMMENDED_OUTPUT_DEVICE" + Eg: "set PA_RECOMMENDED_OUTPUT_DEVICE=1" + A better way to set all of this, I will put on next versions. + +Please send me instruments,banks,master settings,songs(midi+..._zyn files) done with ZynAddSubFX. I'll apreciate this. + + +Have fun! :-) + + diff --git a/ZynAddSubFX.lsm b/ZynAddSubFX.lsm @@ -0,0 +1,22 @@ +Begin4 +Title: ZynAddSubFX +Version: 1.4.3 +Entered-date: 31-08-2003 +Description: A real-time software synthesizer for Linux and Windows with many + features, including polyphony, multi-timbral and microtonal + capabilities. It includes randomness of some parameters,which + makes warm sounds, like analogue synthesizers. + The program has system/insertion effects, too. + ZynAddSubFX has much more features, don't let be cheated by + the size of the source code :) +Keywords: synthesizer,MIDI,ALSA,music,X11,microtonal,real-time,windows +Author: zynaddsubfx@yahoo.com (Nasca Paul) +Maintained-by: zynaddsubfx@yahoo.com (Nasca Paul) +Primary-site: zynaddsubfx.sourceforge.net + sourceforge.net/projects/zynaddsubfx + 189k ZynAddSubFX-1.4.3.tar.gz (source code) +Alternate-site: +Original-site: +Platforms: Linux with X11 or Windows +Copying-policy: version 2 of the GNU General Public License (GNU GPL v.2) +End diff --git a/compile.win32 b/compile.win32 @@ -0,0 +1,32 @@ +ZynAddSubFX Compilation on Windows as standalone .EXE +----------------------------------------------------- +You don't have to compile it, there are Windows binaries available on the webpage. +Anyway if you want to compile, good luck :) + +First, you have to download and install Mingw and MSYS (www.mingw.org). Download the FLTK sources (www.fltk.org), compile and install. +Second, you have to download, compile and install pthreads for windows (http://sources.redhat.com/pthreads-win32). You need to compile in GC mode. +Also, you have to compile the portaudio library (www.portaudio.com). It it doesn't install itself, and you must copy the header files to the "include" directories from mingw(msys) and compiled libraries to the "lib" directory from mingw. + +Change the Makefile.inc, and change the compilation options (like operating system,etc.). Now, run make from msys. +After the compilation, copy in the dll files (pthreadGC.dll and portaudio.dll) to the directory where "zynaddsubfx.exe" is. +Hope all goes right. + +ZynAddSubFX Compilation on Windows as VST plugin (dll file) +---------------------------------------------------------- +Edit the Makefile.inc and set "WINDOWS_VST" to "YES". The audioout and midiin are automatically set to VST. +Get the vstsdk2 and copy it to the directory where ZynAddSubFX-1.x.x is. +If you copy ZynAddSubFX in "C:\temp" and you will run "dir" you should see the ZynAddSubFX-1.x.x and vstsdk2 in the same directory (C:\temp). + +Now you have to compile AudioEffect.cpp and audioeffectx.cpp(from vstsdk2) to the object files AudioEffect.o and audioeffectx.o. +Copy theese object files to zynaddsubfx \src directory. + +Run the makefile. Hope all will goes right. Please notice that "make clean" removes the vst object files that you compiled form vstsdk2. That's why is recomanded to keep a backup copy of theese object files. +You must copy the pthreads.dll file to windows directory (or else, zynaddsubfx will not work). Btw: how can I make pthreads static? +Copy the zynaddsubfx_vst.dll to your dll directory. + +BUGS only on vst port: +Warning! The version 1.2.1(and others) of zynaddsubfx vst port is extremely buggy! It may blow up the instrument banks (*.bnk_zyn). Also it will crash (including the VST host) if it will be loaded second time (Why?). +Also, to avoid more bugs, I had limited zynaddsubfx to one instance. Please report me how it behaves on various vst hosts. +I hope that I will remove theese bugs on later versions. + + diff --git a/examples/Banks/readme.txt b/examples/Banks/readme.txt @@ -0,0 +1,2 @@ +Please send me instruments or banks made by you with ZynAddSubFX. +Thank you. diff --git a/examples/Big_Pad.mas_zyn b/examples/Big_Pad.mas_zyn Binary files differ. diff --git a/examples/Big_Pad_2.mas_zyn b/examples/Big_Pad_2.mas_zyn Binary files differ. diff --git a/examples/Big_Pad_2resonance.mas_zyn b/examples/Big_Pad_2resonance.mas_zyn Binary files differ. diff --git a/examples/Instruments/accomp00.ins_zyn b/examples/Instruments/accomp00.ins_zyn Binary files differ. diff --git a/examples/Instruments/accomp01.ins_zyn b/examples/Instruments/accomp01.ins_zyn Binary files differ. diff --git a/examples/Instruments/choir01.ins_zyn b/examples/Instruments/choir01.ins_zyn Binary files differ. diff --git a/examples/Instruments/fmthrumpet.ins_zyn b/examples/Instruments/fmthrumpet.ins_zyn Binary files differ. diff --git a/examples/Instruments/organ00.ins_zyn b/examples/Instruments/organ00.ins_zyn Binary files differ. diff --git a/examples/Instruments/organ01.ins_zyn b/examples/Instruments/organ01.ins_zyn Binary files differ. diff --git a/examples/Instruments/organ02.ins_zyn b/examples/Instruments/organ02.ins_zyn Binary files differ. diff --git a/examples/Instruments/organ03.ins_zyn b/examples/Instruments/organ03.ins_zyn Binary files differ. diff --git a/examples/Instruments/organ04.ins_zyn b/examples/Instruments/organ04.ins_zyn Binary files differ. diff --git a/examples/Instruments/res01.ins_zyn b/examples/Instruments/res01.ins_zyn Binary files differ. diff --git a/examples/Instruments/res02.ins_zyn b/examples/Instruments/res02.ins_zyn Binary files differ. diff --git a/examples/Instruments/res03.ins_zyn b/examples/Instruments/res03.ins_zyn Binary files differ. diff --git a/examples/Instruments/rhodes00.ins_zyn b/examples/Instruments/rhodes00.ins_zyn Binary files differ. diff --git a/examples/Instruments/rhodes01.ins_zyn b/examples/Instruments/rhodes01.ins_zyn Binary files differ. diff --git a/examples/Instruments/rhodes02.ins_zyn b/examples/Instruments/rhodes02.ins_zyn Binary files differ. diff --git a/examples/Instruments/soft_organ.ins_zyn b/examples/Instruments/soft_organ.ins_zyn Binary files differ. diff --git a/examples/Instruments/synth_brazz.ins_zyn b/examples/Instruments/synth_brazz.ins_zyn Binary files differ. diff --git a/examples/Rhodes_chorus.mas_zyn b/examples/Rhodes_chorus.mas_zyn Binary files differ. diff --git a/examples/Rhodes_chorus2.mas_zyn b/examples/Rhodes_chorus2.mas_zyn Binary files differ. diff --git a/examples/Scales/5-24.scl_zyn b/examples/Scales/5-24.scl_zyn Binary files differ. diff --git a/examples/Scales/8-11.scl_zyn b/examples/Scales/8-11.scl_zyn Binary files differ. diff --git a/examples/Scales/IntenseDiatonic_mapped.scl_zyn b/examples/Scales/IntenseDiatonic_mapped.scl_zyn Binary files differ. diff --git a/examples/Scales/Just Intonation.scl_zyn b/examples/Scales/Just Intonation.scl_zyn Binary files differ. diff --git a/examples/Scales/harrison.scl_zyn b/examples/Scales/harrison.scl_zyn Binary files differ. diff --git a/examples/Scales/pyth.scl_zyn b/examples/Scales/pyth.scl_zyn Binary files differ. diff --git a/examples/Split_keyboard.mas_zyn b/examples/Split_keyboard.mas_zyn Binary files differ. diff --git a/examples/distortion_and_strings.mas_zyn b/examples/distortion_and_strings.mas_zyn Binary files differ. diff --git a/examples/examples.mas_zyn b/examples/examples.mas_zyn Binary files differ. diff --git a/examples/flanged_guitar.mas_zyn b/examples/flanged_guitar.mas_zyn Binary files differ. diff --git a/examples/ins01.mas_zyn b/examples/ins01.mas_zyn Binary files differ. diff --git a/examples/ins02.mas_zyn b/examples/ins02.mas_zyn Binary files differ. diff --git a/examples/ins03.mas_zyn b/examples/ins03.mas_zyn Binary files differ. diff --git a/examples/ins04.mas_zyn b/examples/ins04.mas_zyn Binary files differ. diff --git a/examples/ins05.mas_zyn b/examples/ins05.mas_zyn Binary files differ. diff --git a/examples/ins06.mas_zyn b/examples/ins06.mas_zyn Binary files differ. diff --git a/examples/ins07.mas_zyn b/examples/ins07.mas_zyn Binary files differ. diff --git a/examples/ins08.mas_zyn b/examples/ins08.mas_zyn Binary files differ. diff --git a/examples/oops.mas_zyn b/examples/oops.mas_zyn Binary files differ. diff --git a/examples/organ1.mas_zyn b/examples/organ1.mas_zyn Binary files differ. diff --git a/examples/organ_pad.mas_zyn b/examples/organ_pad.mas_zyn Binary files differ. diff --git a/examples/organ_pad2.mas_zyn b/examples/organ_pad2.mas_zyn Binary files differ. diff --git a/examples/rezzy_synth_reverberated.mas_zyn b/examples/rezzy_synth_reverberated.mas_zyn Binary files differ. diff --git a/examples/string_and_rhodes.mas_zyn b/examples/string_and_rhodes.mas_zyn Binary files differ. diff --git a/examples/synth_reverberated.mas_zyn b/examples/synth_reverberated.mas_zyn Binary files differ. diff --git a/examples/synth_reverberated2.mas_zyn b/examples/synth_reverberated2.mas_zyn Binary files differ. diff --git a/src/DSP/AnalogFilter.C b/src/DSP/AnalogFilter.C @@ -0,0 +1,358 @@ +/* + ZynAddSubFX - a software synthesizer + + AnalogFilter.C - Several analog filters (lowpass, highpass...) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdio.h> +#include "AnalogFilter.h" + +AnalogFilter::AnalogFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages){ + stages=Fstages; + for (int i=0;i<3;i++){ + oldc[i]=0.0;oldd[i]=0.0; + c[i]=0.0;d[i]=0.0; + }; + type=Ftype; + freq=Ffreq; + q=Fq; + gain=1.0; + if (stages>=MAX_FILTER_STAGES) stages=MAX_FILTER_STAGES; + cleanup(); + firsttime=0; + abovenq=0;oldabovenq=0; + setfreq_and_q(Ffreq,Fq); + firsttime=1; + d[0]=0;//this is not used + outgain=1.0; +}; + +AnalogFilter::~AnalogFilter(){ +}; + +void AnalogFilter::cleanup(){ + for (int i=0;i<MAX_FILTER_STAGES+1;i++){ + x[i].c1=0.0;x[i].c2=0.0; + y[i].c1=0.0;y[i].c2=0.0; + oldx[i]=x[i]; + oldy[i]=y[i]; + }; + needsinterpolation=0; +}; + +void AnalogFilter::computefiltercoefs(){ + REALTYPE tmp; + REALTYPE omega,sn,cs,alpha,beta; + int zerocoefs=0;//this is used if the freq is too high + + //do not allow frequencies bigger than samplerate/2 + REALTYPE freq=this->freq; + if (freq>(SAMPLE_RATE/2-500.0)) { + freq=SAMPLE_RATE/2-500.0; + zerocoefs=1; + }; + if (freq<0.1) freq=0.1; + //do not allow bogus Q + if (q<0.0) q=0.0; + REALTYPE tmpq,tmpgain; + if (stages==0) { + tmpq=q; + tmpgain=gain; + } else { + tmpq=(q>1.0 ? pow(q,1.0/(stages+1)) : q); + tmpgain=pow(gain,1.0/(stages+1)); + }; + + //most of theese are implementations of + //the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson + //The original location of the Cookbook is: + //http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt + switch(type){ + case 0://LPF 1 pole + if (zerocoefs==0) tmp=exp(-2.0*PI*freq/SAMPLE_RATE); + else tmp=0.0; + c[0]=1.0-tmp;c[1]=0.0;c[2]=0.0; + d[1]=tmp;d[2]=0.0; + order=1; + break; + case 1://HPF 1 pole + if (zerocoefs==0) tmp=exp(-2.0*PI*freq/SAMPLE_RATE); + else tmp=0.0; + c[0]=(1.0+tmp)/2.0;c[1]=-(1.0+tmp)/2.0;c[2]=0.0; + d[1]=tmp;d[2]=0.0; + order=1; + break; + case 2://LPF 2 poles + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + alpha=sn/(2*tmpq); + tmp=1+alpha; + c[0]=(1.0-cs)/2.0/tmp; + c[1]=(1.0-cs)/tmp; + c[2]=(1.0-cs)/2.0/tmp; + d[1]=-2*cs/tmp*(-1); + d[2]=(1-alpha)/tmp*(-1); + } else { + c[0]=1.0;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + case 3://HPF 2 poles + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + alpha=sn/(2*tmpq); + tmp=1+alpha; + c[0]=(1.0+cs)/2.0/tmp; + c[1]=-(1.0+cs)/tmp; + c[2]=(1.0+cs)/2.0/tmp; + d[1]=-2*cs/tmp*(-1); + d[2]=(1-alpha)/tmp*(-1); + } else { + c[0]=0.0;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + case 4://BPF 2 poles + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + alpha=sn/(2*tmpq); + tmp=1+alpha; + c[0]=alpha/tmp*sqrt(tmpq+1); + c[1]=0; + c[2]=-alpha/tmp*sqrt(tmpq+1); + d[1]=-2*cs/tmp*(-1); + d[2]=(1-alpha)/tmp*(-1); + } else { + c[0]=0.0;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + case 5://NOTCH 2 poles + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + alpha=sn/(2*sqrt(tmpq)); + tmp=1+alpha; + c[0]=1/tmp; + c[1]=-2*cs/tmp; + c[2]=1/tmp; + d[1]=-2*cs/tmp*(-1); + d[2]=(1-alpha)/tmp*(-1); + } else { + c[0]=1.0;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + case 6://PEAK (2 poles) + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + tmpq*=3.0; + alpha=sn/(2*tmpq); + tmp=1+alpha/tmpgain; + c[0]=(1.0+alpha*tmpgain)/tmp; + c[1]=(-2.0*cs)/tmp; + c[2]=(1.0-alpha*tmpgain)/tmp; + d[1]=-2*cs/tmp*(-1); + d[2]=(1-alpha/tmpgain)/tmp*(-1); + } else { + c[0]=1.0;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + case 7://Low Shelf - 2 poles + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + tmpq=sqrt(tmpq); + alpha=sn/(2*tmpq); + beta=sqrt(tmpgain)/tmpq; + tmp=(tmpgain+1.0)+(tmpgain-1.0)*cs+beta*sn; + + c[0]=tmpgain*((tmpgain+1.0)-(tmpgain-1.0)*cs+beta*sn)/tmp; + c[1]=2.0*tmpgain*((tmpgain-1.0)-(tmpgain+1.0)*cs)/tmp; + c[2]=tmpgain*((tmpgain+1.0)-(tmpgain-1.0)*cs-beta*sn)/tmp; + d[1]=-2.0*((tmpgain-1.0)+(tmpgain+1.0)*cs)/tmp*(-1); + d[2]=((tmpgain+1.0)+(tmpgain-1.0)*cs-beta*sn)/tmp*(-1); + } else { + c[0]=tmpgain;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + case 8://High Shelf - 2 poles + if (zerocoefs==0){ + omega=2*PI*freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + tmpq=sqrt(tmpq); + alpha=sn/(2*tmpq); + beta=sqrt(tmpgain)/tmpq; + tmp=(tmpgain+1.0)-(tmpgain-1.0)*cs+beta*sn; + + c[0]=tmpgain*((tmpgain+1.0)+(tmpgain-1.0)*cs+beta*sn)/tmp; + c[1]=-2.0*tmpgain*((tmpgain-1.0)+(tmpgain+1.0)*cs)/tmp; + c[2]=tmpgain*((tmpgain+1.0)+(tmpgain-1.0)*cs-beta*sn)/tmp; + d[1]=2.0*((tmpgain-1.0)-(tmpgain+1.0)*cs)/tmp*(-1); + d[2]=((tmpgain+1.0)-(tmpgain-1.0)*cs-beta*sn)/tmp*(-1); + } else { + c[0]=1.0;c[1]=0.0;c[2]=0.0; + d[1]=0.0;d[2]=0.0; + }; + order=2; + break; + default://wrong type + type=0; + computefiltercoefs(); + break; + }; +}; + + +void AnalogFilter::setfreq(REALTYPE frequency){ + if (frequency<0.1) frequency=0.1; + REALTYPE rap=freq/frequency;if (rap<1.0) rap=1.0/rap; + + oldabovenq=abovenq;abovenq=frequency>(SAMPLE_RATE/2-500.0); + + int nyquistthresh=(abovenq^oldabovenq); + + + if ((rap>3.0)||(nyquistthresh!=0)){//if the frequency is changed fast, it needs interpolation (now, filter and coeficients backup) + for (int i=0;i<3;i++){ + oldc[i]=c[i];oldd[i]=d[i]; + }; + for (int i=0;i<MAX_FILTER_STAGES+1;i++){ + oldx[i]=x[i]; + oldy[i]=y[i]; + }; + if (firsttime==0) needsinterpolation=1; + }; + freq=frequency; + computefiltercoefs(); + firsttime=0; + +}; + +void AnalogFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){ + q=q_; + setfreq(frequency); +}; + +void AnalogFilter::setq(REALTYPE q_){ + q=q_; + computefiltercoefs(); +}; + +void AnalogFilter::settype(int type_){ + type=type_; + computefiltercoefs(); +}; + +void AnalogFilter::setgain(REALTYPE dBgain){ + gain=dB2rap(dBgain); + computefiltercoefs(); +}; + +void AnalogFilter::setstages(int stages_){ + if (stages_>=MAX_FILTER_STAGES) stages_=MAX_FILTER_STAGES-1; + stages=stages_; + cleanup(); + computefiltercoefs(); +}; + +void AnalogFilter::singlefilterout(REALTYPE *smp,fstage &x,fstage &y,REALTYPE *c,REALTYPE *d){ + int i; + REALTYPE y0; + if (order==1) {//First order filter + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + y0=smp[i]*c[0]+x.c1*c[1]+y.c1*d[1]; + y.c1=y0; + x.c1=smp[i]; + //output + smp[i]=y0; + }; + }; + if (order==2) {//Second order filter + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + y0=smp[i]*c[0]+x.c1*c[1]+x.c2*c[2]+y.c1*d[1]+y.c2*d[2]; + y.c2=y.c1; + y.c1=y0; + x.c2=x.c1; + x.c1=smp[i]; + //output + smp[i]=y0; + }; + }; +}; +void AnalogFilter::filterout(REALTYPE *smp){ + REALTYPE *ismp;//used if it needs interpolation + int i; + if (needsinterpolation!=0){ + ismp=new REALTYPE[SOUND_BUFFER_SIZE]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) ismp[i]=smp[i]; + for (i=0;i<stages+1;i++) singlefilterout(ismp,oldx[i],oldy[i],oldc,oldd); + }; + + for (i=0;i<stages+1;i++) singlefilterout(smp,x[i],y[i],c,d); + + if (needsinterpolation!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE x=i/(REALTYPE) SOUND_BUFFER_SIZE; + smp[i]=ismp[i]*(1.0-x)+smp[i]*x; + }; + delete (ismp); + needsinterpolation=0; + }; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]*=outgain; +}; + +REALTYPE AnalogFilter::H(REALTYPE freq){ + REALTYPE fr=freq/SAMPLE_RATE*PI*2.0; + REALTYPE x=c[0],y=0.0; + for (int n=1;n<3;n++){ + x+=cos(n*fr)*c[n]; + y-=sin(n*fr)*c[n]; + }; + REALTYPE h=x*x+y*y; + x=1.0;y=0.0; + for (int n=1;n<3;n++){ + x-=cos(n*fr)*d[n]; + y+=sin(n*fr)*d[n]; + }; + h=h/(x*x+y*y); + return(pow(h,(stages+1.0)/2.0)); +}; + diff --git a/src/DSP/AnalogFilter.h b/src/DSP/AnalogFilter.h @@ -0,0 +1,72 @@ +/* + ZynAddSubFX - a software synthesizer + + Analog Filter.h - Several analog filters (lowpass, highpass...) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ANALOG_FILTER_H +#define ANALOG_FILTER_H + +#include "../globals.h" +#include "Filter_.h" +class AnalogFilter:public Filter_{ + public: + AnalogFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages); + ~AnalogFilter(); + void filterout(REALTYPE *smp); + void setfreq(REALTYPE frequency); + void setfreq_and_q(REALTYPE frequency,REALTYPE q_); + void setq(REALTYPE q_); + + void settype(int type_); + void setgain(REALTYPE dBgain); + void setstages(int stages_); + void cleanup(); + + REALTYPE H(REALTYPE freq);//Obtains the response for a given frequency + + private: + struct fstage{ + REALTYPE c1,c2; + } x[MAX_FILTER_STAGES+1],y[MAX_FILTER_STAGES+1], + oldx[MAX_FILTER_STAGES+1],oldy[MAX_FILTER_STAGES+1]; + + void singlefilterout(REALTYPE *smp,fstage &x,fstage &y,REALTYPE *c,REALTYPE *d); + void computefiltercoefs(); + int type;//The type of the filter (LPF1,HPF1,LPF2,HPF2...) + int stages;//how many times the filter is applied (0->1,1->2,etc.) + REALTYPE freq;//Frequency given in Hz + REALTYPE q; //Q factor (resonance or Q factor) + REALTYPE gain;//the gain of the filter (if are shelf/peak) filters + + int order;//the order of the filter (number of poles) + + REALTYPE c[3],d[3];//coefficients + + REALTYPE oldc[3],oldd[3];//old coefficients(used only if some filter paremeters changes very fast, and it needs interpolation) + + REALTYPE xd[3],yd[3];//used if the filter is applied more times + int needsinterpolation,firsttime; + int abovenq;//this is 1 if the frequency is above the nyquist + int oldabovenq;//if the last time was above nyquist (used to see if it needs interpolation) +}; + + +#endif + diff --git a/src/DSP/FFTwrapper.C b/src/DSP/FFTwrapper.C @@ -0,0 +1,97 @@ +/* + ZynAddSubFX - a software synthesizer + + FFTwrapper.c - A wrapper for Fast Fourier Transforms + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include "FFTwrapper.h" + +FFTwrapper::FFTwrapper(int fftsize_){ + fftsize=fftsize_; + tmpfftdata1=new fftw_real[fftsize]; + tmpfftdata2=new fftw_real[fftsize]; +#ifdef FFTW_VERSION_2 + planfftw=rfftw_create_plan(fftsize,FFTW_REAL_TO_COMPLEX,FFTW_ESTIMATE|FFTW_IN_PLACE); + planfftw_inv=rfftw_create_plan(fftsize,FFTW_COMPLEX_TO_REAL,FFTW_ESTIMATE|FFTW_IN_PLACE); +#else + planfftw=fftw_plan_r2r_1d(fftsize,tmpfftdata1,tmpfftdata1,FFTW_R2HC,FFTW_ESTIMATE); + planfftw_inv=fftw_plan_r2r_1d(fftsize,tmpfftdata2,tmpfftdata2,FFTW_HC2R,FFTW_ESTIMATE); +#endif +}; + +FFTwrapper::~FFTwrapper(){ +#ifdef FFTW_VERSION_2 + rfftw_destroy_plan(planfftw); + rfftw_destroy_plan(planfftw_inv); +#else + fftw_destroy_plan(planfftw); + fftw_destroy_plan(planfftw_inv); +#endif + + delete (tmpfftdata1); + delete (tmpfftdata2); +}; + +/* + * do the Fast Fourier Transform + */ +void FFTwrapper::smps2freqs(REALTYPE *smps,REALTYPE *freqs){ +#ifdef FFTW_VERSION_2 + for (int i=0;i<fftsize;i++) tmpfftdata1[i]=smps[i]; + if (freqs==NULL) { + rfftw_one(planfftw,tmpfftdata1,NULL); + for (int i=0;i<fftsize;i++) smps[i]=tmpfftdata1[i]; + } else { + rfftw_one(planfftw,tmpfftdata1,tmpfftdata2); + for (int i=0;i<fftsize;i++) freqs[i]=tmpfftdata2[i]; + }; +#else + for (int i=0;i<fftsize;i++) tmpfftdata1[i]=smps[i]; + fftw_execute(planfftw); + if (freqs==NULL) for (int i=0;i<fftsize;i++) smps[i]=tmpfftdata1[i]; + else for (int i=0;i<fftsize;i++) freqs[i]=tmpfftdata1[i]; +#endif +}; + +/* + * do the Inverse Fast Fourier Transform + */ +void FFTwrapper::freqs2smps(REALTYPE *freqs,REALTYPE *smps){ +#ifdef FFTW_VERSION_2 + for (int i=0;i<fftsize;i++) tmpfftdata1[i]=freqs[i]; + if (smps==NULL) { + rfftw_one(planfftw_inv,tmpfftdata1,NULL); + for (int i=0;i<fftsize;i++) freqs[i]=tmpfftdata1[i]; + } else { + rfftw_one(planfftw_inv,tmpfftdata1,tmpfftdata2); + for (int i=0;i<fftsize;i++) smps[i]=tmpfftdata2[i]; + }; +#else + for (int i=0;i<fftsize;i++) tmpfftdata2[i]=freqs[i]; + fftw_execute(planfftw_inv); + if (smps==NULL) for (int i=0;i<fftsize;i++) freqs[i]=tmpfftdata2[i]; + else for (int i=0;i<fftsize;i++) smps[i]=tmpfftdata2[i]; +#endif + +}; + + + + diff --git a/src/DSP/FFTwrapper.h b/src/DSP/FFTwrapper.h @@ -0,0 +1,59 @@ +/* + ZynAddSubFX - a software synthesizer + + FFTwrapper.h - A wrapper for Fast Fourier Transforms + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef FFT_WRAPPER_H +#define FFT_WRAPPER_H + +#include "../globals.h" + +#ifdef FFTW_VERSION_2 + +#include <fftw.h> + +/* If you got error messages about rfftw.h, replace the next include line with "#include <srfftw.h>" +or with "#include <drfftw.h> (if one doesn't work try the other). It may be necessary to replace +the <fftw.h> with <dfftw.h> or <sfftw.h>. If the neither one doesn't work, +please install latest version of fftw(recomanded from the sources) from www.fftw.org. +If you'll install fftw3 you need to change the Makefile.inc +Hope all goes right." */ +#include <rfftw.h> + +#else + +#include <fftw3.h> +#define fftw_real double +#define rfftw_plan fftw_plan +#endif + +class FFTwrapper{ + public: + FFTwrapper(int fftsize_); + ~FFTwrapper(); + void smps2freqs(REALTYPE *smps,REALTYPE *freqs); + void freqs2smps(REALTYPE *freqs,REALTYPE *smps); + private: + int fftsize; + fftw_real *tmpfftdata1,*tmpfftdata2; + rfftw_plan planfftw,planfftw_inv; +}; +#endif + diff --git a/src/DSP/Filter.C b/src/DSP/Filter.C @@ -0,0 +1,73 @@ +/* + ZynAddSubFX - a software synthesizer + + Filter.C - Filters, uses analog,formant,etc. filters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdio.h> + +#include "Filter.h" + +Filter::Filter(FilterParams *pars){ + unsigned char Ftype=pars->Ptype; + unsigned char Fstages=pars->Pstages; + + category=pars->Pcategory; + + + switch (category) { + case 1:filter=new FormantFilter(pars); + break; + case 2:filter=new SVFilter(Ftype,1000.0,pars->getq(),Fstages); + filter->outgain=dB2rap(pars->getgain()); + if (filter->outgain>1.0) filter->outgain=sqrt(filter->outgain); + break; + default:filter=new AnalogFilter(Ftype,1000.0,pars->getq(),Fstages); + if ((Ftype>=6)&&(Ftype<=8)) filter->setgain(pars->getgain()); + else filter->outgain=dB2rap(pars->getgain()); + break; + }; +}; + +Filter::~Filter(){ + delete (filter); +}; + +void Filter::filterout(REALTYPE *smp){ + filter->filterout(smp); +}; + +void Filter::setfreq(REALTYPE frequency){ + filter->setfreq(frequency); +}; + +void Filter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){ + filter->setfreq_and_q(frequency,q_); +}; + +void Filter::setq(REALTYPE q_){ + filter->setq(q_); +}; + +REALTYPE Filter::getrealfreq(REALTYPE freqpitch){ + if ((category==0)||(category==2)) return(pow(2.0,freqpitch+9.96578428));//log2(1000)=9.95748 + else return(freqpitch); +}; + diff --git a/src/DSP/Filter.h b/src/DSP/Filter.h @@ -0,0 +1,52 @@ +/* + ZynAddSubFX - a software synthesizer + + Filter.h - Filters, uses analog,formant,etc. filters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef FILTER_H +#define FILTER_H + +#include "../globals.h" + +#include "Filter_.h" +#include "AnalogFilter.h" +#include "FormantFilter.h" +#include "SVFilter.h" +#include "../Params/FilterParams.h" + +class Filter{ + public: + Filter(FilterParams *pars); + ~Filter(); + void filterout(REALTYPE *smp); + void setfreq(REALTYPE frequency); + void setfreq_and_q(REALTYPE frequency,REALTYPE q_); + void setq(REALTYPE q_); + + REALTYPE getrealfreq(REALTYPE freqpitch); + private: + Filter_ *filter; + unsigned char category; + +}; + + +#endif + diff --git a/src/DSP/Filter_.h b/src/DSP/Filter_.h @@ -0,0 +1,42 @@ +/* + ZynAddSubFX - a software synthesizer + + Filter_.h - This class is inherited by filter classes + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef FILTER__H +#define FILTER__H + +#include "../globals.h" + +class Filter_{ + public: + virtual ~Filter_(){}; + virtual void filterout(REALTYPE *smp){}; + virtual void setfreq(REALTYPE frequency){}; + virtual void setfreq_and_q(REALTYPE frequency,REALTYPE q_){}; + virtual void setq(REALTYPE q_){}; + virtual void setgain(REALTYPE dBgain){}; + REALTYPE outgain; + private: +}; + + +#endif + diff --git a/src/DSP/FormantFilter.C b/src/DSP/FormantFilter.C @@ -0,0 +1,163 @@ +/* + ZynAddSubFX - a software synthesizer + + FormantFilter.C - formant filters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdio.h> +#include "FormantFilter.h" + +FormantFilter::FormantFilter(FilterParams *pars){ + numformants=pars->Pnumformants; + for (int i=0;i<numformants;i++) formant[i]=new AnalogFilter(4/*BPF*/,1000.0,10.0,pars->Pstages); + cleanup(); + inbuffer=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpbuf=new REALTYPE [SOUND_BUFFER_SIZE]; + + for (int j=0;j<FF_MAX_VOWELS;j++) + for (int i=0;i<numformants;i++){ + formantpar[j][i].freq=pars->getformantfreq(pars->Pvowels[j].formants[i].freq); + formantpar[j][i].amp=pars->getformantamp(pars->Pvowels[j].formants[i].amp); + formantpar[j][i].q=pars->getformantq(pars->Pvowels[j].formants[i].q); + }; + for (int i=0;i<FF_MAX_FORMANTS;i++) oldformantamp[i]=1.0; + for (int i=0;i<numformants;i++){ + currentformants[i].freq=1000.0; + currentformants[i].amp=1.0; + currentformants[i].q=2.0; + }; + + formantslowness=pow(1.0-(pars->Pformantslowness/128.0),3.0); + + sequencesize=pars->Psequencesize;if (sequencesize==0) sequencesize=1; + for (int k=0;k<sequencesize;k++) sequence[k].nvowel=pars->Psequence[k].nvowel; + + vowelclearness=pow(10.0,(pars->Pvowelclearness-32.0)/48.0); + + sequencestretch=pow(0.1,(pars->Psequencestretch-32.0)/48.0); + if (pars->Psequencereversed) sequencestretch*= -1.0; + + outgain=dB2rap(pars->getgain()); + + oldinput=-1.0; + Qfactor=1.0;oldQfactor=Qfactor; + firsttime=1; +}; + +FormantFilter::~FormantFilter(){ + for (int i=0;i<numformants;i++) delete(formant[i]); + delete (inbuffer); + delete (tmpbuf); +}; + + + + +void FormantFilter::cleanup(){ + for (int i=0;i<numformants;i++) formant[i]->cleanup(); +}; + +void FormantFilter::setpos(REALTYPE input){ + int p1,p2; + + if (firsttime!=0) slowinput=input; + else slowinput=slowinput*(1.0-formantslowness)+input*formantslowness; + + if ((fabs(oldinput-input)<0.001)&&(fabs(slowinput-input)<0.001)&& + (fabs(Qfactor-oldQfactor)<0.001)) { + oldinput=input; + firsttime=0; + return; + } else oldinput=input; + + + REALTYPE pos=fmod(input*sequencestretch,1.0);if (pos<0.0) pos+=1.0; + + F2I(pos*sequencesize,p2); + p1=p2-1;if (p1<0) p1+=sequencesize; + + pos=fmod(pos*sequencesize,1.0); + if (pos<0.0) pos=0.0; else if (pos>1.0) pos=1.0; + pos=(atan((pos*2.0-1.0)*vowelclearness)/atan(vowelclearness)+1.0)*0.5; + + p1=sequence[p1].nvowel; + p2=sequence[p2].nvowel; + + if (firsttime!=0) { + for (int i=0;i<numformants;i++){ + currentformants[i].freq=formantpar[p1][i].freq*(1.0-pos)+formantpar[p2][i].freq*pos; + currentformants[i].amp=formantpar[p1][i].amp*(1.0-pos)+formantpar[p2][i].amp*pos; + currentformants[i].q=formantpar[p1][i].q*(1.0-pos)+formantpar[p2][i].q*pos; + formant[i]->setfreq_and_q(currentformants[i].freq,currentformants[i].q*Qfactor); + oldformantamp[i]=currentformants[i].amp; + }; + firsttime=0; + } else { + for (int i=0;i<numformants;i++){ + currentformants[i].freq=currentformants[i].freq*(1.0-formantslowness) + +(formantpar[p1][i].freq*(1.0-pos)+formantpar[p2][i].freq*pos)*formantslowness; + + currentformants[i].amp=currentformants[i].amp*(1.0-formantslowness) + +(formantpar[p1][i].amp*(1.0-pos)+formantpar[p2][i].amp*pos)*formantslowness; + + currentformants[i].q=currentformants[i].q*(1.0-formantslowness) + +(formantpar[p1][i].q*(1.0-pos)+formantpar[p2][i].q*pos)*formantslowness; + + formant[i]->setfreq_and_q(currentformants[i].freq,currentformants[i].q*Qfactor); + }; + }; + + oldQfactor=Qfactor; +}; + +void FormantFilter::setfreq(REALTYPE frequency){ + setpos(frequency); +}; + +void FormantFilter::setq(REALTYPE q_){ + Qfactor=q_; + for (int i=0;i<numformants;i++) formant[i]->setq(Qfactor*currentformants[i].q); +}; + +void FormantFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){ + Qfactor=q_; + setpos(frequency); +}; + + +void FormantFilter::filterout(REALTYPE *smp){ + int i,j; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + inbuffer[i]=smp[i]; + smp[i]=0.0; + }; + + for (j=0;j<numformants;j++) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpbuf[i]=inbuffer[i]*outgain; + formant[j]->filterout(tmpbuf); + + if (ABOVE_AMPLITUDE_THRESHOLD(oldformantamp[j],currentformants[j].amp)) + for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]+=tmpbuf[i]* + INTERPOLATE_AMPLITUDE(oldformantamp[j],currentformants[j].amp,i,SOUND_BUFFER_SIZE); + else for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]+=tmpbuf[i]*currentformants[j].amp; + oldformantamp[j]=currentformants[j].amp; + }; +}; + diff --git a/src/DSP/FormantFilter.h b/src/DSP/FormantFilter.h @@ -0,0 +1,67 @@ +/* + ZynAddSubFX - a software synthesizer + + FormantFilter.h - formant filter + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef FORMANT_FILTER_H +#define FORMANT_FILTER_H + +#include "../globals.h" +#include "Filter_.h" +#include "AnalogFilter.h" +#include "../Params/FilterParams.h" + + +class FormantFilter:public Filter_{ + public: + FormantFilter(FilterParams *pars); + ~FormantFilter(); + void filterout(REALTYPE *smp); + void setfreq(REALTYPE frequency); + void setfreq_and_q(REALTYPE frequency,REALTYPE q_); + void setq(REALTYPE q_); + + void cleanup(); + private: + AnalogFilter *formant[FF_MAX_FORMANTS]; + REALTYPE *inbuffer,*tmpbuf; + + struct { + REALTYPE freq,amp,q;//frequency,amplitude,Q + } formantpar[FF_MAX_VOWELS][FF_MAX_FORMANTS],currentformants[FF_MAX_FORMANTS]; + + struct { + unsigned char nvowel; + } sequence [FF_MAX_SEQUENCE]; + + REALTYPE oldformantamp[FF_MAX_FORMANTS]; + + int sequencesize,numformants,firsttime; + REALTYPE oldinput,slowinput; + REALTYPE Qfactor,formantslowness,oldQfactor; + REALTYPE vowelclearness,sequencestretch; + + void setpos(REALTYPE input); + +}; + + +#endif + diff --git a/src/DSP/Makefile b/src/DSP/Makefile @@ -0,0 +1,14 @@ +include ../Makefile.inc + +objects=FFTwrapper.o AnalogFilter.o FormantFilter.o SVFilter.o Filter.o + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/DSP/SVFilter.C b/src/DSP/SVFilter.C @@ -0,0 +1,152 @@ +/* + ZynAddSubFX - a software synthesizer + + SVFilter.C - Several state-variable filters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdio.h> +#include "SVFilter.h" + +SVFilter::SVFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages){ + stages=Fstages; + type=Ftype; + freq=Ffreq; + q=Fq; + gain=1.0; + outgain=1.0; + needsinterpolation=0; + firsttime=1; + if (stages>=MAX_FILTER_STAGES) stages=MAX_FILTER_STAGES; + cleanup(); + setfreq_and_q(Ffreq,Fq); +}; + +SVFilter::~SVFilter(){ +}; + +void SVFilter::cleanup(){ + for (int i=0;i<MAX_FILTER_STAGES+1;i++){ + st[i].low=0.0;st[i].high=0.0; + st[i].band=0.0;st[i].notch=0.0; + }; + oldabovenq=0; + abovenq=0; +}; + +void SVFilter::computefiltercoefs(){ + par.f=freq / SAMPLE_RATE*4.0; + if (par.f>0.99999) par.f=0.99999; + par.q=1.0-atan(sqrt(q))*2.0/PI; + par.q=pow(par.q,1.0/(stages+1)); + par.q_sqrt=sqrt(par.q); +}; + + +void SVFilter::setfreq(REALTYPE frequency){ + if (frequency<0.1) frequency=0.1; + REALTYPE rap=freq/frequency;if (rap<1.0) rap=1.0/rap; + + oldabovenq=abovenq;abovenq=frequency>(SAMPLE_RATE/2-500.0); + + int nyquistthresh=(abovenq^oldabovenq); + + + if ((rap>3.0)||(nyquistthresh!=0)){//if the frequency is changed fast, it needs interpolation (now, filter and coeficients backup) + if (firsttime==0) needsinterpolation=1; + ipar=par; + }; + freq=frequency; + computefiltercoefs(); + firsttime=0; + +}; + +void SVFilter::setfreq_and_q(REALTYPE frequency,REALTYPE q_){ + q=q_; + setfreq(frequency); +}; + +void SVFilter::setq(REALTYPE q_){ + q=q_; + computefiltercoefs(); +}; + +void SVFilter::settype(int type_){ + type=type_; + computefiltercoefs(); +}; + +void SVFilter::setgain(REALTYPE dBgain){ + gain=dB2rap(dBgain); + computefiltercoefs(); +}; + +void SVFilter::setstages(int stages_){ + if (stages_>=MAX_FILTER_STAGES) stages_=MAX_FILTER_STAGES-1; + stages=stages_; + cleanup(); + computefiltercoefs(); +}; + +void SVFilter::singlefilterout(REALTYPE *smp,fstage &x,parameters &par){ + int i; + REALTYPE *out=NULL; + switch(type){ + case 0: out=&x.low;break; + case 1: out=&x.high;break; + case 2: out=&x.band;break; + case 3: out=&x.notch;break; + }; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + x.low = x.low + par.f * x.band; + x.high = par.q_sqrt * smp[i] - x.low - par.q*x.band; + x.band = par.f * x.high + x.band; + x.notch = x.high + x.low; + + smp[i]= *out; + }; +}; + +void SVFilter::filterout(REALTYPE *smp){ + int i; + REALTYPE *ismp; + + if (needsinterpolation!=0){ + ismp=new REALTYPE[SOUND_BUFFER_SIZE]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) ismp[i]=smp[i]; + for (i=0;i<stages+1;i++) singlefilterout(ismp,st[i],ipar); + }; + + for (i=0;i<stages+1;i++) singlefilterout(smp,st[i],par); + + if (needsinterpolation!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE x=i/(REALTYPE) SOUND_BUFFER_SIZE; + smp[i]=ismp[i]*(1.0-x)+smp[i]*x; + }; + delete (ismp); + needsinterpolation=0; + }; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) smp[i]*=outgain; + +}; + diff --git a/src/DSP/SVFilter.h b/src/DSP/SVFilter.h @@ -0,0 +1,67 @@ +/* + ZynAddSubFX - a software synthesizer + + SV Filter.h - Several state-variable filters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef SV_FILTER_H +#define SV_FILTER_H + +#include "../globals.h" +#include "Filter_.h" +class SVFilter:public Filter_{ + public: + SVFilter(unsigned char Ftype,REALTYPE Ffreq, REALTYPE Fq,unsigned char Fstages); + ~SVFilter(); + void filterout(REALTYPE *smp); + void setfreq(REALTYPE frequency); + void setfreq_and_q(REALTYPE frequency,REALTYPE q_); + void setq(REALTYPE q_); + + void settype(int type_); + void setgain(REALTYPE dBgain); + void setstages(int stages_); + void cleanup(); + + private: + struct fstage{ + REALTYPE low,high,band,notch; + } st[MAX_FILTER_STAGES+1]; + + struct parameters{ + REALTYPE f,q,q_sqrt; + }par,ipar; + + + void singlefilterout(REALTYPE *smp,fstage &x,parameters &par); + void computefiltercoefs(); + int type;//The type of the filter (LPF1,HPF1,LPF2,HPF2...) + int stages;//how many times the filter is applied (0->1,1->2,etc.) + REALTYPE freq;//Frequency given in Hz + REALTYPE q; //Q factor (resonance or Q factor) + REALTYPE gain;//the gain of the filter (if are shelf/peak) filters + + int abovenq;//this is 1 if the frequency is above the nyquist + int oldabovenq; + int needsinterpolation,firsttime; +}; + + +#endif + diff --git a/src/Effects/Alienwah.C b/src/Effects/Alienwah.C @@ -0,0 +1,267 @@ +/* + ZynAddSubFX - a software synthesizer + + Alienwah.C - "AlienWah" effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include "Alienwah.h" +#include <stdio.h> + +Alienwah::Alienwah(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + + oldl=NULL; + oldr=NULL; + insertion=insertion_; + + Ppreset=0; + setpreset(Ppreset); + cleanup(); + oldclfol.a=fb;oldclfol.b=0.0; + oldclfor.a=fb;oldclfor.b=0.0; +}; + +Alienwah::~Alienwah(){ + if (oldl!=NULL) delete [] oldl; + if (oldr!=NULL) delete [] oldr ; +}; + + +/* + * Apply the effect + */ +void Alienwah::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i; + REALTYPE lfol,lfor; + COMPLEXTYPE clfol,clfor,out,tmp; + + lfo.effectlfoout(&lfol,&lfor); + lfol*=depth*PI*2.0;lfor*=depth*PI*2.0; + clfol.a=cos(lfol+phase)*fb;clfol.b=sin(lfol+phase)*fb; + clfor.a=cos(lfor+phase)*fb;clfor.b=sin(lfor+phase)*fb; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE x=((REALTYPE) i)/SOUND_BUFFER_SIZE; + REALTYPE x1=1.0-x; + //left + tmp.a=clfol.a*x+oldclfol.a*x1; + tmp.b=clfol.b*x+oldclfol.b*x1; + + out.a=tmp.a*oldl[oldk].a-tmp.b*oldl[oldk].b + +(1-fabs(fb))*smpsl[i]*panning; + out.b=tmp.a*oldl[oldk].b+tmp.b*oldl[oldk].a; + oldl[oldk].a=out.a; + oldl[oldk].b=out.b; + REALTYPE l=out.a*10.0*(fb+0.1); + + //right + tmp.a=clfor.a*x+oldclfor.a*x1; + tmp.b=clfor.b*x+oldclfor.b*x1; + + out.a=tmp.a*oldr[oldk].a-tmp.b*oldr[oldk].b + +(1-fabs(fb))*smpsr[i]*(1.0-panning); + out.b=tmp.a*oldr[oldk].b+tmp.b*oldr[oldk].a; + oldr[oldk].a=out.a; + oldr[oldk].b=out.b; + REALTYPE r=out.a*10.0*(fb+0.1); + + + if (++oldk>=Pdelay) oldk=0; + //LRcross + efxoutl[i]=l*(1.0-lrcross)+r*lrcross; + efxoutr[i]=r*(1.0-lrcross)+l*lrcross; + }; + + oldclfol.a=clfol.a;oldclfol.b=clfol.b; + oldclfor.a=clfor.a;oldclfor.b=clfor.b; + + //Insertion effect + if (insertion!=0) { + REALTYPE v1,v2; + if (volume<0.5) { + v1=1.0; + v2=volume*2.0; + } else { + v1=(1.0-volume)*2.0; + v2=1.0; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=smpsl[i]*v1+efxoutl[i]*v2; + smpsr[i]=smpsr[i]*v1+efxoutr[i]*v2; + }; + } else {//System effect + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=2.0*volume; + efxoutr[i]*=2.0*volume; + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + }; + + +}; + +/* + * Cleanup the effect + */ +void Alienwah::cleanup(){ + for (int i=0;i<Pdelay;i++) { + oldl[i].a=0.0; + oldl[i].b=0.0; + oldr[i].a=0.0; + oldr[i].b=0.0; + }; + oldk=0; +}; + + +/* + * Parameter control + */ + +void Alienwah::setdepth(unsigned char Pdepth){ + this->Pdepth=Pdepth; + depth=(Pdepth/127.0); +}; + +void Alienwah::setfb(unsigned char Pfb){ + this->Pfb=Pfb; + fb=fabs((Pfb-64.0)/64.1); + fb=sqrt(fb); + if (fb<0.4) fb=0.4; + if (Pfb<64) fb=-fb; +}; + +void Alienwah::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + outvolume=Pvolume/127.0; + if (insertion==0) volume=1.0; + else volume=outvolume; +}; + +void Alienwah::setpanning(unsigned char Ppanning){ + this->Ppanning=Ppanning; + panning=Ppanning/127.0; +}; + +void Alienwah::setlrcross(unsigned char Plrcross){ + this->Plrcross=Plrcross; + lrcross=Plrcross/127.0; +}; + +void Alienwah::setphase(unsigned char Pphase){ + this->Pphase=Pphase; + phase=(Pphase-64.0)/64.0*PI; +}; + +void Alienwah::setdelay(unsigned char Pdelay){ + if (oldl!=NULL) delete [] oldl; + if (oldr!=NULL) delete [] oldr; + if (Pdelay>=MAX_ALIENWAH_DELAY) Pdelay=MAX_ALIENWAH_DELAY; + this->Pdelay=Pdelay; + oldl=new COMPLEXTYPE[Pdelay]; + oldr=new COMPLEXTYPE[Pdelay]; + cleanup(); +}; + +void Alienwah::setpreset(unsigned char npreset){ + const int PRESET_SIZE=11; + const int NUM_PRESETS=4; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //AlienWah1 + {127,64,70,0,0,62,60,105,25,0,64}, + //AlienWah2 + {127,64,73,106,0,101,60,105,17,0,64}, + //AlienWah3 + {127,64,63,0,1,100,112,105,31,0,42}, + //AlienWah4 + {93,64,25,0,1,66,101,11,47,0,86}}; + + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + if (insertion==0) changepar(0,presets[npreset][0]/2);//lower the volume if this is system effect + Ppreset=npreset; +}; + + +void Alienwah::changepar(int npar,unsigned char value){ + switch(npar){ + case 0: setvolume(value); + break; + case 1: setpanning(value); + break; + case 2: lfo.Pfreq=value; + lfo.updateparams(); + break; + case 3: lfo.Prandomness=value; + lfo.updateparams(); + break; + case 4: lfo.PLFOtype=value; + lfo.updateparams(); + break; + case 5: lfo.Pstereo=value; + lfo.updateparams(); + break; + case 6: setdepth(value); + break; + case 7: setfb(value); + break; + case 8: setdelay(value); + break; + case 9: setlrcross(value); + break; + case 10:setphase(value); + break; + }; +}; + +unsigned char Alienwah::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + case 1: return(Ppanning); + break; + case 2: return(lfo.Pfreq); + break; + case 3: return(lfo.Prandomness); + break; + case 4: return(lfo.PLFOtype); + break; + case 5: return(lfo.Pstereo); + break; + case 6: return(Pdepth); + break; + case 7: return(Pfb); + break; + case 8: return(Pdelay); + break; + case 9: return(Plrcross); + break; + case 10:return(Pphase); + break; + default:return (0); + }; + +}; + + + + diff --git a/src/Effects/Alienwah.h b/src/Effects/Alienwah.h @@ -0,0 +1,77 @@ +/* + ZynAddSubFX - a software synthesizer + + Alienwah.h - "AlienWah" effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ALIENWAH_H +#define ALIENWAH_H +#include "../globals.h" +#include "Effect.h" +#include "EffectLFO.h" + + +#define MAX_ALIENWAH_DELAY 100 + +struct COMPLEXTYPE { + REALTYPE a,b; +}; + +class Alienwah:public Effect { + public: + Alienwah(int insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~Alienwah(); + void out(REALTYPE *smpsl,REALTYPE *smpsr); + + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + void cleanup(); + + private: + //Parametrii Alienwah + EffectLFO lfo;//lfo-ul Alienwah + unsigned char Pvolume; + unsigned char Ppanning; + unsigned char Pdepth;//the depth of the Alienwah + unsigned char Pfb;//feedback + unsigned char Plrcross;//feedback + unsigned char Pdelay; + unsigned char Pphase; + + + //Control Parametrii + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setfb(unsigned char Pfb); + void setlrcross(unsigned char Plrcross); + void setdelay(unsigned char Pdelay); + void setphase(unsigned char Pphase); + + //Valorile interne + int insertion; + REALTYPE volume,panning,fb,depth,lrcross,phase; + COMPLEXTYPE *oldl,*oldr; + COMPLEXTYPE oldclfol,oldclfor; + int oldk; +}; + +#endif + diff --git a/src/Effects/Chorus.C b/src/Effects/Chorus.C @@ -0,0 +1,293 @@ +/* + ZynAddSubFX - a software synthesizer + + Chorus.C - Chorus and Flange effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include "Chorus.h" +#include <stdio.h> + +Chorus::Chorus(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + dlk=0;drk=0; + maxdelay=(int)(MAX_CHORUS_DELAY/1000.0*SAMPLE_RATE); + delayl=new REALTYPE[maxdelay]; + delayr=new REALTYPE[maxdelay]; + insertion=insertion_; + + Ppreset=0; + setpreset(Ppreset); + + lfo.effectlfoout(&lfol,&lfor); + dl2=getdelay(lfol); + dr2=getdelay(lfor); + cleanup(); +}; + +Chorus::~Chorus(){ + delete [] delayl; + delete [] delayr; +}; + +/* + * get the delay value in samples; xlfo is the current lfo value + */ +REALTYPE Chorus::getdelay(REALTYPE xlfo){ + REALTYPE result; + if (Pflangemode==0){ + result=(delay+xlfo*depth)*SAMPLE_RATE; + } else result=0; + + //check if it is too big delay(caused bu errornous setdelay() and setdepth() + if ((result+0.5)>=maxdelay) { + fprintf(stderr,"WARNING: Chorus.C::getdelay(..) too big delay (see setdelay and setdepth funcs.)\n"); + result=maxdelay-1.0; + }; + return(result); +}; + +/* + * Apply the effect + */ +void Chorus::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i; + dl1=dl2;dr1=dr2; + lfo.effectlfoout(&lfol,&lfor); + + dl2=getdelay(lfol); + dr2=getdelay(lfor); + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE inl=smpsl[i]; + REALTYPE inr=smpsr[i]; + //LRcross + REALTYPE l=inl; + REALTYPE r=inr; + inl=l*(1.0-lrcross)+r*lrcross; + inr=r*(1.0-lrcross)+l*lrcross; + + //Left channel + + //compute the delay in samples using linear interpolation between the lfo delays + mdel=(dl1*(SOUND_BUFFER_SIZE-i)+dl2*i)/SOUND_BUFFER_SIZE; + if (++dlk>=maxdelay) dlk=0; + REALTYPE tmp=dlk-mdel+maxdelay*2.0;//where should I get the sample from + + F2I(tmp,dlhi); + dlhi%=maxdelay; + + dlhi2=(dlhi-1+maxdelay)%maxdelay; + dllo=1.0-fmod(tmp,1.0); + efxoutl[i]=delayl[dlhi2]*dllo+delayl[dlhi]*(1.0-dllo); + delayl[dlk]=inl+efxoutl[i]*fb; + + //Right channel + + //compute the delay in samples using linear interpolation between the lfo delays + mdel=(dr1*(SOUND_BUFFER_SIZE-i)+dr2*i)/SOUND_BUFFER_SIZE; + if (++drk>=maxdelay) drk=0; + tmp=drk-mdel+maxdelay*2.0;//where should I get the sample from + + F2I(tmp,dlhi); + dlhi%=maxdelay; + + dlhi2=(dlhi-1+maxdelay)%maxdelay; + dllo=1.0-fmod(tmp,1.0); + efxoutr[i]=delayr[dlhi2]*dllo+delayr[dlhi]*(1.0-dllo); + delayr[dlk]=inr+efxoutr[i]*fb; + + }; + + if (Poutsub!=0) + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i] *= -1.0; + efxoutr[i] *= -1.0; + }; + + //Insertion effect + if (insertion!=0) { + REALTYPE v1,v2; + if (volume<0.5) { + v1=1.0; + v2=volume*2.0; + } else { + v1=(1.0-volume)*2.0; + v2=1.0; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=smpsl[i]*v1+efxoutl[i]*panning*v2*2.0; + smpsr[i]=smpsr[i]*v1+efxoutr[i]*(1.0-panning)*v2*2.0; + }; + } else {//System effect + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=2.0*volume*panning; + efxoutr[i]*=2.0*volume*(1.0-panning); + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + }; +}; + +/* + * Cleanup the effect + */ +void Chorus::cleanup(){ + for (int i=0;i<maxdelay;i++){ + delayl[i]=0.0; + delayr[i]=0.0; + }; + +}; + +/* + * Parameter control + */ +void Chorus::setdepth(unsigned char Pdepth){ + this->Pdepth=Pdepth; + depth=(pow(8.0,(Pdepth/127.0)*2.0)-1.0)/1000.0;//seconds +}; + +void Chorus::setdelay(unsigned char Pdelay){ + this->Pdelay=Pdelay; + delay=(pow(10.0,(Pdelay/127.0)*2.0)-1.0)/1000.0;//seconds +}; + +void Chorus::setfb(unsigned char Pfb){ + this->Pfb=Pfb; + fb=(Pfb-64.0)/64.1; +}; +void Chorus::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + outvolume=Pvolume/127.0; + if (insertion==0) volume=1.0; + else volume=outvolume; +}; + +void Chorus::setpanning(unsigned char Ppanning){ + this->Ppanning=Ppanning; + panning=Ppanning/127.0; +}; + +void Chorus::setlrcross(unsigned char Plrcross){ + this->Plrcross=Plrcross; + lrcross=Plrcross/127.0; +}; + +void Chorus::setpreset(unsigned char npreset){ + const int PRESET_SIZE=12; + const int NUM_PRESETS=10; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //Chorus1 + {64,64,50,0,0,90,40,85,64,119,0,0}, + //Chorus2 + {64,64,45,0,0,98,56,90,64,19,0,0}, + //Chorus3 + {64,64,29,0,1,42,97,95,90,127,0,0}, + //Celeste1 + {64,64,26,0,0,42,115,18,90,127,0,0}, + //Celeste2 + {64,64,29,117,0,50,115,9,31,127,0,1}, + //Flange1 + {64,64,57,0,0,60,23,3,62,0,0,0}, + //Flange2 + {64,64,33,34,1,40,35,3,109,0,0,0}, + //Flange3 + {64,64,53,34,1,94,35,3,54,0,0,1}, + //Flange4 + {64,64,40,0,1,62,12,19,97,0,0,0}, + //Flange5 + {64,64,55,105,0,24,39,19,17,0,0,1}}; + + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + Ppreset=npreset; +}; + + +void Chorus::changepar(int npar,unsigned char value){ + switch(npar){ + case 0: setvolume(value); + break; + case 1: setpanning(value); + break; + case 2: lfo.Pfreq=value; + lfo.updateparams(); + break; + case 3: lfo.Prandomness=value; + lfo.updateparams(); + break; + case 4: lfo.PLFOtype=value; + lfo.updateparams(); + break; + case 5: lfo.Pstereo=value; + lfo.updateparams(); + break; + case 6: setdepth(value); + break; + case 7: setdelay(value); + break; + case 8: setfb(value); + break; + case 9: setlrcross(value); + break; + case 10:if (value>1) value=1; + Pflangemode=value; + break; + case 11:if (value>1) value=1; + Poutsub=value; + break; + }; +}; + +unsigned char Chorus::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + case 1: return(Ppanning); + break; + case 2: return(lfo.Pfreq); + break; + case 3: return(lfo.Prandomness); + break; + case 4: return(lfo.PLFOtype); + break; + case 5: return(lfo.Pstereo); + break; + case 6: return(Pdepth); + break; + case 7: return(Pdelay); + break; + case 8: return(Pfb); + break; + case 9: return(Plrcross); + break; + case 10:return(Pflangemode); + break; + case 11:return(Poutsub); + break; + default:return (0); + }; + +}; + + + + diff --git a/src/Effects/Chorus.h b/src/Effects/Chorus.h @@ -0,0 +1,73 @@ +/* + ZynAddSubFX - a software synthesizer + + Chorus.h - Chorus and Flange effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef CHORUS_H +#define CHORUS_H +#include "../globals.h" +#include "Effect.h" +#include "EffectLFO.h" + +#define MAX_CHORUS_DELAY 250.0 //ms + +class Chorus:public Effect { + public: + Chorus(int insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~Chorus(); + void out(REALTYPE *smpsl,REALTYPE *smpsr); + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + void cleanup(); + + private: + //Parametrii Chorus + EffectLFO lfo;//lfo-ul chorus + unsigned char Pvolume; + unsigned char Ppanning; + unsigned char Pdepth;//the depth of the Chorus(ms) + unsigned char Pdelay;//the delay (ms) + unsigned char Pfb;//feedback + unsigned char Plrcross;//feedback + unsigned char Pflangemode;//how the LFO is scaled, to result chorus or flange + unsigned char Poutsub;//if I wish to substract the output instead of the adding it + + + //Control Parametrii + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setdelay(unsigned char Pdelay); + void setfb(unsigned char Pfb); + void setlrcross(unsigned char Plrcross); + + //Valorile interne + REALTYPE depth,delay,fb,lrcross,volume,panning; + REALTYPE dl1,dl2,dr1,dr2,lfol,lfor; + int insertion,maxdelay; + REALTYPE *delayl,*delayr; + int dlk,drk,dlhi,dlhi2; + REALTYPE getdelay(REALTYPE xlfo); + REALTYPE dllo,mdel; +}; + +#endif + diff --git a/src/Effects/Distorsion.C b/src/Effects/Distorsion.C @@ -0,0 +1,290 @@ +/* + ZynAddSubFX - a software synthesizer + + Distorsion.C - Distorsion effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "../Misc/Util.h" +#include "Distorsion.h" + +Distorsion::Distorsion(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + + lpfl=new AnalogFilter(2,22000,1,0); + lpfr=new AnalogFilter(2,22000,1,0); + hpfl=new AnalogFilter(3,20,1,0); + hpfr=new AnalogFilter(3,20,1,0); + + + insertion=insertion_; + //default values + Ppreset=0; + Pvolume=50; + Plrcross=40; + Pdrive=90; + Plevel=64; + Ptype=0; + Pnegate=0; + Plpf=127; + Phpf=0; + Pstereo=0; + Pprefiltering=0; + + setpreset(Ppreset); + cleanup(); +}; + +Distorsion::~Distorsion(){ + delete (lpfl); + delete (lpfr); + delete (hpfl); + delete (hpfr); + +}; + +/* + * Cleanup the effect + */ +void Distorsion::cleanup(){ + lpfl->cleanup(); + hpfl->cleanup(); + lpfr->cleanup(); + hpfr->cleanup(); +}; + + +/* + * Apply the filters + */ + +void Distorsion::applyfilters(REALTYPE *efxoutl,REALTYPE *efxoutr){ + lpfl->filterout(efxoutl); + hpfl->filterout(efxoutl); + if (Pstereo!=0){//stereo + lpfr->filterout(efxoutr); + hpfr->filterout(efxoutr); + }; + +}; + + +/* + * Effect output + */ +void Distorsion::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i; + REALTYPE l,r,lout,rout; + + REALTYPE inputvol=pow(5.0,(Pdrive-32.0)/127.0); + if (Pnegate!=0) inputvol*=-1.0; + + if (Pstereo!=0){//Stereo + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]=smpsl[i]*inputvol*panning; + efxoutr[i]=smpsr[i]*inputvol*(1.0-panning); + }; + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]=( smpsl[i]*panning + smpsr[i]*(1.0-panning) ) * inputvol; + }; + }; + + if (Pprefiltering!=0) applyfilters(efxoutl,efxoutr); + + //no optimised, yet (no look table) + waveshapesmps(SOUND_BUFFER_SIZE,efxoutl,Ptype+1,Pdrive); + if (Pstereo!=0) waveshapesmps(SOUND_BUFFER_SIZE,efxoutr,Ptype+1,Pdrive); + + if (Pprefiltering==0) applyfilters(efxoutl,efxoutr); + + if (Pstereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) efxoutr[i]=efxoutl[i]; + + REALTYPE level=dB2rap(60.0*Plevel/127.0-40.0); + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + lout=efxoutl[i]; + rout=efxoutr[i]; + l=lout*(1.0-lrcross)+rout*lrcross; + r=rout*(1.0-lrcross)+lout*lrcross; + lout=l;rout=r; + + efxoutl[i]=lout*2.0*level; + efxoutr[i]=rout*2.0*level; + + }; + + + //Insertion effect + if (insertion!=0) { + REALTYPE v1,v2; + if (volume<0.5) { + v1=1.0; + v2=volume*2.0; + } else { + v1=(1.0-volume)*2.0; + v2=1.0; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=smpsl[i]*v1+efxoutl[i]*v2; + smpsr[i]=smpsr[i]*v1+efxoutr[i]*v2; + }; + } else {//System effect + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=2.0*volume; + efxoutr[i]*=2.0*volume; + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + }; + +}; + + +/* + * Parameter control + */ +void Distorsion::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + + if (insertion==0) { + outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0; + volume=1.0; + } else { + volume=outvolume=Pvolume/127.0; + }; + if (Pvolume==0) cleanup(); + +}; + +void Distorsion::setpanning(unsigned char Ppanning){ + this->Ppanning=Ppanning; + panning=(Ppanning+0.5)/127.0; +}; + + +void Distorsion::setlrcross(unsigned char Plrcross){ + this->Plrcross=Plrcross; + lrcross=Plrcross/127.0*1.0; +}; + +void Distorsion::setlpf(unsigned char Plpf){ + this->Plpf=Plpf; + REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40; + lpfl->setfreq(fr); + lpfr->setfreq(fr); +}; + +void Distorsion::sethpf(unsigned char Phpf){ + this->Phpf=Phpf; + REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(25000.0))+20.0; + hpfl->setfreq(fr); + hpfr->setfreq(fr); +}; + + +void Distorsion::setpreset(unsigned char npreset){ + const int PRESET_SIZE=11; + const int NUM_PRESETS=6; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //Overdrive 1 + {127,64,35,56,70,0,0,96,0,0,0}, + //Overdrive 2 + {127,64,35,29,75,1,0,127,0,0,0}, + //A. Exciter 1 + {64,64,35,75,80,5,0,127,105,1,0}, + //A. Exciter 2 + {64,64,35,85,62,1,0,127,118,1,0}, + //Guitar Amp + {127,64,35,63,75,2,0,55,0,0,0}, + //Quantisize + {127,64,35,88,75,4,0,127,0,1,0}}; + + + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + if (insertion==0) changepar(0,(int) (presets[npreset][0]/1.5));//lower the volume if this is system effect + Ppreset=npreset; + cleanup(); +}; + + +void Distorsion::changepar(int npar,unsigned char value){ + switch (npar){ + case 0: setvolume(value); + break; + case 1: setpanning(value); + break; + case 2: setlrcross(value); + break; + case 3: Pdrive=value; + break; + case 4: Plevel=value; + break; + case 5: if (value>12) value=12;//this must be increased if more distorsion types are added + Ptype=value; + break; + case 6: if (value>1) value=1; + Pnegate=value; + break; + case 7: setlpf(value); + break; + case 8: sethpf(value); + break; + case 9: if (value>1) value=1; + Pstereo=value; + break; + case 10:Pprefiltering=value; + break; + }; +}; + +unsigned char Distorsion::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + case 1: return(Ppanning); + break; + case 2: return(Plrcross); + break; + case 3: return(Pdrive); + break; + case 4: return(Plevel); + break; + case 5: return(Ptype); + break; + case 6: return(Pnegate); + break; + case 7: return(Plpf); + break; + case 8: return(Phpf); + break; + case 9: return(Pstereo); + break; + case 10:return(Pprefiltering); + break; + }; + return(0);//in case of bogus parameter number +}; + + + + diff --git a/src/Effects/Distorsion.h b/src/Effects/Distorsion.h @@ -0,0 +1,69 @@ +/* + ZynAddSubFX - a software synthesizer + + Distorsion.h - Distorsion Effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef DISTORSION_H +#define DISTORSION_H + +#include "../globals.h" +#include "../DSP/AnalogFilter.h" +#include "Effect.h" + +class Distorsion:public Effect{ + public: + Distorsion(int insertion,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~Distorsion(); + void out(REALTYPE *smpsl,REALTYPE *smpr); + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + void cleanup(); + void applyfilters(REALTYPE *efxoutl,REALTYPE *efxoutr); + private: + //Parametrii + unsigned char Pvolume; //Volumul or E/R + unsigned char Ppanning;//Panning + unsigned char Plrcross;// L/R Mixing + unsigned char Pdrive; //the input amplification + unsigned char Plevel; //the ouput amplification + unsigned char Ptype; //Distorsion type + unsigned char Pnegate; //if the input is negated + unsigned char Plpf; //lowpass filter + unsigned char Phpf; //highpass filter + unsigned char Pstereo; //0=mono,1=stereo + unsigned char Pprefiltering;//if you want to do the filtering before the distorsion + + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setlrcross(unsigned char Plrcross); + void setlpf(unsigned char Plpf); + void sethpf(unsigned char Phpf); + + //Parametrii reali + REALTYPE volume,panning,lrcross; + AnalogFilter *lpfl,*lpfr,*hpfl,*hpfr; + +}; + + +#endif + + diff --git a/src/Effects/EQ.C b/src/Effects/EQ.C @@ -0,0 +1,213 @@ +/* + ZynAddSubFX - a software synthesizer + + EQ.C - EQ effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "EQ.h" + +EQ::EQ(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + insertion=insertion_; + + for (int i=0;i<MAX_EQ_BANDS;i++){ + filter[i].Ptype=0; + filter[i].Pfreq=64; + filter[i].Pgain=64; + filter[i].Pq=64; + filter[i].Pstages=0; + filter[i].l=new AnalogFilter(6,1000.0,1.0,0); + filter[i].r=new AnalogFilter(6,1000.0,1.0,0); + }; + //default values + Ppreset=0; + Pvolume=50; + + setpreset(Ppreset); + cleanup(); +}; + +EQ::~EQ(){ +}; + +/* + * Cleanup the effect + */ +void EQ::cleanup(){ + for (int i=0;i<MAX_EQ_BANDS;i++){ + filter[i].l->cleanup(); + filter[i].r->cleanup(); + }; +}; + + + +/* + * Effect output + */ +void EQ::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]=smpsl[i]*volume; + efxoutr[i]=smpsr[i]*volume; + }; + + for (i=0;i<MAX_EQ_BANDS;i++){ + if (filter[i].Ptype==0) continue; + filter[i].l->filterout(efxoutl); + filter[i].r->filterout(efxoutr); + }; + + //Insertion effect + if (insertion!=0) { + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + } else {//System effect + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=2.0*volume; + efxoutr[i]*=2.0*volume; + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + }; + +}; + + +/* + * Parameter control + */ +void EQ::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + + outvolume=pow(0.005,(1.0-Pvolume/127.0))*10.0; + if (insertion==0) { + volume=1.0; + } else { + volume=outvolume; + }; + +}; + + +void EQ::setpreset(unsigned char npreset){ + const int PRESET_SIZE=1; + const int NUM_PRESETS=2; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //EQ 1 + {67}, + //EQ 2 + {67}}; + + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + Ppreset=npreset; +}; + + +void EQ::changepar(int npar,unsigned char value){ + switch (npar){ + case 0: setvolume(value); + break; + }; + if (npar<10) return; + + int nb=(npar-10)/5;//number of the band (filter) + if (nb>=MAX_EQ_BANDS) return; + int bp=npar%5;//band paramenter + + REALTYPE tmp; + switch(bp){ + case 0: if (value>9) value=0;//has to be changed if more filters will be added + filter[nb].Ptype=value; + if (value!=0){ + filter[nb].l->settype(value-1); + filter[nb].r->settype(value-1); + }; + break; + case 1: filter[nb].Pfreq=value; + tmp=600.0*pow(30.0,(value-64.0)/64.0); + filter[nb].l->setfreq(tmp); + filter[nb].r->setfreq(tmp); + break; + case 2: filter[nb].Pgain=value; + tmp=30.0*(value-64.0)/64.0; + filter[nb].l->setgain(tmp); + filter[nb].r->setgain(tmp); + break; + case 3: filter[nb].Pq=value; + tmp=pow(30.0,(value-64.0)/64.0); + filter[nb].l->setq(tmp); + filter[nb].r->setq(tmp); + break; + case 4: if (value>=MAX_FILTER_STAGES) value=MAX_FILTER_STAGES-1; + filter[nb].Pstages=value; + filter[nb].l->setstages(value); + filter[nb].r->setstages(value); + break; + }; +}; + +unsigned char EQ::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + }; + + if (npar<10) return(0); + + int nb=(npar-10)/5;//number of the band (filter) + if (nb>=MAX_EQ_BANDS) return(0); + int bp=npar%5;//band paramenter + switch(bp){ + case 0: return(filter[nb].Ptype); + break; + case 1: return(filter[nb].Pfreq); + break; + case 2: return(filter[nb].Pgain); + break; + case 3: return(filter[nb].Pq); + break; + case 4: return(filter[nb].Pstages); + break; + }; + + return(0);//in case of bogus parameter number +}; + + + + +REALTYPE EQ::getfreqresponse(REALTYPE freq){ + REALTYPE resp=1.0; + for (int i=0;i<MAX_EQ_BANDS;i++){ + if (filter[i].Ptype==0) continue; + resp*=filter[i].l->H(freq); + }; + return(rap2dB(resp*outvolume)); +}; + + diff --git a/src/Effects/EQ.h b/src/Effects/EQ.h @@ -0,0 +1,59 @@ +/* + ZynAddSubFX - a software synthesizer + + EQ.h - EQ Effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef EQ_H +#define EQ_H + +#include "../globals.h" +#include "../DSP/AnalogFilter.h" +#include "Effect.h" + +class EQ:public Effect{ + public: + EQ(int insertion,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~EQ(); + void out(REALTYPE *smpsl,REALTYPE *smpr); + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + void cleanup(); + REALTYPE getfreqresponse(REALTYPE freq); + private: + //Parametrii + unsigned char Pvolume;//Volumul or + + void setvolume(unsigned char Pvolume); + + struct { + //parameters + unsigned char Ptype,Pfreq,Pgain,Pq,Pstages; + //internal values + AnalogFilter *l,*r; + }filter[MAX_EQ_BANDS]; + + REALTYPE volume; +}; + + +#endif + + diff --git a/src/Effects/Echo.C b/src/Effects/Echo.C @@ -0,0 +1,263 @@ +/* + ZynAddSubFX - a software synthesizer + + Echo.C - Echo effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "Echo.h" + +Echo::Echo(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + + insertion=insertion_; + //default values + Ppreset=0; + Pvolume=50; + Ppanning=64; + Pdelay=60; + Plrdelay=100; + Plrcross=100; + Pfb=40; + Phidamp=60; + + ldelay=NULL; + rdelay=NULL; + lrdelay=0; + + setpreset(Ppreset); + cleanup(); +}; + +Echo::~Echo(){ + delete[] ldelay; + delete[] rdelay; +}; + +/* + * Cleanup the effect + */ +void Echo::cleanup(){ + int i; + for (i=0;i<dl;i++) ldelay[i]=0.0; + for (i=0;i<dr;i++) rdelay[i]=0.0; + oldl=0.0; + oldr=0.0; +}; + + +/* + * Initialize the delays + */ +void Echo::initdelays(){ + kl=0;kr=0; + dl=delay-lrdelay;if (dl<1) dl=1; + dr=delay+lrdelay;if (dr<1) dr=1; + + if (ldelay!=NULL) delete [] ldelay; + if (rdelay!=NULL) delete [] rdelay; + ldelay=new REALTYPE[dl]; + rdelay=new REALTYPE[dr]; + + cleanup(); +}; + +/* + * Effect output + */ +void Echo::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i; + REALTYPE l,r,ldl,rdl; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + ldl=ldelay[kl]; + rdl=rdelay[kr]; + l=ldl*(1.0-lrcross)+rdl*lrcross; + r=rdl*(1.0-lrcross)+ldl*lrcross; + ldl=l;rdl=r; + + efxoutl[i]=ldl*2.0; + efxoutr[i]=rdl*2.0; + ldl=smpsl[i]*panning-ldl*fb; + rdl=smpsr[i]*(1.0-panning)-rdl*fb; + + //LowPass Filter + ldelay[kl]=ldl=ldl*hidamp+oldl*(1.0-hidamp); + rdelay[kr]=rdl=rdl*hidamp+oldr*(1.0-hidamp); + oldl=ldl; + oldr=rdl; + + if (++kl>=dl) kl=0; + if (++kr>=dr) kr=0; + }; + + + //Insertion effect + if (insertion!=0) { + REALTYPE v1,v2; + if (volume<0.5) { + v1=1.0; + v2=volume*2.0; + } else { + v1=(1.0-volume)*2.0; + v2=1.0; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=smpsl[i]*v1+efxoutl[i]*v2; + smpsr[i]=smpsr[i]*v1+efxoutr[i]*v2; + }; + } else {//System effect + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=2.0*volume; + efxoutr[i]*=2.0*volume; + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + }; + +}; + + +/* + * Parameter control + */ +void Echo::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + + if (insertion==0) { + outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0; + volume=1.0; + } else { + volume=outvolume=Pvolume/127.0; + }; + if (Pvolume==0) cleanup(); + +}; + +void Echo::setpanning(unsigned char Ppanning){ + this->Ppanning=Ppanning; + panning=(Ppanning+0.5)/127.0; +}; + +void Echo::setdelay(unsigned char Pdelay){ + this->Pdelay=Pdelay; + delay=1+(int)(Pdelay/127.0*SAMPLE_RATE*1.5);//0 .. 1.5 sec + initdelays(); +}; + +void Echo::setlrdelay(unsigned char Plrdelay){ + REALTYPE tmp; + this->Plrdelay=Plrdelay; + tmp=(pow(2,fabs(Plrdelay-64.0)/64.0*9)-1.0)/1000.0*SAMPLE_RATE; + if (Plrdelay<64.0) tmp=-tmp; + lrdelay=(int) tmp; + initdelays(); +}; + +void Echo::setlrcross(unsigned char Plrcross){ + this->Plrcross=Plrcross; + lrcross=Plrcross/127.0*1.0; +}; + +void Echo::setfb(unsigned char Pfb){ + this->Pfb=Pfb; + fb=Pfb/128.0; +}; + +void Echo::sethidamp(unsigned char Phidamp){ + this->Phidamp=Phidamp; + hidamp=1.0-Phidamp/127.0; +}; + +void Echo::setpreset(unsigned char npreset){ + const int PRESET_SIZE=7; + const int NUM_PRESETS=9; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //Echo 1 + {67,64,35,64,30,59,0}, + //Echo 2 + {67,64,21,64,30,59,0}, + //Echo 3 + {67,75,60,64,30,59,10}, + //Simple Echo + {67,60,44,64,30,0,0}, + //Canyon + {67,60,102,50,30,82,48}, + //Panning Echo 1 + {67,64,44,17,0,82,24}, + //Panning Echo 2 + {81,60,46,118,100,68,18}, + //Panning Echo 3 + {81,60,26,100,127,67,36}, + //Feedback Echo + {62,64,28,64,100,90,55}}; + + + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + if (insertion!=0) changepar(0,presets[npreset][0]/2);//lower the volume if this is insertion effect + Ppreset=npreset; +}; + + +void Echo::changepar(int npar,unsigned char value){ + switch (npar){ + case 0: setvolume(value); + break; + case 1: setpanning(value); + break; + case 2: setdelay(value); + break; + case 3: setlrdelay(value); + break; + case 4: setlrcross(value); + break; + case 5: setfb(value); + break; + case 6: sethidamp(value); + break; + }; +}; + +unsigned char Echo::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + case 1: return(Ppanning); + break; + case 2: return(Pdelay); + break; + case 3: return(Plrdelay); + break; + case 4: return(Plrcross); + break; + case 5: return(Pfb); + break; + case 6: return(Phidamp); + break; + }; + return(0);//in case of bogus parameter number +}; + + + + diff --git a/src/Effects/Echo.h b/src/Effects/Echo.h @@ -0,0 +1,70 @@ +/* + ZynAddSubFX - a software synthesizer + + Echo.h - Echo Effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ECHO_H +#define ECHO_H + +#include "../globals.h" +#include "Effect.h" + +class Echo:public Effect{ + public: + Echo(int insertion,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~Echo(); + void out(REALTYPE *smpsl,REALTYPE *smpr); + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + void cleanup(); + + private: + //Parametrii + unsigned char Pvolume;//Volumul or E/R + unsigned char Ppanning;//Panning + unsigned char Pdelay; + unsigned char Plrdelay;// L/R delay difference + unsigned char Plrcross;// L/R Mixing + unsigned char Pfb;//Feed-back-ul + unsigned char Phidamp; + + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdelay(unsigned char Pdelay); + void setlrdelay(unsigned char Plrdelay); + void setlrcross(unsigned char Plrcross); + void setfb(unsigned char Pfb); + void sethidamp(unsigned char Phidamp); + + //Parametrii reali + REALTYPE volume,panning,lrcross,fb,hidamp; + int dl,dr,delay,lrdelay; + + void initdelays(); + REALTYPE *ldelay,*rdelay; + REALTYPE oldl,oldr;//pt. lpf + int kl,kr; +}; + + +#endif + + diff --git a/src/Effects/Effect.C b/src/Effects/Effect.C @@ -0,0 +1,24 @@ +/* + ZynAddSubFX - a software synthesizer + + Effect.C - this class is inherited by the all effects(Reverb, Echo, ..) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Effect.h" + diff --git a/src/Effects/Effect.h b/src/Effects/Effect.h @@ -0,0 +1,57 @@ +/* + ZynAddSubFX - a software synthesizer + + Effect.h - this class is inherited by the all effects(Reverb, Echo, ..) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef EFFECT_H +#define EFFECT_H + +#include <pthread.h> +#include "../Misc/Util.h" +#include "../globals.h" + + +class Effect{ + public: + + virtual ~Effect(){}; + virtual void setpreset(unsigned char npreset){}; + virtual void changepar(int npar,unsigned char value){}; + virtual unsigned char getpar(int npar){return(0);}; + virtual void out(REALTYPE *smpsl,REALTYPE *smpsr){}; + virtual void cleanup(){}; + virtual REALTYPE getfreqresponse(REALTYPE freq){return (0);};//this is only used for EQ (for user interface) + + unsigned char Ppreset; + REALTYPE *efxoutl; + REALTYPE *efxoutr; + + REALTYPE outvolume;//this is the volume of effect and is public because need it in system effect. The out volume of such effects are always 1.0, so this setting tells me how is the volume to the Master Output only. + + protected: + + int insertion;//1 for insertion effect +}; + +#endif + + + + diff --git a/src/Effects/EffectLFO.C b/src/Effects/EffectLFO.C @@ -0,0 +1,110 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectLFO.C - Stereo LFO used by some effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "EffectLFO.h" + + +EffectLFO::EffectLFO(){ + xl=0.0;xr=0.0; + Pfreq=40; + Prandomness=0; + PLFOtype=0; + Pstereo=96; + + updateparams(); + + ampl1=(1-lfornd)+lfornd*RND; + ampl2=(1-lfornd)+lfornd*RND; + ampr1=(1-lfornd)+lfornd*RND; + ampr2=(1-lfornd)+lfornd*RND; +}; + +EffectLFO::~EffectLFO(){ +}; + + +/* + * Update the changed parameters + */ +void EffectLFO::updateparams(){ + REALTYPE lfofreq=(pow(2,Pfreq/127.0*10.0)-1.0)*0.03; + incx=fabs(lfofreq)*(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; + if (incx>0.49999999) incx=0.499999999; //Limit the Frequency + + lfornd=Prandomness/127.0; + if (lfornd<0.0) lfornd=0.0; else if (lfornd>1.0) lfornd=1.0; + + if (PLFOtype>1) PLFOtype=1;//this has to be updated if more lfo's are added + lfotype=PLFOtype; + + xr=fmod(xl+(Pstereo-64.0)/127.0+1.0,1.0); +}; + + +/* + * Compute the shape of the LFO + */ +REALTYPE EffectLFO::getlfoshape(REALTYPE x){ + REALTYPE out; + switch (lfotype){ + case 1: //EffectLFO_TRIANGLE + if ((x>0.0)&&(x<0.25)) out=4.0*x; + else if ((x>0.25)&&(x<0.75)) out=2-4*x; + else out=4.0*x-4.0; + break; + //more to be added here; also ::updateparams() need to be updated (to allow more lfotypes) + default:out=cos(x*2*PI);//EffectLFO_SINE + }; + return(out); +}; + +/* + * LFO output + */ +void EffectLFO::effectlfoout(REALTYPE *outl,REALTYPE *outr){ + REALTYPE out; + + out=getlfoshape(xl); + if ((lfotype==0)||(lfotype==1)) out*=(ampl1+xl*(ampl2-ampl1)); + xl+=incx; + if (xl>1.0) { + xl-=1.0; + ampl1=ampl2; + ampl2=(1.0-lfornd)+lfornd*RND; + }; + *outl=(out+1.0)*0.5; + + out=getlfoshape(xr); + if ((lfotype==0)||(lfotype==1)) out*=(ampr1+xr*(ampr2-ampr1)); + xr+=incx; + if (xr>1.0) { + xr-=1.0; + ampr1=ampr2; + ampr2=(1.0-lfornd)+lfornd*RND; + }; + *outr=(out+1.0)*0.5; +}; + diff --git a/src/Effects/EffectLFO.h b/src/Effects/EffectLFO.h @@ -0,0 +1,50 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectLFO.h - Stereo LFO used by some effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef EFFECT_LFO_H +#define EFFECT_LFO_H + +#include "../globals.h" + +class EffectLFO{ + public: + EffectLFO(); + ~EffectLFO(); + void effectlfoout(REALTYPE *outl,REALTYPE *outr); + void updateparams(); + unsigned char Pfreq; + unsigned char Prandomness; + unsigned char PLFOtype; + unsigned char Pstereo;//"64"=0 + private: + REALTYPE getlfoshape(REALTYPE x); + + REALTYPE xl,xr; + REALTYPE incx; + REALTYPE ampl1,ampl2,ampr1,ampr2;//necesar pentru "randomness" + REALTYPE lfointensity; + REALTYPE lfornd; + char lfotype; +}; + + +#endif diff --git a/src/Effects/EffectMgr.C b/src/Effects/EffectMgr.C @@ -0,0 +1,240 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectMgr.C - Effect manager, an interface betwen the program and effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include "EffectMgr.h" + +EffectMgr::EffectMgr(int insertion_,pthread_mutex_t *mutex_){ + efx=NULL; + nefx=0; + insertion=insertion_; + mutex=mutex_; + efxoutl=new REALTYPE[SOUND_BUFFER_SIZE]; + efxoutr=new REALTYPE[SOUND_BUFFER_SIZE];; + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]=0.0; + efxoutr[i]=0.0; + }; +}; + +EffectMgr::~EffectMgr(){ + if (efx!=NULL) delete (efx); + delete (efxoutl); + delete (efxoutr); +}; + +/* + * Change the effect + */ +void EffectMgr::changeeffect(int nefx_){ + if (nefx==nefx_) return; + nefx=nefx_; + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]=0.0; + efxoutr[i]=0.0; + }; + + if (efx!=NULL) delete (efx); + switch (nefx){ + case 1:efx=new Reverb(insertion,efxoutl,efxoutr);break; + case 2:efx=new Echo(insertion,efxoutl,efxoutr);break; + case 3:efx=new Chorus(insertion,efxoutl,efxoutr);break; + case 4:efx=new Phaser(insertion,efxoutl,efxoutr);break; + case 5:efx=new Alienwah(insertion,efxoutl,efxoutr);break; + case 6:efx=new Distorsion(insertion,efxoutl,efxoutr);break; + case 7:efx=new EQ(insertion,efxoutl,efxoutr);break; + //put more effect here + default:efx=NULL;break;//no effect (thru) + }; +}; + +/* + * Obtain the effect number + */ +int EffectMgr::geteffect(){ + return (nefx); +}; + +/* + * Cleanup the current effect + */ +void EffectMgr::cleanup(){ + if (efx!=NULL) efx->cleanup(); +}; + + +/* + * Get the preset of the current effect + */ + +unsigned char EffectMgr::getpreset(){ + if (efx!=NULL) return(efx->Ppreset); + else return(0); +}; + +/* + * Change the preset of the current effect + */ +void EffectMgr::changepreset_nolock(unsigned char npreset){ + if (efx!=NULL) efx->setpreset(npreset); +}; + +/* + * Change the preset of the current effect(with thread locking) + */ +void EffectMgr::changepreset(unsigned char npreset){ + pthread_mutex_lock(mutex); + changepreset_nolock(npreset); + pthread_mutex_unlock(mutex); +}; + + +/* + * Change a parameter of the current effect + */ +void EffectMgr::seteffectpar_nolock(int npar,unsigned char value){ + if (efx==NULL) return; + efx->changepar(npar,value); + + //for (int i=0;i<12;i++) fprintf(stderr,"%d ",efx->getpar(i)); + //fprintf(stderr,"\n"); + +}; + +/* + * Change a parameter of the current effect (with thread locking) + */ +void EffectMgr::seteffectpar(int npar,unsigned char value){ + pthread_mutex_lock(mutex); + seteffectpar_nolock(npar,value); + pthread_mutex_unlock(mutex); +}; + +/* + * Get a parameter of the current effect + */ +unsigned char EffectMgr::geteffectpar(int npar){ + if (efx==NULL) return(0); + return(efx->getpar(npar)); +}; + + +/* + * Apply the effect + */ +void EffectMgr::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i; + if (efx==NULL){ + if (insertion==0) + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=0.0;smpsr[i]=0.0; + }; + return; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]+=denormalkillbuf[i]; + smpsr[i]+=denormalkillbuf[i]; + }; + efx->out(smpsl,smpsr); + +}; + +/* + * Get the effect volume for the system effect + */ +REALTYPE EffectMgr::sysefxgetvolume(){ + if (efx==NULL) return (1.0); + else return(efx->outvolume); +}; + + + +/* + * Save or load the parameters to/from the buffer + */ +void EffectMgr::saveloadbuf(Buffer *buf){ + unsigned char npar,p,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( EffectPparameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + + if (npar==0xff) break; + + switch (npar){ + case 0x80: p=geteffect(); + buf->rwbytepar(n,&p); + if (buf->getmode()==0) { + changeeffect(p); + for (n=0;n<128;n++){ + seteffectpar_nolock(n,0); + }; + }; + break; + case 0x81: if (buf->getmode()!=0) { + for (unsigned char np=0;np<0x7f;np++){ + p=geteffectpar(np); + if (p==0) continue;//do not save parameters if they are zero + buf->rwbyte(&npar); + buf->rwbyte(&np); + buf->rwbyte(&p); + }; + } else { + unsigned char np; + buf->rwbyte(&np); + buf->rwbyte(&p); + seteffectpar_nolock(np,p); + }; + break; + case 0x82: if (efx!=NULL) buf->rwbytepar(n,&(efx->Ppreset)); + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + + + +/* + * Get the EQ response + */ +REALTYPE EffectMgr::getEQfreqresponse(REALTYPE freq){ + if (nefx==7) return(efx->getfreqresponse(freq)); + else return(0.0); +}; + diff --git a/src/Effects/EffectMgr.h b/src/Effects/EffectMgr.h @@ -0,0 +1,75 @@ +/* + ZynAddSubFX - a software synthesizer + + EffectMgr.h - Effect manager, an interface betwen the program and effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef EFFECTMGR_H +#define EFFECTMGR_H + +#include <pthread.h> + +#include "Effect.h" +#include "Reverb.h" +#include "Echo.h" +#include "Chorus.h" +#include "Phaser.h" +#include "Alienwah.h" +#include "Distorsion.h" +#include "EQ.h" +#include "../Misc/Buffer.h" + + +class EffectMgr{ + public: + EffectMgr(int insertion_,pthread_mutex_t *mutex_); + ~EffectMgr(); + void saveloadbuf(Buffer *buf); + void out(REALTYPE *smpsl,REALTYPE *smpsr); + + //get the output(to speakers) volume of the systemeffect + REALTYPE sysefxgetvolume(); + + void cleanup();//cleanup the effec5 + + void changeeffect(int nefx_); + int geteffect(); + void changepreset(unsigned char npreset); + void changepreset_nolock(unsigned char npreset); + unsigned char getpreset(); + void seteffectpar(int npar,unsigned char value); + void seteffectpar_nolock(int npar,unsigned char value);//sets the effect par without thread lock + unsigned char geteffectpar(int npar); + int insertion;//1 if the effect is connected as insertion effect + REALTYPE *efxoutl,*efxoutr; + + //used by UI + REALTYPE getEQfreqresponse(REALTYPE freq); + + private: + int nefx; + Effect *efx; + pthread_mutex_t *mutex; + +}; + +#endif + + + diff --git a/src/Effects/Makefile b/src/Effects/Makefile @@ -0,0 +1,16 @@ +include ../Makefile.inc + +objects=Alienwah.o Chorus.o Echo.o Effect.o \ + EffectLFO.o EffectMgr.o Phaser.o Reverb.o \ + Distorsion.o EQ.o + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Effects/Phaser.C b/src/Effects/Phaser.C @@ -0,0 +1,283 @@ +/* + ZynAddSubFX - a software synthesizer + + Phaser.C - Phaser effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include "Phaser.h" +#include <stdio.h> +#define PHASER_LFO_SHAPE 2 + +Phaser::Phaser(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + + oldl=NULL; + oldr=NULL; + insertion=insertion_; + + Ppreset=0; + setpreset(Ppreset); + cleanup(); +}; + +Phaser::~Phaser(){ + if (oldl!=NULL) delete [] oldl; + if (oldr!=NULL) delete [] oldr; +}; + + +/* + * Effect output + */ +void Phaser::out(REALTYPE *smpsl,REALTYPE *smpsr){ + int i,j; + REALTYPE lfol,lfor,lgain,rgain,tmp; + + lfo.effectlfoout(&lfol,&lfor); + lgain=lfol; + rgain=lfor; + lgain=(exp(lgain*PHASER_LFO_SHAPE)-1)/(exp(PHASER_LFO_SHAPE)-1.0); + rgain=(exp(rgain*PHASER_LFO_SHAPE)-1)/(exp(PHASER_LFO_SHAPE)-1.0); + + + lgain=1.0-phase*(1.0-depth)-(1.0-phase)*lgain*depth; + rgain=1.0-phase*(1.0-depth)-(1.0-phase)*rgain*depth; + + if (lgain>1.0) lgain=1.0;else if (lgain<0.0) lgain=0.0; + if (rgain>1.0) rgain=1.0;else if (rgain<0.0) rgain=0.0; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE x=(REALTYPE) i /SOUND_BUFFER_SIZE; + REALTYPE x1=1.0-x; + REALTYPE gl=lgain*x+oldlgain*x1; + REALTYPE gr=rgain*x+oldrgain*x1; + REALTYPE inl=smpsl[i]*panning+fbl; + REALTYPE inr=smpsr[i]*(1.0-panning)+fbr; + + //Left channel + for (j=0;j<Pstages*2;j++){//Phasing routine + tmp=oldl[j]; + oldl[j]=gl*tmp+inl; + inl=tmp-gl*oldl[j]; + }; + //Right channel + for (j=0;j<Pstages*2;j++){//Phasing routine + tmp=oldr[j]; + oldr[j]=gr*tmp+inr; + inr=tmp-gr*oldr[j]; + }; + //Left/Right crossing + REALTYPE l=inl; + REALTYPE r=inr; + inl=l*(1.0-lrcross)+r*lrcross; + inr=r*(1.0-lrcross)+l*lrcross; + + fbl=inl*fb; + fbr=inr*fb; + efxoutl[i]=inl; + efxoutr[i]=inr; + + }; + + oldlgain=lgain; oldrgain=rgain; + + if (Poutsub!=0) + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*= -1.0; + efxoutr[i]*= -1.0; + }; + + //Insertion effect + if (insertion!=0) { + REALTYPE v1,v2; + if (volume<0.5) { + v1=1.0; + v2=volume*2.0; + } else { + v1=(1.0-volume)*2.0; + v2=1.0; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smpsl[i]=smpsl[i]*v1+efxoutl[i]*v2*2.0; + smpsr[i]=smpsr[i]*v1+efxoutr[i]*v2*2.0; + }; + } else {//System effect + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=2.0; + efxoutr[i]*=2.0; + smpsl[i]=efxoutl[i]; + smpsr[i]=efxoutr[i]; + }; + }; + + +}; + +/* + * Cleanup the effect + */ +void Phaser::cleanup(){ + fbl=0.0;fbr=0.0; + oldlgain=0.0; + oldrgain=0.0; + for (int i=0;i<Pstages*2;i++) { + oldl[i]=0.0; + oldr[i]=0.0; + }; +}; + +/* + * Parameter control + */ +void Phaser::setdepth(unsigned char Pdepth){ + this->Pdepth=Pdepth; + depth=(Pdepth/127.0); +}; + + +void Phaser::setfb(unsigned char Pfb){ + this->Pfb=Pfb; + fb=(Pfb-64.0)/64.1; +}; + +void Phaser::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + outvolume=Pvolume/127.0; + if (insertion==0) volume=1.0; + else volume=outvolume; +}; + +void Phaser::setpanning(unsigned char Ppanning){ + this->Ppanning=Ppanning; + panning=Ppanning/127.0; +}; + +void Phaser::setlrcross(unsigned char Plrcross){ + this->Plrcross=Plrcross; + lrcross=Plrcross/127.0; +}; + +void Phaser::setstages(unsigned char Pstages){ + if (oldl!=NULL) delete [] oldl; + if (oldr!=NULL) delete [] oldr; + if (Pstages>=MAX_PHASER_STAGES) Pstages=MAX_PHASER_STAGES-1; + this->Pstages=Pstages; + oldl=new REALTYPE[Pstages*2]; + oldr=new REALTYPE[Pstages*2]; + cleanup(); +}; + +void Phaser::setphase(unsigned char Pphase){ + this->Pphase=Pphase; + phase=(Pphase/127.0); +}; + + +void Phaser::setpreset(unsigned char npreset){ + const int PRESET_SIZE=12; + const int NUM_PRESETS=6; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //Phaser1 + {64,64,36,0,0,64,110,64,1,0,0,20}, + //Phaser2 + {64,64,35,0,0,88,40,64,3,0,0,20}, + //Phaser3 + {64,64,31,0,0,66,68,107,2,0,0,20}, + //Phaser4 + {39,64,22,0,0,66,67,10,5,0,1,20}, + //Phaser5 + {64,64,20,0,1,110,67,78,10,0,0,20}, + //Phaser6 + {64,64,53,100,0,58,37,78,3,0,0,20}}; + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + Ppreset=npreset; +}; + + +void Phaser::changepar(int npar,unsigned char value){ + switch(npar){ + case 0: setvolume(value); + break; + case 1: setpanning(value); + break; + case 2: lfo.Pfreq=value; + lfo.updateparams(); + break; + case 3: lfo.Prandomness=value; + lfo.updateparams(); + break; + case 4: lfo.PLFOtype=value; + lfo.updateparams(); + break; + case 5: lfo.Pstereo=value; + lfo.updateparams(); + break; + case 6: setdepth(value); + break; + case 7: setfb(value); + break; + case 8: setstages(value); + break; + case 9: setlrcross(value); + break; + case 10:if (value>1) value=1; + Poutsub=value; + break; + case 11:setphase(value); + break; + }; +}; + +unsigned char Phaser::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + case 1: return(Ppanning); + break; + case 2: return(lfo.Pfreq); + break; + case 3: return(lfo.Prandomness); + break; + case 4: return(lfo.PLFOtype); + break; + case 5: return(lfo.Pstereo); + break; + case 6: return(Pdepth); + break; + case 7: return(Pfb); + break; + case 8: return(Pstages); + break; + case 9: return(Plrcross); + break; + case 10:return(Poutsub); + break; + case 11:return(Pphase); + break; + default:return (0); + }; + +}; + + + + diff --git a/src/Effects/Phaser.h b/src/Effects/Phaser.h @@ -0,0 +1,69 @@ +/* + ZynAddSubFX - a software synthesizer + + Phaser.h - Phaser effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef PHASER_H +#define PHASER_H +#include "../globals.h" +#include "Effect.h" +#include "EffectLFO.h" + +#define MAX_PHASER_STAGES 12 +class Phaser:public Effect { + public: + Phaser(int insetion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~Phaser(); + void out(REALTYPE *smpsl,REALTYPE *smpsr); + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + void cleanup(); + + private: + //Parametrii Phaser + EffectLFO lfo;//lfo-ul Phaser + unsigned char Pvolume; + unsigned char Ppanning; + unsigned char Pdepth;//the depth of the Phaser + unsigned char Pfb;//feedback + unsigned char Plrcross;//feedback + unsigned char Pstages; + unsigned char Poutsub;//if I wish to substract the output instead of the adding it + unsigned char Pphase; + + //Control Parametrii + void setvolume(unsigned char Pvolume); + void setpanning(unsigned char Ppanning); + void setdepth(unsigned char Pdepth); + void setfb(unsigned char Pfb); + void setlrcross(unsigned char Plrcross); + void setstages(unsigned char Pstages); + void setphase(unsigned char Pphase); + + //Valorile interne + int insertion; + REALTYPE volume,panning,fb,depth,lrcross,fbl,fbr,phase; + REALTYPE *oldl,*oldr; + REALTYPE oldlgain,oldrgain; +}; + +#endif + diff --git a/src/Effects/Reverb.C b/src/Effects/Reverb.C @@ -0,0 +1,458 @@ +/* + ZynAddSubFX - a software synthesizer + + Reverb.C - Reverberation effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> + +#include <math.h> +#include <stdlib.h> +#include "Reverb.h" + +/*TODO: EarlyReflections,Prdelay,Perbalance */ + +Reverb::Reverb(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ + efxoutl=efxoutl_; + efxoutr=efxoutr_; + inputbuf=new REALTYPE[SOUND_BUFFER_SIZE]; + + insertion=insertion_; + //defaults + Ppreset=0; + Pvolume=48; + Ppan=64; + Ptime=64; + Pidelay=40; + Pidelayfb=0; + Prdelay=0; + Plpf=127; + Phpf=0; + Perbalance=64; + Plohidamp=80; + Ptype=1; + Proomsize=64;roomsize=1.0;rs=1.0; + + for (int i=0;i<REV_COMBS*2;i++) { + comblen[i]=800+(int)(RND*1400); + combk[i]=0; + lpcomb[i]=0; + combfb[i]=-0.97; + comb[i]=NULL; + }; + + for (int i=0;i<REV_APS*2;i++) { + aplen[i]=500+(int)(RND*500); + apk[i]=0; + ap[i]=NULL; + }; + + lpf=NULL;hpf=NULL;//no filter + idelay=NULL; + + setpreset(Ppreset); + cleanup();//do not call this before the comb initialisation +}; + + +Reverb::~Reverb(){ + int i; + if (idelay!=NULL) delete idelay; + if (hpf!=NULL) delete hpf; + if (lpf!=NULL) delete lpf; + + for (i=0;i<REV_APS*2;i++) delete ap[i]; + for (i=0;i<REV_COMBS*2;i++) delete comb[i]; + + delete [] inputbuf; +}; + +/* + * Cleanup the effect + */ +void Reverb::cleanup(){ + int i,j; + for (i=0;i<REV_COMBS*2;i++){ + lpcomb[i]=0.0; + for (j=0;j<comblen[i];j++) comb[i][j]=0.0; + }; + + for (i=0;i<REV_APS*2;i++) + for (j=0;j<aplen[i];j++) ap[i][j]=0.0; + + if (idelay!=NULL) for (i=0;i<idelaylen;i++) idelay[i]=0.0; + + if (hpf!=NULL) hpf->cleanup(); + if (lpf!=NULL) lpf->cleanup(); + +}; + +/* + * Process one channel; 0=left,1=right + */ +void Reverb::processmono(int ch,REALTYPE *output){ + int i,j; + REALTYPE out,fbout,tmp; + //TODO: implement the high part from lohidamp + + for (j=REV_COMBS*ch;j<REV_COMBS*(ch+1);j++){ + + int ck=combk[j]; + int comblength=comblen[j]; + REALTYPE lpcombj=lpcomb[j]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + fbout=comb[j][ck]*combfb[j]; + fbout=fbout*(1.0-lohifb)+lpcombj*lohifb; + lpcombj=fbout; + + comb[j][ck]=inputbuf[i]+fbout; + output[i]+=fbout; + + if ((++ck)>=comblength) ck=0; + }; + + combk[j]=ck; + lpcomb[j]=lpcombj; + }; + + for (j=REV_APS*ch;j<REV_APS*(1+ch);j++){ + int ak=apk[j]; + int aplength=aplen[j]; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmp=ap[j][ak]; + ap[j][ak]=0.7*tmp+output[i]; + output[i]=tmp-0.7*ap[j][ak]; + if ((++ak)>=aplength) ak=0; + }; + apk[j]=ak; + }; +}; + +/* + * Effect output + */ +void Reverb::out(REALTYPE *smps_l, REALTYPE *smps_r){ + int i; + if ((Pvolume==0)&&(insertion!=0)) return; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + inputbuf[i]=(smps_l[i]+smps_r[i])/2.0; + //Initial delay r + if (idelay!=NULL){ + REALTYPE tmp=inputbuf[i]+idelay[idelayk]*idelayfb; + inputbuf[i]=idelay[idelayk]; + idelay[idelayk]=tmp; + idelayk++;if (idelayk>=idelaylen) idelayk=0; + }; + }; + + if (lpf!=NULL) lpf->filterout(inputbuf); + if (hpf!=NULL) hpf->filterout(inputbuf); + + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]=0.0; + efxoutr[i]=0.0; + }; + + processmono(0,efxoutl);//left + processmono(1,efxoutr);//right + + //Insertion effect + if (insertion!=0) { + REALTYPE v1,v2; + if (volume<0.5) { + v1=1.0; + v2=volume*2.0; + } else { + v1=(1.0-volume)*2.0; + v2=1.0; + }; + v2*=rs/REV_COMBS*2.0; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + smps_l[i]=smps_l[i]*v1+efxoutl[i]*v2*pan; + smps_r[i]=smps_r[i]*v1+efxoutr[i]*v2*(1.0-pan); + }; + } else {//System effect + REALTYPE vol=rs*2.0/REV_COMBS; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + efxoutl[i]*=vol*pan; + efxoutr[i]*=vol*(1.0-pan); + smps_l[i]=efxoutl[i]; + smps_r[i]=efxoutr[i]; + }; + }; + +}; + + +/* + * Parameter control + */ +void Reverb::setvolume(unsigned char Pvolume){ + this->Pvolume=Pvolume; + if (insertion==0) { + outvolume=pow(0.01,(1.0-Pvolume/127.0))*4.0; + volume=1.0; + } else { + volume=outvolume=Pvolume/127.0; + if (Pvolume==0) cleanup(); + }; +}; + +void Reverb::setpan(unsigned char Ppan){ + this->Ppan=Ppan; + pan=(REALTYPE)Ppan/127.0; +}; + +void Reverb::settime(unsigned char Ptime){ + int i; + REALTYPE t; + this->Ptime=Ptime; + t=pow(60.0,(REALTYPE)Ptime/127.0)-0.97; + + for (i=0;i<REV_COMBS*2;i++){ + combfb[i]=-exp((REALTYPE)comblen[i]/(REALTYPE)SAMPLE_RATE*log(0.001)/t); + //the feedback is negative because it removes the DC + }; +}; + +void Reverb::setlohidamp(unsigned char Plohidamp){ + REALTYPE x; + + if (Plohidamp<64) Plohidamp=64;//remove this when the high part from lohidamp will be added + + this->Plohidamp=Plohidamp; + if (Plohidamp==64) { + lohidamptype=0; + lohifb=0.0; + } else { + if (Plohidamp<64) lohidamptype=1; + if (Plohidamp>64) lohidamptype=2; + x=fabs((REALTYPE)(Plohidamp-64)/64.1); + lohifb=x*x; + }; +}; + +void Reverb::setidelay(unsigned char Pidelay){ + REALTYPE delay; + this->Pidelay=Pidelay; + delay=pow(50*Pidelay/127.0,2)-1.0; + + if (idelay!=NULL) delete (idelay); + idelay=NULL; + + idelaylen=(int) (SAMPLE_RATE*delay/1000); + if (idelaylen>1) { + idelayk=0; + idelay=new REALTYPE[idelaylen]; + for (int i=0;i<idelaylen;i++) idelay[i]=0.0; + }; +}; + +void Reverb::setidelayfb(unsigned char Pidelayfb){ + this->Pidelayfb=Pidelayfb; + idelayfb=Pidelayfb/128.0; +}; + +void Reverb::sethpf(unsigned char Phpf){ + this->Phpf=Phpf; + if (Phpf==0) {//No HighPass + if (hpf!=NULL) delete(hpf); + hpf=NULL; + } + else{ + REALTYPE fr=exp(pow(Phpf/127.0,0.5)*log(10000.0))+20.0; + if (hpf==NULL) hpf=new AnalogFilter(3,fr,1,0); + else hpf->setfreq(fr); + }; +}; + +void Reverb::setlpf(unsigned char Plpf){ + this->Plpf=Plpf; + if (Plpf==127) {//No LowPass + if (lpf!=NULL) delete(lpf); + lpf=NULL; + } + else{ + REALTYPE fr=exp(pow(Plpf/127.0,0.5)*log(25000.0))+40; + if (lpf==NULL) lpf=new AnalogFilter(2,fr,1,0); + else lpf->setfreq(fr); + }; +}; + +void Reverb::settype(unsigned char Ptype){ + const int NUM_TYPES=2; + int combtunings[NUM_TYPES][REV_COMBS]={ + //this is unused (for random) + {0,0,0,0,0,0,0,0}, + //Freeverb by Jezar at Dreampoint + {1116,1188,1277,1356,1422,1491,1557,1617} + }; + int aptunings[NUM_TYPES][REV_APS]={ + //this is unused (for random) + {0,0,0,0}, + //Freeverb by Jezar at Dreampoint + {225,341,441,556} + }; + + if (Ptype>=NUM_TYPES) Ptype=NUM_TYPES-1; + this->Ptype=Ptype; + + REALTYPE tmp; + for (int i=0;i<REV_COMBS*2;i++) { + if (Ptype==0) tmp=800.0+(int)(RND*1400.0); + else tmp=combtunings[Ptype][i%REV_COMBS]; + tmp*=roomsize; + if (i>REV_COMBS) tmp+=23.0; + tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate + if (tmp<10) tmp=10; + + comblen[i]=(int) tmp; + combk[i]=0; + lpcomb[i]=0; + if (comb[i]!=NULL) delete comb[i]; + comb[i]=new REALTYPE[comblen[i]]; + }; + + for (int i=0;i<REV_APS*2;i++) { + if (Ptype==0) tmp=500+(int)(RND*500); + else tmp=aptunings[Ptype][i%REV_APS]; + tmp*=roomsize; + if (i>REV_APS) tmp+=23.0; + tmp*=SAMPLE_RATE/44100.0;//adjust the combs according to the samplerate + if (tmp<10) tmp=10; + aplen[i]=(int) tmp; + apk[i]=0; + if (ap[i]!=NULL) delete ap[i]; + ap[i]=new REALTYPE[aplen[i]]; + }; + settime(Ptime); + cleanup(); +}; + +void Reverb::setroomsize(unsigned char Proomsize){ + if (Proomsize==0) Proomsize=64;//this is because the older versions consider roomsize=0 + this->Proomsize=Proomsize; + roomsize=(Proomsize-64.0)/64.0; + if (roomsize>0.0) roomsize*=2.0; + roomsize=pow(10.0,roomsize); + rs=sqrt(roomsize); + settype(Ptype); +}; + +void Reverb::setpreset(unsigned char npreset){ + const int PRESET_SIZE=12; + const int NUM_PRESETS=13; + unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ + //Cathedral1 + {80,64,63,24,0,0,0,85,5,83,1,64}, + //Cathedral2 + {80,64,69,35,0,0,0,127,0,71,0,64}, + //Cathedral3 + {80,64,69,24,0,0,0,127,75,78,1,85}, + //Hall1 + {90,64,51,10,0,0,0,127,21,78,1,64}, + //Hall2 + {90,64,53,20,0,0,0,127,75,71,1,64}, + //Room1 + {100,64,33,0,0,0,0,127,0,106,0,30}, + //Room2 + {100,64,21,26,0,0,0,62,0,77,1,45}, + //Basement + {110,64,14,0,0,0,0,127,5,71,0,25}, + //Tunnel + {85,80,84,20,42,0,0,51,0,78,1,105}, + //Echoed1 + {95,64,26,60,71,0,0,114,0,64,1,64}, + //Echoed2 + {90,64,40,88,71,0,0,114,0,88,1,64}, + //VeryLong1 + {90,64,93,15,0,0,0,114,0,77,0,95}, + //VeryLong2 + {90,64,111,30,0,0,0,114,90,74,1,80}}; + + if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; + for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); + if (insertion!=0) changepar(0,presets[npreset][0]/2);//lower the volume if reverb is insertion effect + Ppreset=npreset; +}; + + +void Reverb::changepar(int npar,unsigned char value){ + switch (npar){ + case 0: setvolume(value); + break; + case 1: setpan(value); + break; + case 2: settime(value); + break; + case 3: setidelay(value); + break; + case 4: setidelayfb(value); + break; +// case 5: setrdelay(value); +// break; +// case 6: seterbalance(value); +// break; + case 7: setlpf(value); + break; + case 8: sethpf(value); + break; + case 9: setlohidamp(value); + break; + case 10:settype(value); + break; + case 11:setroomsize(value); + break; + }; +}; + +unsigned char Reverb::getpar(int npar){ + switch (npar){ + case 0: return(Pvolume); + break; + case 1: return(Ppan); + break; + case 2: return(Ptime); + break; + case 3: return(Pidelay); + break; + case 4: return(Pidelayfb); + break; +// case 5: return(Prdelay); +// break; +// case 6: return(Perbalance); +// break; + case 7: return(Plpf); + break; + case 8: return(Phpf); + break; + case 9: return(Plohidamp); + break; + case 10:return(Ptype); + break; + case 11:return(Proomsize); + break; + }; + return(0);//in case of bogus "parameter" +}; + + + diff --git a/src/Effects/Reverb.h b/src/Effects/Reverb.h @@ -0,0 +1,127 @@ +/* + ZynAddSubFX - a software synthesizer + + Reverb.h - Reverberation effect + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef REVERB_H +#define REVERB_H + + +#include "../globals.h" +#include "../DSP/AnalogFilter.h" +#include "Effect.h" + +#define REV_COMBS 8 +#define REV_APS 4 + +class Reverb:public Effect { + public: + Reverb(int insertion,REALTYPE *efxoutl_,REALTYPE *efxoutr_); + ~Reverb(); + void out(REALTYPE *smps_l,REALTYPE *smps_r); + void cleanup(); + + void setpreset(unsigned char npreset); + void changepar(int npar,unsigned char value); + unsigned char getpar(int npar); + + private: + //Parametrii + //Amount of the reverb, + unsigned char Pvolume; + + //LefT/Right Panning + unsigned char Ppan; + + //duration of reverb + unsigned char Ptime; + + //Initial delay + unsigned char Pidelay; + + //Initial delay feedback + unsigned char Pidelayfb; + + //delay between ER/Reverbs + unsigned char Prdelay; + + //EarlyReflections/Reverb Balance + unsigned char Perbalance; + + //HighPassFilter + unsigned char Plpf; + + //LowPassFilter + unsigned char Phpf; + + //Low/HighFrequency Damping + unsigned char Plohidamp;// 0..63 lpf,64=off,65..127=hpf(TODO) + + //Reverb type + unsigned char Ptype; + + //Room Size + unsigned char Proomsize; + + //parameter control + void setvolume(unsigned char Pvolume); + void setpan(unsigned char Ppan); + void settime(unsigned char Ptime); + void setlohidamp(unsigned char Plohidamp); + void setidelay(unsigned char Pidelay); + void setidelayfb(unsigned char Pidelayfb); + void sethpf(unsigned char Phpf); + void setlpf(unsigned char Plpf); + void settype(unsigned char Ptype); + void setroomsize(unsigned char Proomsize); + + REALTYPE volume,pan,erbalance; + //Parametrii 2 + int lohidamptype;//0=disable,1=highdamp(lowpass),2=lowdamp(highpass) + int idelaylen,rdelaylen; + int idelayk; + REALTYPE lohifb,idelayfb,roomsize,rs;//rs is used to "normalise" the volume according to the roomsize + int comblen[REV_COMBS*2]; + int aplen[REV_APS*2]; + + //Valorile interne + + REALTYPE *comb[REV_COMBS*2]; + + int combk[REV_COMBS*2]; + REALTYPE combfb[REV_COMBS*2];//feedback-ul fiecarui filtru "comb" + REALTYPE lpcomb[REV_COMBS*2];//pentru Filtrul LowPass + + REALTYPE *ap[REV_APS*2]; + + int apk[REV_APS*2]; + + REALTYPE *idelay; + AnalogFilter *lpf,*hpf;//filters + REALTYPE *inputbuf; + + void processmono(int ch,REALTYPE *output); +}; + + + + +#endif + diff --git a/src/Input/ALSAMidiIn.C b/src/Input/ALSAMidiIn.C @@ -0,0 +1,94 @@ +/* + ZynAddSubFX - a software synthesizer + + ALSAMidiIn.C - Midi input for ALSA (this creates an ALSA virtual port) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "ALSAMidiIn.h" +#include <stdlib.h> +#include <stdio.h> + + +ALSAMidiIn::ALSAMidiIn(){ + int alsaport; + inputok=0; + char portname[50]; + sprintf(portname,"ZynAddSubFX"); + + if (snd_seq_open(&midi_handle,"default",SND_SEQ_OPEN_INPUT,0)!=0) return; + + snd_seq_set_client_name(midi_handle,"ZynAddSubFX");//thanks to Frank Neumann + + alsaport = snd_seq_create_simple_port(midi_handle,portname + ,SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE + ,SND_SEQ_PORT_TYPE_SYNTH); + if (alsaport<0) return; + + inputok=1; +}; + +ALSAMidiIn::~ALSAMidiIn(){ + snd_seq_close(midi_handle); +}; + + +/* + * Get the midi command,channel and parameters + */ +void ALSAMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams){ + snd_seq_event_t *midievent; + cmdtype=MidiNull; + + if (inputok==0){ + return; + }; + + snd_seq_event_input(midi_handle,&midievent); + + if (midievent==NULL) return; + switch (midievent->type){ + case SND_SEQ_EVENT_NOTEON: + cmdtype=MidiNoteON; + cmdchan=midievent->data.note.channel; + cmdparams[0]=midievent->data.note.note; + cmdparams[1]=midievent->data.note.velocity; + break; + case SND_SEQ_EVENT_NOTEOFF: + cmdtype=MidiNoteOFF; + cmdchan=midievent->data.note.channel; + cmdparams[0]=midievent->data.note.note; + break; + case SND_SEQ_EVENT_PITCHBEND: + cmdtype=MidiController; + cmdchan=midievent->data.control.channel; + cmdparams[0]=C_pitchwheel;//Pitch Bend + cmdparams[1]=midievent->data.control.value; + break; + case SND_SEQ_EVENT_CONTROLLER: + cmdtype=MidiController; + cmdchan=midievent->data.control.channel; + cmdparams[0]=getcontroller(midievent->data.control.param); + cmdparams[1]=midievent->data.control.value; + //fprintf(stderr,"t=%d val=%d\n",midievent->data.control.param,midievent->data.control.value); + break; + + }; +}; + + diff --git a/src/Input/ALSAMidiIn.h b/src/Input/ALSAMidiIn.h @@ -0,0 +1,42 @@ +/* + ZynAddSubFX - a software synthesizer + + ALSAMidiIn.h - Midi input for ALSA (this creates an ALSA virtual port) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ALSA_MIDI_IN_H +#define ALSA_MIDI_IN_H + +#include <alsa/asoundlib.h> +#include "MidiIn.h" + + +class ALSAMidiIn:public MidiIn{ + public: + ALSAMidiIn(); + ~ALSAMidiIn(); + void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams); + + private: + snd_seq_t *midi_handle; +}; + + +#endif + diff --git a/src/Input/Makefile b/src/Input/Makefile @@ -0,0 +1,26 @@ +include ../Makefile.inc + +objects=NULLMidiIn.o MidiIn.o + +ifeq ($(MIDIIN),ALSA) +objects+=ALSAMidiIn.o +endif + +ifeq ($(MIDIIN),OSS) +objects+=OSSMidiIn.o +endif + +ifeq ($(MIDIIN),WIN) +objects+=WINMidiIn.o +endif + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Input/MidiIn.C b/src/Input/MidiIn.C @@ -0,0 +1,73 @@ +/* + ZynAddSubFX - a software synthesizer + + MidiIn.C - This class is inherited by all the Midi input classes + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "../globals.h" +#include "MidiIn.h" + +int MidiIn::getcontroller(unsigned char b){ + int ctl=C_NULL; + switch (b){ + case 1:ctl=C_modwheel;//Modulation Wheel + break; + case 7:ctl=C_volume;//Volume + break; + case 10:ctl=C_panning;//Panning + break; + case 11:ctl=C_expression;//Expression + break; + case 64:ctl=C_sustain;//Sustain pedal + break; + case 65:ctl=C_portamento;//Portamento + break; + case 71:ctl=C_filterq;//Filter Q (Sound Timbre) + break; + case 74:ctl=C_filtercutoff;//Filter Cutoff (Brightness) + break; + case 75:ctl=C_bandwidth;//BandWidth + break; + case 76:ctl=C_fmamp;//FM amplitude + break; + case 77:ctl=C_resonance_center;//Resonance Center Frequency + break; + case 78:ctl=C_resonance_bandwidth;//Resonance Bandwith + break; + case 120:ctl=C_allsoundsoff;//All Sounds OFF + break; + case 121:ctl=C_resetallcontrollers;//Reset All Controllers + break; + case 123:ctl=C_allnotesoff;//All Notes OFF + break; + //RPN and NRPN + case 0x06:ctl=C_dataentryhi;//Data Entry (Coarse) + break; + case 0x26:ctl=C_dataentrylo;//Data Entry (Fine) + break; + case 99:ctl=C_nrpnhi;//NRPN (Coarse) + break; + case 98:ctl=C_nrpnlo;//NRPN (Fine) + break; + default:ctl=C_NULL;//unknown controller + //fprintf(stderr,"Controller=%d , par=%d\n",midievent->data.control.param,cmdparams[1]); + break; + }; + return(ctl); +}; diff --git a/src/Input/MidiIn.h b/src/Input/MidiIn.h @@ -0,0 +1,42 @@ +/* + ZynAddSubFX - a software synthesizer + + MidiIn.h - This class is inherited by all the Midi input classes + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef MIDI_IN_H +#define MIDI_IN_H + +#include "../globals.h" + +enum MidiCmdType{MidiNull,MidiNoteOFF,MidiNoteON,MidiController}; +#define MP_MAX_BYTES 4000 //in case of loooong SYS_EXes + +class MidiIn{ + public: + virtual void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams){}; + virtual ~MidiIn(){}; + int getcontroller(unsigned char b); + protected: + int inputok;//1 if I can read midi bytes from input ports +}; + + +#endif + diff --git a/src/Input/NULLMidiIn.C b/src/Input/NULLMidiIn.C @@ -0,0 +1,43 @@ +/* + ZynAddSubFX - a software synthesizer + + NULLMidiIn.C - a dummy Midi port + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "NULLMidiIn.h" +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +NULLMidiIn::NULLMidiIn(){ +}; + +NULLMidiIn::~NULLMidiIn(){ +}; + + +/* + * Get the midi command,channel and parameters + * It returns MidiNull because it is a dummy driver + */ +void NULLMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,unsigned char *cmdparams){ + cmdtype=MidiNull; +}; + + diff --git a/src/Input/NULLMidiIn.h b/src/Input/NULLMidiIn.h @@ -0,0 +1,40 @@ +/* + ZynAddSubFX - a software synthesizer + + NULLMidiIn.h - a dummy Midi port + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef NULL_MIDI_IN_H +#define NULL_MIDI_IN_H + +#include "MidiIn.h" + + +class NULLMidiIn:public MidiIn{ + public: + NULLMidiIn(); + ~NULLMidiIn(); + void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,unsigned char *cmdparams); + + private: +}; + + +#endif + diff --git a/src/Input/OSSMidiIn.C b/src/Input/OSSMidiIn.C @@ -0,0 +1,115 @@ +/* + ZynAddSubFX - a software synthesizer + + OSSMidiIn.C - Midi input for Open Sound System + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/soundcard.h> + +#include "OSSMidiIn.h" +#include "../Misc/Util.h" + +OSSMidiIn::OSSMidiIn(){ + inputok=0; + midi_handle=open(config.cfg.LinuxOSSSeqInDev,O_RDONLY,0); + if (midi_handle!=-1) inputok=1; + + lastmidicmd=0; + cmdtype=0; + cmdchan=0; + +}; + +OSSMidiIn::~OSSMidiIn(){ + close(midi_handle); +}; + +unsigned char OSSMidiIn::readbyte(){ + unsigned char tmp[4]; + read(midi_handle,&tmp[0],1); + while (tmp[0]!=SEQ_MIDIPUTC){ + read(midi_handle,&tmp[0],4); + }; + return(tmp[1]); +}; + +unsigned char OSSMidiIn::getmidibyte(){ + unsigned char b; + do { + b=readbyte(); + } while (b==0xfe);//drops the Active Sense Messages + return(b); +}; + +/* + * Get the midi command,channel and parameters + */ +void OSSMidiIn::getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams){ + unsigned char tmp,i; + if (inputok==0) { + cmdtype=MidiNull; + return; + }; + i=0; + if (lastmidicmd==0){//asteapta prima data pana cand vine prima comanda midi + while (tmp<0x80) tmp=getmidibyte(); + lastmidicmd=tmp; + }; + + tmp=getmidibyte(); + + if (tmp>=0x80) { + lastmidicmd=tmp; + tmp=getmidibyte(); + }; + + if ((lastmidicmd>=0x80)&&(lastmidicmd<=0x8f)){//Note OFF + cmdtype=MidiNoteOFF; + cmdchan=lastmidicmd%16; + cmdparams[0]=tmp;//note number + }; + + if ((lastmidicmd>=0x90)&&(lastmidicmd<=0x9f)){//Note ON + cmdtype=MidiNoteON; + cmdchan=lastmidicmd%16; + cmdparams[0]=tmp;//note number + cmdparams[1]=getmidibyte();//velocity + if (cmdparams[1]==0) cmdtype=MidiNoteOFF;//if velocity==0 then is note off + }; + if ((lastmidicmd>=0xB0)&&(lastmidicmd<=0xBF)){//Controllers + cmdtype=MidiController; + cmdchan=lastmidicmd%16; + cmdparams[0]=getcontroller(tmp); + cmdparams[1]=getmidibyte(); + }; + if ((lastmidicmd>=0xE0)&&(lastmidicmd<=0xEF)){//Pitch Wheel + cmdtype=MidiController; + cmdchan=lastmidicmd%16; + cmdparams[0]=C_pitchwheel; + cmdparams[1]=tmp+getmidibyte()*(int) 128; + }; +}; + + diff --git a/src/Input/OSSMidiIn.h b/src/Input/OSSMidiIn.h @@ -0,0 +1,48 @@ +/* + ZynAddSubFX - a software synthesizer + + OSSMidiIn.h - Midi input for Open Sound System + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef OSS_MIDI_IN_H +#define OSS_MIDI_IN_H + +#include "MidiIn.h" + +class OSSMidiIn:public MidiIn{ + public: + OSSMidiIn(); + ~OSSMidiIn(); + unsigned char getmidibyte(); + unsigned char readbyte(); + + //Midi parser + void getmidicmd(MidiCmdType &cmdtype,unsigned char &cmdchan,int *cmdparams); + unsigned char cmdtype;//the Message Type (noteon,noteof,sysex..) + unsigned char cmdchan;//the channel number + + private: + int midi_handle; + unsigned char lastmidicmd;//last byte (>=80) received from the Midi + +}; + + +#endif + diff --git a/src/Input/WINMidiIn.C b/src/Input/WINMidiIn.C @@ -0,0 +1,84 @@ +/* + ZynAddSubFX - a software synthesizer + + WINMidiIn.C - Midi input for Windows + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <windows.h> +#include <mmsystem.h> +#include <pthread.h> + +#include "WINMidiIn.h" +#include "MidiIn.h" +#include "../Misc/Util.h" + +Master *winmaster; +HMIDIIN winmidiinhandle; +MidiIn midictl;//used to convert the controllers to ZynAddSubFX controllers + +void CALLBACK WinMidiInProc(HMIDIIN hMidiIn,UINT wMsg,DWORD dwInstance, + DWORD dwParam1,DWORD dwParam2){ + int midicommand=MidiNull; + if (wMsg==MIM_DATA){ + int cmd,par1,par2; + cmd=dwParam1&0xff; + if (cmd==0xfe) return; + par1=(dwParam1>>8)&0xff; + par2=dwParam1>>16; + //printf("%x %x %x\n",cmd,par1,par2);fflush(stdout); + int cmdchan=cmd&0x0f; + int cmdtype=(cmd>>4)&0x0f; + + int tmp=0; + pthread_mutex_lock(&winmaster->mutex); + switch(cmdtype){ + case(0x8)://noteon + winmaster->NoteOff(cmdchan,par1); + break; + case(0x9)://noteoff + winmaster->NoteOn(cmdchan,par1,par2&0xff); + break; + case(0xb)://controller + winmaster->SetController(cmdchan,midictl.getcontroller(par1),par2&0xff); + break; + case(0xe)://pitch wheel + tmp=par1+par2*(long int) 128; + printf("%d\n",tmp); + winmaster->SetController(cmdchan,C_pitchwheel,tmp); + break; + default:break; + }; + pthread_mutex_unlock(&winmaster->mutex); + + }; +}; + +void InitWinMidi(Master *master_){ + winmaster=master_; + + long int result=midiInOpen(&winmidiinhandle,config.cfg.WindowsMidiInId,(DWORD)WinMidiInProc,0,CALLBACK_FUNCTION); + result=midiInStart(winmidiinhandle); +}; + +void StopWinMidi(){ + midiInStop(winmidiinhandle); + midiInClose(winmidiinhandle); +}; diff --git a/src/Input/WINMidiIn.h b/src/Input/WINMidiIn.h @@ -0,0 +1,34 @@ +/* + ZynAddSubFX - a software synthesizer + + WINMidiIn.h - Midi input for Windows + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef WIN_MIDI_IN_H +#define WIN_MIDI_IN_H + + +#include "../Misc/Master.h" + +void InitWinMidi(Master *master_); +void StopWinMidi(); + + +#endif + diff --git a/src/Makefile b/src/Makefile @@ -0,0 +1,81 @@ +include Makefile.inc + +ifneq ($(MAKECMDGOALS),debug) + CXXFLAGS= -O6 +else + CXXFLAGS= -O0 -ggdb +endif + +CXXFLAGS += -DOS_$(OS_PORT) -D$(MIDIIN)MIDIIN -D$(AUDIOOUT)AUDIOOUT -DFFTW_VERSION_$(FFTW_VERSION) -DASM_F2I_$(ASM_F2I) `fltk-config --cflags` + +export CXXFLAGS +LIBS= -lm `fltk-config --ldflags` + +ifeq ($(FFT_VERSION),2) +LIBS += -lrfftw -lfftw +else +LIBS += -lfftw3 +endif + +ifeq ($(OS_PORT),LINUX) +LIBS+= -lpthread +else +LIBS+= -lpthreadGC +endif + +ifeq ($(MIDIIN),ALSA) +LIBS+= -lasound +endif + +ifeq ($(MIDIIN),WIN) +LIBS+= -lwinmm +endif + + +ifeq ($(AUDIOOUT),PA) +LIBS+= -lportaudio +endif + +ifeq ($(AUDIOOUT),JACK) +CXXFLAGS += `pkg-config --cflags jack` +LIBS+= `pkg-config --libs jack` +endif + +objects=main.o +subdirs=DSP Effects Input Misc Output Params Synth Seq + +all: + $(MAKE) -C UI $@ + rm -f Make.deps + @for name in $(subdirs); do sh -c "cd $$name ; $(CXX) -MM -MG -w *.C >> ../Make.deps ; cd .."; done + @for name in $(subdirs); do sh -c "make -C $$name $@"; done + $(MAKE) objs + rm -f zynaddsubfx zynaddsubfx.exe + + +ifneq ($(AUDIOOUT),VST) + $(CXX) -o zynaddsubfx */*.o *.o $(LIBS) +else + gcc -mdll -o temp1.tmp -Wl,--base-file,temp2.tmp */*.o *.o $(LIBS) + dlltool --dllname zynaddsubfx_vst.dll --def zynaddsubfx_gcc.def --base-file temp2.tmp --output-exp temp3.tmp + gcc -mdll -o zynaddsubfx_vst.dll */*.o *.o $(LIBS) -Wl,temp3.tmp + rm temp1.tmp temp2.tmp temp3.tmp +endif + +objs:$(objects) + +debug: all + +main.o:Misc/Master.h Misc/Util.h Output/OSSaudiooutput.h\ + Input/OSSMidiIn.h Input/ALSAMidiIn.h \ + UI/MasterUI.h + + +.PHONY : clean +clean: + rm -f $(objects) makeinclude.deps zynaddsubfx zynaddsubfx_vst.dll zynaddsubfx.exe + @for name in $(subdirs); do sh -c "make -C $$name $@"; done + rm -f Make.deps + rm -f */*.o *.o + $(MAKE) -C UI $@ + diff --git a/src/Makefile.inc b/src/Makefile.inc @@ -0,0 +1,58 @@ +CXX=gcc + +#You can set the on what OS is compiling (Linux/Windows) +OS_PORT=LINUX +#OS_PORT=WINDOWS + +#The version of the FFTW which is used (2 or 3) +#FFTW_VERSION=2 +FFTW_VERSION=3 + +#Assembler FLOAT to INT conversions +ASM_F2I=YES +#ASM_F2I=NO + +# L I N U X C O N F I G U R A T I O N +#Next line sets the midi input. It can be "ALSA", "OSS" or "NONE". +LINUX_MIDIIN=ALSA +#LINUX_MIDIIN=OSS +#LINUX_MIDIIN=NONE + +#Next line sets the audio output (OSS/JACK/PA) +LINUX_AUDIOOUT=OSS +#LINUX_AUDIOOUT=NONE +#LINUX_AUDIOOUT=JACK +#for PortAudio (PA) +#LINUX_AUDIOOUT=PA + + +# W I N D O W S C O N F I G U R A T I O N + +#Next line sets the midi input +#WINDOWS_MIDIIN=NONE +WINDOWS_MIDIIN=WIN + +#Next line sets the audio output +#WINDOWS_AUDIOOUT=NONE +WINDOWS_AUDIOOUT=PA + +#Next line sets if the synth is compiled for VST (as .dll file) +#If this setting is "YES", MIDI in and AUDIOOUT are set automatically to VST +WINDOWS_VST=NO +#WINDOWS_VST=YES + +#configuration end + +ifeq ($(OS_PORT),LINUX) + MIDIIN=$(LINUX_MIDIIN) + AUDIOOUT=$(LINUX_AUDIOOUT) + WINDOWS_VST=NO +else + MIDIIN=$(WINDOWS_MIDIIN) + AUDIOOUT=$(WINDOWS_AUDIOOUT) + ifeq ($(WINDOWS_VST),YES) + MIDIIN=VST + AUDIOOUT=VST + endif +endif + diff --git a/src/Misc/Bank.C b/src/Misc/Bank.C @@ -0,0 +1,394 @@ +/* + ZynAddSubFX - a software synthesizer + + Bank.h - Instrument Bank + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Bank.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +Bank::Bank(){ + bankfilename=NULL;bankfiletitle=NULL;lock=1; + snprintf(defaultinsname,PART_MAX_NAME_LEN,"%s"," "); + for (int i=0;i<128;i++){ + ins[i].name[0]='\0'; + ins[i].size=0; + ins[i].data=NULL; + }; + + struct stat statbuf; + + char bankcfg[1000];//hope the filename is shorter than that :) +#if defined(OS_WINDOWS) + strcpy(bankcfg,"zynaddsubfx_usedbank"); +#endif +#if defined(OS_LINUX) + strcpy(bankcfg,getenv("HOME")); + strcat(bankcfg,"/.zynaddsubfx_usedbank"); +#endif + + int result=stat(bankcfg,&statbuf); + if (result==0){ + char *fn=new char [statbuf.st_size+2]; + for (int i=0;i<statbuf.st_size;i++) fn[i]=0; + int file=open(bankcfg,O_RDONLY,00444+00222); + if (file!=-1){ + read(file,fn,statbuf.st_size); + loadfilebank(fn); + }; + close(file); + delete(fn); + } else { + + result=1; +#if defined(OS_LINUX) + result=stat("/usr/local/share/zynaddsubfx/default.bnk_zyn",&statbuf); + if (result==0) loadfilebank("/usr/local/share/zynaddsubfx/default.bnk_zyn"); + else { + result=stat("/usr/share/zynaddsubfx/default.bnk_zyn",&statbuf); + if (result==0) loadfilebank("/usr/share/zynaddsubfx/default.bnk_zyn"); + }; +#endif + if (result!=0) loadfilebank("default.bnk_zyn"); + }; +}; + +Bank::~Bank(){ + if (bankfilename==NULL) return; + + char bankcfg[1000];//hope the filename is shorter than that :) +#if defined(OS_WINDOWS) + strcpy(bankcfg,"zynaddsubfx_usedbank"); +#endif +#if defined(OS_LINUX) + strcpy(bankcfg,getenv("HOME")); + strcat(bankcfg,"/.zynaddsubfx_usedbank"); +#endif + + int file=open(bankcfg,O_CREAT|O_WRONLY|O_TRUNC,00444+00222); + if (file!=-1){ + write(file,bankfilename,strlen(bankfilename)+1); + close(file); + }; + savefile(); +}; + + +/* + * Get the name of an instrument from the bank + */ +char *Bank::getname (unsigned char ninstrument){ + if (emptyslot(ninstrument)) return (&defaultinsname[0]); + return(&ins[ninstrument].name[0]); +}; + +/* + * Get the numbered name of an instrument from the bank + */ +char *Bank::getnamenumbered (unsigned char ninstrument){ + if (ninstrument>=128) return(&tmpinsname[0][0]); + snprintf(&tmpinsname[ninstrument][0],PART_MAX_NAME_LEN+10,"%d. %s\0",ninstrument+1,getname(ninstrument)); + return(&tmpinsname[ninstrument][0]); +}; + +/* + * Changes the name of an instrument + */ +void Bank::setname(unsigned char ninstrument,const char *newname){ + if (emptyslot(ninstrument)) return; + strncpy(&ins[ninstrument].name[0],newname,PART_MAX_NAME_LEN-1); + ins[ninstrument].name[PART_MAX_NAME_LEN-1]='\0';//just in case + getnamenumbered (ninstrument); +}; + +/* + * Check if there is no instrument on a slot from the bank + */ +int Bank::emptyslot(unsigned char ninstrument){ + if (ninstrument>=128) return(1); + if (ins[ninstrument].data==NULL) return (1); + else return(0); +}; + +/* + * Removes the instrument from the bank + */ +void Bank::clearslot(unsigned char ninstrument){ + if (ninstrument>=128) return; + ins[ninstrument].name[0]='\0'; + ins[ninstrument].size=0; + if (ins[ninstrument].data!=NULL) delete (ins[ninstrument].data); + ins[ninstrument].data=NULL; +}; + +/* + * Save the instrument to a slot (the instrument is stored in a buffer who was filled + * with instrument parameters) + */ +void Bank::savetoslot(unsigned char ninstrument,const char *name,Buffer *buf){ + if (ninstrument>=128) return; + clearslot(ninstrument); + ins[ninstrument].size=buf->getsize(); + ins[ninstrument].data=new unsigned char [buf->getsize()]; + buf->getalldata(buf->getsize(),ins[ninstrument].data); + setname(ninstrument,name); + savefile(); +}; + +/* + * Loads the instrument from the bank to a buffer (who will be "dumped" to instrument parameters) + */ +void Bank::loadfromslot(unsigned char ninstrument,Buffer *buf){ + if (emptyslot(ninstrument)!=0) return; + buf->putalldata(ins[ninstrument].size,ins[ninstrument].data); + buf->changemode(0); +}; + +/* + * Loads the bank from the current file + */ +int Bank::loadfile(){ + int file; + file=open(bankfilename,O_RDONLY|O_BINARY,00444+00222); + if (file==-1) return(2);//something went wrong (access denied,..etc.) + + //Load the id. + char id[2]; + read(file,&id,2); + if ((id[0]!='N')||(id[1]!='P')) { + close(file); + return(3);//invalid data + }; + + //Load the format descriptor + unsigned char fmt; //0x00..0x7f + read(file,&fmt,1); + unsigned char type=fmt%0x10; + if (type!=3){ + close(file); + return(4);//the data is loaded as something wrong (eg. a master is loaded as a instrument) + }; + //coding=fmt/0x10; + + //load the crc + unsigned char CRC; //0x00..0x7f + read(file,&CRC,1); + //if (CRC!=0){};CHECK IF IT IS OK + + //get the meta_data - this has to be changed in future + unsigned short int metadatasize; + read (file,&metadatasize,2); + char tmp[2]; + read (file,&tmp[0],2); + + int err=0,ni=0; + do { + clearslot(ni); + //get the slot number (used only to see if there is a error) + unsigned char slotnr; + read (file,&slotnr,1); + if (slotnr!=ni){ + err=1; + break; + }; + //get the name + unsigned char namesize; + read (file,&namesize,1); + read (file,&ins[ni].name[0],namesize); + //get the data + unsigned int datasize; + read (file,&datasize,4); + if (datasize!=0){ + ins[ni].data=new unsigned char [datasize]; + ins[ni].size=datasize; + for (unsigned int i=0;i<datasize;i++) ins[ni].data[i]=0xff;//if the file data will be not loaded (because of some error), the data is filled with "Buffer exit codes" + if (read (file,&ins[ni].data[0],datasize)==-1) { + err=1; + break; + }; + }; + //get the meta_data - this has to be changed in future + unsigned short int metadatasize; + read (file,&metadatasize,2); + char tmp[2]; + read (file,&tmp[0],2); + + ni++; + } while ((err==0)&&(ni<128)); + + if (err!=0) { + fprintf(stderr,"The bank file is corrupt.\n"); + if (ni<128) clearslot(ni); + }; + close(file); + return(0); +}; + +/* + * Saves the bank to the current file + */ +int Bank::savefile(){ + int file; + if (lock!=0) return(2); + file=open(bankfilename,O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,00444+00222);//overwrite if the file exists + if (file==-1) return(2);//something went wrong (access denied,..etc.) + + //Save the id. + char id[2]; id[0]='N';id[1]='P'; + write(file,&id,2); + + //Save the format descriptor (for future formats) + unsigned char type=3,//bank + coding=0;//the encoding (Raw, 7 bit encoding,compressed) (0x00..0x07) + unsigned char fmt=type+coding*0x10; //0x00..0x7f + write(file,&fmt,1); + + //Save the CRC or 0 for no CRC + unsigned char CRC=0;//todo, if I do the CRC I do: crc=1+crc % 127;! + write (file,&CRC,1); + + //write the bank meta_data buffer (for future versions) + unsigned short int metadatasize=2; + write (file,&metadatasize,2); + char tmp[2]; tmp[0]=0xfe;tmp[1]=0xff; + write (file,&tmp[0],metadatasize); + + //Save the data + for (int ni=0;ni<128;ni++){ + //write the slot number (used only to see if there is a error) + unsigned char slotnr=ni; + write (file,&slotnr,1); + //write the instrument name + unsigned char namesize=strlen(ins[ni].name); + if (namesize>=PART_MAX_NAME_LEN) namesize=PART_MAX_NAME_LEN; + write (file,&namesize,1); + write (file,&ins[ni].name[0],namesize); + //write the instrument data + unsigned int datasize=ins[ni].size; + write (file,&datasize,4); + write (file,&ins[ni].data[0],datasize); + //write the instrument meta_data buffer (for future versions) + unsigned short int metadatasize=2; + write (file,&metadatasize,2); + char tmp[2]; tmp[0]=0xfe;tmp[1]=0xff; + write (file,&tmp[0],metadatasize); + }; + + close(file); + return(0); +}; + + +/* + * Change the current bank filename + */ +void Bank::changebankfilename(const char *newbankfilename,int ro){ + if (bankfilename!=NULL) delete(bankfilename); + bankfilename=new char [strlen(newbankfilename)+2]; + sprintf(bankfilename,"%s\0",newbankfilename); + + if (bankfiletitle!=NULL) delete(bankfiletitle); + bankfiletitle=new char [strlen(newbankfilename)+50]; + if (ro==0) sprintf(bankfiletitle,"Bank: %s\0",newbankfilename); + else sprintf(bankfiletitle,"Bank: (LOCKED) %s\0",newbankfilename); +}; + +/* + * Load a bank from a file and makes it current + */ +int Bank::loadfilebank(const char *newbankfilename){ + int file,err=0; + if (bankfilename!=NULL) savefile();//save the current bank + file=open(newbankfilename,O_RDWR|O_BINARY); + if (file==-1) err=1; + close(file); + if (err!=0){ + file=open(newbankfilename,O_RDONLY|O_BINARY); + if (file==-1) err=2; + close(file); + }; + if (err==2) return(2);//the file cannot be opened + + if (err==0) { + changebankfilename(newbankfilename,0); + lock=0; + } else { + changebankfilename(newbankfilename,1); + lock=1; + }; + + if (loadfile()!=0) { + lock=1; + return(2);//something went wrong + }; + if (err==0) return(0);//ok + else return(1);//the file is openend R/O +}; + +/* + * Save the bank to a file and makes it current + */ +int Bank::savefilebank(const char *newbankfilename, int overwrite){ + int file; + if (overwrite==0) file=open(newbankfilename,O_CREAT|O_EXCL|O_WRONLY|O_BINARY,00444+00222); + else file=open(newbankfilename,O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,00444+00222);//overwrite if the file exists + if (file==-1) { + if (errno==EEXIST) return(1);//file exists already + else return(2);//Access Denied or any other problem + }; + lock=0; + changebankfilename(newbankfilename,0); + savefile(); + return(0); +}; + +/* + * Makes a new bank, put it on a file and makes it current bank + */ +int Bank::newfilebank(const char *newbankfilename, int overwrite){ + int file; + savefile();//saves the current bank before changing the file + if (overwrite==0) file=open(newbankfilename,O_CREAT|O_EXCL|O_WRONLY|O_BINARY,00444+00222); + else file=open(newbankfilename,O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,00444+00222);//overwrite if the file exists + if (file==-1) { + if (errno==EEXIST) return(1);//file exists already + else return(2);//Access Denied or any other problem + }; + lock=0; + changebankfilename(newbankfilename,0); + for (int i=0;i<128;i++) clearslot(i); + savefile(); + return(0); +}; + +/* + * Check if the bank is locked (i.e. the file opened was readonly) + */ +int Bank::locked(){ + return(lock); +}; + diff --git a/src/Misc/Bank.h b/src/Misc/Bank.h @@ -0,0 +1,62 @@ +/* + ZynAddSubFX - a software synthesizer + + Bank.C - Instrument Bank + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef BANK_H +#define BANK_H + +#include "../globals.h" +#include "Buffer.h" + +class Bank{ + public: + Bank(); + ~Bank(); + char *getname(unsigned char ninstrument); + char *getnamenumbered(unsigned char ninstrument); + void setname(unsigned char ninstrument,const char *newname); + int emptyslot(unsigned char ninstrument); + void clearslot(unsigned char ninstrument); + void savetoslot(unsigned char ninstrument,const char *name,Buffer *buf); + void loadfromslot(unsigned char ninstrument,Buffer *buf); + int loadfilebank(const char *newbankfilename); + int savefilebank(const char *newbankfilename,int overwrite); + int newfilebank(const char *newbankfilename,int overwrite); + + char *bankfiletitle; //this is shown on the UI of the bank (the title of the window) + int locked(); + private: + void changebankfilename(const char *newbankfilename,int ro); + int savefile(); + int loadfile(); + + int lock; + char *bankfilename; + char defaultinsname[PART_MAX_NAME_LEN],tmpinsname[128][PART_MAX_NAME_LEN+20]; + struct insstuct{ + char name[PART_MAX_NAME_LEN]; + unsigned int size; + unsigned char *data; + } ins[128]; +}; + +#endif + diff --git a/src/Misc/Buffer.C b/src/Misc/Buffer.C @@ -0,0 +1,273 @@ +/* + ZynAddSubFX - a software synthesizer + + Buffer.C - A buffer used to save/load parameters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> +#include "Buffer.h" + +Buffer::Buffer(){ + mode=1; + minimal=0; + datak=datasize=0; + data=firstdata=NULL; +}; + +Buffer::~Buffer(){ + resetbuffer(); +}; + +/* + * Get or set byte to/from buffer (depends on the mode) + */ +void Buffer::rwbyte(unsigned char *b){ + if (data==NULL){//first time + data=new list; + firstdata=data; + for (int i=0;i<BUFFER_CHUNK_SIZE;i++) + data->d[i]=0xff; + datak=0; + data->next=NULL; + }; + + if (mode==0) *b=data->d[datak]; + else { + data->d[datak]=*b; + datasize++; + }; + + datak++; + + if (datak>=BUFFER_CHUNK_SIZE) { + if (mode==0) {//read from the buffer + if (data->next!=NULL) data=data->next; + else *b=0xff; + } else {//write to the buffer + list *tmp=new list; + tmp->next=NULL; + for (int i=0;i<BUFFER_CHUNK_SIZE;i++) + tmp->d[i]=0xff; + data->next=tmp; + data=tmp; + }; + datak=0; + }; + +#ifdef DEBUG_BUFFER + if (*b<16) fprintf(stderr,"0"); + fprintf(stderr,"[%d]%x ",mode,*b); +// fprintf(stderr,"%x ",*b); +// if (*b==0xff) fprintf(stderr,"*"); + fflush(stderr); +#endif +}; + +/* + * Get or set byte to/from buffer (depends on the mode) + * Also get the byte with parameter number. + */ +void Buffer::rwbytepar(unsigned char npar,unsigned char *b){ + if (mode!=0) rwbyte(&npar); + rwbyte(b); + +#ifdef DEBUG_BUFFER + fprintf(stderr," "); +#endif +}; + + +/* + * Get or set word to/from buffer (depends on the mode) + */ +void Buffer::rwword(unsigned short int *s){ + unsigned char b1,b2; + b1= *s/128; + b2= *s%128; + rwbyte(&b1); + rwbyte(&b2); + if (mode==0) *s=b1*128+b2; + +#ifdef DEBUG_BUFFER + fprintf(stderr," "); +#endif +}; + +/* + * Get or set word to/from buffer (depends on the mode) + * Also get the parameter number. + */ +void Buffer::rwwordpar(unsigned char npar,unsigned short int *s){ + if (mode!=0) rwbyte(&npar); + rwword(s); + +#ifdef DEBUG_BUFFER + fprintf(stderr," "); +#endif +}; + +/* + * Get or set word to/from buffer (depends on the mode) + * Also get the parameter number. + * Wrap if the word is less than 0. + */ +void Buffer::rwwordparwrap(unsigned char npar,short int *s){ + unsigned short int tmp; + if (mode!=0) rwbyte(&npar); + + if (getmode()!=0) { + tmp=(0x4000+ *s)%0x4000; + rwword(&tmp); + } else { + rwword(&tmp); + *s =tmp; + if (tmp>0x2000) *s=(signed short int)tmp-0x4000; + }; + +#ifdef DEBUG_BUFFER + fprintf(stderr," "); +#endif +}; + + +/* + * Reset the buffer + */ +void Buffer::resetbuffer(){ + datak=0; + datasize=0; + data=firstdata; + + if (data==NULL) return; + while (data->next!=NULL){ + list *tmp=data; + data=data->next; + delete(tmp); + }; + + delete(data); + data=firstdata=NULL; + +}; + +/* + * Change the mode: 0 => the buffer becomes a read buffer + other value => the buffer becomes a write buffer + */ +void Buffer::changemode(int mode){ + +// fprintf(stderr,"ch %d %d \n",this->mode,mode); + if (mode!=0) resetbuffer(); + else { + datak=0; + data=firstdata; + }; + this->mode=mode; +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n\n-=CHANGING MODE (%d)=-\n\n",mode); +#endif +}; + +/* + * Get the mode of the buffer (0=read, other value=write) + */ +int Buffer::getmode(){ + return(this->mode); +}; + +/* + * Change the "minimal" value of the buffer + * If it is different than 0, the program will not save into the buffer + * unused data (like disabled parts..) + */ +void Buffer::changeminimal(int minimal){ + this->minimal=minimal; +}; + +/* + * Get the "minimal" mode + */ +int Buffer::getminimal(){ + return(this->minimal); +}; + + +/* + * skip if there are data that are saved on "better" specifications + * (eg. a part or a voice that are higher + * than the number of theese suported by the program) + * This is used if you load some data with an older version of the program + */ +void Buffer::skipbranch(){ + unsigned char tmp=0,k=1; + int found0xfe=0; + do { + this->rwbyte(&tmp); + if (tmp==0xfe) { + k++; + found0xfe=1; + }; + if (tmp==0xff) k--; + } while ((k>1)||(found0xfe==0)); +}; + +/* + * Dumps all data from the buffer (used to save to file) + */ +void Buffer::getalldata(int n,unsigned char *d){ +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n\n-= GET ALL DATA=-\n\n"); +#endif + int tmpmode=mode,tmpdatak=datak; + list *tmpdata=data; + mode=0;//read + datak=0; + data=firstdata; + + for (int k=0;k<n;k++) rwbyte(&d[k]); + + mode=tmpmode; + datak=tmpdatak; + data=tmpdata; +}; + +/* + * Dumps all data to the buffer (used to load file) + */ +void Buffer::putalldata(int n,unsigned char *d){ +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n\n-= DUMP ALL DATA=-\n\n"); +#endif + resetbuffer(); + int tmpmode=mode; + + mode=1;//write + for (int k=0;k<n;k++) rwbyte(&d[k]); + datak=0; + datasize=n; +}; + +/* + * Get the size of the data stored in the buffer (used by save/load to/from file) + */ +int Buffer::getsize(){ + return(datasize); +}; + + diff --git a/src/Misc/Buffer.h b/src/Misc/Buffer.h @@ -0,0 +1,63 @@ +/* + ZynAddSubFX - a software synthesizer + + Buffer.h - A buffer used to save/load parameters + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef BUFFER_H +#define BUFFER_H +#include "../globals.h" + +//#define DEBUG_BUFFER + +class Buffer{ +#define BUFFER_CHUNK_SIZE 1000 + public: + Buffer(); + ~Buffer(); + int getmode(); + int getminimal(); + void changeminimal(int minimal); + void changemode(int mode); + void rwbyte(unsigned char *b);//read or write byte + void rwbytepar(unsigned char npar,unsigned char *b);//read or write a parameter + + void rwword(unsigned short int *s);//read or write word + void rwwordpar(unsigned char npar,unsigned short int *s); + void rwwordparwrap(unsigned char npar,short int *s); + void skipbranch(); + void resetbuffer(); + + int getsize(); + void getalldata(int n,unsigned char *d); + void putalldata(int n,unsigned char *d); + + private: + + struct list{ + unsigned char d[BUFFER_CHUNK_SIZE]; + struct list *next; + } *data,*firstdata; + + int datak,datasize; + int mode;//0 - read, 1 write + int minimal;//If it is different than 0, the program will not save into the buffer unused data (like disabled parts..) +}; + +#endif diff --git a/src/Misc/Config.C b/src/Misc/Config.C @@ -0,0 +1,221 @@ +/* + ZynAddSubFX - a software synthesizer + + Config.C - Configuration file functions + Copyright (C) 2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#ifdef OS_WINDOWS +#include <windows.h> +#include <mmsystem.h> +#endif + +#include "Config.h" +#define MAX_STRING_SIZE 250 + +Config::Config(){ + maxstringsize=MAX_STRING_SIZE;//for ui + //defaults + cfg.SampleRate=44100; + cfg.SoundBufferSize=256; + cfg.OscilSize=512; + cfg.SwapStereo=0; + + cfg.LinuxOSSWaveOutDev=new char[MAX_STRING_SIZE]; + snprintf(cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE,"/dev/dsp"); + cfg.LinuxOSSSeqInDev=new char[MAX_STRING_SIZE]; + snprintf(cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE,"/dev/sequencer"); + + cfg.DumpFile=new char[MAX_STRING_SIZE]; + snprintf(cfg.DumpFile,MAX_STRING_SIZE,"zynaddsubfx_dump.txt"); + + cfg.WindowsWaveOutId=0; + cfg.WindowsMidiInId=0; + + cfg.BankUIAutoClose=0; + cfg.DumpNotesToFile=0; + cfg.DumpAppend=1; + + winwavemax=1;winmidimax=1; +//try to find out how many input midi devices are there +#ifdef WINMIDIIN + winmidimax=midiInGetNumDevs(); + if (winmidimax==0) winmidimax=1; +#endif + winmididevices=new winmidionedevice[winmidimax]; + for (int i=0;i<winmidimax;i++) { + winmididevices[i].name=new char[MAX_STRING_SIZE]; + for (int j=0;j<MAX_STRING_SIZE;j++) winmididevices[i].name[j]='\0'; + }; + +//get the midi input devices name +#ifdef WINMIDIIN + MIDIINCAPS midiincaps; + for (int i=0;i<winmidimax;i++){ + if (! midiInGetDevCaps(i,&midiincaps,sizeof(MIDIINCAPS))) + snprintf(winmididevices[i].name,MAX_STRING_SIZE,"%s",midiincaps.szPname); + }; +#endif + + char filename[MAX_STRING_SIZE]; + getConfigFileName(filename,MAX_STRING_SIZE); + readConfig(filename); + + ui.showinstrumentinfo=0; +}; + +Config::~Config(){ + char filename[MAX_STRING_SIZE]; + getConfigFileName(filename,MAX_STRING_SIZE); + saveConfig(filename); + delete(cfg.LinuxOSSWaveOutDev); + delete(cfg.LinuxOSSSeqInDev); + delete(cfg.DumpFile); + + for (int i=0;i<winmidimax;i++) delete (winmididevices[i].name); + delete(winmididevices); +}; + +void Config::readConfig(char *filename){ + FILE *file=fopen(filename,"r"); + if (file==NULL) return; + while (!feof(file)){ + //read a line + char line[MAX_STRING_SIZE+1];line[MAX_STRING_SIZE]=0; + if (fgets(line,MAX_STRING_SIZE,file)==NULL) continue; + if (strlen(line)<2) continue; + + //find out if the line begins with "#" (comment) + char firstchar=0; + for (int i=0;i<strlen(line);i++) + if (line[i]>33) { + firstchar=line[i]; + break; + }; + if (firstchar=='#') continue; + //get the parameter and the value + char par[MAX_STRING_SIZE],val[MAX_STRING_SIZE]; + par[0]=0;val[0]=0; + if (sscanf(line,"%s = %s",par,val)!=2) continue;//bad line + if ((strlen(par)<1)|| (strlen(val)<1)) continue;//empty parameter/value + + + int intvalue=0; + char *tmp; + intvalue=strtoul(val,&tmp,10); + + //Check the parameter + if (strstr(par,"SAMPLE_RATE")!=NULL){ + cfg.SampleRate=intvalue; + }; + if (strstr(par,"SOUND_BUFFER_SIZE")!=NULL){ + cfg.SoundBufferSize=intvalue; + }; + if (strstr(par,"OSCIL_SIZE")!=NULL){ + cfg.OscilSize=intvalue; + }; + if (strstr(par,"SWAP_STEREO")!=NULL){ + cfg.SwapStereo=intvalue; + }; + if (strstr(par,"BANK_WINDOW_AUTO_CLOSE")!=NULL){ + cfg.BankUIAutoClose=intvalue; + }; + if (strstr(par,"LINUX_OSS_WAVE_OUT_DEV")!=NULL){ + if (strlen(val)<2) continue; + snprintf(cfg.LinuxOSSWaveOutDev,MAX_STRING_SIZE,val); + }; + if (strstr(par,"LINUX_OSS_SEQ_IN_DEV")!=NULL){ + if (strlen(val)<2) continue; + snprintf(cfg.LinuxOSSSeqInDev,MAX_STRING_SIZE,val); + }; + + if (strstr(par,"WINDOWS_WAVE_OUT_ID")!=NULL){ + cfg.WindowsWaveOutId=intvalue; + }; + + if (strstr(par,"WINDOWS_MIDI_IN_ID")!=NULL){ + cfg.WindowsMidiInId=intvalue; + }; + + if (strstr(par,"DUMP_NOTES_TO_FILE")!=NULL){ + cfg.DumpNotesToFile=intvalue; + }; + if (strstr(par,"DUMP_APPEND")!=NULL){ + cfg.DumpAppend=intvalue; + }; + if (strstr(par,"DUMP_FILE")!=NULL){ + if (strlen(val)<2) continue; + snprintf(cfg.DumpFile,MAX_STRING_SIZE,val); + }; +}; + fclose(file); + + //now, correct the bogus (incorrect) parameters + if (cfg.SampleRate<4000) cfg.SampleRate=4000; + if (cfg.SoundBufferSize<2) cfg.SoundBufferSize=2; + + if (cfg.OscilSize<MAX_AD_HARMONICS*2) cfg.OscilSize=MAX_AD_HARMONICS*2; + cfg.OscilSize=(int) pow(2,ceil(log (cfg.OscilSize-1.0)/log(2.0))); + + cfg.SwapStereo=(cfg.SwapStereo!=0?1:0); +#ifdef OS_WINDOWS + if (cfg.WindowsWaveOutId>=winwavemax) cfg.WindowsWaveOutId=0; + if (cfg.WindowsMidiInId>=winmidimax) cfg.WindowsMidiInId=0; +#endif +}; + +void Config::saveConfig(char *filename){ + FILE *file=fopen(filename,"w"); + if (file==NULL) return; + fprintf(file,"#ZynAddSubFX configuration file\n"); + fprintf(file,"SAMPLE_RATE = %d\n",cfg.SampleRate); + fprintf(file,"SOUND_BUFFER_SIZE = %d\n",cfg.SoundBufferSize); + fprintf(file,"OSCIL_SIZE = %d\n",cfg.OscilSize); + fprintf(file,"SWAP_STEREO = %d\n",cfg.SwapStereo); + + fprintf(file,"BANK_WINDOW_AUTO_CLOSE = %d\n",cfg.BankUIAutoClose); + + fprintf(file,"DUMP_NOTES_TO_FILE = %d\n",cfg.DumpNotesToFile); + fprintf(file,"DUMP_APPEND = %d\n",cfg.DumpAppend); + fprintf(file,"DUMP_FILE = %s\n",cfg.DumpFile); + + fprintf(file,"#Linux\n"); + fprintf(file,"LINUX_OSS_WAVE_OUT_DEV = %s\n",cfg.LinuxOSSWaveOutDev); + fprintf(file,"LINUX_OSS_SEQ_IN_DEV = %s\n",cfg.LinuxOSSSeqInDev); + + fprintf(file,"#Windows\n"); + fprintf(file,"WINDOWS_WAVE_OUT_ID = %d\n",cfg.WindowsWaveOutId); + fprintf(file,"WINDOWS_MIDI_IN_ID = %d\n",cfg.WindowsMidiInId); + + fclose(file); +}; + +void Config::getConfigFileName(char *name, int namesize){ + name[0]=0; +#ifdef OS_LINUX + snprintf(name,namesize,"%s%s",getenv("HOME"),"/.zynaddsubfx.cfg"); +#else + snprintf(name,namesize,"%s","zynaddsubfx.cfg"); +#endif + +}; + diff --git a/src/Misc/Config.h b/src/Misc/Config.h @@ -0,0 +1,57 @@ +/* + ZynAddSubFX - a software synthesizer + + Config.h - Configuration file functions + Copyright (C) 2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef CONFIG_H +#define CONFIG_H +#include "../globals.h" + +class Config{ + public: + Config(); + ~Config(); + struct { + char *LinuxOSSWaveOutDev,*LinuxOSSSeqInDev; + int SampleRate,SoundBufferSize,OscilSize,SwapStereo; + int WindowsWaveOutId,WindowsMidiInId; + int BankUIAutoClose; + int DumpNotesToFile,DumpAppend; + char *DumpFile; + } cfg; + int winwavemax,winmidimax;//number of wave/midi devices on Windows + int maxstringsize; + + struct winmidionedevice{ + char *name; + }; + winmidionedevice *winmididevices; + + struct { + int showinstrumentinfo; + } ui; + + private: + void readConfig(char *filename); + void saveConfig(char *filename); + void getConfigFileName(char *name,int namesize); +}; +#endif + diff --git a/src/Misc/Dump.C b/src/Misc/Dump.C @@ -0,0 +1,102 @@ +/* + ZynAddSubFX - a software synthesizer + + Dump.C - It dumps the notes to a text file + + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <stdlib.h> +#include <time.h> +#include "Util.h" +#include "Dump.h" + +Dump dump; + +Dump::Dump(){ + file=NULL; + tick=0; + k=0; + keyspressed=0; + startnow(); +}; + +Dump::~Dump(){ + if (file!=NULL) { + double duration=(double)tick*(double) SOUND_BUFFER_SIZE/(double) SAMPLE_RATE; + fprintf(file,"\n# statistics: duration = %d seconds; keyspressed = %d\n\n\n\n",(int) duration,keyspressed); + fclose(file); + }; +}; + +void Dump::startnow(){ + if (file!=NULL) return;//the file is already open + + if (config.cfg.DumpNotesToFile!=0){ + if (config.cfg.DumpAppend!=0) file=fopen(config.cfg.DumpFile,"a"); + else file=fopen(config.cfg.DumpFile,"w"); + + if (file==NULL) return; + }; + + if (config.cfg.DumpAppend!=0) fprintf(file,"#************************************\n"); + + time_t tm=time(NULL); + + + fprintf(file,"#date/time = %s\n",ctime(&tm)); + fprintf(file,"#1 tick = %g milliseconds\n",SOUND_BUFFER_SIZE*1000.0/SAMPLE_RATE); + fprintf(file,"SAMPLERATE = %d\n",SAMPLE_RATE); + fprintf(file,"TICKSIZE = %d #samples\n",SOUND_BUFFER_SIZE); + fprintf(file,"\n\nSTART\n"); +}; + +void Dump::inctick(){ + tick++; +}; + + +void Dump::dumpnote(char chan,char note, char vel){ + if (file==NULL) return; + if (vel==0) fprintf(file,"n %d -> %d %d \n",tick,chan,note);//note off + else fprintf(file,"N %d -> %d %d %d \n",tick,chan,note,vel);//note on + + if (vel!=0) keyspressed++; +#ifndef JACKAUDIOOUT + if (k++>25) { + fflush(file); + k=0; + }; +#endif +}; + +void Dump::dumpcontroller(char chan,unsigned int type,int par){ + if (file==NULL) return; + switch(type){ + case C_pitchwheel:fprintf(file,"P %d -> %d %d\n",tick,chan,par); + break; + default:fprintf(file,"C %d -> %d %d %d\n",tick,chan,type,par); + break; + }; +#ifndef JACKAUDIOOUT + if (k++>25) { + fflush(file); + k=0; + }; +#endif +}; + + diff --git a/src/Misc/Dump.h b/src/Misc/Dump.h @@ -0,0 +1,43 @@ +/* + ZynAddSubFX - a software synthesizer + + Dump.h - It dumps the notes to a text file + + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef DUMP_H +#define DUMP_H + +#include <stdio.h> + +class Dump{ + public: + Dump(); + ~Dump(); + void startnow(); + void inctick(); + + void dumpnote(char chan,char note, char vel); + void dumpcontroller(char chan,unsigned int type,int par); + + private: + FILE *file; + int tick; + int k; + int keyspressed; +}; +#endif diff --git a/src/Misc/Makefile b/src/Misc/Makefile @@ -0,0 +1,14 @@ +include ../Makefile.inc + +objects=Bank.o Buffer.o Master.o Microtonal.o Part.o Util.o Config.o Dump.o + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Misc/Master.C b/src/Misc/Master.C @@ -0,0 +1,685 @@ +/* + ZynAddSubFX - a software synthesizer + + Master.C - It sends Midi Messages to Parts, receives samples from parts, + process them with system/insertion effects and mix them + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Master.h" +#include <stdio.h> + + +Master::Master(){ + int npart,nefx; + swaplr=0; + + pthread_mutex_init(&mutex,NULL); + fft=new FFTwrapper(OSCIL_SIZE); + + tmpmixl=new REALTYPE[SOUND_BUFFER_SIZE]; + tmpmixr=new REALTYPE[SOUND_BUFFER_SIZE]; + audiooutl=new REALTYPE[SOUND_BUFFER_SIZE]; + audiooutr=new REALTYPE[SOUND_BUFFER_SIZE]; + + ksoundbuffersample=-1;//this is only time when this is -1; this means that the GetAudioOutSamples was never called + ksoundbuffersamplelow=0.0; + oldsamplel=0.0;oldsampler=0.0; + shutup=0; + vuresetpeaks(); + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) { + vuoutpeakpart[npart]=1e-9; + fakepeakpart[npart]=0; + }; + + for (int i=0;i<SOUND_BUFFER_SIZE;i++) { + audiooutl[i]=0.0; + audiooutr[i]=0.0; + }; + + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + part[npart]=new Part(&microtonal,fft,&mutex); + part[npart]->Prcvchn=npart%NUM_MIDI_CHANNELS; + }; + partonoff(0,1);//enable the first part + + volume=1.0; + setPvolume(80); + setPkeyshift(64); + + //Insertion Effects init + for (nefx=0;nefx<NUM_INS_EFX;nefx++) { + insefx[nefx]=new EffectMgr(1,&mutex); + Pinsparts[nefx]=-1; + }; + + //System Effects init + for (nefx=0;nefx<NUM_SYS_EFX;nefx++) { + sysefx[nefx]=new EffectMgr(0,&mutex); + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (nefx==0) setPsysefxvol(npart,nefx,64); + else setPsysefxvol(npart,nefx,0); + }; + for (int nefxto=0;nefxto<NUM_SYS_EFX;nefxto++) + setPsysefxsend(nefx,nefxto,0); + }; + + sysefx[0]->changeeffect(1); + + + //save all parameters to "masterdefaults" Buffer (I need later when I clear all parameters) + //this has to be after the master initialisation + masterdefaultsbuf.resetbuffer(); + masterdefaultsbuf.changeminimal(0);//save all parameters, even disabled + masterdefaultsbuf.changemode(1); + this->saveloadbuf(&masterdefaultsbuf); + //save all instrument patameters + instrumentdefaultsbuf.resetbuffer(); + instrumentdefaultsbuf.changeminimal(0); + instrumentdefaultsbuf.changemode(1); + part[0]->saveloadbuf(&instrumentdefaultsbuf,1); +}; + +/* + * Note On Messages (velocity=0 for NoteOff) + */ +void Master::NoteOn(unsigned char chan,unsigned char note,unsigned char velocity){ + dump.dumpnote(chan,note,velocity); + seq.recordnote(chan,note,velocity); + + noteon(chan,note,velocity); +}; + +/* + * Internal Note On (velocity=0 for NoteOff) + */ +void Master::noteon(unsigned char chan,unsigned char note,unsigned char velocity){ + int npart; + if (velocity!=0){ + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (chan==part[npart]->Prcvchn){ + fakepeakpart[npart]=velocity*2; + if (part[npart]->Penabled!=0) part[npart]->NoteOn(note,velocity,keyshift); + }; + }; + }else{ + this->NoteOff(chan,note); + }; + HDDRecorder.triggernow(); +}; + +/* + * Note Off Messages + */ +void Master::NoteOff(unsigned char chan,unsigned char note){ + dump.dumpnote(chan,note,0); + seq.recordnote(chan,note,0); + + noteoff(chan,note); +}; + +/* + * Internal Note Off + */ +void Master::noteoff(unsigned char chan,unsigned char note){ + int npart; + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0)) + part[npart]->NoteOff(note); + }; +}; + +/* + * Controllers + */ +void Master::SetController(unsigned char chan,unsigned int type,int par){ + dump.dumpcontroller(chan,type,par); + seq.recordcontroller(chan,type,par); + + setcontroller(chan,type,par); +}; + +/* + * Internal Controllers + */ +void Master::setcontroller(unsigned char chan,unsigned int type,int par){ + if ((type==C_dataentryhi)||(type==C_dataentrylo)|| + (type==C_nrpnhi)||(type==C_nrpnlo)){//Process RPN and NRPN by the Master (ignore the chan) + ctl.setparameternumber(type,par); + + int parhi=-1,parlo=-1,valhi=-1,vallo=-1; + if (ctl.getnrpn(&parhi,&parlo,&valhi,&vallo)==0){//this is NRPN + //fprintf(stderr,"rcv. NRPN: %d %d %d %d\n",parhi,parlo,valhi,vallo); + switch (parhi){ + case 0x04://System Effects + if (parlo<NUM_SYS_EFX) { + sysefx[parlo]->seteffectpar_nolock(valhi,vallo); + }; + break; + case 0x08://Insertion Effects + if (parlo<NUM_INS_EFX) { + insefx[parlo]->seteffectpar_nolock(valhi,vallo); + }; + break; + + }; + }; + } else {//other controllers + for (int npart=0;npart<NUM_MIDI_PARTS;npart++){//Send the controller to all part assigned to the channel + if ((chan==part[npart]->Prcvchn) && (part[npart]->Penabled!=0)) + part[npart]->SetController(type,par); + }; + }; +}; + + +/* + * Enable/Disable a part + */ +void Master::partonoff(int npart,int what){ + if (npart>=NUM_MIDI_PARTS) return; + if (what==0){//disable part + fakepeakpart[npart]=0; + part[npart]->Penabled=0; + part[npart]->cleanup(); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx]==npart) { + insefx[nefx]->cleanup(); + }; + }; + } else {//enabled + part[npart]->Penabled=1; + fakepeakpart[npart]=0; + }; +}; + +/* + * Master audio out (the final sound) + */ +void Master::AudioOut(REALTYPE *outl,REALTYPE *outr){ + int i,npart,nefx; + + //Swaps the Left channel with Right Channel (if it is asked for) + if (swaplr!=0){ + REALTYPE *tmp=outl; + outl=outr; + outr=tmp; + }; + + //clean up the output samples + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]=0.0; + outr[i]=0.0; + }; + + //Compute part samples and store them part[npart]->partoutl,partoutr + for (npart=0;npart<NUM_MIDI_PARTS;npart++) + if (part[npart]->Penabled!=0) part[npart]->ComputePartSmps(); + + //Insertion effects + for (nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx]>=0) { + int efxpart=Pinsparts[nefx]; + if (part[efxpart]->Penabled!=0) + insefx[nefx]->out(part[efxpart]->partoutl,part[efxpart]->partoutr); + }; + }; + + + //Apply the part volumes and pannings (after insertion effects) + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + if (part[npart]->Penabled==0) continue; + + REALTYPE newvol_l=part[npart]->volume; + REALTYPE newvol_r=part[npart]->volume; + REALTYPE oldvol_l=part[npart]->oldvolumel; + REALTYPE oldvol_r=part[npart]->oldvolumer; + REALTYPE pan=part[npart]->panning; + if (pan<0.5) newvol_l*=pan*2.0; + else newvol_r*=(1.0-pan)*2.0; + + if (ABOVE_AMPLITUDE_THRESHOLD(oldvol_l,newvol_l)|| + ABOVE_AMPLITUDE_THRESHOLD(oldvol_r,newvol_r)){//the volume or the panning has changed and needs interpolation + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE vol_l=INTERPOLATE_AMPLITUDE(oldvol_l,newvol_l,i,SOUND_BUFFER_SIZE); + REALTYPE vol_r=INTERPOLATE_AMPLITUDE(oldvol_r,newvol_r,i,SOUND_BUFFER_SIZE); + part[npart]->partoutl[i]*=vol_l; + part[npart]->partoutr[i]*=vol_r; + }; + part[npart]->oldvolumel=newvol_l; + part[npart]->oldvolumer=newvol_r; + + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed + part[npart]->partoutl[i]*=newvol_l; + part[npart]->partoutr[i]*=newvol_r; + }; + }; + }; + + + //System effects + for (nefx=0;nefx<NUM_SYS_EFX;nefx++){ + if (sysefx[nefx]->geteffect()==0) continue;//the effect is disabled + + //Clean up the samples used by the system effects + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]=0.0; + tmpmixr[i]=0.0; + }; + + //Mix the channels according to the part settings about System Effect + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + //skip if the part has no output to effect + if (Psysefxvol[nefx][npart]==0) continue; + + //skip if the part is disabled + if (part[npart]->Penabled==0) continue; + + //the output volume of each part to system effect + REALTYPE vol=sysefxvol[nefx][npart]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]+=part[npart]->partoutl[i]*vol; + tmpmixr[i]+=part[npart]->partoutr[i]*vol; + }; + }; + + // system effect send to next ones + for (int nefxfrom=0;nefxfrom<nefx;nefxfrom++){ + if (Psysefxsend[nefxfrom][nefx]!=0){ + REALTYPE v=sysefxsend[nefxfrom][nefx]; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + tmpmixl[i]+=sysefx[nefxfrom]->efxoutl[i]*v; + tmpmixr[i]+=sysefx[nefxfrom]->efxoutr[i]*v; + }; + }; + }; + + sysefx[nefx]->out(tmpmixl,tmpmixr); + + //Add the System Effect to sound output + REALTYPE outvol=sysefx[nefx]->sysefxgetvolume(); + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]+=tmpmixl[i]*outvol; + outr[i]+=tmpmixr[i]*outvol; + }; + + }; + + //Mix all parts + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//the volume did not changed + outl[i]+=part[npart]->partoutl[i]; + outr[i]+=part[npart]->partoutr[i]; + }; + }; + + //Insertion effects for Master Out + for (nefx=0;nefx<NUM_INS_EFX;nefx++){ + if (Pinsparts[nefx] == -2) + insefx[nefx]->out(outl,outr); + }; + + //Master Volume + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]*=volume; + outr[i]*=volume; + }; + + //Peak computation (for vumeters) + vuoutpeakl=1e-12;vuoutpeakr=1e-12; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + if (fabs(outl[i])>vuoutpeakl) vuoutpeakl=fabs(outl[i]); + if (fabs(outr[i])>vuoutpeakr) vuoutpeakr=fabs(outr[i]); + }; + if ((vuoutpeakl>1.0)||(vuoutpeakr>1.0)) vuclipped=1; + if (vumaxoutpeakl<vuoutpeakl) vumaxoutpeakl=vuoutpeakl; + if (vumaxoutpeakr<vuoutpeakr) vumaxoutpeakr=vuoutpeakr; + + //Part Peak computation (for Part vumeters or fake part vumeters) + for (npart=0;npart<NUM_MIDI_PARTS;npart++){ + vuoutpeakpart[npart]=1.0e-12; + if (part[npart]->Penabled!=0) { + REALTYPE *outl=part[npart]->partoutl, + *outr=part[npart]->partoutr; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE tmp=fabs(outl[i]+outr[i]); + if (tmp>vuoutpeakpart[npart]) vuoutpeakpart[npart]=tmp; + }; + vuoutpeakpart[npart]*=volume; + } else { + if (fakepeakpart[npart]>1) fakepeakpart[npart]--; + }; + }; + + + //Shutup if it is asked (with fade-out) + if (shutup!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE; + outl[i]*=tmp; + outr[i]*=tmp; + }; + ShutUp(); + }; + + //update the LFO's time + LFOParams::time++; + + if (HDDRecorder.recording()) HDDRecorder.recordbuffer(outl,outr); + dump.inctick(); +}; + +void Master::GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr){ + if (ksoundbuffersample==-1){//first time + AudioOut(&audiooutl[0],&audiooutr[0]); + ksoundbuffersample=0; + }; + + + if (samplerate==SAMPLE_RATE){//no resample + int ksample=0; + while (ksample<nsamples){ + outl[ksample]=audiooutl[ksoundbuffersample]; + outr[ksample]=audiooutr[ksoundbuffersample]; + + ksample++; + ksoundbuffersample++; + if (ksoundbuffersample>=SOUND_BUFFER_SIZE){ + AudioOut(&audiooutl[0],&audiooutr[0]); + ksoundbuffersample=0; + }; + }; + } else {//Resample + int ksample=0; + REALTYPE srinc=SAMPLE_RATE/(REALTYPE)samplerate; + + while (ksample<nsamples){ + if (ksoundbuffersample!=0){ + outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow + +audiooutl[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow); + outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow + +audiooutr[ksoundbuffersample-1]*(1.0-ksoundbuffersamplelow); + } else { + outl[ksample]=audiooutl[ksoundbuffersample]*ksoundbuffersamplelow + +oldsamplel*(1.0-ksoundbuffersamplelow); + outr[ksample]=audiooutr[ksoundbuffersample]*ksoundbuffersamplelow + +oldsampler*(1.0-ksoundbuffersamplelow); + }; + + ksample++; + + ksoundbuffersamplelow+=srinc; + if (ksoundbuffersamplelow>=1.0){ + ksoundbuffersample+=(int) floor(ksoundbuffersamplelow); + ksoundbuffersamplelow=ksoundbuffersamplelow-floor(ksoundbuffersamplelow); + }; + + if (ksoundbuffersample>=SOUND_BUFFER_SIZE){ + oldsamplel=audiooutl[SOUND_BUFFER_SIZE-1]; + oldsampler=audiooutr[SOUND_BUFFER_SIZE-1]; + AudioOut(&audiooutl[0],&audiooutr[0]); + ksoundbuffersample=0; + }; + }; + }; +}; + + +Master::~Master(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) delete (part[npart]); + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) delete (insefx[nefx]); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) delete (sysefx[nefx]); + + delete [] audiooutl; + delete [] audiooutr; + delete [] tmpmixl; + delete [] tmpmixr; + delete (fft); + + pthread_mutex_destroy(&mutex); +}; + + +/* + * Parameter control + */ +void Master::setPvolume(char Pvolume_){ + Pvolume=Pvolume_; + volume=dB2rap((Pvolume-96.0)/96.0*40.0); +}; + +void Master::setPkeyshift(char Pkeyshift_){ + Pkeyshift=Pkeyshift_; + keyshift=(int)Pkeyshift-64; +}; + + +void Master::setPsysefxvol(int Ppart,int Pefx,char Pvol){ + Psysefxvol[Pefx][Ppart]=Pvol; + sysefxvol[Pefx][Ppart]=pow(0.1,(1.0-Pvol/96.0)*2.0); +}; + +void Master::setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol){ + Psysefxsend[Pefxfrom][Pefxto]=Pvol; + sysefxsend[Pefxfrom][Pefxto]=pow(0.1,(1.0-Pvol/96.0)*2.0); +}; + + +/* + * Panic! (Clean up all parts and effects) + */ +void Master::ShutUp(){ + for (int npart=0;npart<NUM_MIDI_PARTS;npart++) { + part[npart]->cleanup(); + fakepeakpart[npart]=0; + }; + for (int nefx=0;nefx<NUM_INS_EFX;nefx++) insefx[nefx]->cleanup(); + for (int nefx=0;nefx<NUM_SYS_EFX;nefx++) sysefx[nefx]->cleanup(); + vuresetpeaks(); + shutup=0; +}; + + +/* + * Reset peaks and clear the "cliped" flag (for VU-meter) + */ +void Master::vuresetpeaks(){ + vuoutpeakl=1e-9;vuoutpeakr=1e-9;vumaxoutpeakl=1e-9;vumaxoutpeakr=1e-9; + vuclipped=0; +}; + + +/* + * Swap 2 effect (effect1<->effect2) + */ +void Master::swapcopyeffects(int what,int type,int neff1,int neff2){ + EffectMgr *eff1,*eff2; + if (neff1==neff2) return;//to swap a effect with itself or copy to itself is meaningless + + if (type==0) { + eff1=sysefx[neff1]; + eff2=sysefx[neff2]; + } else { + eff1=insefx[neff1]; + eff2=insefx[neff2]; + }; + + //get the eff2 parameters (it is needef for swapping) + unsigned char effect=eff2->geteffect(); + unsigned char preset=eff2->getpreset(); + unsigned char par[128]; + for (int i=0;i<128;i++) par[i]=eff2->geteffectpar(i); + //copy the eff1 to eff2 + eff2->changeeffect(eff1->geteffect()); + eff2->changepreset_nolock(eff1->getpreset()); + for (int i=0;i<128;i++) eff2->seteffectpar_nolock(i,eff1->geteffectpar(i)); + if (what==0){//if swapping is needed, copy the saved parameters to eff1 + eff1->changeeffect(effect); + eff1->changepreset_nolock(preset); + for (int i=0;i<128;i++) eff1->seteffectpar_nolock(i,par[i]); + }; +}; + + + +/* + * Get the effect volume for the system effect + */ +void Master::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n\n\n\n( MASTER parameters) \n"); + if (buf->getmode()==1)fprintf(stderr,"\nTest LOAD\n"); + else fprintf(stderr,"\nTest SAVE\n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Master + case 0x80: buf->rwbytepar(n,&Pvolume); + if (buf->getmode()==0) setPvolume(Pvolume); + break; + case 0x81: buf->rwbytepar(n,&Pkeyshift); + if (buf->getmode()==0) setPkeyshift(Pkeyshift); + break; + case 0xA0: if (buf->getmode()!=0) {//save the Parts + for (unsigned char npart=0;npart<NUM_MIDI_PARTS;npart++){ + if ((buf->getminimal()!=0) && (part[npart]->Penabled==0)) continue; + buf->rwbyte(&npar); + buf->rwbyte(&npart);//Write the number of part + part[npart]->saveloadbuf(buf,0); + }; + } else {//load the Part + unsigned char npart; + buf->rwbyte(&npart); + if (npart<NUM_MIDI_PARTS) { + part[npart]->disablekitloading=0; + part[npart]->saveloadbuf(buf,0); + } else buf->skipbranch(); + }; + break; + case 0xB0: if (buf->getmode()!=0) {//SYSTEM EFFECTS + for (unsigned char neffect=0;neffect<NUM_SYS_EFX;neffect++){ + buf->rwbyte(&npar); + buf->rwbyte(&neffect); + sysefx[neffect]->saveloadbuf(buf); + }; + } else { + unsigned char neffect; + buf->rwbyte(&neffect); + if (neffect<NUM_SYS_EFX) sysefx[neffect]->saveloadbuf(buf); + else buf->skipbranch(); + }; + break; + case 0xB1: if (buf->getmode()!=0) {//Part send to System Effects + for (unsigned char neffect=0;neffect<NUM_SYS_EFX;neffect++){ + for (unsigned char npart=0;npart<NUM_MIDI_PARTS;npart++){ + buf->rwbyte(&npar); + buf->rwbyte(&npart); + buf->rwbyte(&neffect); + buf->rwbyte(&Psysefxvol[neffect][npart]); + }; + }; + } else { + unsigned char neffect,npart; + buf->rwbyte(&npart); + buf->rwbyte(&neffect); + if ((npart<NUM_MIDI_PARTS) && (neffect<NUM_SYS_EFX)){ + buf->rwbyte(&tmp); + setPsysefxvol(npart,neffect,tmp); + } else buf->rwbyte(&tmp); + }; + break; + case 0xB2: if (buf->getmode()!=0) {//System Effect send to System Effect + for (unsigned char neff1=0;neff1<NUM_SYS_EFX;neff1++){ + for (unsigned char neff2=0;neff2<NUM_SYS_EFX;neff2++){ + buf->rwbyte(&npar); + buf->rwbyte(&neff1); + buf->rwbyte(&neff2); + buf->rwbyte(&Psysefxsend[neff1][neff2]); + }; + }; + } else { + unsigned char neff1,neff2; + buf->rwbyte(&neff1); + buf->rwbyte(&neff2); + if ((neff1<NUM_SYS_EFX) && (neff2<NUM_SYS_EFX)){ + buf->rwbyte(&tmp); + setPsysefxsend(neff1,neff2,tmp); + } else buf->rwbyte(&tmp); + }; + break; + case 0xC0: if (buf->getmode()!=0) {//INSERTION EFFECTS + for (unsigned char neffect=0;neffect<NUM_INS_EFX;neffect++){ + buf->rwbyte(&npar); + buf->rwbyte(&neffect); + insefx[neffect]->saveloadbuf(buf); + }; + } else { + unsigned char neffect; + buf->rwbyte(&neffect); + if (neffect<NUM_INS_EFX) insefx[neffect]->saveloadbuf(buf); + else buf->skipbranch(); + }; + break; + case 0xC1: if (buf->getmode()!=0) { + for (unsigned int neffect=0;neffect<NUM_INS_EFX;neffect++){ + buf->rwbyte(&npar); + buf->rwwordparwrap(neffect,&Pinsparts[neffect]); + }; + } else { + unsigned char neffect; + buf->rwbyte(&neffect); + buf->rwwordparwrap(npar,&Pinsparts[neffect]); + if (Pinsparts[neffect]>=NUM_MIDI_PARTS) Pinsparts[neffect]=-1; + }; + break; + case 0xD0: if (buf->getmode()!=0) buf->rwbyte(&npar); + microtonal.saveloadbuf(buf); + break; + case 0xE0: buf->rwbytepar(n,&ctl.NRPN.receive); + break; + + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + + + + + + + diff --git a/src/Misc/Master.h b/src/Misc/Master.h @@ -0,0 +1,140 @@ +/* + ZynAddSubFX - a software synthesizer + + Master.h - It sends Midi Messages to Parts, receives samples from parts, + process them with system/insertion effects and mix them + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef MASTER_H +#define MASTER_H + +#include "../globals.h" +#include "../Effects/EffectMgr.h" +#include "Part.h" +#include "../Misc/Buffer.h" +#include "../Output/Recorder.h" +#include "Microtonal.h" + +#include "Bank.h" +#include "Dump.h" +#include "../Seq/Sequencer.h" + +extern Dump dump; +class Master{ + public: + Master(); + ~Master(); + void saveloadbuf(Buffer *buf); + + //Midi IN + void NoteOn(unsigned char chan,unsigned char note,unsigned char velocity); + void NoteOff(unsigned char chan,unsigned char note); + void SetController(unsigned char chan,unsigned int type,int par); + //void NRPN... + + + void ShutUp(); + int shutup; + + //Audio Output + void AudioOut(REALTYPE *outl,REALTYPE *outr); + //Audio Output (for callback mode). This allows the program to be controled by an external program + void GetAudioOutSamples(int nsamples,int samplerate,REALTYPE *outl,REALTYPE *outr); + + + void partonoff(int npart,int what); + + //parts + Part *part[NUM_MIDI_PARTS]; + + //parameters + unsigned char Pvolume; + unsigned char Pkeyshift; + unsigned char Psysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; + unsigned char Psysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; + + //parameters control + void setPvolume(char Pvolume_); + void setPkeyshift(char Pkeyshift_); + void setPsysefxvol(int Ppart,int Pefx,char Pvol); + void setPsysefxsend(int Pefxfrom,int Pefxto,char Pvol); + + //effects + EffectMgr *sysefx[NUM_SYS_EFX];//system + EffectMgr *insefx[NUM_INS_EFX];//insertion + void swapcopyeffects(int what,int type,int neff1,int neff2); + + //HDD recorder + Recorder HDDRecorder; + + //part that's apply the insertion effect; -1 to disable + short int Pinsparts[NUM_INS_EFX]; + + //peaks for VU-meter + void vuresetpeaks(); + REALTYPE vuoutpeakl,vuoutpeakr,vumaxoutpeakl,vumaxoutpeakr; + int vuclipped; + + //peaks for part VU-meters + REALTYPE vuoutpeakpart[NUM_MIDI_PARTS]; + unsigned char fakepeakpart[NUM_MIDI_PARTS];//this is used to compute the "peak" when the part is disabled + + Controller ctl; + int swaplr;//1 if L and R are swapped + + //Sequencer + Sequencer seq; + + //other objects + Microtonal microtonal; + Bank bank; + FFTwrapper *fft; + pthread_mutex_t mutex; + + private: + REALTYPE volume; + REALTYPE sysefxvol[NUM_SYS_EFX][NUM_MIDI_PARTS]; + REALTYPE sysefxsend[NUM_SYS_EFX][NUM_SYS_EFX]; + + //Temporary mixing samples for part samples which is sent to system effect + REALTYPE *tmpmixl; + REALTYPE *tmpmixr; + + + int keyshift; + + //Audio Output samples (if it used GetAudioOutSamples - eg. for Jack output; elsewhere is unused) + REALTYPE *audiooutl; + REALTYPE *audiooutr; + + int ksoundbuffersample;//this is used to know if there is need to call AudioOut by GetAudioOutSamples method + REALTYPE ksoundbuffersamplelow;//this is used for resampling (eg. if Jack samplerate!= SAMPLE_RATE) + REALTYPE oldsamplel,oldsampler;//this is used for resampling + + //Theese are called by the NoteOn, NoteOff,SetController (which are from external sources like MIDI, Virtual Keyboard) + //and are called by internal parts of the program (like sequencer) + void noteon(unsigned char chan,unsigned char note,unsigned char velocity); + void noteoff(unsigned char chan,unsigned char note); + void setcontroller(unsigned char chan,unsigned int type,int par); + +}; + + +#endif + diff --git a/src/Misc/Microtonal.C b/src/Misc/Microtonal.C @@ -0,0 +1,563 @@ +/* + ZynAddSubFX - a software synthesizer + + Microtonal.C - Tuning settings and microtonal capabilities + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <string.h> +#include "Microtonal.h" + +#define MAX_LINE_SIZE 80 + +Microtonal::Microtonal(){ + Pname=new unsigned char[MICROTONAL_MAX_NAME_LEN]; + Pcomment=new unsigned char[MICROTONAL_MAX_NAME_LEN]; + reset(); +}; + +void Microtonal::reset(){ + Pinvertupdown=0; + Pinvertupdowncenter=60; + octavesize=12; + Penabled=0; + PAnote=69; + PAfreq=440.0; + Pscaleshift=64; + + Pfirstkey=0;Plastkey=127; + Pmiddlenote=60;Pmapsize=12; + Pmappingenabled=0; + + for (int i=0;i<128;i++) Pmapping[i]=i; + + for (int i=0;i<MAX_OCTAVE_SIZE;i++){ + octave[i].tuning=tmpoctave[i].tuning=pow(2,(i%octavesize+1)/12.0); + octave[i].type=tmpoctave[i].type=1; + octave[i].x1=tmpoctave[i].x1=(i%octavesize+1)*100; + octave[i].x2=tmpoctave[i].x2=0; + }; + octave[11].type=2;octave[11].x1=2;octave[11].x2=1; + for (int i=0;i<MICROTONAL_MAX_NAME_LEN;i++){ + Pname[i]='\0'; + Pcomment[i]='\0'; + }; + snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"12tET"); + snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"Equal Temperament 12 notes per octave"); + Pglobalfinedetune=64; +}; + +Microtonal::~Microtonal(){ + delete (Pname); + delete (Pcomment); +}; + +/* + * Get the size of the octave + */ +unsigned char Microtonal::getoctavesize(){ + if (Penabled!=0) return(octavesize); + else return(12); +}; + +/* + * Get the frequency according the note number + */ +REALTYPE Microtonal::getnotefreq(int note,int keyshift){ + // in this function will appears many times things like this: + // var=(a+b*100)%b + // I had written this way because if I use var=a%b gives unwanted results when a<0 + // This is the same with divisions. + + if ((Pinvertupdown!=0)&&((Pmappingenabled==0)||(Penabled==0))) note=(int) Pinvertupdowncenter*2-note; + + //compute global fine detune + REALTYPE globalfinedetunerap=pow(2.0,(Pglobalfinedetune-64.0)/1200.0);//-64.0 .. 63.0 cents + + if (Penabled==0) return(pow(2.0,(note-PAnote+keyshift)/12.0)*PAfreq*globalfinedetunerap);//12tET + + int scaleshift=((int)Pscaleshift-64+(int) octavesize*100)%octavesize; + + //compute the keyshift + REALTYPE rap_keyshift=1.0; + if (keyshift!=0){ + int kskey=(keyshift+(int)octavesize*100)%octavesize; + int ksoct=(keyshift+(int)octavesize*100)/octavesize-100; + rap_keyshift=(kskey==0) ? (1.0):(octave[kskey-1].tuning); + rap_keyshift*=pow(octave[octavesize-1].tuning,ksoct); + }; + + //if the mapping is enabled + if (Pmappingenabled!=0){ + if ((note<Pfirstkey)||(note>Plastkey)) return (-1.0); + //Compute how many mapped keys are from middle note to reference note + //and find out the proportion between the freq. of middle note and "A" note + int tmp=PAnote-Pmiddlenote,minus=0; + if (tmp<0) { tmp=-tmp; minus=1; }; + int deltanote=0; + for (int i=0;i<tmp;i++) if (Pmapping[i%Pmapsize]>=0) deltanote++; + REALTYPE rap_anote_middlenote=(deltanote==0) ? (1.0) : (octave[(deltanote-1)%octavesize].tuning); + if (deltanote!=0) rap_anote_middlenote*=pow(octave[octavesize-1].tuning,(deltanote-1)/octavesize); + if (minus!=0) rap_anote_middlenote=1.0/rap_anote_middlenote; + + //Convert from note (midi) to degree (note from the tunning) + int degoct=(note-(int)Pmiddlenote+(int) Pmapsize*200)/(int)Pmapsize-200; + int degkey=(note-Pmiddlenote+(int)Pmapsize*100)%Pmapsize; + degkey=Pmapping[degkey]; + if (degkey<0) return(-1.0);//this key is not mapped + + //invert the keyboard upside-down if it is asked for + //TODO: do the right way by using Pinvertupdowncenter + if (Pinvertupdown!=0){ + degkey=octavesize-degkey-1; + degoct=-degoct; + }; + //compute the frequency of the note + degkey=degkey+scaleshift; + degoct+=degkey/octavesize; + degkey%=octavesize; + + REALTYPE freq=(degkey==0) ? (1.0):octave[degkey-1].tuning; + freq*=pow(octave[octavesize-1].tuning,degoct); + freq*=PAfreq/rap_anote_middlenote; + freq*=globalfinedetunerap; + if (scaleshift!=0) freq/=octave[scaleshift-1].tuning; + return(freq*rap_keyshift); + } else {//if the mapping is disabled + int nt=note-PAnote+scaleshift; + int ntkey=(nt+(int)octavesize*100)%octavesize; + int ntoct=(nt-ntkey)/octavesize; + + REALTYPE oct=octave[octavesize-1].tuning; + REALTYPE freq=octave[(ntkey+octavesize-1)%octavesize].tuning*pow(oct,ntoct)*PAfreq; + if (ntkey==0) freq/=oct; + if (scaleshift!=0) freq/=octave[scaleshift-1].tuning; +// fprintf(stderr,"note=%d freq=%.3f cents=%d\n",note,freq,(int)floor(log(freq/PAfreq)/log(2.0)*1200.0+0.5)); + freq*=globalfinedetunerap; + return(freq*rap_keyshift); + }; +}; + + +/* + * Convert a line to tunings; returns -1 if it ok + */ +int Microtonal::linetotunings(unsigned int nline,const char *line){ + int x1=-1,x2=-1,type=-1; + REALTYPE x=-1.0,tmp,tuning; + if (strstr(line,"/")==NULL){ + if (strstr(line,".")==NULL){// M case (M=M/1) + sscanf(line,"%d",&x1); + x2=1; + type=2;//division + } else {// float number case + sscanf(line,"%f",&x); + if (x<0.000001) return(1); + type=1;//float type(cents) + }; + } else {// M/N case + sscanf(line,"%d/%d",&x1,&x2); + if ((x1<0)||(x2<0)) return(1); + if (x2==0) x2=1; + type=2;//division + }; + + if (x1<=0) x1=1;//not allow zero frequency sounds (consider 0 as 1) + + //convert to float if the number are too big + if ((type==2)&&((x1>(128*128*128-1))||(x2>(128*128*128-1)))){ + type=1; + x=((REALTYPE) x1)/x2; + }; + switch (type){ + case 1: x1=(int) floor(x); + tmp=fmod(x,1.0); + x2=(int) (floor (tmp*1e6)); + tuning=pow(2.0,x/1200.0); + break; + case 2: x=((REALTYPE)x1)/x2; + tuning=x; + break; + }; + + tmpoctave[nline].tuning=tuning; + tmpoctave[nline].type=type; + tmpoctave[nline].x1=x1; + tmpoctave[nline].x2=x2; + + return(-1);//ok +}; + +/* + * Convert the text to tunnings + */ +int Microtonal::texttotunings(const char *text){ + unsigned int i,k=0,nl=0; + char *lin; + lin=new char[MAX_LINE_SIZE+1]; + while (k<strlen(text)){ + for (i=0;i<MAX_LINE_SIZE;i++){ + lin[i]=text[k++]; + if (lin[i]<0x20) break; + }; + lin[i]='\0'; + if (strlen(lin)==0) continue; + int err=linetotunings(nl,lin); + if (err!=-1) { + delete [] lin; + return(nl);//Parse error + }; + nl++; + }; + delete [] lin; + if (nl>MAX_OCTAVE_SIZE) nl=MAX_OCTAVE_SIZE; + if (nl==0) return(-2);//the input is empty + octavesize=nl; + for (i=0;i<octavesize;i++){ + octave[i].tuning=tmpoctave[i].tuning; + octave[i].type=tmpoctave[i].type; + octave[i].x1=tmpoctave[i].x1; + octave[i].x2=tmpoctave[i].x2; + }; + return(-1);//ok +}; + +/* + * Convert the text to mapping + */ +void Microtonal::texttomapping(const char *text){ + unsigned int i,k=0; + char *lin; + lin=new char[MAX_LINE_SIZE+1]; + for (i=0;i<128;i++) Pmapping[i]=-1; + int tx=0; + while (k<strlen(text)){ + for (i=0;i<MAX_LINE_SIZE;i++){ + lin[i]=text[k++]; + if (lin[i]<0x20) break; + }; + lin[i]='\0'; + if (strlen(lin)==0) continue; + + if (sscanf(lin,"%d",&Pmapping[tx])==0) Pmapping[tx]=-1; + if (Pmapping[tx]<-1) Pmapping[tx]=-1; + + if ((tx++)>127) tx=127; + }; + delete [] lin; + + if (tx==0) tx=1; + Pmapsize=tx; +}; + +/* + * Convert tunning to text line + */ +void Microtonal::tuningtoline(int n,char *line,int maxn){ + if ((n>octavesize) || (n>MAX_OCTAVE_SIZE)) { + line[0]='\0'; + return; + }; + if (octave[n].type==1) snprintf(line,maxn,"%d.%d",octave[n].x1,octave[n].x2); + if (octave[n].type==2) snprintf(line,maxn,"%d/%d",octave[n].x1,octave[n].x2); +}; + + +int Microtonal::loadline(FILE *file,char *line){ + do { + if (fgets(line,500,file)==0) return(1); + } while (line[0]=='!'); + return(0); +}; +/* + * Loads the tunnings from a scl file + */ +int Microtonal::loadscl(const char *filename){ + FILE *file=fopen(filename, "r"); + char tmp[500]; + fseek(file,0,SEEK_SET); + //loads the short description + if (loadline(file,&tmp[0])!=0) return(2); + for (int i=0;i<500;i++) if (tmp[i]<32) tmp[i]=0; + snprintf((char *) Pname,MICROTONAL_MAX_NAME_LEN,"%s\0",tmp); + snprintf((char *) Pcomment,MICROTONAL_MAX_NAME_LEN,"%s\0",tmp); + //loads the number of the notes + if (loadline(file,&tmp[0])!=0) return(2); + int nnotes=MAX_OCTAVE_SIZE; + sscanf(&tmp[0],"%d",&nnotes); + if (nnotes>MAX_OCTAVE_SIZE) return (2); + //load the tunnings + for (int nline=0;nline<nnotes;nline++){ + if (loadline(file,&tmp[0])!=0) return(2); + linetotunings(nline,&tmp[0]); + }; + fclose(file); + + octavesize=nnotes; + for (int i=0;i<octavesize;i++){ + octave[i].tuning=tmpoctave[i].tuning; + octave[i].type=tmpoctave[i].type; + octave[i].x1=tmpoctave[i].x1; + octave[i].x2=tmpoctave[i].x2; + }; + + return(0); +}; + +/* + * Loads the mapping from a kbm file + */ +int Microtonal::loadkbm(const char *filename){ + FILE *file=fopen(filename, "r"); + int x; + char tmp[500]; + + fseek(file,0,SEEK_SET); + //loads the mapsize + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Pmapsize=x; + //loads first MIDI note to retune + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Pfirstkey=x; + //loads last MIDI note to retune + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Plastkey=x; + //loads last the middle note where scale fro scale degree=0 + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + Pmiddlenote=x; + //loads the reference note + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) return(2); + if (x<1) x=0;if (x>127) x=127;//just in case... + PAnote=x; + //loads the reference freq. + if (loadline(file,&tmp[0])!=0) return(2); + REALTYPE tmpPAfreq=440.0; + if (sscanf(&tmp[0],"%f",&tmpPAfreq)==0) return(2); + PAfreq=tmpPAfreq; + + //the scale degree(which is the octave) is not loaded, it is obtained by the tunnings with getoctavesize() method + if (loadline(file,&tmp[0])!=0) return(2); + + //load the mappings + if (Pmapsize!=0){ + for (int nline=0;nline<Pmapsize;nline++){ + if (loadline(file,&tmp[0])!=0) return(2); + if (sscanf(&tmp[0],"%d",&x)==0) x=-1; + Pmapping[nline]=x; + }; + Pmappingenabled=1; + } else { + Pmappingenabled=0; + Pmapping[0]=0; + Pmapsize=1; + }; + fclose(file); + + return(0); +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void Microtonal::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Microtonal parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Microtonal parameters + case 0x80: buf->rwbytepar(n,&Penabled); + break; + case 0x81: buf->rwbytepar(n,&Pinvertupdown); + break; + case 0x82: buf->rwbytepar(n,&Pinvertupdowncenter); + break; + case 0x83: buf->rwbytepar(n,&PAnote); + break; + case 0x84: if (buf->getmode()!=0){ + buf->rwbyte(&npar); + unsigned short int freqint=(unsigned short int) floor(PAfreq); + if (freqint>16383) freqint=16383; + buf->rwword(&freqint); + unsigned short int freqmod=(unsigned short int)(fmod(PAfreq,1.0)*10000.0); + buf->rwword(&freqmod); + } else { + unsigned short int freqint; + buf->rwword(&freqint); + unsigned short int freqmod; + buf->rwword(&freqmod); + PAfreq=freqint+freqmod/10000.0; + }; + break; + case 0x85: if ((buf->getmode()!=0) && (buf->getminimal()!=0) && (Penabled==0)) break; + buf->rwbytepar(n,&Pscaleshift); + break; + case 0x86: if (buf->getmode()!=0){ + if ((Penabled==0) && (buf->getminimal()!=0)) break; + for (unsigned char k=0;k<octavesize;k++){ + buf->rwbyte(&npar); + tmp=0;buf->rwbyte(&tmp);//need in the future if the octave will be >127 keys + buf->rwbyte(&k); + buf->rwbyte(&octave[k].type); + unsigned int x=octave[k].x1; + tmp=x/16384;buf->rwbyte(&tmp); + tmp=(x%16384)/128;buf->rwbyte(&tmp); + tmp=x%128;buf->rwbyte(&tmp); + x=octave[k].x2; + tmp=x/16384;buf->rwbyte(&tmp); + tmp=(x%16384)/128;buf->rwbyte(&tmp); + tmp=x%128;buf->rwbyte(&tmp); + }; + } else { + buf->rwbyte(&tmp); //need in the future for octacesize>127 + unsigned char k; + buf->rwbyte(&k); + if (k>=MAX_OCTAVE_SIZE) k=MAX_OCTAVE_SIZE; + buf->rwbyte(&octave[k].type); + unsigned int x=0; + buf->rwbyte(&tmp);x=tmp*(int) 16384; + buf->rwbyte(&tmp);x+=tmp*(int) 128; + buf->rwbyte(&tmp);x+=tmp; + octave[k].x1=x; + buf->rwbyte(&tmp);x=tmp*(int) 16384; + buf->rwbyte(&tmp);x+=tmp*(int) 128; + buf->rwbyte(&tmp);x+=tmp; + octave[k].x2=x; + + if (octave[k].type==1) { + octave[k].tuning=pow(2.0 + ,(octave[k].x1+octave[k].x2/(REALTYPE)1e6)/1200.0); + }; + if (octave[k].type==2) { + if (octave[k].x2==0) octave[k].x2=1; + octave[k].tuning=octave[k].x1/(REALTYPE) octave[k].x2; + }; + + }; + break; + case 0x87: if ((buf->getmode()!=0) && (buf->getminimal()!=0) && (Penabled==0)) break; + buf->rwbytepar(n,&octavesize); + break; + case 0x88: if (buf->getmode()!=0){ + if ((Penabled==0) && (buf->getminimal()!=0)) break; + buf->rwbyte(&npar); + int k=strlen((char *)Pname); + if (k>MICROTONAL_MAX_NAME_LEN-2) { + k=MICROTONAL_MAX_NAME_LEN-2; + }; + Pname[k]='\0'; + for (int i=0;i<k+1;i++){ + unsigned char tmp=Pname[i]; + buf->rwbyte(&tmp); + }; + } else { + unsigned char k=0,tmp=1; + while ((tmp!=0)&&(k<=MICROTONAL_MAX_NAME_LEN-2)){ + buf->rwbyte(&tmp); + Pname[k++]=tmp; + }; + Pname[k]='\0'; + }; + break; + case 0x89: if (buf->getmode()!=0){ + if ((Penabled==0) && (buf->getminimal()!=0)) break; + buf->rwbyte(&npar); + int k=strlen((char *)Pcomment); + if (k>MICROTONAL_MAX_NAME_LEN-2) { + k=MICROTONAL_MAX_NAME_LEN-2; + }; + Pcomment[k]='\0'; + for (int i=0;i<k+1;i++){ + unsigned char tmp=Pcomment[i]; + buf->rwbyte(&tmp); + }; + } else { + unsigned char k=0,tmp=1; + while ((tmp!=0)&&(k<=MICROTONAL_MAX_NAME_LEN-2)){ + buf->rwbyte(&tmp); + Pcomment[k++]=tmp; + }; + Pcomment[k]='\0'; + }; + break; + case 0x90: if ((buf->getmode()!=0) && (buf->getminimal()!=0) && (Penabled==0)) break; + buf->rwbytepar(n,&Pmappingenabled); + break; + case 0x91: if ((buf->getmode()!=0) && (buf->getminimal()!=0) && ((Penabled==0)||(Pmappingenabled==0))) break; + buf->rwbytepar(n,&Pfirstkey); + break; + case 0x92: if ((buf->getmode()!=0) && (buf->getminimal()!=0) && ((Penabled==0)||(Pmappingenabled==0))) break; + buf->rwbytepar(n,&Plastkey); + break; + case 0x93: if ((buf->getmode()!=0) && (buf->getminimal()!=0) && ((Penabled==0)||(Pmappingenabled==0))) break; + buf->rwbytepar(n,&Pmiddlenote); + break; + case 0x94: if (buf->getmode()!=0){ + if ((buf->getminimal()!=0) && ((Penabled==0)||(Pmappingenabled==0))) break; + buf->rwbyte(&npar); + buf->rwbyte(&Pmapsize); + for (unsigned char k=0;k<Pmapsize;k++){ + unsigned short int tmp=16383;//-1 + if (Pmapping[k]>=0) tmp=Pmapping[k]; + buf->rwword(&tmp); + }; + } else { + buf->rwbyte(&Pmapsize); + for (unsigned char k=0;k<Pmapsize;k++){ + unsigned short int tmp; + buf->rwword(&tmp); + if (tmp!=16383) Pmapping[k]=tmp; + else Pmapping[k]=-1; + }; + }; + break; + case 0x95: buf->rwbytepar(n,&Pglobalfinedetune); + break; + + }; + }; + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; diff --git a/src/Misc/Microtonal.h b/src/Misc/Microtonal.h @@ -0,0 +1,102 @@ +/* + ZynAddSubFX - a software synthesizer + + Microtonal.h - Tuning settings and microtonal capabilities + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef MICROTONAL_H +#define MICROTONAL_H + +#include "../globals.h" +#include "Buffer.h" +#define MAX_OCTAVE_SIZE 128 +#define MICROTONAL_MAX_NAME_LEN 120 + +#include <stdio.h> + +class Microtonal{ + public: + Microtonal(); + ~Microtonal(); + void reset(); + REALTYPE getnotefreq(int note,int keyshift); + + //Parameters + + //if the keys are inversed (the pitch is lower to keys from the right direction) + unsigned char Pinvertupdown; + + //the central key of the inversion + unsigned char Pinvertupdowncenter; + + //0 for 12 key temperate scale, 1 for microtonal + unsigned char Penabled; + + //the note of "A" key + unsigned char PAnote; + + //the frequency of the "A" note + REALTYPE PAfreq; + + //if the scale is "tuned" to a note, you can tune to other note + unsigned char Pscaleshift; + + //first and last key (to retune) + unsigned char Pfirstkey; + unsigned char Plastkey; + + //The middle note where scale degree 0 is mapped to + unsigned char Pmiddlenote; + + //Map size + unsigned char Pmapsize; + + //Mapping ON/OFF + unsigned char Pmappingenabled; + //Mapping (keys) + short int Pmapping[128]; + + unsigned char Pglobalfinedetune; + + // Functions + unsigned char getoctavesize(); + void tuningtoline(int n,char *line,int maxn); + int loadscl(const char *filename);//load the tunnings from a .scl file + int loadkbm(const char *filename);//load the mapping from .kbm file + int texttotunings(const char *text); + void texttomapping(const char *text); + unsigned char *Pname; + unsigned char *Pcomment; + void saveloadbuf(Buffer *buf); + private: + int linetotunings(unsigned int nline,const char *line); + int loadline(FILE *file,char *line);//loads a line from the text file, while ignoring the lines beggining with "!" + unsigned char octavesize; + struct { + // the real tuning (eg. +1.05946 for one halftone) + // or 2.0 for one octave + REALTYPE tuning; + //folowing parameters are used for save/load from parameters buffers(file) + unsigned char type; + unsigned int x1,x2;// smaller than pow(128.0,3.0)-1.0 + } octave[MAX_OCTAVE_SIZE],tmpoctave[MAX_OCTAVE_SIZE]; + +}; + +#endif diff --git a/src/Misc/Part.C b/src/Misc/Part.C @@ -0,0 +1,915 @@ +/* + ZynAddSubFX - a software synthesizer + + Part.C - Part implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Part.h" +#include "Microtonal.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +Part::Part(Microtonal *microtonal_,FFTwrapper *fft_, pthread_mutex_t *mutex_){ + microtonal=microtonal_; + fft=fft_; + mutex=mutex_; + partoutl=new REALTYPE [SOUND_BUFFER_SIZE]; + partoutr=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpoutl=new REALTYPE [SOUND_BUFFER_SIZE]; + tmpoutr=new REALTYPE [SOUND_BUFFER_SIZE]; + + for (int n=0;n<NUM_KIT_ITEMS;n++){ + kit[n].Penabled=0;kit[n].Pmuted=0; + kit[n].Pminkey=0;kit[n].Pmaxkey=127; + kit[n].Padenabled=0;kit[n].Psubenabled=0; + kit[n].Pname=new unsigned char [PART_MAX_NAME_LEN]; + for (int i=0;i<PART_MAX_NAME_LEN;i++) kit[n].Pname[i]='\0'; + kit[n].Psendtoparteffect=0; + kit[n].adpars=NULL;kit[n].subpars=NULL; + }; + kit[0].Penabled=1; + kit[0].adpars=new ADnoteParameters(fft); + kit[0].subpars=new SUBnoteParameters(); + ADPartParameters=kit[0].adpars; + SUBPartParameters=kit[0].subpars; + + //Part's Insertion Effects init + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { + partefx[nefx]=new EffectMgr(1,mutex); + Pefxroute[nefx]=0;//route to next effect + }; + + for (int n=0;n<NUM_PART_EFX+1;n++) { + partfxinputl[n]=new REALTYPE [SOUND_BUFFER_SIZE]; + partfxinputr[n]=new REALTYPE [SOUND_BUFFER_SIZE]; + }; + + //parameters setup + Penabled=0; + Pminkey=0; + Pmaxkey=127; + Pnoteon=1; + Ppolymode=1; + setPvolume(96); + Pkeyshift=64; + Prcvchn=0; + setPpanning(64); + Pvelsns=64; + Pveloffs=64; + Pkeylimit=15; + Pkitmode=0; + Pdrummode=0; + killallnotes=0; + oldfreq=-1.0; + + PADnoteenabled=1; + PSUBnoteenabled=0; + + int i,j; + for (i=0;i<POLIPHONY;i++){ + partnote[i].status=KEY_OFF; + partnote[i].note=-1; + partnote[i].itemsplaying=0; + for (j=0;j<NUM_KIT_ITEMS;j++){ + partnote[i].kititem[j].adnote=NULL; + partnote[i].kititem[j].subnote=NULL; + }; + partnote[i].time=0; + }; + cleanup(); + Pname=new unsigned char [PART_MAX_NAME_LEN]; + for (i=0;i<PART_MAX_NAME_LEN;i++) Pname[i]='\0'; + + info.Ptype=0; + memset(info.Pauthor,0,MAX_INFO_TEXT_SIZE+1); + memset(info.Pcomments,0,MAX_INFO_TEXT_SIZE+1); + + oldvolumel=oldvolumer=0.5; + lastnote=-1;disablekitloading=0; +}; + + +/* + * Cleanup the part + */ +void Part::cleanup(){ + for (int k=0;k<POLIPHONY;k++) KillNotePos(k); + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + partoutl[i]=denormalkillbuf[i]; + partoutr[i]=denormalkillbuf[i]; + tmpoutl[i]=0.0; + tmpoutr[i]=0.0; + }; + ctl.resetall(); + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) partefx[nefx]->cleanup(); + for (int n=0;n<NUM_PART_EFX+1;n++) { + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + partfxinputl[n][i]=denormalkillbuf[i]; + partfxinputr[n][i]=denormalkillbuf[i]; + }; + }; +}; + +Part::~Part(){ + cleanup(); + for (int n=0;n<NUM_KIT_ITEMS;n++){ + if (kit[n].adpars!=NULL) delete (kit[n].adpars); + if (kit[n].subpars!=NULL) delete (kit[n].subpars); + kit[n].adpars=NULL;kit[n].subpars=NULL; + delete(kit[n].Pname); + }; + + delete (Pname); + delete (partoutl); + delete (partoutr); + delete (tmpoutl); + delete (tmpoutr); + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) + delete (partefx[nefx]); + for (int n=0;n<NUM_PART_EFX;n++) { + delete (partfxinputl[n]); + delete (partfxinputr[n]); + }; +}; + +/* + * Note On Messages + */ +void Part::NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift){ + int i,pos; + + lastnote=note; + if ((note<Pminkey)||(note>Pmaxkey)) return; + + pos=-1; + for (i=0;i<POLIPHONY;i++){ + if (partnote[i].status==KEY_OFF){ + pos=i; + break; + }; + }; + + if (Ppolymode==0){//if the mode is 'mono' turn off all other notes + for (i=0;i<POLIPHONY;i++) + if (partnote[i].status==KEY_PLAYING) NoteOff(partnote[i].note); + RelaseSustainedKeys(); + }; + + if (pos==-1){ + //test + fprintf(stderr,"NOTES TOO MANY (> POLIPHONY) - (Part.C::NoteOn(..))\n"); + } else { + if (Pnoteon!=0){ + //start the note + partnote[pos].status=KEY_PLAYING; + partnote[pos].note=note; + + //this computes the velocity sensing of the part + REALTYPE vel=VelF(velocity/127.0,Pvelsns); + + //compute the velocity offset + vel+=(Pveloffs-64.0)/64.0; + if (vel<0.0) vel=0.0; else if (vel>1.0) vel=1.0; + + //compute the keyshift + int partkeyshift=(int)Pkeyshift-64; + int keyshift=masterkeyshift+partkeyshift; + + //initialise note frequency + REALTYPE notebasefreq; + if (Pdrummode==0){ + notebasefreq=microtonal->getnotefreq(note,keyshift); + if (notebasefreq<0.0) return;//the key is no mapped + } else { + notebasefreq=440.0*pow(2.0,(note-69.0)/12.0); + }; + + //Portamento + if (oldfreq<1.0) oldfreq=notebasefreq;//this is only the first note is played + + int portamento=ctl.initportamento(oldfreq,notebasefreq); + + if (portamento!=0) ctl.portamento.noteusing=pos; + oldfreq=notebasefreq; + + partnote[pos].itemsplaying=0; + if (Pkitmode==0){//init the notes for the "normal mode" + partnote[pos].kititem[0].sendtoparteffect=0; + if (PADnoteenabled!=0) partnote[pos].kititem[0].adnote=new ADnote(ADPartParameters,&ctl,notebasefreq,vel,portamento,note); + if (PSUBnoteenabled!=0) partnote[pos].kititem[0].subnote=new SUBnote(SUBPartParameters,&ctl,notebasefreq,vel,portamento,note); + if ((PADnoteenabled!=0)||(PSUBnoteenabled!=0)) partnote[pos].itemsplaying++; + } else {//init the notes for the "kit mode" + for (int item=0;item<NUM_KIT_ITEMS;item++){ + if (kit[item].Pmuted!=0) continue; + if ((note<kit[item].Pminkey)||(note>kit[item].Pmaxkey)) continue; + + int ci=partnote[pos].itemsplaying;//ci=current item + + partnote[pos].kititem[ci].sendtoparteffect=( kit[item].Psendtoparteffect<NUM_PART_EFX ? + kit[item].Psendtoparteffect: NUM_PART_EFX);//if this parameter is 127 for "unprocessed" + + if ((kit[item].adpars!=NULL)&&(kit[item].Padenabled)!=0) + partnote[pos].kititem[ci].adnote=new ADnote(kit[item].adpars,&ctl,notebasefreq,vel,portamento,note); + + if ((kit[item].subpars!=NULL)&&(kit[item].Psubenabled)!=0) + partnote[pos].kititem[ci].subnote=new SUBnote(kit[item].subpars,&ctl,notebasefreq,vel,portamento,note); + + if ((kit[item].adpars!=NULL)|| (kit[item].subpars!=NULL)) { + partnote[pos].itemsplaying++; + if ( ((kit[item].Padenabled!=0)||(kit[item].Psubenabled!=0)) + && (Pkitmode==2) ) break; + }; + }; + }; + }; + }; + + //this only relase the keys if there is maximum number of keys allowed + setkeylimit(Pkeylimit); +}; + +/* + * Note Off Messages + */ +void Part::NoteOff(unsigned char note){//relase the key + int i; + for (i=POLIPHONY-1;i>=0;i--){ //first note in, is first out if there are same note multiple times + if ((partnote[i].status==KEY_PLAYING)&&(partnote[i].note==note)) { + if (ctl.sustain.sustain==0){ //the sustain pedal is not pushed + RelaseNotePos(i); + break; + } else {//the sustain pedal is pushed + partnote[i].status=KEY_RELASED_AND_SUSTAINED; + }; + }; + }; +}; + +/* + * Controllers + */ +void Part::SetController(unsigned int type,int par){ + switch (type){ + case C_pitchwheel:ctl.setpitchwheel(par); + break; + case C_expression:ctl.setexpression(par); + setPvolume(Pvolume);//update the volume + break; + case C_portamento:ctl.setportamento(par); + break; + case C_panning:ctl.setpanning(par); + setPpanning(Ppanning);//update the panning + break; + case C_filtercutoff:ctl.setfiltercutoff(par); + break; + case C_filterq:ctl.setfilterq(par); + break; + case C_bandwidth:ctl.setbandwidth(par); + break; + case C_modwheel:ctl.setmodwheel(par); + break; + case C_fmamp:ctl.setfmamp(par); + break; + case C_volume:ctl.setvolume(par); + if (ctl.volume.receive!=0) volume=ctl.volume.volume; + else setPvolume(Pvolume); + break; + case C_sustain:ctl.setsustain(par); + if (ctl.sustain.sustain==0) RelaseSustainedKeys(); + break; + case C_allsoundsoff:AllNotesOff();//Panic + break; + case C_resetallcontrollers: + ctl.resetall(); + RelaseSustainedKeys(); + if (ctl.volume.receive!=0) volume=ctl.volume.volume; + else setPvolume(Pvolume); + setPvolume(Pvolume);//update the volume + setPpanning(Ppanning);//update the panning + + ADPartParameters->GlobalPar.Reson-> + sendcontroller(C_resonance_center,1.0); + + ADPartParameters->GlobalPar.Reson-> + sendcontroller(C_resonance_bandwidth,1.0); + //more update to add here if I add controllers + break; + case C_allnotesoff:RelaseAllKeys(); + break; + case C_resonance_center: + ctl.setresonancecenter(par); + ADPartParameters->GlobalPar.Reson-> + sendcontroller(C_resonance_center,ctl.resonancecenter.relcenter); + break; + case C_resonance_bandwidth: + ctl.setresonancebw(par); + ADPartParameters->GlobalPar.Reson-> + sendcontroller(C_resonance_bandwidth,ctl.resonancebandwidth.relbw); + break; + }; +}; +/* + * Relase the sustained keys + */ + +void Part::RelaseSustainedKeys(){ + for (int i=0;i<POLIPHONY;i++) + if (partnote[i].status==KEY_RELASED_AND_SUSTAINED) RelaseNotePos(i); +}; + +/* + * Relase all keys + */ + +void Part::RelaseAllKeys(){ + for (int i=0;i<POLIPHONY;i++){ + if ((partnote[i].status!=KEY_RELASED)&& + (partnote[i].status!=KEY_OFF)) //thanks to Frank Neumann + RelaseNotePos(i); + }; +}; + +/* + * Release note at position + */ +void Part::RelaseNotePos(int pos){ + + for (int j=0;j<NUM_KIT_ITEMS;j++){ + + if (partnote[pos].kititem[j].adnote!=NULL) + if (partnote[pos].kititem[j].adnote) + partnote[pos].kititem[j].adnote->relasekey(); + + if (partnote[pos].kititem[j].subnote!=NULL) + if (partnote[pos].kititem[j].subnote!=NULL) + partnote[pos].kititem[j].subnote->relasekey(); + }; + partnote[pos].status=KEY_RELASED; +}; + + +/* + * Kill note at position + */ +void Part::KillNotePos(int pos){ + partnote[pos].status=KEY_OFF; + partnote[pos].note=-1; + partnote[pos].time=0; + partnote[pos].itemsplaying=0; + + for (int j=0;j<NUM_KIT_ITEMS;j++){ + if (partnote[pos].kititem[j].adnote!=NULL) { + delete(partnote[pos].kititem[j].adnote); + partnote[pos].kititem[j].adnote=NULL; + }; + if (partnote[pos].kititem[j].subnote!=NULL) { + delete(partnote[pos].kititem[j].subnote); + partnote[pos].kititem[j].subnote=NULL; + }; + }; + if (pos==ctl.portamento.noteusing) { + ctl.portamento.noteusing=-1; + ctl.portamento.used=0; + }; +}; + + +/* + * Set Part's key limit + */ +void Part::setkeylimit(unsigned char Pkeylimit){ + this->Pkeylimit=Pkeylimit; + int keylimit=Pkeylimit; + if (keylimit==0) keylimit=POLIPHONY-5; + + //release old keys if the number of notes>keylimit + if (Ppolymode!=0){ + int notecount=0; + for (int i=0;i<POLIPHONY;i++){ + if ((partnote[i].status==KEY_PLAYING)||(partnote[i].status==KEY_RELASED_AND_SUSTAINED)) + notecount++; + }; + int oldestnotepos=-1,maxtime=0; + if (notecount>keylimit){//find out the oldest note + for (int i=0;i<POLIPHONY;i++){ + if ( ((partnote[i].status==KEY_PLAYING)||(partnote[i].status==KEY_RELASED_AND_SUSTAINED)) + && (partnote[i].time>maxtime)){ + maxtime=partnote[i].time; + oldestnotepos=i; + }; + }; + }; + if (oldestnotepos!=-1) RelaseNotePos(oldestnotepos); + }; +}; + + +/* + * Prepare all notes to be turned off + */ +void Part::AllNotesOff(){ + killallnotes=1; +}; + + +/* + * Compute Part samples and store them in the partoutl[] and partoutr[] + */ +void Part::ComputePartSmps(){ + int i,k; + int noteplay;//0 if there is nothing activated + for (int nefx=0;nefx<NUM_PART_EFX+1;nefx++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + partfxinputl[nefx][i]=0.0; + partfxinputr[nefx][i]=0.0; + }; + }; + + for (k=0;k<POLIPHONY;k++){ + if (partnote[k].status==KEY_OFF) continue; + noteplay=0; + partnote[k].time++; + //get the sampledata of the note and kill it if it's finished + + for (int item=0;item<partnote[k].itemsplaying;item++){ + + int sendcurrenttofx=partnote[k].kititem[item].sendtoparteffect; + + ADnote *adnote=partnote[k].kititem[item].adnote; + SUBnote *subnote=partnote[k].kititem[item].subnote; + //get from the ADnote + if (adnote!=NULL) { + noteplay++; + if (adnote->ready!=0) adnote->noteout(&tmpoutl[0],&tmpoutr[0]); + else for (i=0;i<SOUND_BUFFER_SIZE;i++){tmpoutl[i]=0.0;tmpoutr[i]=0.0;}; + if (adnote->finished()!=0){ + delete (adnote); + partnote[k].kititem[item].adnote=NULL; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the ADnote to part(mix) + partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; + partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; + }; + }; + //get from the SUBnote + if (subnote!=NULL) { + noteplay++; + if (subnote->ready!=0) subnote->noteout(&tmpoutl[0],&tmpoutr[0]); + else for (i=0;i<SOUND_BUFFER_SIZE;i++){tmpoutl[i]=0.0;tmpoutr[i]=0.0;}; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){//add the SUBnote to part(mix) + partfxinputl[sendcurrenttofx][i]+=tmpoutl[i]; + partfxinputr[sendcurrenttofx][i]+=tmpoutr[i]; + }; + if (subnote->finished()!=0){ + delete (subnote); + partnote[k].kititem[item].subnote=NULL; + }; + }; + + }; + //Kill note if there is no synth on that note + if (noteplay==0) KillNotePos(k); + }; + + + //Apply part's effects and mix them + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { + partefx[nefx]->out(partfxinputl[nefx],partfxinputr[nefx]); + int routeto=(Pefxroute[nefx]==0 ? nefx+1 : NUM_PART_EFX); + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + partfxinputl[routeto][i]+=partfxinputl[nefx][i]; + partfxinputr[routeto][i]+=partfxinputr[nefx][i]; + }; + }; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + partoutl[i]=partfxinputl[NUM_PART_EFX][i]; + partoutr[i]=partfxinputr[NUM_PART_EFX][i]; + }; + + //Kill All Notes if killallnotes!=0 + if (killallnotes!=0) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + REALTYPE tmp=(SOUND_BUFFER_SIZE-i)/(REALTYPE) SOUND_BUFFER_SIZE; + partoutl[i]*=tmp; + partoutr[i]*=tmp; + tmpoutl[i]=0.0; + tmpoutr[i]=0.0; + }; + for (int k=0;k<POLIPHONY;k++) KillNotePos(k); + killallnotes=0; + for (int nefx=0;nefx<NUM_PART_EFX;nefx++) { + partefx[nefx]->cleanup(); + }; + }; + ctl.updateportamento(); +}; + +/* + * Parameter control + */ +void Part::setPvolume(char Pvolume_){ + Pvolume=Pvolume_; + volume=dB2rap((Pvolume-96.0)/96.0*40.0)*ctl.expression.relvolume; +}; + +void Part::setPpanning(char Ppanning_){ + Ppanning=Ppanning_; + panning=Ppanning/127.0+ctl.panning.pan; + if (panning<0.0) panning=0.0;else if (panning>1.0) panning=1.0; + +}; + +/* + * Enable or disable a kit item + */ +void Part::setkititemstatus(int kititem,int Penabled_){ + if ((kititem==0)&&(kititem>=NUM_KIT_ITEMS)) return;//nonexistent kit item and the first kit item is always enabled + kit[kititem].Penabled=Penabled_; + if (Penabled_==0){ + if (kit[kititem].adpars!=NULL) delete (kit[kititem].adpars); + if (kit[kititem].subpars!=NULL) delete (kit[kititem].subpars); + kit[kititem].adpars=NULL;kit[kititem].subpars=NULL; + kit[kititem].Pname[0]='\0'; + } else { + if (kit[kititem].adpars==NULL) kit[kititem].adpars=new ADnoteParameters(fft); + if (kit[kititem].subpars==NULL) kit[kititem].subpars=new SUBnoteParameters(); + }; +}; + + +/* + * Swap the item with other or copy the item to another item + */ +void Part::swapcopyitem(int item1, int item2, int mode){ + if (item1==item2) return; + if ((item1>=NUM_KIT_ITEMS) || (item2>=NUM_KIT_ITEMS)) return; + + int e1=kit[item1].Penabled; + int e2=kit[item2].Penabled; + + if ((e1==0) && (e2==0)) return;//both items are disabled + + kit[0].Padenabled=PADnoteenabled; + kit[0].Psubenabled=PSUBnoteenabled; + + if ((e1==0)&&(mode==0)) {//copy a null item to a existent item + setkititemstatus (item2,0);//delete item 2 + }; + + if (e1==0) setkititemstatus(item1,1); + if (e2==0) setkititemstatus(item2,1); + + Buffer tmpbuf; + if (mode!=0){//swap + tmpbuf.changemode(1); + tmpbuf.changeminimal(0); + saveloadbufkititem(&tmpbuf,item2,1); + }; + + slbuf.changemode(1);//write to buffer + slbuf.changeminimal(0); + saveloadbufkititem(&slbuf,item1,1); + + slbuf.changemode(0);//read from buffer + saveloadbufkititem(&slbuf,item2,1); + + if (mode!=0){//swap + tmpbuf.changemode(0); + saveloadbufkititem(&tmpbuf,item1,1); + }; + + PADnoteenabled=kit[0].Padenabled; + PSUBnoteenabled=kit[0].Psubenabled; +}; + + +void Part::saveloadbufkititem(Buffer *buf,unsigned char item,int saveitem0){ + unsigned char npar,n,tmp; + int fmon,min,fmexton;//fmon is 0 if there is no need to save the FM parameters + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n\n( Part paramete kit item %d) \n",item); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + if (item>=NUM_KIT_ITEMS){//too big kit item + buf->skipbranch(); + return; + }; + + for (n=0x80;n<0xF0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + case 0x81: buf->rwbytepar(n,&kit[item].Pmuted); + break; + case 0x82: buf->rwbytepar(n,&kit[item].Pminkey); + break; + case 0x83: buf->rwbytepar(n,&kit[item].Pmaxkey); + break; + case 0x84: buf->rwbytepar(n,&kit[item].Psendtoparteffect); + break; + case 0x90: buf->rwbytepar(n,&kit[item].Padenabled); + break; + case 0x91: buf->rwbytepar(n,&kit[item].Psubenabled); + break; + case 0xA0: if (buf->getmode()!=0){//saving + if ((buf->getminimal()!=0)&&(kit[item].Padenabled==0)) break; + if ((item==0)&&(saveitem0==0)) break;//the first item parameters are already saved (as ADPartParameters) + if (kit[item].adpars==NULL) break; + buf->rwbyte(&npar); + }; + kit[item].adpars->saveloadbuf(buf); + break; + case 0xA1: if (buf->getmode()!=0){//saving + if ((buf->getminimal()!=0)&&(kit[item].Psubenabled==0)) break; + if ((item==0)&&(saveitem0==0)) break;//the first item parameters are already saved (as SUBPartParameters) + if (kit[item].subpars==NULL) break; + buf->rwbyte(&npar); + }; + kit[item].subpars->saveloadbuf(buf); + break; + case 0xB0: if (buf->getmode()!=0) { + buf->rwbyte(&npar); + int k=strlen( (char *) kit[item].Pname); + if (k>PART_MAX_NAME_LEN-2) { + k=PART_MAX_NAME_LEN-2; + }; + kit[item].Pname[k]='\0'; + for (int i=0;i<k+1;i++){ + unsigned char tmp=kit[item].Pname[i]; + buf->rwbyte(&tmp); + }; + } else { + unsigned char k=0,tmp=1; + while ((tmp!=0)&&(k<=PART_MAX_NAME_LEN-2)){ + buf->rwbyte(&tmp); + kit[item].Pname[k++]=tmp; + }; + kit[item].Pname[k]='\0'; + }; + + }; + }; + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; + +}; + +/* + * Save or load the parameters to/from the buffer + */ +void Part::saveloadbuf(Buffer *buf,int instrumentonly){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Part parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + if ((buf->getmode()==0)&&(disablekitloading==0)){//clears all kit items + for (int item=0;item<NUM_KIT_ITEMS;item++) { + if (item>0) setkititemstatus(item,0); + kit[item].Pmuted=0; + kit[item].Pminkey=0;kit[item].Pmaxkey=127; + kit[item].Padenabled=0;kit[item].Psubenabled=0; + kit[item].Psendtoparteffect=0; + for (int i=0;i<PART_MAX_NAME_LEN;i++) kit[item].Pname[i]='\0'; + }; + }; + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Part parameters + case 0x80: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Penabled); + if (buf->getmode()==0) cleanup(); + break; + case 0x81: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pvolume); + if (buf->getmode()==0) setPvolume(Pvolume); + break; + case 0x82: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Ppanning); + if (buf->getmode()==0) setPpanning(Ppanning); + break; + case 0x83: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pvelsns); + break; + case 0x84: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pveloffs); + break; + case 0x85: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pkeyshift); + break; + case 0x86: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Prcvchn); + break; + case 0x87: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pnoteon); + break; + case 0x88: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pminkey); + break; + case 0x89: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pmaxkey); + break; + case 0x8A: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Ppolymode); + break; + case 0x8B: if (instrumentonly!=0) break; + buf->rwbytepar(n,&Pkeylimit); + break; + //Instrument data + case 0xB0: buf->rwbytepar(n,&PADnoteenabled); + break; + case 0xB1: buf->rwbytepar(n,&PSUBnoteenabled); + break; + case 0xB2: tmp=0; + if ((disablekitloading!=0)&&(buf->getmode()==0)) + buf->rwbytepar(n,&tmp); + else buf->rwbytepar(n,&Pkitmode); + break; + case 0xB3: buf->rwbytepar(n,&Pdrummode); + break; + case 0xB8: buf->rwbytepar(n,&info.Ptype); + break; + case 0xB9: if (buf->getmode()!=0) { + buf->rwbyte(&npar); + int k=strlen( (char *) info.Pauthor); + if (k>MAX_INFO_TEXT_SIZE-1) { + k=MAX_INFO_TEXT_SIZE-1; + }; + info.Pauthor[k]='\0'; + for (int i=0;i<k+1;i++){ + unsigned char tmp=info.Pauthor[i]; + if (tmp>127) tmp=127; + buf->rwbyte(&tmp); + }; + } else { + unsigned char k=0,tmp=1; + while ((tmp!=0)&&(k<=MAX_INFO_TEXT_SIZE-1)){ + buf->rwbyte(&tmp); + info.Pauthor[k++]=tmp; + }; + info.Pauthor[k]='\0'; + }; + break; + case 0xBA: if (buf->getmode()!=0) { + buf->rwbyte(&npar); + int k=strlen( (char *) info.Pcomments); + if (k>MAX_INFO_TEXT_SIZE-1) { + k=MAX_INFO_TEXT_SIZE-1; + }; + info.Pcomments[k]='\0'; + for (int i=0;i<k+1;i++){ + unsigned char tmp=info.Pcomments[i]; + if (tmp>127) tmp=127; + buf->rwbyte(&tmp); + }; + } else { + unsigned char k=0,tmp=1; + while ((tmp!=0)&&(k<=MAX_INFO_TEXT_SIZE-1)){ + buf->rwbyte(&tmp); + info.Pcomments[k++]=tmp; + }; + info.Pcomments[k]='\0'; + }; + break; + case 0xC0: if ((buf->getminimal()!=0) && (buf->getmode()!=0) + && (PADnoteenabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + ADPartParameters->saveloadbuf(buf); + break; + case 0xC1: if ((buf->getminimal()!=0) && (buf->getmode()!=0) + && (PSUBnoteenabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + SUBPartParameters->saveloadbuf(buf); + break; + case 0xD0: if (buf->getmode()!=0) { + if (instrumentonly!=2){ + buf->rwbyte(&npar); + int k=strlen( (char *) Pname); + if (k>PART_MAX_NAME_LEN-2) { + k=PART_MAX_NAME_LEN-2; + }; + Pname[k]='\0'; + for (int i=0;i<k+1;i++){ + unsigned char tmp=Pname[i]; + buf->rwbyte(&tmp); + }; + }; + } else { + unsigned char k=0,tmp=1; + while ((tmp!=0)&&(k<=PART_MAX_NAME_LEN-2)){ + buf->rwbyte(&tmp); + Pname[k++]=tmp; + }; + Pname[k]='\0'; + }; + break; + case 0xE0: if (instrumentonly!=0) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + ctl.saveloadbuf(buf); + break; + case 0xE1: if (buf->getmode()!=0) {//PART INSERTION EFFECTS + for (unsigned char neffect=0;neffect<NUM_PART_EFX;neffect++){ + buf->rwbyte(&npar); + buf->rwbyte(&neffect); + partefx[neffect]->saveloadbuf(buf); + }; + } else { + unsigned char neffect; + buf->rwbyte(&neffect); + if (neffect<NUM_PART_EFX) partefx[neffect]->saveloadbuf(buf); + else buf->skipbranch(); + }; + break; + //Kit Parameters + case 0xE2: if (buf->getmode()!=0) {//save + if (Pkitmode==0) break; + for (unsigned char item=0;item<NUM_KIT_ITEMS;item++){ + if (kit[item].Penabled==0) continue; + buf->rwbyte(&npar); + buf->rwbyte(&item);//Write the item's number + saveloadbufkititem(buf,item,0); + }; + } else {//load + if (disablekitloading!=0) { + buf->skipbranch(); + break; + }; + unsigned char item; + buf->rwbyte(&item); + if (item<NUM_KIT_ITEMS){ + setkititemstatus(item,1); + saveloadbufkititem(buf,item,0); + } else buf->skipbranch(); + }; + break; + case 0xE3: if (buf->getmode()!=0) {//part insertion effect routing + for (unsigned char neffect=0;neffect<NUM_PART_EFX;neffect++){ + buf->rwbyte(&npar); + buf->rwbyte(&neffect); + buf->rwbyte(&Pefxroute[neffect]); + }; + } else { + unsigned char neffect; + buf->rwbyte(&neffect); + if (neffect<NUM_PART_EFX) buf->rwbyte(&Pefxroute[neffect]); + else buf->rwbyte(&neffect);//this line just throw away the byte + }; + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; + + kit[0].Padenabled=PADnoteenabled; + kit[0].Psubenabled=PSUBnoteenabled; + +}; + + + + diff --git a/src/Misc/Part.h b/src/Misc/Part.h @@ -0,0 +1,156 @@ +/* + ZynAddSubFX - a software synthesizer + + Part.h - Part implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef PART_H +#define PART_H + +#define MAX_INFO_TEXT_SIZE 1000 + +#include "../globals.h" +#include "../Params/ADnoteParameters.h" +#include "../Params/SUBnoteParameters.h" +#include "../Synth/ADnote.h" +#include "../Synth/SUBnote.h" +#include "../Params/Controller.h" +#include "../Misc/Microtonal.h" +#include "../DSP/FFTwrapper.h" +#include "../Effects/EffectMgr.h" + +class Part{ + + public: + Part(Microtonal *microtonal_,FFTwrapper *fft_,pthread_mutex_t *mutex_); + ~Part(); + + /* Midi commands implemented */ + void NoteOn(unsigned char note,unsigned char velocity,int masterkeyshift); + void NoteOff(unsigned char note); + void AllNotesOff();//panic + void SetController(unsigned int type,int par); + void RelaseSustainedKeys();//this is called when the sustain pedal is relased + void RelaseAllKeys();//this is called on AllNotesOff controller + + /* The synthesizer part output */ + void ComputePartSmps();//Part output + + void saveloadbuf(Buffer *buf,int instrumentonly); + //instrumentonly: 0 - save all, 1 - save only instrumnet, 2 - save only instrument without the name(used in bank) + + void saveloadbufkititem(Buffer *buf,unsigned char item,int saveitem0); + void swapcopyitem(int item1,int item2,int mode); + + void cleanup(); + + ADnoteParameters *ADPartParameters; + SUBnoteParameters *SUBPartParameters; + + //the part's kit + struct { + unsigned char Penabled,Pmuted,Pminkey,Pmaxkey; + unsigned char *Pname; + unsigned char Padenabled,Psubenabled; + unsigned char Psendtoparteffect; + ADnoteParameters *adpars; + SUBnoteParameters *subpars; + } kit[NUM_KIT_ITEMS]; + + + //Part parameters + void setkeylimit(unsigned char Pkeylimit); + void setkititemstatus(int kititem,int Penabled_); + + unsigned char Penabled;//if the part is enabled + unsigned char Pminkey;//the minimum key that the part receives noteon messages + unsigned char Pmaxkey;//the maximum key that the part receives noteon messages + unsigned char *Pname; //name of the instrument + unsigned char Pvolume;//part volume + void setPvolume(char Pvolume); + unsigned char Pkeyshift;//Part keyshift + unsigned char Prcvchn;//from what midi channel it receive commnads + unsigned char Ppanning;//part panning + void setPpanning(char Ppanning); + unsigned char Pvelsns;//velocity sensing (amplitude velocity scale) + unsigned char Pveloffs;//velocity offset + unsigned char PADnoteenabled;//if ADnote is enabled + unsigned char PSUBnoteenabled;//if SUBnote is enabled + unsigned char Pnoteon;//if the part receives NoteOn messages + unsigned char Pkitmode;//if the kitmode is enabled + unsigned char Pdrummode;//if all keys are mapped and the system is 12tET (used for drums) + + unsigned char Ppolymode;//Part mode - 0=monophonic , 1=polyphonic + unsigned char Pkeylimit;//how many keys are alowed to be played same time (0=off), the older will be relased + + struct{ + unsigned char Ptype; + unsigned char Pauthor[MAX_INFO_TEXT_SIZE+1]; + unsigned char Pcomments[MAX_INFO_TEXT_SIZE+1]; + } info; + + + REALTYPE *partoutl;//Left channel output of the part + REALTYPE *partoutr;//Right channel output of the part + + REALTYPE *partfxinputl[NUM_PART_EFX+1],*partfxinputr[NUM_PART_EFX+1];//Left and right signal that pass thru part effects; partfxinputl/r[NUM_PART_EFX] is for "no effect" buffer + + enum NoteStatus{KEY_OFF,KEY_PLAYING,KEY_RELASED_AND_SUSTAINED,KEY_RELASED}; + + REALTYPE volume,oldvolumel,oldvolumer;//this is applied by Master + REALTYPE panning;//this is applied by Master, too + + Controller ctl;//Part controllers + + EffectMgr *partefx[NUM_PART_EFX];//insertion part effects (they are part of the instrument) + unsigned char Pefxroute[NUM_PART_EFX];//how the effect's output is routed(to next effect/to out) + + pthread_mutex_t *mutex; + + int lastnote,disablekitloading; + + private: + void KillNotePos(int pos); + void RelaseNotePos(int pos); + int killallnotes;//is set to 1 if I want to kill all notes + + struct PartNotes{ + NoteStatus status; + int note;//if there is no note playing, the "note"=-1 + int itemsplaying; + struct { + ADnote *adnote; + SUBnote *subnote; + int sendtoparteffect; + } kititem[NUM_KIT_ITEMS]; + int time; + }; + + PartNotes partnote[POLIPHONY]; + + REALTYPE *tmpoutl;//used to get the note + REALTYPE *tmpoutr; + + REALTYPE oldfreq;//this is used for portamento + Microtonal *microtonal; + FFTwrapper *fft; +}; + +#endif + diff --git a/src/Misc/Util.C b/src/Misc/Util.C @@ -0,0 +1,299 @@ +/* + ZynAddSubFX - a software synthesizer + + Util.C - Miscellaneous functions + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Util.h" +#include <math.h> +#include <stdio.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> + +int SAMPLE_RATE=44100; +int SOUND_BUFFER_SIZE=256; +int OSCIL_SIZE=512; + +Buffer slbuf;//the Buffer used for save/load parameters to/from disk + +Buffer masterdefaultsbuf;//this is used to store all parameters at start of program and reload when I need to clear all data (eg. before loading master parameters) +Buffer instrumentdefaultsbuf;//this is used to store all instrument parameters at start of program and reload when I need to clear all data (eg. before loading instrument parameters) +Buffer clipboardbuf;//buffer used for the clipboard + +Config config; +REALTYPE *denormalkillbuf; + + +/* + * Transform the velocity according the scaling parameter (velocity sensing) + */ +REALTYPE VelF(REALTYPE velocity,unsigned char scaling){ + REALTYPE x; + x=pow(VELOCITY_MAX_SCALE,(64.0-scaling)/64.0); + if ((scaling==127)||(velocity>0.99)) return(1.0); + else return(pow(velocity,x)); +}; + +/* + * Get the detune in cents + */ +REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune){ + REALTYPE det=0.0,octdet=0.0,cdet=0.0,findet=0.0; + //Get Octave + int octave=coarsedetune/1024; + if (octave>=8) octave-=16; + octdet=octave*1200.0; + + //Coarse and fine detune + int cdetune=coarsedetune%1024; + if (cdetune>512) cdetune-=1024; + + int fdetune=finedetune-8192; + + switch (type){ +// case 1: is used for the default (see below) + case 2: cdet=fabs(cdetune*10.0); + findet=fabs(fdetune/8192.0)*10.0; + break; + case 3: cdet=fabs(cdetune*100); + findet=pow(10,fabs(fdetune/8192.0)*3.0)/10.0-0.1; + break; + case 4: cdet=fabs(cdetune*701.95500087);//perfect fifth + findet=(pow(2,fabs(fdetune/8192.0)*12.0)-1.0)/4095*1200; + break; + //case ...: need to update N_DETUNE_TYPES, if you'll add more + default:cdet=fabs(cdetune*50.0); + findet=fabs(fdetune/8192.0)*35.0;//almost like "Paul's Sound Designer 2" + break; + }; + if (finedetune<8192) findet=-findet; + if (cdetune<0) cdet=-cdet; + + det=octdet+cdet+findet; + return(det); +}; + + +/* + * Waveshape (this is called by OscilGen::waveshape and Distorsion::process) + */ + +void waveshapesmps(int n,REALTYPE *smps,unsigned char type,unsigned char drive){ + int i; + REALTYPE ws=drive/127.0; + REALTYPE tmpv; + + switch(type){ + case 1: ws=pow(10,ws*ws*3.0)-1.0+0.001;//Arctangent + for (i=0;i<n;i++) + smps[i]=atan(smps[i]*ws)/atan(ws); + break; + case 2: ws=ws*ws*32.0+0.0001;//Asymmetric + if (ws<1.0) tmpv=sin(ws)+0.1; + else tmpv=1.1; + for (i=0;i<n;i++) { + smps[i]=sin(smps[i]*(0.1+ws-ws*smps[i]))/tmpv; + }; + break; + case 3: ws=ws*ws*ws*20.0+0.0001;//Pow + for (i=0;i<n;i++) { + smps[i]*=ws; + if (fabs(smps[i])<1.0) { + smps[i]=(smps[i]-pow(smps[i],3.0))*3.0; + if (ws<1.0) smps[i]/=ws; + } else smps[i]=0.0; + }; + break; + case 4: ws=ws*ws*ws*32.0+0.0001;//Sine + if (ws<1.57) tmpv=sin(ws); + else tmpv=1.0; + for (i=0;i<n;i++) smps[i]=sin(smps[i]*ws)/tmpv; + break; + case 5: ws=ws*ws+0.000001;//Quantisize + for (i=0;i<n;i++) + smps[i]=floor(smps[i]/ws+0.5)*ws; + break; + case 6: ws=ws*ws*ws*32+0.0001;//Zigzag + if (ws<1.0) tmpv=sin(ws); + else tmpv=1.0; + for (i=0;i<n;i++) + smps[i]=asin(sin(smps[i]*ws))/tmpv; + break; + case 7: ws=pow(2.0,-ws*ws*8.0); //Limiter + for (i=0;i<n;i++) { + REALTYPE tmp=smps[i]; + if (fabs(tmp)>ws) { + if (tmp>=0.0) smps[i]=1.0; + else smps[i]=-1.0; + } else smps[i]/=ws; + }; + break; + case 8: ws=pow(2.0,-ws*ws*8.0); //Upper Limiter + for (i=0;i<n;i++) { + REALTYPE tmp=smps[i]; + if (tmp>ws) smps[i]=ws; + smps[i]*=2.0; + }; + break; + case 9: ws=pow(2.0,-ws*ws*8.0); //Lower Limiter + for (i=0;i<n;i++) { + REALTYPE tmp=smps[i]; + if (tmp<-ws) smps[i]=-ws; + smps[i]*=2.0; + }; + break; + case 10:ws=(pow(2.0,ws*6.0)-1.0)/pow(2.0,6.0); //Inverse Limiter + for (i=0;i<n;i++) { + REALTYPE tmp=smps[i]; + if (fabs(tmp)>ws) { + if (tmp>=0.0) smps[i]=tmp-ws; + else smps[i]=tmp+ws; + } else smps[i]=0; + }; + break; + case 11:ws=pow(5,ws*ws*1.0)-1.0;//Clip + for (i=0;i<n;i++) + smps[i]=smps[i]*(ws+0.5)*0.9999-floor(0.5+smps[i]*(ws+0.5)*0.9999); + break; + case 12:ws=ws*ws*ws*30+0.001;//Asym2 + if (ws<0.3) tmpv=ws; + else tmpv=1.0; + for (i=0;i<n;i++) { + REALTYPE tmp=smps[i]*ws; + if ((tmp>-2.0) && (tmp<1.0)) smps[i]=tmp*(1.0-tmp)*(tmp+2.0)/tmpv; + else smps[i]=0.0; + }; + break; + case 13:ws=ws*ws*ws*32.0+0.0001;//Pow2 + if (ws<1.0) tmpv=ws*(1+ws)/2.0; + else tmpv=1.0; + for (i=0;i<n;i++) { + REALTYPE tmp=smps[i]*ws; + if ((tmp>-1.0)&&(tmp<1.618034)) smps[i]=tmp*(1.0-tmp)/tmpv; + else if (tmp>0.0) smps[i]=-1.0; + else smps[i]=-2.0; + }; + break; + //update to Distorsion::changepar (Ptype max) if there is added more waveshapings functions + }; + +}; + + +/* + * Save buffer to file + */ +int savebufferfile(Buffer *buf,const char *filename,int overwrite,int whatIsave){ + unsigned char *data=NULL; + int n,file=0; + + n=buf->getsize(); + data=new unsigned char[n+1]; + buf->getalldata(n,data); + + if (overwrite==0) file=open(filename,O_CREAT|O_EXCL|O_WRONLY|O_BINARY,00444+00222); + else file=open(filename,O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,00444+00222);//overwrite if the file exists + if (file==-1) { + if (errno==EEXIST) return(1);//file exists already + else return(2);//Access Denied or any other problem + }; + + //Save the id. + char id[2]; id[0]='N';id[1]='P'; + write(file,&id,2); + + //Save the format descriptor (for future formats) + unsigned char type=whatIsave,//what the data represents? ( Master/Effect/Voice 0x00..0x0f) + coding=0;//the encoding (Raw, 7 bit encoding,compressed) (0x00..0x07) + unsigned char fmt=type+coding*0x10; //0x00..0x7f + write(file,&fmt,1); + + //Save the CRC or 0 for no CRC + unsigned CRC=0;//todo, if I do the CRC I do: crc=1+crc % 127;! + write (file,&CRC,1); + + //Save the data + int result=write(file,data,n); + if (result== -1) return(2); + close(file); + + delete (data); + return(0);//OK +}; + +/* + * Load the buffer from the file + */ +int loadbufferfile(Buffer *buf,const char *filename,int whatIload){ + int n=512,file=0,result,i; + unsigned char b=0; + unsigned char *data=new unsigned char[n]; + + buf->resetbuffer(); + buf->changemode(1); + + file=open(filename,O_RDONLY|O_BINARY,00444+00222); + + if (file==-1) { + return(2);//Access Denied or any other problem + }; + + //Load the id. + char id[2]; + read(file,&id,2); + if ((id[0]!='N')||(id[1]!='P')) { + close(file); + return(3);//invalid data + }; + + //Load the format descriptor + unsigned char fmt; //0x00..0x7f + read(file,&fmt,1); + unsigned char type=fmt%0x10; + if (type!=whatIload){ + close(file); + return(4);//the data is loaded as something wrong (eg. a master is loaded as a instrument) + }; +// coding=fmt/0x10; + + //load the crc + unsigned char CRC; //0x00..0x7f + read(file,&CRC,1); +// if (CRC!=0){};CHECK IF IT IS OK + + //Load the data + do { + result=read(file,data,n); + for (i=0;i<result;i++){ + b=data[i]; + buf->rwbyte(&b);//I need to write the data to a buffer and process it according to a format + }; + } while (result!=0); + + if (result== -1) return(2); + close(file); + delete(data); + return(0);//OK +}; + diff --git a/src/Misc/Util.h b/src/Misc/Util.h @@ -0,0 +1,64 @@ +/* + ZynAddSubFX - a software synthesizer + + Util.h - Miscellaneous functions + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef UTIL_H +#define UTIL_H + +#include <pthread.h> +#include "../globals.h" +#include "Buffer.h" +#include "Microtonal.h" +#include "Bank.h" +#include "../DSP/FFTwrapper.h" +#include "Config.h" + +//Velocity Sensing function +extern REALTYPE VelF(REALTYPE velocity,unsigned char scaling); + +//Buffer used for Save/Load +extern Buffer slbuf; + +//this is used to store all parameters at start of program and reload when I need to clear all data (eg. before loading master parameters) +extern Buffer masterdefaultsbuf; + +//this is used to store the default instrument settings (necessary when the instrument is cleared) +extern Buffer instrumentdefaultsbuf; + +//the buffer used as clipboard +extern Buffer clipboardbuf; + +extern int savebufferfile(Buffer *buf,const char *filename,int overwrite,int whatIsave); +extern int loadbufferfile(Buffer *buf,const char *filename,int whatIload); +//whatIsave and whatIload are 0 for Master,1 Voice,2 for Microtonal... + +//Waveshaping(called by Distorsion effect and waveshape from OscilGen) +void waveshapesmps(int n,REALTYPE *smps,unsigned char type,unsigned char drive); + +#define N_DETUNE_TYPES 4 //the number of detune types +extern REALTYPE getdetune(unsigned char type,unsigned short int coarsedetune,unsigned short int finedetune); + +extern REALTYPE *denormalkillbuf;//the buffer to add noise in order to avoid denormalisation + +extern Config config; + +#endif + diff --git a/src/Output/JACKaudiooutput.C b/src/Output/JACKaudiooutput.C @@ -0,0 +1,98 @@ +/* + ZynAddSubFX - a software synthesizer + + JACKaudiooutput.C - Audio output for JACK + Copyright (C) 2002 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "JACKaudiooutput.h" + +Master *jackmaster; +jack_client_t *jackclient; +jack_port_t *outport_left,*outport_right; + +int jackprocess(jack_nframes_t nframes,void *arg); +int jacksrate(jack_nframes_t nframes,void *arg); +void jackshutdown(void *arg); + +void JACKaudiooutputinit(Master *master_){ + jackmaster=master_; + jackclient=0; + char tmpstr[100]; + + for (int i=0;i<15;i++){ + if (i!=0) snprintf(tmpstr,100,"ZynAddSubFX_%d",i); + else snprintf(tmpstr,100,"ZynAddSubFX"); + jackclient=jack_client_new(tmpstr); + if (jackclient!=0) break; + }; + + if (jackclient==0) { + fprintf(stderr,"\nERROR: Cannot make a jack client (possible reasons: JACK server is not running or jackd is launched by root and zynaddsubfx by another user.).\n\n\n"); + exit(1); + }; + + fprintf(stderr,"Internal SampleRate = %d\nJack Output SampleRate= %d\n",SAMPLE_RATE,jack_get_sample_rate(jackclient)); + if ((unsigned int)jack_get_sample_rate(jackclient)!=(unsigned int) SAMPLE_RATE) + fprintf(stderr,"It is recomanded that the both samplerates to be equal.\n"); + + jack_set_process_callback(jackclient,jackprocess,0); + jack_set_sample_rate_callback(jackclient,jacksrate,0); + jack_on_shutdown(jackclient,jackshutdown,0); + + outport_left=jack_port_register(jackclient,"out_1", + JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput|JackPortIsTerminal,0); + outport_right=jack_port_register(jackclient,"out_2", + JACK_DEFAULT_AUDIO_TYPE,JackPortIsOutput|JackPortIsTerminal,0); + + if (jack_activate(jackclient)){ + fprintf(stderr,"Cannot activate jack client\n"); + exit(1); + }; + + /* + jack_connect(jackclient,jack_port_name(outport_left),"alsa_pcm:out_1"); + jack_connect(jackclient,jack_port_name(outport_right),"alsa_pcm:out_2"); + */ +}; + +int jackprocess(jack_nframes_t nframes,void *arg){ + jack_default_audio_sample_t *outl=(jack_default_audio_sample_t *) jack_port_get_buffer (outport_left, nframes); + jack_default_audio_sample_t *outr=(jack_default_audio_sample_t *) jack_port_get_buffer (outport_right, nframes); + + pthread_mutex_lock(&jackmaster->mutex); + jackmaster->GetAudioOutSamples(nframes,jack_get_sample_rate(jackclient),outl,outr); + pthread_mutex_unlock(&jackmaster->mutex); + + return(0); +}; + +void JACKfinish(){ + jack_client_close(jackclient); +}; + +int jacksrate(jack_nframes_t nframes,void *arg){ + + return(0); +}; + +void jackshutdown(void *arg){ +}; + + + diff --git a/src/Output/JACKaudiooutput.h b/src/Output/JACKaudiooutput.h @@ -0,0 +1,44 @@ +/* + ZynAddSubFX - a software synthesizer + + JACKaudiooutput.h - Audio output for JACK + Copyright (C) 2002 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef JACK_AUDIO_OUTPUT_H +#define JACK_AUDIO_OUTPUT_H + +#include <jack/jack.h> +#include "../globals.h" +#include "../Misc/Master.h" + + +#if (REALTYPE!=jack_default_audio_sample_t) +#error "The internal sample datatype of ZynAddSubFX and the datatype of jack differs.\ + In order to compile ZynAddSubFX the 'REALTYPE' and 'jack_default_audio_sample_t' must be equal.\ + Set the 'REALTYPE' data type (which is defined in 'globals.h') to what is defined \ + in the file types.h from jack include directory as 'jack_default_audio_sample_t' (as float or double)." +#endif + + + + +void JACKaudiooutputinit(Master *master_); +void JACKfinish(); + +#endif + diff --git a/src/Output/Makefile b/src/Output/Makefile @@ -0,0 +1,30 @@ +include ../Makefile.inc + +objects=Recorder.o + +ifeq ($(AUDIOOUT),JACK) +objects+=JACKaudiooutput.o +endif + +ifeq ($(AUDIOOUT),PA) +objects+=PAaudiooutput.o +endif + +ifeq ($(AUDIOOUT),OSS) +objects+=OSSaudiooutput.o +endif + +ifeq ($(AUDIOOUT),VST) +objects+=VSTaudiooutput.o +endif + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Output/OSSaudiooutput.C b/src/Output/OSSaudiooutput.C @@ -0,0 +1,86 @@ +/* + ZynAddSubFX - a software synthesizer + + OSSaudiooutput.C - Audio output for Open Sound System + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <sys/soundcard.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include "OSSaudiooutput.h" +#include "../Misc/Util.h" + +OSSaudiooutput::OSSaudiooutput(){ + int i; + int snd_bitsize=16; + snd_fragment=0x00080009;//fragment size (?) + snd_stereo=1;//stereo + snd_format=AFMT_S16_LE; + snd_samplerate=SAMPLE_RATE; + + smps=new short int[SOUND_BUFFER_SIZE*2]; + for (i=0;i<SOUND_BUFFER_SIZE*2;i++) smps[i]=0; + + snd_handle=open(config.cfg.LinuxOSSWaveOutDev,O_WRONLY,0); + if (snd_handle == -1) { + fprintf(stderr,"ERROR - I can't open the %s .\n",config.cfg.LinuxOSSWaveOutDev); + return; + }; + ioctl(snd_handle,SNDCTL_DSP_RESET,NULL); + + ioctl(snd_handle,SNDCTL_DSP_SETFMT,&snd_format); + ioctl(snd_handle,SNDCTL_DSP_STEREO,&snd_stereo); + ioctl(snd_handle,SNDCTL_DSP_SPEED,&snd_samplerate); + ioctl(snd_handle,SNDCTL_DSP_SAMPLESIZE,&snd_bitsize); + ioctl(snd_handle,SNDCTL_DSP_SETFRAGMENT,&snd_fragment); + +}; + + +/* + * Output the samples to the soundcard + * The samples are bigger than -1.0 and smaller 1.0 + */ +void OSSaudiooutput::OSSout(REALTYPE *smp_left,REALTYPE *smp_right){ + int i; + REALTYPE l,r; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + l=smp_left[i]; + r=smp_right[i]; + + if (l<-1.0) l=-1.0; else if (l>1.0) l=1.0; + if (r<-1.0) r=-1.0; else if (r>1.0) r=1.0; + + smps[i*2]=(short int) (l*32767.0); + smps[i*2+1]=(short int) (r*32767.0); + }; + write(snd_handle,smps,SOUND_BUFFER_SIZE*4);// *2 because is 16 bit, again * 2 because is stereo +}; + + +OSSaudiooutput::~OSSaudiooutput(){ + close(snd_handle); + delete [] smps; +}; + diff --git a/src/Output/OSSaudiooutput.h b/src/Output/OSSaudiooutput.h @@ -0,0 +1,48 @@ +/* + ZynAddSubFX - a software synthesizer + + OSSaudiooutput.h - Audio output for Open Sound System + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef OSS_AUDIO_OUTPUT_H +#define OSS_AUDIO_OUTPUT_H + + +#include <sys/soundcard.h> +#include "../globals.h" +class OSSaudiooutput{ + public: + OSSaudiooutput(); + ~OSSaudiooutput(); + + //the out is [-1.0 .. 1.0] + /* smp_left[] and smp_right[] has the size of SOUND_BUFFER_SIZE */ + void OSSout(REALTYPE *smp_left,REALTYPE *smp_right); + private: + int snd_handle; + int snd_fragment; + int snd_stereo; + int snd_format; + int snd_samplerate; + + short int *smps;//Samples to be sent to soundcard +}; + +#endif + diff --git a/src/Output/PAaudiooutput.C b/src/Output/PAaudiooutput.C @@ -0,0 +1,70 @@ +/* + ZynAddSubFX - a software synthesizer + + PAaudiooutput.C - Audio output for PortAudio + Copyright (C) 2002 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "PAaudiooutput.h" + +Master *PAmaster; +PaStream *stream; +REALTYPE *outl,*outr; + +int PAprocess(void *inputBuffer,void *outputBuffer, + unsigned long framesPerBuffer, + PaTimestamp outTime,void *userData){ + + if (framesPerBuffer!=SOUND_BUFFER_SIZE) { + fprintf(stderr,"Bug: PAudioOutput::PAprocess SOUND_BUFFER_SIZE!=framesPerBuffer"); + fprintf(stderr,"%d %d\n",framesPerBuffer,SOUND_BUFFER_SIZE); + }; + + pthread_mutex_lock(&PAmaster->mutex); + PAmaster->GetAudioOutSamples(SOUND_BUFFER_SIZE,SAMPLE_RATE,outl,outr); + pthread_mutex_unlock(&PAmaster->mutex); + + float *out=(float *)outputBuffer; + + for (int i=0;i<framesPerBuffer;i++){ + if (i>=SOUND_BUFFER_SIZE) break;//this should never happens, except only when framesPerBuffer!>SOUND_BUFFER_SIZE + out[i*2]=outl[i]; + out[i*2+1]=outr[i]; + }; + + return(0); +}; + +void PAaudiooutputinit(Master *master_){ + PAmaster=master_; + outl=new REALTYPE [SOUND_BUFFER_SIZE]; + outr=new REALTYPE [SOUND_BUFFER_SIZE]; + Pa_Initialize(); + Pa_OpenDefaultStream(&stream,0,2,paFloat32,SAMPLE_RATE,SOUND_BUFFER_SIZE,0,PAprocess,NULL); + Pa_StartStream(stream); +}; + +void PAfinish(){ + Pa_StopStream(stream); + delete (outl); + delete (outr); +}; + + + + diff --git a/src/Output/PAaudiooutput.h b/src/Output/PAaudiooutput.h @@ -0,0 +1,34 @@ +/* + ZynAddSubFX - a software synthesizer + + PAaudiooutput.h - Audio output for PortAudio + Copyright (C) 2002 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef PA_AUDIO_OUTPUT_H +#define PA_AUDIO_OUTPUT_H + +#include <portaudio.h> + +#include "../globals.h" +#include "../Misc/Master.h" + +void PAaudiooutputinit(Master *master_); +void PAfinish(); + +#endif + diff --git a/src/Output/Recorder.C b/src/Output/Recorder.C @@ -0,0 +1,138 @@ +/* + ZynAddSubFX - a software synthesizer + + Recorder.C - Records sound to a file + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "Recorder.h" + +Recorder::Recorder(){ + recordbuf_16bit=new short int [SOUND_BUFFER_SIZE*2]; + status=0;file=-1; + sampleswritten=0; + notetrigger=0; + for (int i=0;i<SOUND_BUFFER_SIZE*2;i++){ + recordbuf_16bit[i]=0; + }; +}; + +Recorder::~Recorder(){ + if (recording()==1) stop(); + delete [] recordbuf_16bit; +}; + +int Recorder::preparefile(char *filename_,int overwrite){ + if (overwrite==0) file=open(filename_,O_CREAT|O_EXCL|O_WRONLY|O_BINARY,00444+00222); + else file=open(filename_,O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,00444+00222);//overwrite if the file exists + if (file==-1) { + if (errno==EEXIST) return(1);//file exists already + else return(2);//Access Denied or any other problem + }; + status=1;//ready + + //prepare the space fot the wav header + //the header itself, will be written when the file is closed + unsigned char zerobuf[44]; for (int i=0;i<44;i++) zerobuf[i]=0; + write(file,zerobuf,44); + + return(0); +}; + +void Recorder::start(){ + notetrigger=0; + status=2;//recording +}; + +void Recorder::stop(){ + unsigned int chunksize; + lseek(file,0,SEEK_SET); + + write(file,"RIFF",4); + chunksize=sampleswritten*4+36; + write(file,&chunksize,4); + + write(file,"WAVEfmt ",8); + chunksize=16; + write(file,&chunksize,4); + unsigned short int formattag=1;//uncompresed wave + write(file,&formattag,2); + unsigned short int nchannels=2;//stereo + write(file,&nchannels,2); + unsigned int samplerate=SAMPLE_RATE;//samplerate + write(file,&samplerate,4); + unsigned int bytespersec=SAMPLE_RATE*4;//bytes/sec + write(file,&bytespersec,4); + unsigned short int blockalign=4;//2 channels * 16 bits/8 + write(file,&blockalign,2); + unsigned short int bitspersample=16; + write(file,&bitspersample,2); + + write(file,"data",4); + chunksize=sampleswritten*blockalign; + write(file,&chunksize,4); + + close(file); + file=-1; + status=0; + sampleswritten=0; +}; + +void Recorder::pause(){ + status=0; +}; + +int Recorder::recording(){ + if ((status==2)&&(notetrigger!=0)) return(1); + else return(0); +}; + +void Recorder::recordbuffer(REALTYPE *outl,REALTYPE *outr){ + int tmp; + if (status!=2) return; + for (int i=0;i<SOUND_BUFFER_SIZE;i++){ + tmp=(int)(outl[i]*32767.0); + if (tmp<-32768) tmp=-32768; + if (tmp>32767) tmp=32767; + recordbuf_16bit[i*2]=tmp; + + tmp=(int)(outr[i]*32767.0); + if (tmp<-32768) tmp=-32768; + if (tmp>32767) tmp=32767; + recordbuf_16bit[i*2+1]=tmp; + }; + if (write(file,recordbuf_16bit,SOUND_BUFFER_SIZE*4)<SOUND_BUFFER_SIZE*4) { + fprintf(stderr,"Error while recording !\n"); + stop(); + }; + sampleswritten+=SOUND_BUFFER_SIZE; +}; + +void Recorder::triggernow(){ + if (status==2) notetrigger=1; +}; diff --git a/src/Output/Recorder.h b/src/Output/Recorder.h @@ -0,0 +1,52 @@ +/* + ZynAddSubFX - a software synthesizer + + Recorder.h - Records sound to a file + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef RECORDER_H +#define RECORDER_H + +#include "../globals.h" + +class Recorder{ + public: + Recorder(); + ~Recorder(); + int preparefile(char *filename_,int overwrite);//returns 1 if the file exists + void start(); + void stop(); + void pause(); + int recording(); + void triggernow(); + void recordbuffer(REALTYPE *outl,REALTYPE *outr); + + /* Status: + 0 - not ready(no file selected), + 1 - ready + 2 - recording */ + int status; + + private: + int file; + short int *recordbuf_16bit; + int sampleswritten,notetrigger; +}; + +#endif diff --git a/src/Output/VSTaudiooutput.C b/src/Output/VSTaudiooutput.C @@ -0,0 +1,54 @@ +/* + ZynAddSubFX - a software synthesizer + + VSTaudiooutput.C - Audio output for VST + Copyright (C) 2002 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#include <string.h> +#include "VSTaudiooutput.h" + +//the constructor and the destructor are defined in main.C + +void VSTSynth::process (float **inputs, float **outputs, long sampleframes){ + float *outl=inputs[0]; + float *outr=inputs[1]; + pthread_mutex_lock(&vmaster->mutex); + vmaster->GetAudioOutSamples(sampleframes,(int) getSampleRate(),outl,outr); + pthread_mutex_unlock(&vmaster->mutex); +}; + +void VSTSynth::processReplacing (float **inputs, float **outputs, long sampleframes){ + process(inputs,outputs,sampleframes); +}; + +long int VSTSynth::canDo(char *txt){ + if (strcmp(txt,"receiveVstEvents")!=0) return (1); + if (strcmp(txt,"receiveVstMidiEvent")!=0) return (1); + return(-1); +}; + +bool VSTSynth::getVendorString(char *txt){ + strcpy(txt,"Nasca O. Paul"); + return(true); +}; + +bool VSTSynth::getProductString(char *txt){ + strcpy(txt,"ZynAddSubFX"); + return(true); +}; + diff --git a/src/Output/VSTaudiooutput.h b/src/Output/VSTaudiooutput.h @@ -0,0 +1,54 @@ +/* + ZynAddSubFX - a software synthesizer + + VSTaudiooutput.h - Audio output for VST + Copyright (C) 2002 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef VST_AUDIO_OUTPUT_H +#define VST_AUDIO_OUTPUT_H + +#include <pthread.h> + +#include "../globals.h" +#include "../Misc/Master.h" +#include "../UI/MasterUI.h" + +#include "../../../vstsdk2/source/common/audioeffectx.h" + +class VSTSynth:public AudioEffectX{ + public: + VSTSynth (audioMasterCallback audioMaster); + ~VSTSynth(); + + virtual void process (float **inputs, float **outputs, long sampleframes); + virtual void processReplacing (float **inputs, float **outputs, long sampleframes); + virtual long processEvents(VstEvents *events);//this is used for Midi input + virtual long int canDo(char *txt); + virtual bool getVendorString(char *txt); + virtual bool getProductString(char *txt); + + MasterUI *ui; + int Pexitprogram; + + protected: + Master *vmaster; + pthread_t thr; +}; + +#endif + diff --git a/src/Params/ADnoteParameters.C b/src/Params/ADnoteParameters.C @@ -0,0 +1,482 @@ +/* + ZynAddSubFX - a software synthesizer + + ADnoteParameters.C - Parameters for ADnote (ADsynth) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "ADnoteParameters.h" + +ADnoteParameters::ADnoteParameters(FFTwrapper *fft_){ + int nvoice; + fft=fft_; + //Default Parameters + /* Frequency Global Parameters */ + GlobalPar.PStereo=1;//stereo + GlobalPar.PDetune=8192;//zero + GlobalPar.PCoarseDetune=0; + GlobalPar.PDetuneType=1; + GlobalPar.FreqEnvelope=new EnvelopeParams(0,0); + GlobalPar.FreqEnvelope->ASRinit(64,50,64,60); + GlobalPar.FreqLfo=new LFOParams(70,0,64,0,0,0,0,0); + + /* Amplitude Global Parameters */ + GlobalPar.PVolume=90; + GlobalPar.PPanning=64;//center + GlobalPar.PAmpVelocityScaleFunction=64; + GlobalPar.AmpEnvelope=new EnvelopeParams(64,1); + GlobalPar.AmpEnvelope->ADSRinit_dB(0,40,127,25); + GlobalPar.AmpLfo=new LFOParams(80,0,64,0,0,0,0,1); + GlobalPar.PPunchStrength=0; + GlobalPar.PPunchTime=60; + GlobalPar.PPunchStretch=64; + GlobalPar.PPunchVelocitySensing=72; + + /* Filter Global Parameters*/ + GlobalPar.PFilterVelocityScale=64; + GlobalPar.PFilterVelocityScaleFunction=64; + GlobalPar.GlobalFilter=new FilterParams(2,94,40); + GlobalPar.FilterEnvelope=new EnvelopeParams(0,1); + GlobalPar.FilterEnvelope->ADSRinit_filter(64,40,64,70,60,64); + GlobalPar.FilterLfo=new LFOParams(80,0,64,0,0,0,0,2); + GlobalPar.Reson=new Resonance(); + + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + VoicePar[nvoice].Enabled=0; + VoicePar[nvoice].Type=0; + VoicePar[nvoice].Pfixedfreq=0; + VoicePar[nvoice].PfixedfreqET=0; + VoicePar[nvoice].Presonance=1; + VoicePar[nvoice].Pfilterbypass=0; + VoicePar[nvoice].Pextoscil=-1; + VoicePar[nvoice].PextFMoscil=-1; + VoicePar[nvoice].Poscilphase=64; + VoicePar[nvoice].PFMoscilphase=64; + VoicePar[nvoice].PDelay=0; + VoicePar[nvoice].PVolume=100; + VoicePar[nvoice].PVolumeminus=0; + VoicePar[nvoice].PPanning=64;//center + VoicePar[nvoice].PDetune=8192;//8192=0 + VoicePar[nvoice].PCoarseDetune=0; + VoicePar[nvoice].PDetuneType=0; + VoicePar[nvoice].PFreqLfoEnabled=0; + VoicePar[nvoice].PFreqEnvelopeEnabled=0; + VoicePar[nvoice].PAmpEnvelopeEnabled=0; + VoicePar[nvoice].PAmpLfoEnabled=0; + VoicePar[nvoice].PAmpVelocityScaleFunction=127; + VoicePar[nvoice].PFilterEnabled=0; + VoicePar[nvoice].PFilterEnvelopeEnabled=0; + VoicePar[nvoice].PFilterLfoEnabled=0; + VoicePar[nvoice].PFMEnabled=0; + + //I use the internal oscillator intern (-1) + VoicePar[nvoice].PFMVoice=-1; + + VoicePar[nvoice].PFMVolume=90; + VoicePar[nvoice].PFMVolumeDamp=64; + VoicePar[nvoice].PFMDetune=8192; + VoicePar[nvoice].PFMCoarseDetune=0; + VoicePar[nvoice].PFMDetuneType=0; + VoicePar[nvoice].PFMFreqEnvelopeEnabled=0; + VoicePar[nvoice].PFMAmpEnvelopeEnabled=0; + VoicePar[nvoice].PFMVelocityScaleFunction=64; + + EnableVoice(nvoice); + }; + VoicePar[0].Enabled=1; +}; + +/* + * Init the voice parameters + */ +void ADnoteParameters::EnableVoice(int nvoice){ + VoicePar[nvoice].OscilSmp=new OscilGen(fft,GlobalPar.Reson); + VoicePar[nvoice].FMSmp=new OscilGen(fft,NULL); + VoicePar[nvoice].OscilSmp->prepare(); + VoicePar[nvoice].FMSmp->prepare(); + + VoicePar[nvoice].AmpEnvelope=new EnvelopeParams(64,1); + VoicePar[nvoice].AmpEnvelope->ADSRinit_dB(0,100,127,100); + VoicePar[nvoice].AmpLfo=new LFOParams(90,32,64,0,0,30,0,1); + + VoicePar[nvoice].FreqEnvelope=new EnvelopeParams(0,0); + VoicePar[nvoice].FreqEnvelope->ASRinit(30,40,64,60); + VoicePar[nvoice].FreqLfo=new LFOParams(50,40,0,0,0,0,0,0); + + VoicePar[nvoice].VoiceFilter=new FilterParams(2,50,60); + VoicePar[nvoice].FilterEnvelope=new EnvelopeParams(0,0); + VoicePar[nvoice].FilterEnvelope->ADSRinit_filter(90,70,40,70,10,40); + VoicePar[nvoice].FilterLfo=new LFOParams(50,20,64,0,0,0,0,2); + + VoicePar[nvoice].FMFreqEnvelope=new EnvelopeParams(0,0); + VoicePar[nvoice].FMFreqEnvelope->ASRinit(20,90,40,80); + VoicePar[nvoice].FMAmpEnvelope=new EnvelopeParams(64,1); + VoicePar[nvoice].FMAmpEnvelope->ADSRinit(80,90,127,100); +}; + + +/* + * Kill the voice + */ +void ADnoteParameters::KillVoice(int nvoice){ + delete (VoicePar[nvoice].OscilSmp); + delete (VoicePar[nvoice].FMSmp); + + delete (VoicePar[nvoice].AmpEnvelope); + delete (VoicePar[nvoice].AmpLfo); + + delete (VoicePar[nvoice].FreqEnvelope); + delete (VoicePar[nvoice].FreqLfo); + + delete (VoicePar[nvoice].VoiceFilter); + delete (VoicePar[nvoice].FilterEnvelope); + delete (VoicePar[nvoice].FilterLfo); + + delete (VoicePar[nvoice].FMFreqEnvelope); + delete (VoicePar[nvoice].FMAmpEnvelope); +}; + +ADnoteParameters::~ADnoteParameters(){ + delete(GlobalPar.FreqEnvelope); + delete(GlobalPar.FreqLfo); + delete(GlobalPar.AmpEnvelope); + delete(GlobalPar.AmpLfo); + delete(GlobalPar.GlobalFilter); + delete(GlobalPar.FilterEnvelope); + delete(GlobalPar.FilterLfo); + delete(GlobalPar.Reson); + + for (int nvoice=0;nvoice<NUM_VOICES;nvoice++){ + KillVoice(nvoice); + }; +}; + +void ADnoteParameters::copypastevoice(int n,int what){ + if (what==0){//copy + clipboardbuf.changemode(1);//write to buffer + clipboardbuf.changeminimal(0); + saveloadbufvoice(&clipboardbuf,n); + } else {//paste + clipboardbuf.changemode(0);//read from buffer + saveloadbufvoice(&clipboardbuf,n); + }; +}; + +/* + * Save or load the voice parameters to/from the buffer + */ +void ADnoteParameters::saveloadbufvoice(Buffer *buf,unsigned char nvoice){ + unsigned char npar,n,tmp; + int fmon,min,fmexton;//fmon is 0 if there is no need to save the FM parameters + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n\n( ADnoteParameters VOICE %d) \n",nvoice); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + if (nvoice>=NUM_VOICES){//too big voice + buf->skipbranch(); + return; + }; + + if ((buf->getminimal()!=0) && (buf->getmode()!=0)) min=1; else min=0; + if (min && (VoicePar[nvoice].PFMEnabled==0)) fmon=1; else fmon=0; + if (min && (VoicePar[nvoice].PFMVoice!= -1)) fmexton=1; else fmexton=0; + + for (n=0x80;n<0xF0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Misc Voice Parameters + case 0x80: buf->rwbytepar(n,&VoicePar[nvoice].Enabled); + break; + case 0x81: buf->rwbytepar(n,&VoicePar[nvoice].PDelay); + break; + case 0x82: buf->rwbytepar(n,&VoicePar[nvoice].PPanning); + break; + case 0x83: buf->rwbytepar(n,&VoicePar[nvoice].Poscilphase); + break; + case 0x84: buf->rwwordparwrap(n,&VoicePar[nvoice].Pextoscil); + if (VoicePar[nvoice].Pextoscil>nvoice-1) VoicePar[nvoice].Pextoscil=-1; + break; + case 0x85: if ((VoicePar[nvoice].Pextoscil!= -1) && (min)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].OscilSmp->saveloadbuf(buf); + break; + case 0x86: buf->rwbytepar(n,&VoicePar[nvoice].Presonance); + break; + case 0x87: buf->rwbytepar(n,&VoicePar[nvoice].Type); + break; + //Amplitude Global Parameters + case 0x90: buf->rwbytepar(n,&VoicePar[nvoice].PVolume); + break; + case 0x91: buf->rwbytepar(n,&VoicePar[nvoice].PAmpVelocityScaleFunction); + break; + case 0x92: buf->rwbytepar(n,&VoicePar[nvoice].PAmpEnvelopeEnabled); + break; + case 0x93: buf->rwbytepar(n,&VoicePar[nvoice].PAmpLfoEnabled); + break; + case 0x94: buf->rwbytepar(n,&VoicePar[nvoice].PVolumeminus); + break; + case 0x98: if ((min) && (VoicePar[nvoice].PAmpLfoEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].AmpLfo->saveloadbuf(buf); + break; + case 0x99: if ((min) && (VoicePar[nvoice].PAmpEnvelopeEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].AmpEnvelope->saveloadbuf(buf); + break; + + + //Frequency Voice Parameters + case 0xA0: buf->rwwordpar(n,&VoicePar[nvoice].PDetune); + break; + case 0xA1: buf->rwwordpar(n,&VoicePar[nvoice].PCoarseDetune); + break; + case 0xA2: buf->rwbytepar(n,&VoicePar[nvoice].PFreqEnvelopeEnabled); + break; + case 0xA3: buf->rwbytepar(n,&VoicePar[nvoice].PFreqLfoEnabled); + break; + case 0xA4: buf->rwbytepar(n,&VoicePar[nvoice].PDetuneType); + break; + case 0xA5: buf->rwbytepar(n,&VoicePar[nvoice].Pfixedfreq); + break; + case 0xA6: buf->rwbytepar(n,&VoicePar[nvoice].PfixedfreqET); + break; + case 0xA8: if ((min) && (VoicePar[nvoice].PFreqLfoEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FreqLfo->saveloadbuf(buf); + break; + case 0xA9: if ((min) && (VoicePar[nvoice].PFreqEnvelopeEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FreqEnvelope->saveloadbuf(buf); + break; + + //Filter Voice Parameters + case 0xB0: buf->rwbytepar(n,&VoicePar[nvoice].PFilterEnabled); + break; + case 0xB1: buf->rwbytepar(n,&VoicePar[nvoice].PFilterEnvelopeEnabled); + break; + case 0xB2: buf->rwbytepar(n,&VoicePar[nvoice].PFilterLfoEnabled); + break; + case 0xB3: buf->rwbytepar(n,&VoicePar[nvoice].Pfilterbypass); + break; + case 0xB8: if ((min) && (VoicePar[nvoice].PFilterEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].VoiceFilter->saveloadbuf(buf); + break; + case 0xB9: if ((min) && ((VoicePar[nvoice].PFilterEnabled==0) || (VoicePar[nvoice].PFilterLfoEnabled==0))) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FilterLfo->saveloadbuf(buf); + break; + case 0xBA: if ((min) && ((VoicePar[nvoice].PFilterEnabled==0) || (VoicePar[nvoice].PFilterEnvelopeEnabled==0))) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FilterEnvelope->saveloadbuf(buf); + break; + + //FM Voice Parameters + case 0xC0: buf->rwbytepar(n,&VoicePar[nvoice].PFMEnabled); + break; + case 0xC1: if (fmon) break; + buf->rwwordparwrap(n,&VoicePar[nvoice].PFMVoice); + if (VoicePar[nvoice].PFMVoice>nvoice-1) VoicePar[nvoice].PFMVoice=-1; + break; + case 0xC2: if ((fmon)||(fmexton)) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMoscilphase); + break; + case 0xC3: if (fmon) break; + buf->rwwordparwrap(n,&VoicePar[nvoice].PextFMoscil); + if (VoicePar[nvoice].PextFMoscil>nvoice-1) VoicePar[nvoice].PextFMoscil=-1; + break; + case 0xC4: if (fmon) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMVolume); + break; + case 0xC5: if (fmon) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMVolumeDamp); + break; + case 0xC6: if (fmon) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMVelocityScaleFunction); + break; + case 0xC7: if ((fmon)||(fmexton)) break; + buf->rwwordpar(n,&VoicePar[nvoice].PFMDetune); + break; + case 0xC8: if ((fmon)||(fmexton)) break; + buf->rwwordpar(n,&VoicePar[nvoice].PFMCoarseDetune); + break; + case 0xC9: if (fmon) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMAmpEnvelopeEnabled); + break; + case 0xCA: if ((fmon)||(fmexton)) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMFreqEnvelopeEnabled); + break; + case 0xCB: if (fmon) break; + buf->rwbytepar(n,&VoicePar[nvoice].PFMDetuneType); + break; + case 0xD0: if ((fmon) || (fmexton)) break; + if ((VoicePar[nvoice].PextFMoscil!= -1) && (min)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FMSmp->saveloadbuf(buf); + break; + case 0xD1: if (fmon) break; + if ((VoicePar[nvoice].PFMAmpEnvelopeEnabled==0) && (min)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FMAmpEnvelope->saveloadbuf(buf); + break; + case 0xD2: if ((fmon)||(fmexton)) break; + if ((VoicePar[nvoice].PFMFreqEnvelopeEnabled==0) && (min)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + VoicePar[nvoice].FMFreqEnvelope->saveloadbuf(buf); + break; + + }; + }; + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; + +}; + +/* + * Save or load the parameters to/from the buffer + */ +void ADnoteParameters::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( ADnoteParameters Global) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + if (buf->getmode()==0){ + for (unsigned int nvoice=0;nvoice<NUM_VOICES;nvoice++){ + VoicePar[nvoice].Enabled=0; + }; + }; + + for (n=0x80;n<0xF0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Misc Global Parameters + case 0x80: buf->rwbytepar(n,&GlobalPar.PStereo); + break; + case 0x81: buf->rwbytepar(n,&GlobalPar.PPanning); + break; + case 0x82: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.Reson->saveloadbuf(buf); + break; + //Amplitude Global Parameters + case 0x90: buf->rwbytepar(n,&GlobalPar.PVolume); + break; + case 0x91: buf->rwbytepar(n,&GlobalPar.PAmpVelocityScaleFunction); + break; + case 0x92: buf->rwbytepar(n,&GlobalPar.PPunchStrength); + case 0x93: buf->rwbytepar(n,&GlobalPar.PPunchTime); + case 0x94: buf->rwbytepar(n,&GlobalPar.PPunchStretch); + case 0x95: buf->rwbytepar(n,&GlobalPar.PPunchVelocitySensing); + case 0x98: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.AmpLfo->saveloadbuf(buf); + break; + case 0x99: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.AmpEnvelope->saveloadbuf(buf); + break; + + + //Frequency Global Parameters + case 0xA0: buf->rwwordpar(n,&GlobalPar.PDetune); + break; + case 0xA1: buf->rwwordpar(n,&GlobalPar.PCoarseDetune); + break; + case 0xA2: buf->rwbytepar(n,&GlobalPar.PDetuneType); + break; + case 0xA8: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.FreqLfo->saveloadbuf(buf); + break; + case 0xA9: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.FreqEnvelope->saveloadbuf(buf); + break; + + + //Filter Global Parameters + case 0xB0: buf->rwbytepar(n,&GlobalPar.PFilterVelocityScale); + break; + case 0xB1: buf->rwbytepar(n,&GlobalPar.PFilterVelocityScaleFunction); + break; + case 0xB8: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.GlobalFilter->saveloadbuf(buf); + break; + case 0xB9: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.FilterLfo->saveloadbuf(buf); + break; + case 0xBA: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalPar.FilterEnvelope->saveloadbuf(buf); + break; + + //Voices Parameters + case 0xC0: if (buf->getmode()!=0) { + for (unsigned char nvoice=0;nvoice<NUM_VOICES;nvoice++){ + int mustbesaved=0; + for (int i=0;i<NUM_VOICES;i++){ + if ((VoicePar[i].Pextoscil!=1)||(VoicePar[i].PextFMoscil!=1)) + mustbesaved=1; + }; + if ((buf->getminimal()!=0) && (VoicePar[nvoice].Enabled==0) && + (mustbesaved!=0)) continue; + buf->rwbyte(&npar); + buf->rwbyte(&nvoice);//Write the number of voice + saveloadbufvoice(buf,nvoice); + }; + } else { + unsigned char nvoice; + buf->rwbyte(&nvoice); + saveloadbufvoice(buf,nvoice); + }; + break; + + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + + + diff --git a/src/Params/ADnoteParameters.h b/src/Params/ADnoteParameters.h @@ -0,0 +1,269 @@ +/* + ZynAddSubFX - a software synthesizer + + ADnoteParameters.h - Parameters for ADnote (ADsynth) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef AD_NOTE_PARAMETERS_H +#define AD_NOTE_PARAMETERS_H + + +#include "../globals.h" +#include "EnvelopeParams.h" +#include "LFOParams.h" +#include "FilterParams.h" +#include "../Synth/OscilGen.h" +#include "../Synth/Resonance.h" +#include "../Misc/Util.h" +#include "../DSP/FFTwrapper.h" + + enum FMTYPE{NONE,MORPH,RING_MOD,PHASE_MOD,FREQ_MOD,PITCH_MOD}; + + /*****************************************************************/ + /* GLOBAL PARAMETERS */ + /*****************************************************************/ + + struct ADnoteGlobalParam{ + + /* The instrument type - MONO/STEREO + If the mode is MONO, the panning of voices are not used + Stereo=1, Mono=0. */ + + unsigned char PStereo; + + + /****************************************** + * FREQUENCY GLOBAL PARAMETERS * + ******************************************/ + unsigned short int PDetune;//fine detune + unsigned short int PCoarseDetune;//coarse detune+octave + unsigned char PDetuneType;//detune type + + EnvelopeParams *FreqEnvelope; //Frequency Envelope + + LFOParams *FreqLfo;//Frequency LFO + + /******************************************** + * AMPLITUDE GLOBAL PARAMETERS * + ********************************************/ + + /* Panning - 0 - random + 1 - left + 64 - center + 127 - right */ + unsigned char PPanning; + + unsigned char PVolume; + + unsigned char PAmpVelocityScaleFunction; + + EnvelopeParams *AmpEnvelope; + + LFOParams *AmpLfo; + + unsigned char PPunchStrength,PPunchTime,PPunchStretch,PPunchVelocitySensing; + + /****************************************** + * FILTER GLOBAL PARAMETERS * + ******************************************/ + FilterParams *GlobalFilter; + + // filter velocity sensing + unsigned char PFilterVelocityScale; + + // filter velocity sensing + unsigned char PFilterVelocityScaleFunction; + + EnvelopeParams *FilterEnvelope; + + LFOParams *FilterLfo; + + // RESONANCE + Resonance *Reson; + }; + + + + /***********************************************************/ + /* VOICE PARAMETERS */ + /***********************************************************/ + struct ADnoteVoiceParam{ + + /* If the voice is enabled */ + unsigned char Enabled; + + /* Type of the voice (0=Sound,1=Noise)*/ + unsigned char Type; + + /* Voice Delay */ + unsigned char PDelay; + + /* If the resonance is enabled for this voice */ + unsigned char Presonance; + + // What external oscil should I use, -1 for internal OscilSmp&FMSmp + short int Pextoscil,PextFMoscil; + // it is not allowed that the externoscil,externFMoscil => current voice + + // oscillator phases + unsigned char Poscilphase,PFMoscilphase; + + // filter bypass + unsigned char Pfilterbypass; + + /* Voice oscillator */ + OscilGen *OscilSmp; + + /********************************** + * FREQUENCY PARAMETERS * + **********************************/ + + /* If the base frequency is fixed to 440 Hz*/ + unsigned char Pfixedfreq; + + /* Equal temperate (this is used only if the Pfixedfreq is enabled) + If this parameter is 0, the frequency is fixed (to 440 Hz); + if this parameter is 64, 1 MIDI halftone -> 1 frequency halftone */ + unsigned char PfixedfreqET; + + /* Fine detune */ + unsigned short int PDetune; + + /* Coarse detune + octave */ + unsigned short int PCoarseDetune; + + /* Detune type */ + unsigned char PDetuneType; + + /* Frequency Envelope */ + unsigned char PFreqEnvelopeEnabled; + EnvelopeParams *FreqEnvelope; + + /* Frequency LFO */ + unsigned char PFreqLfoEnabled; + LFOParams *FreqLfo; + + + /*************************** + * AMPLITUDE PARAMETERS * + ***************************/ + + /* Panning 0 - random + 1 - left + 64 - center + 127 - right + The Panning is ignored if the instrument is mono */ + unsigned char PPanning; + + /* Voice Volume */ + unsigned char PVolume; + + /* If the Volume negative */ + unsigned char PVolumeminus; + + /* Velocity sensing */ + unsigned char PAmpVelocityScaleFunction; + + /* Amplitude Envelope */ + unsigned char PAmpEnvelopeEnabled; + EnvelopeParams *AmpEnvelope; + + /* Amplitude LFO */ + unsigned char PAmpLfoEnabled; + LFOParams *AmpLfo; + + + + /************************* + * FILTER PARAMETERS * + *************************/ + + /* Voice Filter */ + unsigned char PFilterEnabled; + FilterParams *VoiceFilter; + + /* Filter Envelope */ + unsigned char PFilterEnvelopeEnabled; + EnvelopeParams *FilterEnvelope; + + /* LFO Envelope */ + unsigned char PFilterLfoEnabled; + LFOParams *FilterLfo; + + /**************************** + * MODULLATOR PARAMETERS * + ****************************/ + + /* Modullator Parameters (0=off,1=Morph,2=RM,3=PM,4=FM.. */ + unsigned char PFMEnabled; + + /* Voice that I use as modullator instead of FMSmp. + It is -1 if I use FMSmp(default). + It maynot be equal or bigger than current voice */ + short int PFMVoice; + + /* Modullator oscillator */ + OscilGen *FMSmp; + + /* Modullator Volume */ + unsigned char PFMVolume; + + /* Modullator damping at higher frequencies */ + unsigned char PFMVolumeDamp; + + /* Modullator Velocity Sensing */ + unsigned char PFMVelocityScaleFunction; + + /* Fine Detune of the Modullator*/ + unsigned short int PFMDetune; + + /* Coarse Detune of the Modullator */ + unsigned short int PFMCoarseDetune; + + /* The detune type */ + unsigned char PFMDetuneType; + + /* Frequency Envelope of the Modullator */ + unsigned char PFMFreqEnvelopeEnabled; + EnvelopeParams *FMFreqEnvelope; + + /* Frequency Envelope of the Modullator */ + unsigned char PFMAmpEnvelopeEnabled; + EnvelopeParams *FMAmpEnvelope; + }; + +class ADnoteParameters{ + public: + ADnoteParameters(FFTwrapper *fft_); + ~ADnoteParameters(); + + ADnoteGlobalParam GlobalPar; + ADnoteVoiceParam VoicePar[NUM_VOICES]; + + void saveloadbuf(Buffer *buf); + void saveloadbufvoice(Buffer *buf,unsigned char nvoice); + + void copypastevoice(int n,int what); + private: + void EnableVoice(int nvoice); + void KillVoice(int nvoice); + FFTwrapper *fft; +}; + +#endif diff --git a/src/Params/Controller.C b/src/Params/Controller.C @@ -0,0 +1,306 @@ +/* + ZynAddSubFX - a software synthesizer + + Controller.C - (Midi) Controllers implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "Controller.h" +#include <math.h> +#include <stdio.h> + +Controller::Controller(){ + setpitchwheelbendrange(200);//2 halftones + expression.receive=1; + panning.depth=64; + filtercutoff.depth=64; + filterq.depth=64; + bandwidth.depth=64; + modwheel.depth=80; + modwheel.exponential=0; + fmamp.receive=1; + volume.receive=0; + sustain.receive=1; + NRPN.receive=1; + + portamento.portamento=0; + portamento.used=0; + portamento.receive=1; + portamento.time=64; + portamento.updowntimestretch=64; + portamento.pitchthresh=3; + portamento.pitchthreshtype=1; + portamento.noteusing=-1; + resonancecenter.depth=64; + resonancebandwidth.depth=64; + + initportamento(440.0,440.0); + setportamento(0); + + resetall(); +}; + +Controller::~Controller(){ +}; + +void Controller::resetall(){ + setpitchwheel(0);//center + setexpression(127); + setpanning(64); + setfiltercutoff(64); + setfilterq(64); + setbandwidth(64); + setmodwheel(64); + setfmamp(127); + setvolume(127); + setsustain(0); + setresonancecenter(64); + setresonancebw(64); + + //reset the NRPN + NRPN.parhi=-1; + NRPN.parlo=-1; + NRPN.valhi=-1; + NRPN.vallo=-1; +}; + +void Controller::setpitchwheel(int value){ + pitchwheel.data=value; + REALTYPE cents=value/8192.0; + cents*=pitchwheel.bendrange; + pitchwheel.relfreq=pow(2,cents/1200.0); + //fprintf(stderr,"%ld %ld -> %.3f\n",pitchwheel.bendrange,pitchwheel.data,pitchwheel.relfreq);fflush(stderr); +}; + +void Controller::setpitchwheelbendrange(unsigned short int value){ + pitchwheel.bendrange=value; +}; + +void Controller::setexpression(int value){ + expression.data=value; + if (expression.receive!=0) expression.relvolume=value/127.0; + else expression.relvolume=1.0; +}; + +void Controller::setpanning(int value){ + panning.data=value; + panning.pan=(value/128.0-0.5)*(panning.depth/64.0); +}; + +void Controller::setfiltercutoff(int value){ + filtercutoff.data=value; + filtercutoff.relfreq=(value-64.0)*filtercutoff.depth/4096.0*3.321928;//3.3219..=ln2(10) +}; + +void Controller::setfilterq(int value){ + filterq.data=value; + filterq.relq=pow(30.0,(value-64.0)/64.0*(filterq.depth/64.0)); +}; + +void Controller::setbandwidth(int value){ + bandwidth.data=value; + bandwidth.relbw=pow(25.0,(value-64.0)/64.0*(bandwidth.depth/64.0)); +}; + +void Controller::setmodwheel(int value){ + modwheel.data=value; + if (modwheel.exponential==0) { + REALTYPE tmp=pow(25.0,pow(modwheel.depth/127.0,1.5)*2.0)/25.0; + modwheel.relmod=(value/64.0-1.0)*tmp+1.0; + if (modwheel.relmod<0.0) modwheel.relmod=0.0; + } else modwheel.relmod=pow(25.0,(value-64.0)/64.0*(modwheel.depth/80.0)); +}; + +void Controller::setfmamp(int value){ + fmamp.data=value; + fmamp.relamp=value/127.0; + if (fmamp.receive!=0) fmamp.relamp=value/127.0; + else fmamp.relamp=1.0; +}; + +void Controller::setvolume(int value){ + volume.data=value; + if (volume.receive!=0) volume.volume=pow(0.1,(127-value)/127.0*2.0); + else volume.volume=1.0; +}; + +void Controller::setsustain(int value){ + sustain.data=value; + if (sustain.receive!=0) sustain.sustain=((value<64) ? 0 : 1 ); + else sustain.sustain=0; +}; + +void Controller::setportamento(int value){ + portamento.data=value; + if (portamento.receive!=0) portamento.portamento=((value<64) ? 0 : 1 ); +}; + +int Controller::initportamento(REALTYPE oldfreq,REALTYPE newfreq){ + portamento.x=0.0; + if ((portamento.used!=0) || (portamento.portamento==0)) return(0); + REALTYPE portamentotime=pow(100.0,portamento.time/127.0)/50.0;//portamento time in seconds + + if ((portamento.updowntimestretch>=64)&&(newfreq<oldfreq)){ + if (portamento.updowntimestretch==127) return(0); + portamentotime*=pow(0.1,(portamento.updowntimestretch-64)/63.0); + } + if ((portamento.updowntimestretch<64)&&(newfreq>oldfreq)){ + if (portamento.updowntimestretch==0) return(0); + portamentotime*=pow(0.1,(64.0-portamento.updowntimestretch)/64.0); + }; + + portamento.dx=SOUND_BUFFER_SIZE/(portamentotime*SAMPLE_RATE); + portamento.origfreqrap=oldfreq/newfreq; + + REALTYPE tmprap=( (portamento.origfreqrap>1.0) ? + (portamento.origfreqrap) : + (1.0/portamento.origfreqrap) ); + + REALTYPE thresholdrap=pow(2.0,portamento.pitchthresh/12.0); + if ((portamento.pitchthreshtype==0) && (tmprap-0.00001>thresholdrap) ) return(0); + if ((portamento.pitchthreshtype==1) && (tmprap+0.00001<thresholdrap) ) return(0); + + portamento.used=1; + portamento.freqrap=portamento.origfreqrap; + return (1); +}; + +void Controller::updateportamento(){ + if (portamento.used==0) return; + + portamento.x+=portamento.dx; + if (portamento.x>1.0) { + portamento.x=1.0; + portamento.used=0; + }; + portamento.freqrap=(1.0-portamento.x)*portamento.origfreqrap+portamento.x; +}; + + +void Controller::setresonancecenter(int value){ + resonancecenter.data=value; + resonancecenter.relcenter=pow(3.0,(value-64.0)/64.0*(resonancecenter.depth/64.0)); +}; +void Controller::setresonancebw(int value){ + resonancebandwidth.data=value; + resonancebandwidth.relbw=pow(1.5,(value-64.0)/64.0*(resonancebandwidth.depth/127.0)); +}; + + +//Returns 0 if there is NRPN or 1 if there is not +int Controller::getnrpn(int *parhi, int *parlo, int *valhi, int *vallo){ + if (NRPN.receive==0) return(1); + if ((NRPN.parhi<0)||(NRPN.parlo<0)||(NRPN.valhi<0)||(NRPN.vallo<0)) + return(1); + + *parhi=NRPN.parhi; + *parlo=NRPN.parlo; + *valhi=NRPN.valhi; + *vallo=NRPN.vallo; + return(0); +}; + + +void Controller::setparameternumber(unsigned int type,int value){ + switch(type){ + case C_nrpnhi:NRPN.parhi=value; + NRPN.valhi=-1;NRPN.vallo=-1;//clear the values + break; + case C_nrpnlo:NRPN.parlo=value; + NRPN.valhi=-1;NRPN.vallo=-1;//clear the values + break; + case C_dataentryhi:if ((NRPN.parhi>=0)&&(NRPN.parlo>=0)) NRPN.valhi=value; + break; + case C_dataentrylo:if ((NRPN.parhi>=0)&&(NRPN.parlo>=0)) NRPN.vallo=value; + break; + }; +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void Controller::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Controller parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Controller parameters + case 0x80: buf->rwwordparwrap(n,&pitchwheel.bendrange); + break; + case 0x81: buf->rwbytepar(n,&expression.receive); + break; + case 0x82: buf->rwbytepar(n,&panning.depth); + break; + case 0x83: buf->rwbytepar(n,&filtercutoff.depth); + break; + case 0x84: buf->rwbytepar(n,&filterq.depth); + break; + case 0x85: buf->rwbytepar(n,&bandwidth.depth); + break; + case 0x86: buf->rwbytepar(n,&modwheel.depth); + break; + case 0x87: buf->rwbytepar(n,&fmamp.receive); + break; + case 0x88: buf->rwbytepar(n,&volume.receive); + break; + case 0x89: buf->rwbytepar(n,&sustain.receive); + break; + case 0x8A: buf->rwbytepar(n,&portamento.receive); + break; + case 0x8B: buf->rwbytepar(n,&portamento.time); + break; + case 0x8C: buf->rwbytepar(n,&portamento.pitchthresh); + break; + case 0x8D: buf->rwbytepar(n,&portamento.pitchthreshtype); + break; + case 0x8E: buf->rwbytepar(n,&portamento.portamento); + break; + case 0x8F: buf->rwbytepar(n,&resonancecenter.depth); + break; + case 0x90: buf->rwbytepar(n,&resonancebandwidth.depth); + break; + case 0x91: buf->rwbytepar(n,&modwheel.exponential); + break; + case 0x92: buf->rwbytepar(n,&portamento.updowntimestretch); + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + + diff --git a/src/Params/Controller.h b/src/Params/Controller.h @@ -0,0 +1,173 @@ +/* + ZynAddSubFX - a software synthesizer + + Controller.h - (Midi) Controllers implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#include "../globals.h" +#include "../Misc/Buffer.h" +class Controller{ + public: + Controller(); + ~Controller(); + void resetall(); + void saveloadbuf(Buffer *buf); + //Controllers functions + void setpitchwheel(int value); + void setpitchwheelbendrange(unsigned short int value); + void setexpression(int value); + void setpanning(int value); + void setfiltercutoff(int value); + void setfilterq(int value); + void setbandwidth(int value); + void setmodwheel(int value); + void setfmamp(int value); + void setvolume(int value); + void setsustain(int value); + void setportamento(int value); + void setresonancecenter(int value); + void setresonancebw(int value); + + + void setparameternumber(unsigned int type,int value);//used for RPN and NRPN's + int getnrpn(int *parhi, int *parlo, int *valhi, int *vallo); + + int initportamento(REALTYPE oldfreq,REALTYPE newfreq);//returns 1 if the portamento's conditions are true, else return 0 + void updateportamento(); //update portamento values + + // Controllers values + struct {//Pitch Wheel + int data; + short int bendrange;//bendrange is in cents + REALTYPE relfreq;//the relative frequency (default is 1.0) + } pitchwheel; + + struct{//Expression + int data; + REALTYPE relvolume; + unsigned char receive; + } expression; + + struct{//Panning + int data; + REALTYPE pan; + unsigned char depth; + } panning; + + + struct{//Filter cutoff + int data; + REALTYPE relfreq; + unsigned char depth; + } filtercutoff; + + struct{//Filter Q + int data; + REALTYPE relq; + unsigned char depth; + } filterq; + + struct{//Bandwidth + int data; + REALTYPE relbw; + unsigned char depth; + } bandwidth; + + struct {//Modulation Wheel + int data; + REALTYPE relmod; + unsigned char depth; + unsigned char exponential; + } modwheel; + + struct{//FM amplitude + int data; + REALTYPE relamp; + unsigned char receive; + } fmamp; + + struct{//Volume + int data; + REALTYPE volume; + unsigned char receive; + } volume; + + struct{//Sustain + int data,sustain; + unsigned char receive; + } sustain; + + struct{//Portamento + //parameters + int data; + unsigned char portamento; + + //pitchthresh is the threshold of enabling protamento + //pitchthreshtype -> enable the portamento only below(0)/above(1) the threshold + unsigned char receive,time,pitchthresh,pitchthreshtype; + + //'up portanemto' means when the frequency is rising (eg: the portamento is from 200Hz to 300 Hz) + //'down portanemto' means when the frequency is lowering (eg: the portamento is from 300Hz to 200 Hz) + unsigned char updowntimestretch;//this value represent how the portamento time is reduced + //0 - for down portamento, 1..63 - the up portamento's time is smaller than the down portamento + //64 - the portamento time is always the same + //64-126 - the down portamento's time is smaller than the up portamento + //127 - for upper portamento + + REALTYPE freqrap;//this value is used to compute the actual portamento + int noteusing;//this is used by the Part:: for knowing which note uses the portamento + int used;//if a the portamento is used by a note + //internal data + REALTYPE x,dx;//x is from 0.0 (start portamento) to 1.0 (finished portamento), dx is x increment + REALTYPE origfreqrap;// this is used for computing oldfreq value from x + } portamento; + + struct{//Resonance Center Frequency + int data; + REALTYPE relcenter; + unsigned char depth; + } resonancecenter; + + struct{//Resonance Bandwidth + int data; + REALTYPE relbw; + unsigned char depth; + } resonancebandwidth; + + + /* RPN and NPRPN */ + struct{//nrpn + int parhi,parlo; + int valhi,vallo; + unsigned char receive;//this is saved to disk by Master + } NRPN; + + private: +}; + + + + + +#endif + diff --git a/src/Params/EnvelopeParams.C b/src/Params/EnvelopeParams.C @@ -0,0 +1,206 @@ +/* + ZynAddSubFX - a software synthesizer + + EnvelopeParams.C - Parameters for Envelope + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> + +#include <math.h> +#include <stdlib.h> +#include "EnvelopeParams.h" + +EnvelopeParams::EnvelopeParams(unsigned char Penvstretch_,unsigned char Pforcedrelase_){ + int i; + + PA_dt=10;PD_dt=10;PR_dt=10;PA_val=64;PD_val=64;PS_val=64;PR_val=64; + + for (i=0;i<MAX_ENVELOPE_POINTS;i++){ + Penvdt[i]=32; + Penvval[i]=64; + }; + Penvdt[0]=0;//no used + Penvsustain=1; + Penvpoints=1; + Envmode=1; + Penvstretch=Penvstretch_; + Pforcedrelase=Pforcedrelase_; + Pfreemode=1; + Plinearenvelope=0; +}; + +EnvelopeParams::~EnvelopeParams(){ +}; + +REALTYPE EnvelopeParams::getdt(char i){ + REALTYPE result=(pow(2.0,Penvdt[i]/127.0*12.0)-1.0)*10.0;//miliseconds + return(result); +}; + + +/* + * ADSR/ASR... initialisations + */ +void EnvelopeParams::ADSRinit(char A_dt,char D_dt,char S_val,char R_dt){ + Plinearenvelope=1; + Envmode=1; + PA_dt=A_dt;PD_dt=D_dt;PS_val=S_val;PR_dt=R_dt; + Pfreemode=0; + converttofree(); +}; + +void EnvelopeParams::ADSRinit_dB(char A_dt,char D_dt,char S_val,char R_dt){ + Envmode=2; + PA_dt=A_dt;PD_dt=D_dt;PS_val=S_val;PR_dt=R_dt; + Pfreemode=0; + converttofree(); +}; + +void EnvelopeParams::ASRinit(char A_val,char A_dt,char R_val,char R_dt){ + Envmode=3; + PA_val=A_val;PA_dt=A_dt;PR_val=R_val;PR_dt=R_dt; + Pfreemode=0; + converttofree(); + +}; + +void EnvelopeParams::ADSRinit_filter(char A_val,char A_dt,char D_val,char D_dt,char R_dt,char R_val){ + Envmode=4; + PA_val=A_val;PA_dt=A_dt;PD_val=D_val;PD_dt=D_dt;PR_dt=R_dt;PR_val=R_val; + Pfreemode=0; + converttofree(); +}; + +void EnvelopeParams::ASRinit_bw(char A_val,char A_dt,char R_val,char R_dt){ + Envmode=5; + PA_val=A_val;PA_dt=A_dt;PR_val=R_val;PR_dt=R_dt; + Pfreemode=0; + converttofree(); + +}; + +/* + * Convert the Envelope to freemode + */ +void EnvelopeParams::converttofree(){ + switch (Envmode){ + case 1: Penvpoints=4;Penvsustain=2; + Penvval[0]=0;Penvdt[1]=PA_dt;Penvval[1]=127; + Penvdt[2]=PD_dt;Penvval[2]=PS_val; + Penvdt[3]=PR_dt;Penvval[3]=0; + break; + case 2: Penvpoints=4;Penvsustain=2; + Penvval[0]=0;Penvdt[1]=PA_dt; + Penvval[1]=127;Penvdt[2]=PD_dt; + Penvval[2]=PS_val;Penvdt[3]=PR_dt;Penvval[3]=0; + break; + case 3: Penvpoints=3;Penvsustain=1; + Penvval[0]=PA_val;Penvdt[1]=PA_dt; + Penvval[1]=64;Penvdt[2]=PR_dt;Penvval[2]=PR_val; + break; + case 4: Penvpoints=4;Penvsustain=2; + Penvval[0]=PA_val;Penvdt[1]=PA_dt; + Penvval[1]=PD_val;Penvdt[2]=PD_dt;Penvval[2]=64; + Penvdt[3]=PR_dt;Penvval[3]=PR_val; + break; + case 5: Penvpoints=3;Penvsustain=1; + Penvval[0]=PA_val;Penvdt[1]=PA_dt; + Penvval[1]=64;Penvdt[2]=PR_dt;Penvval[2]=PR_val; + break; + }; +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void EnvelopeParams::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp,np; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Envelope parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + for (n=0x80;n<0xF0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Envelope parameters + case 0x80: buf->rwbytepar(n,&Pfreemode); + break; + case 0x81: buf->rwbytepar(n,&Penvstretch); + break; + case 0x82: buf->rwbytepar(n,&Pforcedrelase); + break; + case 0x83: buf->rwbytepar(n,&Penvpoints); + break; + case 0x84: buf->rwbytepar(n,&Penvsustain); + break; + case 0x85: buf->rwbytepar(n,&Plinearenvelope); + break; + case 0x90: if (buf->getmode()!=0){ + for (np=0;np<Penvpoints;np++){ + buf->rwbytepar(n,&np); + buf->rwbyte(&Penvdt[np]); + buf->rwbyte(&Penvval[np]); + }; + } else { + buf->rwbytepar(np,&np); + if (np<MAX_ENVELOPE_POINTS){//for safety + buf->rwbyte(&Penvdt[np]); + buf->rwbyte(&Penvval[np]); + } else{ + buf->rwbyte(&tmp); + buf->rwbyte(&tmp); + }; + }; + break; + case 0xA0: buf->rwbytepar(n,&PA_dt); + break; + case 0xA1: buf->rwbytepar(n,&PD_dt); + break; + case 0xA2: buf->rwbytepar(n,&PR_dt); + break; + case 0xA3: buf->rwbytepar(n,&PA_val); + break; + case 0xA4: buf->rwbytepar(n,&PD_val); + break; + case 0xA5: buf->rwbytepar(n,&PS_val); + break; + case 0xA6: buf->rwbytepar(n,&PR_val); + break; + }; + }; + + if (Pfreemode==0) converttofree(); + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + + diff --git a/src/Params/EnvelopeParams.h b/src/Params/EnvelopeParams.h @@ -0,0 +1,69 @@ +/* + ZynAddSubFX - a software synthesizer + + EnvelopeParams.h - Parameters for Envelope + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ENVELOPE_PARAMS_H +#define ENVELOPE_PARAMS_H + +#include "../globals.h" +#include "../Misc/Buffer.h" + +#define MAX_ENVELOPE_POINTS 40 +#define MIN_ENVELOPE_DB -40 + +class EnvelopeParams{ + public: + EnvelopeParams(unsigned char Penvstretch_,unsigned char Pforcedrelase_); + ~EnvelopeParams(); + void ADSRinit(char A_dt,char D_dt,char S_val,char R_dt); + void ADSRinit_dB(char A_dt,char D_dt,char S_val,char R_dt); + void ASRinit(char A_val,char A_dt,char R_val,char R_dt); + void ADSRinit_filter(char A_val,char A_dt,char D_val,char D_dt,char R_dt,char R_val); + void ASRinit_bw(char A_val,char A_dt,char R_val,char R_dt); + void converttofree(); + void saveloadbuf(Buffer *buf); + REALTYPE getdt(char i); + + /* Parametrii MIDI */ + unsigned char Pfreemode;//1 daca este in modul free sau 0 daca este in mod ADSR,ASR,... + unsigned char Penvpoints; + unsigned char Penvsustain;//127 pentru dezactivat,0 pentru relase "fortat" (folosit in amplitudine) + unsigned char Penvdt[MAX_ENVELOPE_POINTS]; + unsigned char Penvval[MAX_ENVELOPE_POINTS]; + unsigned char Penvstretch;//64=normal stretch (piano-like), 0=no stretch + unsigned char Pforcedrelase;//0 - OFF, 1 - ON + unsigned char Plinearenvelope;//if the amplitude envelope is linear + + unsigned char PA_dt,PD_dt,PR_dt, + PA_val,PD_val,PS_val,PR_val; + + int Envmode;// 1 for ADSR parameters (linear amplitude) + // 2 for ADSR_dB parameters (dB amplitude) + // 3 for ASR parameters (frequency LFO) + // 4 for ADSR_filter parameters (filter parameters) + // 5 for ASR_bw parameters (bandwidth parameters) + + private: +}; + + +#endif + diff --git a/src/Params/FilterParams.C b/src/Params/FilterParams.C @@ -0,0 +1,299 @@ +/* + ZynAddSubFX - a software synthesizer + + FilterParams.C - Parameters for filter + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "FilterParams.h" + +FilterParams::FilterParams(unsigned char Ptype_,unsigned char Pfreq_,unsigned char Pq_){ + Ptype=Ptype_; + Pfreq=Pfreq_; + Pq=Pq_; + Pstages=0; + Pfreqtrack=64; + Pgain=64; + Pcategory=0; + + Pnumformants=3; + Pformantslowness=64; + for (int j=0;j<FF_MAX_VOWELS;j++){ + for (int i=0;i<FF_MAX_FORMANTS;i++){ + Pvowels[j].formants[i].freq=(int)(RND*127.0);//some random freqs + Pvowels[j].formants[i].q=64; + Pvowels[j].formants[i].amp=127; + }; + }; + + Psequencesize=3; + for (int i=0;i<FF_MAX_SEQUENCE;i++) + Psequence[i].nvowel=i%FF_MAX_VOWELS; + + Psequencestretch=40; + Psequencereversed=0; + Pcenterfreq=64;//1 kHz + Poctavesfreq=64; + Pvowelclearness=64; +}; + +FilterParams::~FilterParams(){ +}; + + +/* + * Parameter control + */ +REALTYPE FilterParams::getfreq(){ + return((Pfreq/64.0-1.0)*5.0); +}; + +REALTYPE FilterParams::getq(){ + return(exp(pow((REALTYPE) Pq/127.0,2)*log(1000.0))-0.9); +}; +REALTYPE FilterParams::getfreqtracking(REALTYPE notefreq){ + return(log(notefreq/440.0)*(Pfreqtrack-64.0)/(64.0*LOG_2)); +}; + +REALTYPE FilterParams::getgain(){ + return((Pgain/64.0-1.0)*30.0);//-30..30dB +}; + +/* + * Get the center frequency of the formant's graph + */ +REALTYPE FilterParams::getcenterfreq(){ + return(10000.0*pow(10,-(1.0-Pcenterfreq/127.0)*2.0)); +}; + +/* + * Get the number of octave that the formant functions applies to + */ +REALTYPE FilterParams::getoctavesfreq(){ + return(0.25+10.0*Poctavesfreq/127.0); +}; + +/* + * Get the frequency from x, where x is [0..1] + */ +REALTYPE FilterParams::getfreqx(REALTYPE x){ + if (x>1.0) x=1.0; + REALTYPE octf=pow(2.0,getoctavesfreq()); + return(getcenterfreq()/sqrt(octf)*pow(octf,x)); +}; + +/* + * Get the x coordinate from frequency (used by the UI) + */ +REALTYPE FilterParams::getfreqpos(REALTYPE freq){ + return((log(freq)-log(getfreqx(0.0)))/log(2.0)/getoctavesfreq()); +}; + + +/* + * Get the freq. response of the formant filter + */ +void FilterParams::formantfilterH(int nvowel,int nfreqs,REALTYPE *freqs){ + REALTYPE c[3],d[3],curfreq=1000.0; + REALTYPE filter_freq,filter_q,filter_amp; + REALTYPE omega,sn,cs,alpha,beta; + + for (int i=0;i<nfreqs;i++) freqs[i]=0.0; + + //for each formant... + for (int nformant=0;nformant<Pnumformants;nformant++){ + //compute formant parameters(frequency,amplitude,etc.) + filter_freq=getformantfreq(Pvowels[nvowel].formants[nformant].freq); + filter_q=getformantq(Pvowels[nvowel].formants[nformant].q)*getq(); + if (Pstages>0) filter_q=(filter_q>1.0 ? pow(filter_q,1.0/(Pstages+1)) : filter_q); + + filter_amp=getformantamp(Pvowels[nvowel].formants[nformant].amp); + + + if (filter_freq<=(SAMPLE_RATE/2-100.0)){ + omega=2*PI*filter_freq/SAMPLE_RATE; + sn=sin(omega); + cs=cos(omega); + alpha=sn/(2*filter_q); + REALTYPE tmp=1+alpha; + c[0]=alpha/tmp*sqrt(filter_q+1); + c[1]=0; + c[2]=-alpha/tmp*sqrt(filter_q+1); + d[1]=-2*cs/tmp*(-1); + d[2]=(1-alpha)/tmp*(-1); + } else continue; + + + for (int i=0;i<nfreqs;i++) { + REALTYPE freq=getfreqx(i/(REALTYPE) nfreqs); + if (freq>SAMPLE_RATE/2) { + for (int tmp=i;tmp<nfreqs;tmp++) freqs[tmp]=0.0; + break; + }; + REALTYPE fr=freq/SAMPLE_RATE*PI*2.0; + REALTYPE x=c[0],y=0.0; + for (int n=1;n<3;n++){ + x+=cos(n*fr)*c[n]; + y-=sin(n*fr)*c[n]; + }; + REALTYPE h=x*x+y*y; + x=1.0;y=0.0; + for (int n=1;n<3;n++){ + x-=cos(n*fr)*d[n]; + y+=sin(n*fr)*d[n]; + }; + h=h/(x*x+y*y); + + freqs[i]+=pow(h,(Pstages+1.0)/2.0)*filter_amp; + }; + }; + for (int i=0;i<nfreqs;i++) { + if (freqs[i]>0.000000001) freqs[i]=rap2dB(freqs[i])+getgain(); + else freqs[i]=-90.0; + }; + +}; + +/* + * Transforms a parameter to the real value + */ +REALTYPE FilterParams::getformantfreq(unsigned char freq){ + REALTYPE result=getfreqx(freq/127.0); + return(result); +}; + +REALTYPE FilterParams::getformantamp(unsigned char amp){ + REALTYPE result=pow(0.1,(1.0-amp/127.0)*4.0); + return(result); +}; + +REALTYPE FilterParams::getformantq(unsigned char q){ + //temp + REALTYPE result=pow(25.0,(q-32.0)/64.0); + return(result); +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void FilterParams::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Filter parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //FILTER parameters + case 0x80: buf->rwbytepar(n,&Ptype); + break; + case 0x81: buf->rwbytepar(n,&Pfreq); + break; + case 0x82: buf->rwbytepar(n,&Pq); + break; + case 0x83: buf->rwbytepar(n,&Pstages); + break; + case 0x84: buf->rwbytepar(n,&Pfreqtrack); + break; + case 0x85: buf->rwbytepar(n,&Pcategory); + break; + case 0x86: buf->rwbytepar(n,&Pgain); + break; + //Formant Filter Parameters + case 0xA0: buf->rwbytepar(n,&Pnumformants); + break; + case 0xA1: buf->rwbytepar(n,&Pformantslowness); + break; + case 0xA2: buf->rwbytepar(n,&Pvowelclearness); + break; + case 0xA3: buf->rwbytepar(n,&Pcenterfreq); + break; + case 0xA4: buf->rwbytepar(n,&Poctavesfreq); + break; + case 0xA8: if (buf->getmode()!=0) {//save the formants of the vowels + for (unsigned char nvowel=0;nvowel<FF_MAX_VOWELS;nvowel++){ + for (unsigned char nformant=0;nformant<FF_MAX_FORMANTS;nformant++){ + buf->rwbyte(&npar); + buf->rwbyte(&nvowel); + buf->rwbyte(&nformant); + buf->rwbyte(&Pvowels[nvowel].formants[nformant].freq); + buf->rwbyte(&Pvowels[nvowel].formants[nformant].amp); + buf->rwbyte(&Pvowels[nvowel].formants[nformant].q); + }; + }; + } else { + unsigned char nvowel,nformant; + buf->rwbyte(&nvowel); + buf->rwbyte(&nformant); + if ((nvowel<FF_MAX_VOWELS) && (nformant<FF_MAX_FORMANTS)){ + buf->rwbyte(&Pvowels[nvowel].formants[nformant].freq); + buf->rwbyte(&Pvowels[nvowel].formants[nformant].amp); + buf->rwbyte(&Pvowels[nvowel].formants[nformant].q); + } else { + buf->rwbyte(&tmp); + buf->rwbyte(&tmp); + buf->rwbyte(&tmp); + }; + }; + break; + + //Formant Filter Parameters (sequence) + case 0xB0: buf->rwbytepar(n,&Psequencesize); + break; + case 0xB1: buf->rwbytepar(n,&Psequencestretch); + break; + case 0xB2: buf->rwbytepar(n,&Psequencereversed); + break; + case 0xB3: buf->rwbytepar(n,&Psequencesize); + break; + case 0xB8: if (buf->getmode()!=0){//sequence values + for (unsigned char nseq=0;nseq<Psequencesize;nseq++){ + buf->rwbytepar(n,&nseq); + buf->rwbyte(&Psequence[nseq].nvowel); + }; + } else { + unsigned char nseq; + buf->rwbytepar(n,&nseq); + if (nseq<FF_MAX_SEQUENCE){//for safety + buf->rwbyte(&Psequence[nseq].nvowel); + } else buf->rwbyte(&tmp); + }; + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; diff --git a/src/Params/FilterParams.h b/src/Params/FilterParams.h @@ -0,0 +1,83 @@ +/* + ZynAddSubFX - a software synthesizer + + FilterParams.h - Parameters for filter + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef FILTER_PARAMS_H +#define FILTER_PARAMS_H + +#include "../globals.h" +#include "../Misc/Buffer.h" + +class FilterParams{ + public: + FilterParams(unsigned char Ptype_,unsigned char Pfreq,unsigned char Pq_); + ~FilterParams(); + void saveloadbuf(Buffer *buf); + + REALTYPE getfreq(); + REALTYPE getq(); + REALTYPE getfreqtracking(REALTYPE notefreq); + REALTYPE getgain(); + + unsigned char Pcategory;//Filter category (Analog/Formant) + unsigned char Ptype;// Filter type (for analog lpf,hpf,bpf..) + unsigned char Pfreq;// Frequency (64-central frequency) + unsigned char Pq; // Q parameters (resonance or bandwidth) + unsigned char Pstages; //filter stages+1 + unsigned char Pfreqtrack;//how the filter frequency is changing according the note frequency + unsigned char Pgain;//filter's output gain + + //Formant filter parameters + unsigned char Pnumformants;//how many formants are used + unsigned char Pformantslowness;//how slow varies the formants + unsigned char Pvowelclearness;//how vowels are kept clean (how much try to avoid "mixed" vowels) + unsigned char Pcenterfreq,Poctavesfreq;//the center frequency of the res. func., and the number of octaves + + struct { + struct { + unsigned char freq,amp,q;//frequency,amplitude,Q + }formants[FF_MAX_FORMANTS]; + }Pvowels[FF_MAX_VOWELS]; + + + unsigned char Psequencesize;//how many vowels are in the sequence + unsigned char Psequencestretch;//how the sequence is stretched (how the input from filter envelopes/LFOs/etc. is "stretched") + unsigned char Psequencereversed;//if the input from filter envelopes/LFOs/etc. is reversed(negated) + struct { + unsigned char nvowel;//the vowel from the position + } Psequence[FF_MAX_SEQUENCE]; + + REALTYPE getcenterfreq(); + REALTYPE getoctavesfreq(); + REALTYPE getfreqpos(REALTYPE freq); + REALTYPE getfreqx(REALTYPE x); + + void formantfilterH(int nvowel,int nfreqs,REALTYPE *freqs);//used by UI + + REALTYPE getformantfreq(unsigned char freq); + REALTYPE getformantamp(unsigned char amp); + REALTYPE getformantq(unsigned char q); + + private: +}; + +#endif + diff --git a/src/Params/LFOParams.C b/src/Params/LFOParams.C @@ -0,0 +1,91 @@ +/* + ZynAddSubFX - a software synthesizer + + LFOParams.C - Parameters for LFO + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdio.h> +#include "../globals.h" +#include "LFOParams.h" + +int LFOParams::time; + +LFOParams::LFOParams(char Pfreq_,char Pintensity_,char Pstartphase_, char PLFOtype_,char Prandomness_, char Pdelay_,char Pcontinous_,char fel_){ + Pfreq=Pfreq_; + Pintensity=Pintensity_; + Pstartphase=Pstartphase_; + PLFOtype=PLFOtype_; + Prandomness=Prandomness_; + Pdelay=Pdelay_; + Pcontinous=Pcontinous_; + fel=fel_; + time=0; +}; + +LFOParams::~LFOParams(){ +}; + +/* + * Save or load the parameters to/from the buffer + */ +void LFOParams::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( LFO parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //LFO parameters + case 0x80: buf->rwbytepar(n,&Pfreq); + break; + case 0x81: buf->rwbytepar(n,&Pintensity); + break; + case 0x82: buf->rwbytepar(n,&Pstartphase); + break; + case 0x83: buf->rwbytepar(n,&PLFOtype); + break; + case 0x84: buf->rwbytepar(n,&Prandomness); + break; + case 0x85: buf->rwbytepar(n,&Pdelay); + break; + case 0x86: buf->rwbytepar(n,&Pcontinous); + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + diff --git a/src/Params/LFOParams.h b/src/Params/LFOParams.h @@ -0,0 +1,51 @@ +/* + ZynAddSubFX - a software synthesizer + + LFOParams.h - Parameters for LFO + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef LFO_PARAMS_H +#define LFO_PARAMS_H + +#include "../Misc/Buffer.h" + +class LFOParams{ + public: + LFOParams(char Pfreq_,char Pintensity_,char Pstartphase_, char PLFOtype_,char Prandomness_, char Pdelay_,char Pcontinous,char fel_); + ~LFOParams(); + + void saveloadbuf(Buffer *buf); + + /* Parametrii MIDI */ + unsigned char Pfreq; // frequency + unsigned char Pintensity; // intensity + unsigned char Pstartphase;// start phase (0=random) + unsigned char PLFOtype; // LFO typpe (sin,triangle,square,ramp,...) + unsigned char Prandomness;// randomness (0=off) + unsigned char Pdelay; // delay (0=off) + unsigned char Pcontinous; // 1 if LFO is continous + + int fel;//what kind is the LFO (0 - frequency, 1 - amplitude, 2 - filter) + + static int time;//is used by Pcontinous parameter + private: +}; + + +#endif diff --git a/src/Params/Makefile b/src/Params/Makefile @@ -0,0 +1,15 @@ +include ../Makefile.inc + +objects=ADnoteParameters.o EnvelopeParams.o FilterParams.o \ + LFOParams.o SUBnoteParameters.o Controller.o + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Params/SUBnoteParameters.C b/src/Params/SUBnoteParameters.C @@ -0,0 +1,195 @@ +/* + ZynAddSubFX - a software synthesizer + + SUBnoteParameters.C - Parameters for SUBnote (SUBsynth) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "../globals.h" +#include "SUBnoteParameters.h" +#include <stdio.h> + +SUBnoteParameters::SUBnoteParameters(){ + PVolume=96; + PPanning=64; + PAmpVelocityScaleFunction=90; + + Pfixedfreq=0; + PfixedfreqET=0; + Pnumstages=2; + Pbandwidth=40; + Phmagtype=0; + Pbwscale=64; + Pstereo=1; + Pstart=1; + + PDetune=8192; + PCoarseDetune=0; + PDetuneType=1; + PFreqEnvelopeEnabled=0; + PBandWidthEnvelopeEnabled=0; + + for (int n=0;n<MAX_SUB_HARMONICS;n++){ + Phmag[n]=0; + Phrelbw[n]=64; + }; + Phmag[0]=127; + + AmpEnvelope=new EnvelopeParams(64,1); + AmpEnvelope->ADSRinit_dB(0,40,127,25); + FreqEnvelope=new EnvelopeParams(64,0); + FreqEnvelope->ASRinit(30,50,64,60); + BandWidthEnvelope=new EnvelopeParams(64,0); + BandWidthEnvelope->ASRinit_bw(100,70,64,60); + + PGlobalFilterEnabled=0; + GlobalFilter=new FilterParams(2,80,40); + PGlobalFilterVelocityScale=64; + PGlobalFilterVelocityScaleFunction=64; + GlobalFilterEnvelope=new EnvelopeParams(0,1); + GlobalFilterEnvelope->ADSRinit_filter(64,40,64,70,60,64); +}; + +SUBnoteParameters::~SUBnoteParameters(){ + delete (AmpEnvelope); + delete (FreqEnvelope); + delete (BandWidthEnvelope); + delete (GlobalFilter); + delete (GlobalFilterEnvelope); +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void SUBnoteParameters::saveloadbuf(Buffer *buf){ + unsigned char npar,n,nharmonic,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( SUBnotePparameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + if (buf->getmode()==0){ + for (nharmonic=0;nharmonic<MAX_SUB_HARMONICS;nharmonic++){ + Phmag[nharmonic]=0; + Phrelbw[nharmonic]=64; + }; + }; + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Misc Parameters + case 0x80: buf->rwbytepar(n,&Pstereo); + break; + case 0x81: buf->rwbytepar(n,&PPanning); + break; + case 0x82: buf->rwbytepar(n,&Phmagtype); + break; + case 0x83: if (buf->getmode()!=0){ + for (nharmonic=0;nharmonic<MAX_SUB_HARMONICS;nharmonic++){ + if (Phmag[nharmonic]==0) continue; + buf->rwbytepar(n,&nharmonic); + buf->rwbyte(&Phmag[nharmonic]); + buf->rwbyte(&Phrelbw[nharmonic]); + }; + } else { + buf->rwbytepar(n,&nharmonic); + if (nharmonic<MAX_SUB_HARMONICS){//for safety + buf->rwbyte(&Phmag[nharmonic]); + buf->rwbyte(&Phrelbw[nharmonic]); + } else{ + buf->rwbyte(&tmp); + buf->rwbyte(&tmp); + }; + }; + break; + case 0x84: buf->rwbytepar(n,&Pnumstages); + break; + case 0x85: buf->rwbytepar(n,&Pstart); + break; + //Amplitude Parameters + case 0x90: buf->rwbytepar(n,&PVolume); + break; + case 0x91: buf->rwbytepar(n,&PAmpVelocityScaleFunction); + break; + case 0x98: if (buf->getmode()!=0) buf->rwbyte(&npar); + AmpEnvelope->saveloadbuf(buf); + break; + //Frequency Parameters + case 0xA0: buf->rwwordpar(n,&PDetune); + break; + case 0xA1: buf->rwwordpar(n,&PCoarseDetune); + break; + case 0xA2: buf->rwbytepar(n,&PDetuneType); + break; + case 0xA3: buf->rwbytepar(n,&Pbandwidth); + break; + case 0xA4: buf->rwbytepar(n,&Pbwscale); + break; + case 0xA5: buf->rwbytepar(n,&PFreqEnvelopeEnabled); + break; + case 0xA6: buf->rwbytepar(n,&PBandWidthEnvelopeEnabled); + break; + case 0xA7: buf->rwbytepar(n,&Pfixedfreq); + break; + case 0xA8: if ((buf->getminimal()!=0) && (buf->getmode()!=0) + && (PFreqEnvelopeEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + FreqEnvelope->saveloadbuf(buf); + break; + case 0xA9: if ((buf->getminimal()!=0) && (buf->getmode()!=0) + && (PBandWidthEnvelopeEnabled==0)) break; + if (buf->getmode()!=0) buf->rwbyte(&npar); + BandWidthEnvelope->saveloadbuf(buf); + break; + case 0xAA: buf->rwbytepar(n,&PfixedfreqET); + break; + //Filter Parameters + case 0xB0: buf->rwbytepar(n,&PGlobalFilterEnabled); + break; + case 0xB1: buf->rwbytepar(n,&PGlobalFilterVelocityScale); + break; + case 0xB2: buf->rwbytepar(n,&PGlobalFilterVelocityScaleFunction); + break; + case 0xB8: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalFilter->saveloadbuf(buf); + break; + case 0xB9: if (buf->getmode()!=0) buf->rwbyte(&npar); + GlobalFilterEnvelope->saveloadbuf(buf); + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + + diff --git a/src/Params/SUBnoteParameters.h b/src/Params/SUBnoteParameters.h @@ -0,0 +1,102 @@ +/* + ZynAddSubFX - a software synthesizer + + SUBnoteParameters.h - Parameters for SUBnote (SUBsynth) + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef SUB_NOTE_PARAMETERS_H +#define SUB_NOTE_PARAMETERS_H + +#include "../globals.h" +#include "../Misc/Buffer.h" +#include "EnvelopeParams.h" +#include "FilterParams.h" + +class SUBnoteParameters{ + public: + SUBnoteParameters(); + ~SUBnoteParameters(); + + void saveloadbuf(Buffer *buf); + + //Parameters + //AMPLITUDE PARAMETRERS + unsigned char Pstereo;//0 for mono,1 for stereo + unsigned char PVolume; + unsigned char PPanning; + unsigned char PAmpVelocityScaleFunction; + EnvelopeParams *AmpEnvelope; + + //Frequency Parameters + unsigned short int PDetune; + unsigned short int PCoarseDetune; + unsigned char PDetuneType; + unsigned char PFreqEnvelopeEnabled; + EnvelopeParams *FreqEnvelope; + unsigned char PBandWidthEnvelopeEnabled; + EnvelopeParams *BandWidthEnvelope; + + //Filter Parameters (Global) + unsigned char PGlobalFilterEnabled; + FilterParams *GlobalFilter; + unsigned char PGlobalFilterVelocityScale; + unsigned char PGlobalFilterVelocityScaleFunction; + EnvelopeParams *GlobalFilterEnvelope; + + + //Other Parameters + + //If the base frequency is fixed to 440 Hz + unsigned char Pfixedfreq; + + /* Equal temperate (this is used only if the Pfixedfreq is enabled) + If this parameter is 0, the frequency is fixed (to 440 Hz); + if this parameter is 64, 1 MIDI halftone -> 1 frequency halftone */ + unsigned char PfixedfreqET; + + + //how many times the filters are applied + unsigned char Pnumstages; + + //bandwidth + unsigned char Pbandwidth; + + //How the magnitudes are computed (0=linear,1=-60dB,2=-60dB) + unsigned char Phmagtype; + + //Magnitudes + unsigned char Phmag[MAX_SUB_HARMONICS]; + + //Relative BandWidth ("64"=1.0) + unsigned char Phrelbw[MAX_SUB_HARMONICS]; + + //how much the bandwidth is increased according to lower/higher frequency; 64-default + unsigned char Pbwscale; + + //how the harmonics start("0"=0,"1"=random,"2"=1) + unsigned char Pstart; + + + private: +}; + +#endif + + + diff --git a/src/Seq/Makefile b/src/Seq/Makefile @@ -0,0 +1,14 @@ +include ../Makefile.inc + +objects=Sequencer.o + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Seq/Sequencer.C b/src/Seq/Sequencer.C @@ -0,0 +1,204 @@ +/* + ZynAddSubFX - a software synthesizer + + Sequencer.C - The Sequencer + Copyright (C) 2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + +#include <sys/time.h> +#include <time.h> + +#include "Sequencer.h" + + + +Sequencer::Sequencer(){ + rec=0; + play=0; + for (int i=0;i<NUM_MIDI_CHANNELS;i++){ + midichan[i].track.first=NULL; + midichan[i].track.current=NULL; + midichan[i].track.size=0; + midichan[i].track.length=0.0; + midichan[i].record.first=NULL; + midichan[i].record.current=NULL; + midichan[i].record.size=0; + midichan[i].record.length=0.0; + }; + + resettime(&rectime); + resettime(&playtime); +}; + +Sequencer::~Sequencer(){ + for (int i=0;i<NUM_MIDI_CHANNELS;i++){ + deletelist(&midichan[i].track); + deletelist(&midichan[i].record); + }; +}; + +void Sequencer::recordnote(char chan, char note, char vel){ + if (rec==0) return; + if (chan>=NUM_MIDI_CHANNELS) return; + + updatecounter(&rectime); + int dt=(int) (rectime.rel*1000.0); + tmpevent.deltatime=dt; + + tmpevent.type=1; + tmpevent.par1=note; + tmpevent.par2=vel; + + writeevent(&midichan[chan].record,&tmpevent); + midichan[chan].record.length=rectime.abs; + + printf("Note %d %d %d \n",chan,note,vel); +}; + +void Sequencer::recordcontroller(char chan,unsigned int type,int par){ + if (rec==0) return; + if (chan>=NUM_MIDI_CHANNELS) return; + + updatecounter(&rectime); + int dt=(int) (rectime.rel*1000.0); + tmpevent.deltatime=dt; + + tmpevent.type=2; + tmpevent.par1=type; + tmpevent.par2=par; + + writeevent(&midichan[chan].record,&tmpevent); + midichan[chan].record.length=rectime.abs; + + printf("Ctl %d %d %d \n",chan,type,par); +}; + + + +void Sequencer::startrec(){ + if (rec!=0) return; + resettime(&rectime); + rec=1; +}; + +void Sequencer::stoprec(){ + if (rec==0) return; + //for now, only record over track (erase the track) + for (int i=0;i<NUM_MIDI_CHANNELS;i++){ + deletelist(&midichan[i].track); + midichan[i].track=midichan[i].record; + deletelistreference(&midichan[i].record); + }; + rec=0; +}; + +void Sequencer::startplay(){ + if (play!=0) return; + play=1; + resettime(&playtime); + + //test - canalul 1, deocamdata + rewindlist(&midichan[0].track); + printf("\n\n==================================="); + do { + readevent(&midichan[0].track,&tmpevent); + printf("Play note %d %d \n",tmpevent.par1,tmpevent.par2); + } while(tmpevent.type>=0); + +}; +void Sequencer::stopplay(){ + if (play==0) return; + play=0; +}; + +/************** Track stuff ***************/ + + +void Sequencer::writeevent(list *l,event *ev){ + listpos *tmp=new listpos; + tmp->next=NULL; + tmp->ev=*ev; + if (l->current!=NULL) l->current->next=tmp; + else l->first=tmp; + l->current=tmp; + l->size++; +}; + +void Sequencer::readevent(list *l,event *ev){ + if (l->current==NULL) { + ev->type=-1; + return; + }; + *ev=l->current->ev; + l->current=l->current->next; +}; + + +void Sequencer::rewindlist(list *l){ + l->current=l->first; +}; + +void Sequencer::deletelist(list *l){ + l->current=l->first; + if (l->current==NULL) return; + while (l->current->next!=NULL){ + listpos *tmp=l->current; + l->current=l->current->next; + delete(tmp); + }; + deletelistreference(l); +}; + +void Sequencer::deletelistreference(list *l){ + l->current=l->first=NULL; + l->size=0; + l->length=0.0; +}; + +/************** Timer stuff ***************/ + +void Sequencer::resettime(timestruct *t){ + t->abs=0.0; + t->rel=0.0; + + timeval tval; + + if (gettimeofday(&tval,NULL)==0) + t->last=tval.tv_sec+tval.tv_usec*0.000001; + else t->last=0.0; + +}; + +void Sequencer::updatecounter(timestruct *t){ + timeval tval; + double current; + if (gettimeofday(&tval,NULL)==0) + current=tval.tv_sec+tval.tv_usec*0.000001; + else current=0.0; + + t->rel=current - t->last; + t->abs+=t->rel; + t->last=current; + +// printf("%f %f %f\n",t->last,t->abs,t->rel); +}; + diff --git a/src/Seq/Sequencer.h b/src/Seq/Sequencer.h @@ -0,0 +1,92 @@ +/* + ZynAddSubFX - a software synthesizer + + Sequencer.h - The Sequencer + Copyright (C) 2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef SEQUENCER_H +#define SEQUENCER_H + +#include "../globals.h" + +class Sequencer{ + public: + Sequencer(); + ~Sequencer(); + + //theese functions are called by the master and are ignored if the recorder/player are stopped + void recordnote(char chan, char note, char vel); + void recordcontroller(char chan,unsigned int type,int par); + //int playnote(char &chan, char &note, char &vel);//returns 1 if somehing must be played + //(if returns 1) you need to call it until returns 0 + + + //UI controlling functions + void startrec(); + void stoprec(); + + void startplay(); + void stopplay(); + + int rec,play; + + private: + + /* Events */ + struct event{ + int deltatime; + int type,par1,par2;//type=1 for note,2 for controller + }tmpevent; + struct listpos{ + event ev; + struct listpos *next; + }; + struct list{ + listpos *first,*current; + int size;//how many events are + double length;//in seconds + }; + struct { + list track//the stored track + ,record;//the track being recorded + } midichan[NUM_MIDI_CHANNELS]; + + void writeevent(list *l,event *ev); + void readevent(list *l,event *ev); + + void rewindlist(list *l); + void deletelist(list *l); + void deletelistreference(list *l); + + /* Timer */ + struct timestruct{ + double abs;//the time from the begining of the track + double rel;//the time difference between the last and the current event + double last;//the time of the last event (absolute, since 1 Jan 1970) + //theese must be double, because the float's precision is too low + //and all theese represents the time in seconds + } rectime,playtime; + + void resettime(timestruct *t); + void updatecounter(timestruct *t);//this updates the timer values + +}; + +#endif + diff --git a/src/Synth/ADnote.C b/src/Synth/ADnote.C @@ -0,0 +1,930 @@ +/* + ZynAddSubFX - a software synthesizer + + ADnote.C - The "additive" synthesizer + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> + + +#include "../globals.h" +#include "../Misc/Util.h" +#include "ADnote.h" + + +ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_){ + ready=0; + + tmpwave=new REALTYPE [SOUND_BUFFER_SIZE]; + bypassl=new REALTYPE [SOUND_BUFFER_SIZE]; + bypassr=new REALTYPE [SOUND_BUFFER_SIZE]; + + partparams=pars; + ctl=ctl_; + portamento=portamento_; + midinote=midinote_; + NoteEnabled=ON; + basefreq=freq; + if (velocity>1.0) velocity=1.0; + this->velocity=velocity; + time=0.0; + stereo=pars->GlobalPar.PStereo; + + NoteGlobalPar.Detune=getdetune(pars->GlobalPar.PDetuneType + ,pars->GlobalPar.PCoarseDetune,pars->GlobalPar.PDetune);; + + if (pars->GlobalPar.PPanning==0) NoteGlobalPar.Panning=RND; + else NoteGlobalPar.Panning=pars->GlobalPar.PPanning/128.0; + + + NoteGlobalPar.FilterCenterPitch=pars->GlobalPar.GlobalFilter->getfreq()+//center freq + pars->GlobalPar.PFilterVelocityScale/127.0*6.0* //velocity sensing + (VelF(velocity,pars->GlobalPar.PFilterVelocityScaleFunction)-1); + + if (pars->GlobalPar.PPunchStrength!=0) { + NoteGlobalPar.Punch.Enabled=1; + NoteGlobalPar.Punch.t=1.0;//start from 1.0 and to 0.0 + NoteGlobalPar.Punch.initialvalue=( (pow(10,1.5*pars->GlobalPar.PPunchStrength/127.0)-1.0) + *VelF(velocity,pars->GlobalPar.PPunchVelocitySensing) ); + REALTYPE time=pow(10,3.0*pars->GlobalPar.PPunchTime/127.0)/10000.0;//0.1 .. 100 ms + REALTYPE stretch=pow(440.0/freq,pars->GlobalPar.PPunchStretch/64.0); + NoteGlobalPar.Punch.dt=1.0/(time*SAMPLE_RATE*stretch); + } else NoteGlobalPar.Punch.Enabled=0; + + for (int nvoice=0;nvoice<NUM_VOICES;nvoice++){ + NoteVoicePar[nvoice].OscilSmp=NULL; + NoteVoicePar[nvoice].FMSmp=NULL; + NoteVoicePar[nvoice].VoiceOut=NULL; + + NoteVoicePar[nvoice].FMVoice=-1; + + if (pars->VoicePar[nvoice].Enabled==0) { + NoteVoicePar[nvoice].Enabled=OFF; + continue; //the voice is disabled + }; + + NoteVoicePar[nvoice].Enabled=ON; + NoteVoicePar[nvoice].fixedfreq=pars->VoicePar[nvoice].Pfixedfreq; + NoteVoicePar[nvoice].fixedfreqET=pars->VoicePar[nvoice].PfixedfreqET; + + //use the Globalpars.detunetype if the detunetype is 0 + if (pars->VoicePar[nvoice].PDetuneType!=0){ + NoteVoicePar[nvoice].Detune=getdetune(pars->VoicePar[nvoice].PDetuneType + ,pars->VoicePar[nvoice].PCoarseDetune,8192);//coarse detune + NoteVoicePar[nvoice].FineDetune=getdetune(pars->VoicePar[nvoice].PDetuneType + ,0,pars->VoicePar[nvoice].PDetune);//fine detune + } else { + NoteVoicePar[nvoice].Detune=getdetune(pars->GlobalPar.PDetuneType + ,pars->VoicePar[nvoice].PCoarseDetune,8192);//coarse detune + NoteVoicePar[nvoice].FineDetune=getdetune(pars->GlobalPar.PDetuneType + ,0,pars->VoicePar[nvoice].PDetune);//fine detune + }; + if (pars->VoicePar[nvoice].PFMDetuneType!=0){ + NoteVoicePar[nvoice].FMDetune=getdetune(pars->VoicePar[nvoice].PFMDetuneType + ,pars->VoicePar[nvoice].PFMCoarseDetune,pars->VoicePar[nvoice].PFMDetune); + } else { + NoteVoicePar[nvoice].FMDetune=getdetune(pars->GlobalPar.PDetuneType + ,pars->VoicePar[nvoice].PFMCoarseDetune,pars->VoicePar[nvoice].PFMDetune); + }; + + oscposhi[nvoice]=0;oscposlo[nvoice]=0.0; + oscposhiFM[nvoice]=0;oscposloFM[nvoice]=0.0; + + NoteVoicePar[nvoice].OscilSmp=new REALTYPE[OSCIL_SIZE+1];//the extra point contains the first point + + //Get the voice's oscil or external's voice oscil + int vc=nvoice; + if (pars->VoicePar[nvoice].Pextoscil!=-1) vc=pars->VoicePar[nvoice].Pextoscil; + oscposhi[nvoice]=pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp,getvoicebasefreq(nvoice), + pars->VoicePar[nvoice].Presonance); + //I store the first elment to the last position for speedups + NoteVoicePar[nvoice].OscilSmp[OSCIL_SIZE]=NoteVoicePar[nvoice].OscilSmp[0]; + oscposhi[nvoice]+=(int)((pars->VoicePar[nvoice].Poscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4); + oscposhi[nvoice]%=OSCIL_SIZE; + + + NoteVoicePar[nvoice].FreqLfo=NULL; + NoteVoicePar[nvoice].FreqEnvelope=NULL; + + NoteVoicePar[nvoice].AmpLfo=NULL; + NoteVoicePar[nvoice].AmpEnvelope=NULL; + + NoteVoicePar[nvoice].VoiceFilter=NULL; + NoteVoicePar[nvoice].FilterEnvelope=NULL; + NoteVoicePar[nvoice].FilterLfo=NULL; + + NoteVoicePar[nvoice].FilterCenterPitch=pars->VoicePar[nvoice].VoiceFilter->getfreq(); + NoteVoicePar[nvoice].filterbypass=pars->VoicePar[nvoice].Pfilterbypass; + + switch(pars->VoicePar[nvoice].PFMEnabled){ + case 1:NoteVoicePar[nvoice].FMEnabled=MORPH;break; + case 2:NoteVoicePar[nvoice].FMEnabled=RING_MOD;break; + case 3:NoteVoicePar[nvoice].FMEnabled=PHASE_MOD;break; + case 4:NoteVoicePar[nvoice].FMEnabled=FREQ_MOD;break; + case 5:NoteVoicePar[nvoice].FMEnabled=PITCH_MOD;break; + default:NoteVoicePar[nvoice].FMEnabled=NONE; + }; + + NoteVoicePar[nvoice].FMVoice=pars->VoicePar[nvoice].PFMVoice; + NoteVoicePar[nvoice].FMFreqEnvelope=NULL; + NoteVoicePar[nvoice].FMAmpEnvelope=NULL; + + //Compute the Voice's modulator volume (incl. damping) + REALTYPE fmvoldamp=pow(440.0/getvoicebasefreq(nvoice),pars->VoicePar[nvoice].PFMVolumeDamp/64.0-1.0); + switch (NoteVoicePar[nvoice].FMEnabled){ + case PHASE_MOD:fmvoldamp=pow(440.0/getvoicebasefreq(nvoice),pars->VoicePar[nvoice].PFMVolumeDamp/64.0); + NoteVoicePar[nvoice].FMVolume=(exp(pars->VoicePar[nvoice].PFMVolume/127.0*FM_AMP_MULTIPLIER)-1.0)*fmvoldamp*4.0; + break; + case FREQ_MOD:NoteVoicePar[nvoice].FMVolume=(exp(pars->VoicePar[nvoice].PFMVolume/127.0*FM_AMP_MULTIPLIER)-1.0)*fmvoldamp*4.0; + break; + // case PITCH_MOD:NoteVoicePar[nvoice].FMVolume=(pars->VoicePar[nvoice].PFMVolume/127.0*8.0)*fmvoldamp;//??????????? + // break; + default:if (fmvoldamp>1.0) fmvoldamp=1.0; + NoteVoicePar[nvoice].FMVolume=pars->VoicePar[nvoice].PFMVolume/127.0*fmvoldamp; + }; + + //Voice's modulator velocity sensing + NoteVoicePar[nvoice].FMVolume*=VelF(velocity,partparams->VoicePar[nvoice].PFMVelocityScaleFunction); + + FMoldsmp[nvoice]=0.0;//this is for FM (integration) + + firsttick[nvoice]=1; + NoteVoicePar[nvoice].DelayTicks=(int)((exp(pars->VoicePar[nvoice].PDelay/127.0*log(50.0))-1.0)/SOUND_BUFFER_SIZE/10.0*SAMPLE_RATE); + }; + + initparameters(); + ready=1; +}; + + +/* + * Kill a voice of ADnote + */ +void ADnote::KillVoice(int nvoice){ + + delete (NoteVoicePar[nvoice].OscilSmp); + + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope); + NoteVoicePar[nvoice].FreqEnvelope=NULL; + + if (NoteVoicePar[nvoice].FreqLfo!=NULL) delete(NoteVoicePar[nvoice].FreqLfo); + NoteVoicePar[nvoice].FreqLfo=NULL; + + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].AmpEnvelope); + NoteVoicePar[nvoice].AmpEnvelope=NULL; + + if (NoteVoicePar[nvoice].AmpLfo!=NULL) delete (NoteVoicePar[nvoice].AmpLfo); + NoteVoicePar[nvoice].AmpLfo=NULL; + + if (NoteVoicePar[nvoice].VoiceFilter!=NULL) delete (NoteVoicePar[nvoice].VoiceFilter); + NoteVoicePar[nvoice].VoiceFilter=NULL; + + if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) delete (NoteVoicePar[nvoice].FilterEnvelope); + NoteVoicePar[nvoice].FilterEnvelope=NULL; + + if (NoteVoicePar[nvoice].FilterLfo!=NULL) delete (NoteVoicePar[nvoice].FilterLfo); + NoteVoicePar[nvoice].FilterLfo=NULL; + + if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) delete (NoteVoicePar[nvoice].FMFreqEnvelope); + NoteVoicePar[nvoice].FMFreqEnvelope=NULL; + + if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].FMAmpEnvelope); + NoteVoicePar[nvoice].FMAmpEnvelope=NULL; + + if ((NoteVoicePar[nvoice].FMEnabled!=NONE)&&(NoteVoicePar[nvoice].FMVoice<0)) delete NoteVoicePar[nvoice].FMSmp; + + if (NoteVoicePar[nvoice].VoiceOut!=NULL) + for (int i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0;//do not delete, yet: perhaps is used by another voice + + NoteVoicePar[nvoice].Enabled=OFF; +}; + +/* + * Kill the note + */ +void ADnote::KillNote(){ + int nvoice; + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (NoteVoicePar[nvoice].Enabled==ON) KillVoice(nvoice); + + //delete VoiceOut + if (NoteVoicePar[nvoice].VoiceOut!=NULL) delete(NoteVoicePar[nvoice].VoiceOut); + NoteVoicePar[nvoice].VoiceOut=NULL; + }; + + delete (NoteGlobalPar.FreqEnvelope); + delete (NoteGlobalPar.FreqLfo); + delete (NoteGlobalPar.AmpEnvelope); + delete (NoteGlobalPar.AmpLfo); + delete (NoteGlobalPar.GlobalFilterL); + if (stereo!=0) delete (NoteGlobalPar.GlobalFilterR); + delete (NoteGlobalPar.FilterEnvelope); + delete (NoteGlobalPar.FilterLfo); + + NoteEnabled=OFF; +}; + +ADnote::~ADnote(){ + if (NoteEnabled==ON) KillNote(); + delete [] tmpwave; + delete [] bypassl; + delete [] bypassr; +}; + + +/* + * Init the parameters + */ +void ADnote::initparameters(){ + int nvoice,i,tmp[NUM_VOICES]; + + // Global Parameters + NoteGlobalPar.FreqEnvelope=new Envelope(partparams->GlobalPar.FreqEnvelope,basefreq); + NoteGlobalPar.FreqLfo=new LFO(partparams->GlobalPar.FreqLfo); + + NoteGlobalPar.AmpEnvelope=new Envelope(partparams->GlobalPar.AmpEnvelope,basefreq); + NoteGlobalPar.AmpLfo=new LFO(partparams->GlobalPar.AmpLfo); + + NoteGlobalPar.Volume=4.0*pow(0.1,3.0*(1.0-partparams->GlobalPar.PVolume/96.0))//-60 dB .. 0 dB + *VelF(velocity,partparams->GlobalPar.PAmpVelocityScaleFunction);//velocity sensing + + NoteGlobalPar.AmpEnvelope->envout_dB();//discard the first envelope output + globalnewamplitude=NoteGlobalPar.Volume*NoteGlobalPar.AmpEnvelope->envout_dB()*NoteGlobalPar.AmpLfo->amplfoout(); + + NoteGlobalPar.GlobalFilterL=new Filter(partparams->GlobalPar.GlobalFilter); + if (stereo!=0) NoteGlobalPar.GlobalFilterR=new Filter(partparams->GlobalPar.GlobalFilter); + + NoteGlobalPar.FilterEnvelope=new Envelope(partparams->GlobalPar.FilterEnvelope,basefreq); + NoteGlobalPar.FilterLfo=new LFO(partparams->GlobalPar.FilterLfo); + NoteGlobalPar.FilterQ=partparams->GlobalPar.GlobalFilter->getq(); + NoteGlobalPar.FilterFreqTracking=partparams->GlobalPar.GlobalFilter->getfreqtracking(basefreq); + + // Forbids the Modulation Voice to be greater or equal than voice + for (i=0;i<NUM_VOICES;i++) if (NoteVoicePar[i].FMVoice>=i) NoteVoicePar[i].FMVoice=-1; + + // Voice Parameter init + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (NoteVoicePar[nvoice].Enabled==0) continue; + + NoteVoicePar[nvoice].noisetype=partparams->VoicePar[nvoice].Type; + /* Voice Amplitude Parameters Init */ + NoteVoicePar[nvoice].Volume=pow(0.1,3.0*(1.0-partparams->VoicePar[nvoice].PVolume/127.0)) // -60 dB .. 0 dB + *VelF(velocity,partparams->VoicePar[nvoice].PAmpVelocityScaleFunction);//velocity + + if (partparams->VoicePar[nvoice].PVolumeminus!=0) NoteVoicePar[nvoice].Volume=-NoteVoicePar[nvoice].Volume; + + if (partparams->VoicePar[nvoice].PPanning==0) + NoteVoicePar[nvoice].Panning=RND;// random panning + else NoteVoicePar[nvoice].Panning=partparams->VoicePar[nvoice].PPanning/128.0; + + newamplitude[nvoice]=1.0; + if (partparams->VoicePar[nvoice].PAmpEnvelopeEnabled!=0) { + NoteVoicePar[nvoice].AmpEnvelope=new Envelope(partparams->VoicePar[nvoice].AmpEnvelope,basefreq); + NoteVoicePar[nvoice].AmpEnvelope->envout_dB();//discard the first envelope sample + newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpEnvelope->envout_dB(); + }; + + if (partparams->VoicePar[nvoice].PAmpLfoEnabled!=0){ + NoteVoicePar[nvoice].AmpLfo=new LFO(partparams->VoicePar[nvoice].AmpLfo); + newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpLfo->amplfoout(); + }; + + /* Voice Frequency Parameters Init */ + if (partparams->VoicePar[nvoice].PFreqEnvelopeEnabled!=0) + NoteVoicePar[nvoice].FreqEnvelope=new Envelope(partparams->VoicePar[nvoice].FreqEnvelope,basefreq); + + if (partparams->VoicePar[nvoice].PFreqLfoEnabled!=0) NoteVoicePar[nvoice].FreqLfo=new LFO(partparams->VoicePar[nvoice].FreqLfo); + + /* Voice Filter Parameters Init */ + if (partparams->VoicePar[nvoice].PFilterEnabled!=0){ + NoteVoicePar[nvoice].VoiceFilter=new Filter(partparams->VoicePar[nvoice].VoiceFilter); + }; + + if (partparams->VoicePar[nvoice].PFilterEnvelopeEnabled!=0) + NoteVoicePar[nvoice].FilterEnvelope=new Envelope(partparams->VoicePar[nvoice].FilterEnvelope,basefreq); + + if (partparams->VoicePar[nvoice].PFilterLfoEnabled!=0) + NoteVoicePar[nvoice].FilterLfo=new LFO(partparams->VoicePar[nvoice].FilterLfo); + + NoteVoicePar[nvoice].FilterFreqTracking=partparams->VoicePar[nvoice].VoiceFilter->getfreqtracking(basefreq); + + /* Voice Modulation Parameters Init */ + if ((NoteVoicePar[nvoice].FMEnabled!=NONE)&&(NoteVoicePar[nvoice].FMVoice<0)){ + NoteVoicePar[nvoice].FMSmp=new REALTYPE[OSCIL_SIZE+1]; + + //Perform Anti-aliasing only on MORPH or RING MODULATION + REALTYPE tmp=1.0; + switch(NoteVoicePar[nvoice].FMEnabled){ + case MORPH: + case RING_MOD:tmp=getFMvoicebasefreq(nvoice); + break; + default: break; + }; + + int vc=nvoice; + if (partparams->VoicePar[nvoice].PextFMoscil!=-1) vc=partparams->VoicePar[nvoice].PextFMoscil; + + oscposhiFM[nvoice]=(oscposhi[nvoice]+partparams->VoicePar[vc].FMSmp->get(NoteVoicePar[nvoice].FMSmp,tmp)) % OSCIL_SIZE; + NoteVoicePar[nvoice].FMSmp[OSCIL_SIZE]=NoteVoicePar[nvoice].FMSmp[0]; + oscposhiFM[nvoice]+=(int)((partparams->VoicePar[nvoice].PFMoscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4); + oscposhiFM[nvoice]%=OSCIL_SIZE; + }; + + if (partparams->VoicePar[nvoice].PFMFreqEnvelopeEnabled!=0) + NoteVoicePar[nvoice].FMFreqEnvelope=new Envelope(partparams->VoicePar[nvoice].FMFreqEnvelope,basefreq); + + FMnewamplitude[nvoice]=NoteVoicePar[nvoice].FMVolume*ctl->fmamp.relamp; + + if (partparams->VoicePar[nvoice].PFMAmpEnvelopeEnabled!=0){ + NoteVoicePar[nvoice].FMAmpEnvelope=new Envelope(partparams->VoicePar[nvoice].FMAmpEnvelope,basefreq); + FMnewamplitude[nvoice]*=NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB(); + }; + }; + + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + for (i=nvoice+1;i<NUM_VOICES;i++) tmp[i]=0; + for (i=nvoice+1;i<NUM_VOICES;i++) + if ((NoteVoicePar[i].FMVoice==nvoice)&&(tmp[i]==0)){ + NoteVoicePar[nvoice].VoiceOut=new REALTYPE[SOUND_BUFFER_SIZE]; + tmp[i]=1; + }; + if (NoteVoicePar[nvoice].VoiceOut!=NULL) for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0; + }; +}; + + + +/* + * Computes the frequency of an oscillator + */ +void ADnote::setfreq(int nvoice,REALTYPE freq){ + REALTYPE speed; + freq=fabs(freq); + speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + + F2I(speed,oscfreqhi[nvoice]); + oscfreqlo[nvoice]=speed-floor(speed); +}; + +/* + * Computes the frequency of an modullator oscillator + */ +void ADnote::setfreqFM(int nvoice,REALTYPE freq){ + REALTYPE speed; + freq=fabs(freq); + speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE; + if (speed>OSCIL_SIZE) speed=OSCIL_SIZE; + + F2I(speed,oscfreqhiFM[nvoice]); + oscfreqloFM[nvoice]=speed-floor(speed); +}; + +/* + * Get Voice base frequency + */ +REALTYPE ADnote::getvoicebasefreq(int nvoice){ + REALTYPE detune=NoteVoicePar[nvoice].Detune/100.0+ + NoteVoicePar[nvoice].FineDetune/100.0*ctl->bandwidth.relbw+ + NoteGlobalPar.Detune/100.0; + if (NoteVoicePar[nvoice].fixedfreq==0) return(this->basefreq*pow(2,detune/12.0)); + else {//the fixed freq is enabled + REALTYPE fixedfreq=440.0; + int fixedfreqET=NoteVoicePar[nvoice].fixedfreqET; + if (fixedfreqET!=0) {//if the frequency varies according the keyboard note + REALTYPE tmp=(midinote-69.0)/12.0*(pow(2.0,(fixedfreqET-1)/63.0)-1.0); + if (fixedfreqET<=64) fixedfreq*=pow(2.0,tmp); + else fixedfreq*=pow(3.0,tmp); + }; + return(fixedfreq*pow(2.0,detune/12.0)); + }; +}; + +/* + * Get Voice's Modullator base frequency + */ +REALTYPE ADnote::getFMvoicebasefreq(int nvoice){ + REALTYPE detune=NoteVoicePar[nvoice].FMDetune/100.0; + return(getvoicebasefreq(nvoice)*pow(2,detune/12.0)); +}; + +/* + * Computes all the parameters for each tick + */ +void ADnote::computecurrentparameters(){ + int nvoice; + REALTYPE voicefreq,voicepitch,filterpitch,filterfreq,FMfreq,FMrelativepitch,globalpitch,globalfilterpitch; + globalpitch=0.01*(NoteGlobalPar.FreqEnvelope->envout()+ + NoteGlobalPar.FreqLfo->lfoout()*ctl->modwheel.relmod); + globaloldamplitude=globalnewamplitude; + globalnewamplitude=NoteGlobalPar.Volume*NoteGlobalPar.AmpEnvelope->envout_dB()*NoteGlobalPar.AmpLfo->amplfoout(); + + globalfilterpitch=NoteGlobalPar.FilterEnvelope->envout()+NoteGlobalPar.FilterLfo->lfoout() + +NoteGlobalPar.FilterCenterPitch; + + REALTYPE tmpfilterfreq=globalfilterpitch+ctl->filtercutoff.relfreq + +NoteGlobalPar.FilterFreqTracking; + + tmpfilterfreq=NoteGlobalPar.GlobalFilterL->getrealfreq(tmpfilterfreq); + + REALTYPE globalfilterq=NoteGlobalPar.FilterQ*ctl->filterq.relq; + NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq,globalfilterq); + if (stereo!=0) NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq,globalfilterq); + + //compute the portamento, if it is used by this note + REALTYPE portamentofreqrap=1.0; + if (portamento!=0){//this voice use portamento + portamentofreqrap=ctl->portamento.freqrap; + if (ctl->portamento.used==0){//the portamento has finished + portamento=0;//this note is no longer "portamented" + }; + }; + + //compute parameters for all voices + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (NoteVoicePar[nvoice].Enabled!=ON) continue; + NoteVoicePar[nvoice].DelayTicks-=1; + if (NoteVoicePar[nvoice].DelayTicks>0) continue; + + /*******************/ + /* Voice Amplitude */ + /*******************/ + oldamplitude[nvoice]=newamplitude[nvoice]; + newamplitude[nvoice]=1.0; + + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) + newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpEnvelope->envout_dB(); + + if (NoteVoicePar[nvoice].AmpLfo!=NULL) + newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpLfo->amplfoout(); + + /****************/ + /* Voice Filter */ + /****************/ + if (NoteVoicePar[nvoice].VoiceFilter!=NULL){ + filterpitch=NoteVoicePar[nvoice].FilterCenterPitch; + + if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) + filterpitch+=NoteVoicePar[nvoice].FilterEnvelope->envout(); + + if (NoteVoicePar[nvoice].FilterLfo!=NULL) + filterpitch+=NoteVoicePar[nvoice].FilterLfo->lfoout(); + + filterfreq=filterpitch+NoteVoicePar[nvoice].FilterFreqTracking; + filterfreq=NoteVoicePar[nvoice].VoiceFilter->getrealfreq(filterfreq); + + NoteVoicePar[nvoice].VoiceFilter->setfreq(filterfreq); + }; + + if (NoteVoicePar[nvoice].noisetype==0){//compute only if the voice isn't noise + + /*******************/ + /* Voice Frequency */ + /*******************/ + voicepitch=0.0; + if (NoteVoicePar[nvoice].FreqLfo!=NULL) + voicepitch+=NoteVoicePar[nvoice].FreqLfo->lfoout()/100.0 + *ctl->bandwidth.relbw; + + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) voicepitch+=NoteVoicePar[nvoice].FreqEnvelope->envout()/100.0; + voicefreq=getvoicebasefreq(nvoice)*pow(2,(voicepitch+globalpitch)/12.0);//Hz frequency + voicefreq*=ctl->pitchwheel.relfreq;//change the frequency by the controller + setfreq(nvoice,voicefreq*portamentofreqrap); + + /***************/ + /* Modulator */ + /***************/ + if (NoteVoicePar[nvoice].FMEnabled!=NONE){ + FMrelativepitch=NoteVoicePar[nvoice].FMDetune/100.0; + if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) FMrelativepitch+=NoteVoicePar[nvoice].FMFreqEnvelope->envout()/100; + FMfreq=pow(2.0,FMrelativepitch/12.0)*voicefreq*portamentofreqrap; + setfreqFM(nvoice,FMfreq); + + FMoldamplitude[nvoice]=FMnewamplitude[nvoice]; + FMnewamplitude[nvoice]=NoteVoicePar[nvoice].FMVolume*ctl->fmamp.relamp; + if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) + FMnewamplitude[nvoice]*=NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB(); + }; + }; + + }; + time+=(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; +}; + + +/* + * Fadein in a way that removes clicks but keep sound "punchy" + */ +inline void ADnote::fadein(REALTYPE *smps){ + int zerocrossings=0; + for (int i=1;i<SOUND_BUFFER_SIZE;i++) + if ((smps[i-1]<0.0) && (smps[i]>0.0)) zerocrossings++;//this is only the possitive crossings + + REALTYPE tmp=(SOUND_BUFFER_SIZE-1.0)/(zerocrossings+1)/3.0; + if (tmp<8.0) tmp=8.0; + + int n; + F2I(tmp,n);//how many samples is the fade-in + if (n>SOUND_BUFFER_SIZE) n=SOUND_BUFFER_SIZE; + for (int i=0;i<n;i++) {//fade-out + REALTYPE tmp=0.5-cos((REALTYPE)i/(REALTYPE) n*PI)*0.5; + smps[i]*=tmp; + }; +}; + +/* + * Computes the Oscillator (Without Modulation) + */ +inline void ADnote::ComputeVoiceOscillator(int nvoice){ + int i,poshi; + REALTYPE poslo; + + poshi=oscposhi[nvoice]; + poslo=oscposlo[nvoice]; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]=NoteVoicePar[nvoice].OscilSmp[poshi]*(1.0-poslo)+NoteVoicePar[nvoice].OscilSmp[poshi+1]*poslo; + poslo+=oscfreqlo[nvoice]; + if (poslo>=1.0) { + poslo-=1.0; + poshi++; + }; + poshi+=oscfreqhi[nvoice]; + poshi&=OSCIL_SIZE-1; + }; + oscposhi[nvoice]=poshi; + oscposlo[nvoice]=poslo; +}; + +/* + * Computes the Oscillator (Morphing) + */ +inline void ADnote::ComputeVoiceOscillatorMorph(int nvoice){ + int i; + REALTYPE amp; + ComputeVoiceOscillator(nvoice); + if (FMnewamplitude[nvoice]>1.0) FMnewamplitude[nvoice]=1.0; + if (FMoldamplitude[nvoice]>1.0) FMoldamplitude[nvoice]=1.0; + + if (NoteVoicePar[nvoice].FMVoice>=0){ + //if I use VoiceOut[] as modullator + int FMVoice=NoteVoicePar[nvoice].FMVoice; + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tmpwave[i]=tmpwave[i]*(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i]; + }; + } else { + int poshiFM=oscposhiFM[nvoice]; + REALTYPE posloFM=oscposloFM[nvoice]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tmpwave[i]=tmpwave[i]*(1.0-amp)+amp + *(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM); + posloFM+=oscfreqloFM[nvoice]; + if (posloFM>=1.0) { + posloFM-=1.0; + poshiFM++; + }; + poshiFM+=oscfreqhiFM[nvoice]; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice]=poshiFM; + oscposloFM[nvoice]=posloFM; + }; +}; + +/* + * Computes the Oscillator (Ring Modulation) + */ +inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice){ + int i; + REALTYPE amp; + ComputeVoiceOscillator(nvoice); + if (FMnewamplitude[nvoice]>1.0) FMnewamplitude[nvoice]=1.0; + if (FMoldamplitude[nvoice]>1.0) FMoldamplitude[nvoice]=1.0; + if (NoteVoicePar[nvoice].FMVoice>=0){ + // if I use VoiceOut[] as modullator + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + int FMVoice=NoteVoicePar[nvoice].FMVoice; + for (i=0;i<SOUND_BUFFER_SIZE;i++) + tmpwave[i]*=(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i]; + }; + } else { + int poshiFM=oscposhiFM[nvoice]; + REALTYPE posloFM=oscposloFM[nvoice]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + tmpwave[i]*=( NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM)*amp + +(1.0-amp); + posloFM+=oscfreqloFM[nvoice]; + if (posloFM>=1.0) { + posloFM-=1.0; + poshiFM++; + }; + poshiFM+=oscfreqhiFM[nvoice]; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice]=poshiFM; + oscposloFM[nvoice]=posloFM; + }; +}; + + + +/* + * Computes the Oscillator (Phase Modulation or Frequency Modulation) + */ +inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMmode){ + int carposhi; + int i,FMmodfreqhi; + REALTYPE FMmodfreqlo,carposlo; + + if (NoteVoicePar[nvoice].FMVoice>=0){ + //if I use VoiceOut[] as modulator + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=NoteVoicePar[NoteVoicePar[nvoice].FMVoice].VoiceOut[i]; + } else { + //Compute the modulator and store it in tmpwave[] + int poshiFM=oscposhiFM[nvoice]; + REALTYPE posloFM=oscposloFM[nvoice]; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]=(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM) + +NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM); + posloFM+=oscfreqloFM[nvoice]; + if (posloFM>=1.0) { + posloFM=fmod(posloFM,1.0); + poshiFM++; + }; + poshiFM+=oscfreqhiFM[nvoice]; + poshiFM&=OSCIL_SIZE-1; + }; + oscposhiFM[nvoice]=poshiFM; + oscposloFM[nvoice]=posloFM; + }; + // Amplitude interpolation + if (ABOVE_AMPLITUDE_THRESHOLD(FMoldamplitude[nvoice],FMnewamplitude[nvoice])){ + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]*=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice] + ,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE); + }; + } else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=FMnewamplitude[nvoice]; + + + //normalize makes all sample-rates, oscil_sizes toproduce same sound + if (FMmode!=0){//Frequency modulation + REALTYPE normalize=OSCIL_SIZE/262144.0*44100.0/(REALTYPE)SAMPLE_RATE; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + FMoldsmp[nvoice]=fmod(FMoldsmp[nvoice]+tmpwave[i]*normalize,OSCIL_SIZE); + tmpwave[i]=FMoldsmp[nvoice]; + }; + } else {//Phase modulation + REALTYPE normalize=OSCIL_SIZE/262144.0; + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=normalize; + }; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + F2I(tmpwave[i],FMmodfreqhi); + FMmodfreqlo=fmod(tmpwave[i]+0.0000000001,1.0); + if (FMmodfreqhi<0) FMmodfreqlo++; + + //carrier + carposhi=oscposhi[nvoice]+FMmodfreqhi; + carposlo=oscposlo[nvoice]+FMmodfreqlo; + + if (carposlo>=1.0) { + carposhi++; + carposlo=fmod(carposlo,1.0); + }; + carposhi&=(OSCIL_SIZE-1); + + tmpwave[i]=NoteVoicePar[nvoice].OscilSmp[carposhi]*(1.0-carposlo) + +NoteVoicePar[nvoice].OscilSmp[carposhi+1]*carposlo; + + oscposlo[nvoice]+=oscfreqlo[nvoice]; + if (oscposlo[nvoice]>=1.0) { + oscposlo[nvoice]=fmod(oscposlo[nvoice],1.0); + oscposhi[nvoice]++; + }; + + oscposhi[nvoice]+=oscfreqhi[nvoice]; + oscposhi[nvoice]&=OSCIL_SIZE-1; + }; +}; + + +/*Calculeaza Oscilatorul cu PITCH MODULATION*/ +inline void ADnote::ComputeVoiceOscillatorPitchModulation(int nvoice){ +//TODO +}; + +/* + * Computes the Noise + */ +inline void ADnote::ComputeVoiceNoise(int nvoice){ + for (int i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=RND*2.0-1.0; +}; + + + +/* + * Compute the ADnote samples + * Returns 0 if the note is finished + */ +int ADnote::noteout(REALTYPE *outl,REALTYPE *outr){ + int i,nvoice; + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]=denormalkillbuf[i]; + outr[i]=denormalkillbuf[i]; + }; + + if (NoteEnabled==OFF) return(0); + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + bypassl[i]=0.0; + bypassr[i]=0.0; + }; + + computecurrentparameters(); + + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if ((NoteVoicePar[nvoice].Enabled!=ON) || (NoteVoicePar[nvoice].DelayTicks>0)) continue; + if (NoteVoicePar[nvoice].noisetype==0){//voice mode=sound + switch (NoteVoicePar[nvoice].FMEnabled){ + case MORPH:ComputeVoiceOscillatorMorph(nvoice);break; + case RING_MOD:ComputeVoiceOscillatorRingModulation(nvoice);break; + case PHASE_MOD:ComputeVoiceOscillatorFrequencyModulation(nvoice,0);break; + case FREQ_MOD:ComputeVoiceOscillatorFrequencyModulation(nvoice,1);break; + //case PITCH_MOD:ComputeVoiceOscillatorPitchModulation(nvoice);break; + default:ComputeVoiceOscillator(nvoice); + }; + } else ComputeVoiceNoise(nvoice); + // Voice Processing + + // Amplitude + if (ABOVE_AMPLITUDE_THRESHOLD(oldamplitude[nvoice],newamplitude[nvoice])){ + // Amplitude interpolation + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + tmpwave[i]*=INTERPOLATE_AMPLITUDE(oldamplitude[nvoice] + ,newamplitude[nvoice],i,SOUND_BUFFER_SIZE); + }; + } else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=newamplitude[nvoice]; + + // Fade in + if (firsttick[nvoice]!=0){ + fadein(&tmpwave[0]); + firsttick[nvoice]=0; + }; + + + // Filter + if (NoteVoicePar[nvoice].VoiceFilter!=NULL) NoteVoicePar[nvoice].VoiceFilter->filterout(&tmpwave[0]); + + //check if the amplitude envelope is finished, if yes, the voice will be fadeout + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) { + if (NoteVoicePar[nvoice].AmpEnvelope->finished()!=0) + for (i=0;i<SOUND_BUFFER_SIZE;i++) + tmpwave[i]*=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE; + //the voice is killed later + }; + + + // Put the ADnote samples in VoiceOut (without appling Global volume, because I wish to use this voice as a modullator) + if (NoteVoicePar[nvoice].VoiceOut!=NULL) + for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=tmpwave[i]; + + + // Add the voice that do not bypass the filter to out + if (NoteVoicePar[nvoice].filterbypass==0){//no bypass + if (stereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) outl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume;//mono + else for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo + outl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0; + outr[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0; + }; + } else {//bypass the filter + if (stereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) bypassl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume;//mono + else for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo + bypassl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0; + bypassr[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0; + }; + }; + // chech if there is necesary to proces the voice longer (if the Amplitude envelope isn't finished) + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) { + if (NoteVoicePar[nvoice].AmpEnvelope->finished()!=0) KillVoice(nvoice); + }; + }; + + + //Processing Global parameters + NoteGlobalPar.GlobalFilterL->filterout(&outl[0]); + + if (stereo==0) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//set the right channel=left channel + outr[i]=outl[i]; + bypassr[i]=bypassl[i]; + } + } else NoteGlobalPar.GlobalFilterR->filterout(&outr[0]); + + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]+=bypassl[i]; + outr[i]+=bypassr[i]; + }; + + if (ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude,globalnewamplitude)){ + // Amplitude Interpolation + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE tmpvol=INTERPOLATE_AMPLITUDE(globaloldamplitude + ,globalnewamplitude,i,SOUND_BUFFER_SIZE); + outl[i]*=tmpvol*NoteGlobalPar.Panning; + outr[i]*=tmpvol*(1.0-NoteGlobalPar.Panning); + }; + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]*=globalnewamplitude*NoteGlobalPar.Panning; + outr[i]*=globalnewamplitude*(1.0-NoteGlobalPar.Panning); + }; + }; + + //Apply the punch + if (NoteGlobalPar.Punch.Enabled!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE punchamp=NoteGlobalPar.Punch.initialvalue*NoteGlobalPar.Punch.t+1.0; + outl[i]*=punchamp; + outr[i]*=punchamp; + NoteGlobalPar.Punch.t-=NoteGlobalPar.Punch.dt; + if (NoteGlobalPar.Punch.t<0.0) { + NoteGlobalPar.Punch.Enabled=0; + break; + }; + }; + }; + + // Check if the global amplitude is finished. + // If it does, disable the note + if (NoteGlobalPar.AmpEnvelope->finished()!=0) { + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//fade-out + REALTYPE tmp=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE; + outl[i]*=tmp; + outr[i]*=tmp; + }; + KillNote(); + }; + return(1); +}; + + +/* + * Relase the key (NoteOff) + */ +void ADnote::relasekey(){ +int nvoice; + for (nvoice=0;nvoice<NUM_VOICES;nvoice++){ + if (NoteVoicePar[nvoice].Enabled==0) continue; + if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) NoteVoicePar[nvoice].AmpEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) NoteVoicePar[nvoice].FreqEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) NoteVoicePar[nvoice].FilterEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) NoteVoicePar[nvoice].FMFreqEnvelope->relasekey(); + if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) NoteVoicePar[nvoice].FMAmpEnvelope->relasekey(); + }; + NoteGlobalPar.FreqEnvelope->relasekey(); + NoteGlobalPar.FilterEnvelope->relasekey(); + NoteGlobalPar.AmpEnvelope->relasekey(); + +}; + +/* + * Check if the note is finished + */ +int ADnote::finished(){ + if (NoteEnabled==ON) return(0); + else return(1); +}; + + + diff --git a/src/Synth/ADnote.h b/src/Synth/ADnote.h @@ -0,0 +1,252 @@ +/* + ZynAddSubFX - a software synthesizer + + ADnote.h - The "additive" synthesizer + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef AD_NOTE_H +#define AD_NOTE_H + +#include "../globals.h" +#include "Envelope.h" +#include "LFO.h" +#include "../DSP/Filter.h" +#include "../Params/ADnoteParameters.h" +#include "../Params/Controller.h" + +//Globals + +//FM amplitude tune +#define FM_AMP_MULTIPLIER 14.73 // ln(2500000) + +class ADnote{ //ADDitive note + public: + ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_); + ~ADnote(); + int noteout(REALTYPE *outl,REALTYPE *outr); + void relasekey(); + int finished(); + + + /*ready - this is 0 if it is not ready (the parameters has to be computed) + or other value if the parameters has been computed and if it is ready to output*/ + char ready; + + private: + + void setfreq(int nvoice,REALTYPE freq); + void setfreqFM(int nvoice,REALTYPE freq); + void computecurrentparameters(); + void initparameters(); + void KillVoice(int nvoice); + void KillNote(); + inline REALTYPE getvoicebasefreq(int nvoice); + inline REALTYPE getFMvoicebasefreq(int nvoice); + inline void ComputeVoiceOscillator(int nvoice); + inline void ComputeVoiceOscillatorMorph(int nvoice); + inline void ComputeVoiceOscillatorRingModulation(int nvoice); + inline void ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMmode);//FMmode=0 for phase modulation, 1 for Frequency modulation +// inline void ComputeVoiceOscillatorFrequencyModulation(int nvoice); + inline void ComputeVoiceOscillatorPitchModulation(int nvoice); + + inline void ComputeVoiceNoise(int nvoice); + + inline void fadein(REALTYPE *smps); + + + //GLOBALS + ADnoteParameters *partparams; + unsigned char stereo;//if the note is stereo (allows note Panning) + int midinote; + REALTYPE velocity,basefreq; + + ONOFFTYPE NoteEnabled; + Controller *ctl; + + /*****************************************************************/ + /* GLOBAL PARAMETERS */ + /*****************************************************************/ + + struct ADnoteGlobal{ + /****************************************** + * FREQUENCY GLOBAL PARAMETERS * + ******************************************/ + REALTYPE Detune;//cents + + Envelope *FreqEnvelope; + LFO *FreqLfo; + + /******************************************** + * AMPLITUDE GLOBAL PARAMETERS * + ********************************************/ + REALTYPE Volume;// [ 0 .. 1 ] + + REALTYPE Panning;// [ 0 .. 1 ] + + Envelope *AmpEnvelope; + LFO *AmpLfo; + + struct { + int Enabled; + REALTYPE initialvalue,dt,t; + } Punch; + + /****************************************** + * FILTER GLOBAL PARAMETERS * + ******************************************/ + Filter *GlobalFilterL,*GlobalFilterR; + + REALTYPE FilterCenterPitch;//octaves + REALTYPE FilterQ; + REALTYPE FilterFreqTracking; + + Envelope *FilterEnvelope; + + LFO *FilterLfo; + } NoteGlobalPar; + + + + /***********************************************************/ + /* VOICE PARAMETERS */ + /***********************************************************/ + struct ADnoteVoice{ + /* If the voice is enabled */ + ONOFFTYPE Enabled; + + /* Voice Type (sound/noise)*/ + int noisetype; + + /* Filter Bypass */ + int filterbypass; + + /* Delay (ticks) */ + int DelayTicks; + + /* Waveform of the Voice */ + REALTYPE *OscilSmp; + + /************************************ + * FREQUENCY PARAMETERS * + ************************************/ + int fixedfreq;//if the frequency is fixed to 440 Hz + int fixedfreqET;//if the "fixed" frequency varies according to the note (ET) + + // cents = basefreq*VoiceDetune + REALTYPE Detune,FineDetune; + + Envelope *FreqEnvelope; + LFO *FreqLfo; + + + /*************************** + * AMPLITUDE PARAMETERS * + ***************************/ + + /* Panning 0.0=left, 0.5 - center, 1.0 = right */ + REALTYPE Panning; + REALTYPE Volume;// [-1.0 .. 1.0] + + Envelope *AmpEnvelope; + LFO *AmpLfo; + + /************************* + * FILTER PARAMETERS * + *************************/ + + Filter *VoiceFilter; + + REALTYPE FilterCenterPitch;/* Filter center Pitch*/ + REALTYPE FilterFreqTracking; + + Envelope *FilterEnvelope; + LFO *FilterLfo; + + + /**************************** + * MODULLATOR PARAMETERS * + ****************************/ + + FMTYPE FMEnabled; + + int FMVoice; + + // Voice Output used by other voices if use this as modullator + REALTYPE *VoiceOut; + + /* Wave of the Voice */ + REALTYPE *FMSmp; + + REALTYPE FMVolume; + REALTYPE FMDetune; //in cents + + Envelope *FMFreqEnvelope; + Envelope *FMAmpEnvelope; + } NoteVoicePar[NUM_VOICES]; + + + /********************************************************/ + /* INTERNAL VALUES OF THE NOTE AND OF THE VOICES */ + /********************************************************/ + + //time from the start of the note + REALTYPE time; + + //fractional part (skip) + REALTYPE oscposlo[NUM_VOICES],oscfreqlo[NUM_VOICES]; + + //integer part (skip) + int oscposhi[NUM_VOICES],oscfreqhi[NUM_VOICES]; + + //fractional part (skip) of the Modullator + REALTYPE oscposloFM[NUM_VOICES],oscfreqloFM[NUM_VOICES]; + + //integer part (skip) of the Modullator + unsigned short int oscposhiFM[NUM_VOICES],oscfreqhiFM[NUM_VOICES]; + + //used to compute and interpolate the amplitudes of voices and modullators + REALTYPE oldamplitude[NUM_VOICES], + newamplitude[NUM_VOICES], + FMoldamplitude[NUM_VOICES], + FMnewamplitude[NUM_VOICES]; + + //used by Frequency Modulation (for integration) + REALTYPE FMoldsmp[NUM_VOICES]; + + //temporary buffer + REALTYPE *tmpwave; + + //Filter bypass samples + REALTYPE *bypassl,*bypassr; + + //interpolate the amplitudes + REALTYPE globaloldamplitude,globalnewamplitude; + + //1 - if it is the fitst tick (used to fade in the sound) + char firsttick[NUM_VOICES]; + + //1 if the note has portamento + int portamento; +}; + +#endif + + + + diff --git a/src/Synth/Envelope.C b/src/Synth/Envelope.C @@ -0,0 +1,166 @@ +/* + ZynAddSubFX - a software synthesizer + + Envelope.C - Envelope implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdio.h> +#include "Envelope.h" + +Envelope::Envelope(EnvelopeParams *envpars,REALTYPE basefreq){ + int i; + envpoints=envpars->Penvpoints; + if (envpoints>MAX_ENVELOPE_POINTS) envpoints=MAX_ENVELOPE_POINTS; + envsustain=(envpars->Penvsustain==0)?-1:envpars->Penvsustain; + forcedrelase=envpars->Pforcedrelase; + envstretch=pow(440.0/basefreq,envpars->Penvstretch/64.0); + linearenvelope=envpars->Plinearenvelope; + + if (envpars->Pfreemode==0) envpars->converttofree(); + + REALTYPE bufferdt=SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; + + int mode=envpars->Envmode; + + //for amplitude envelopes + if ((mode==1)&&(linearenvelope==0)) mode=2;//change to log envelope + if ((mode==2)&&(linearenvelope!=0)) mode=1;//change to linear + + for (i=0;i<MAX_ENVELOPE_POINTS;i++) { + REALTYPE tmp=envpars->getdt(i)/1000.0*envstretch; + if (tmp>bufferdt) envdt[i]=bufferdt/tmp; + else envdt[i]=2.0;//any value larger than 1 + + switch (mode){ + case 2:envval[i]=(1.0-envpars->Penvval[i]/127.0)*MIN_ENVELOPE_DB; + break; + case 3:envval[i]=(pow(2,6.0*fabs(envpars->Penvval[i]-64.0)/64.0)-1.0)*100.0; + if (envpars->Penvval[i]<64) envval[i]=-envval[i]; + break; + case 4:envval[i]=(envpars->Penvval[i]-64.0)/64.0*6.0;//6 octaves (filtru) + break; + case 5:envval[i]=(envpars->Penvval[i]-64.0)/64.0*10; + break; + default:envval[i]=envpars->Penvval[i]/127.0; + }; + + }; + + envdt[0]=1.0; + + currentpoint=1;//the envelope starts from 1 + keyreleased=0; + t=0.0; + envfinish=0; + inct=envdt[1]; + envoutval=0.0; +}; + +Envelope::~Envelope(){ +}; + + +/* + * Relase the key (note envelope) + */ +void Envelope::relasekey(){ + if (keyreleased==1) return; + keyreleased=1; + if (forcedrelase!=0) t=0.0; +}; + +/* + * Envelope Output + */ +REALTYPE Envelope::envout(){ + REALTYPE out; + + if (envfinish!=0) {//if the envelope is finished + envoutval=envval[envpoints-1]; + return(envoutval); + }; + if ((currentpoint==envsustain+1)&&(keyreleased==0)) {//if it is sustaining now + envoutval=envval[envsustain]; + return(envoutval); + }; + + if ((keyreleased!=0) && (forcedrelase!=0)){//do the forced release + + int tmp=(envsustain<0) ? (envpoints-1):(envsustain+1);//if there is no sustain point, use the last point for release + + if (envdt[tmp]<0.00000001) out=envval[tmp]; + else out=envoutval+(envval[tmp]-envoutval)*t; + t+=envdt[tmp]*envstretch; + + if (t>=1.0) { + currentpoint=envsustain+2; + forcedrelase=0; + t=0.0; + inct=envdt[currentpoint]; + if ((currentpoint>=envpoints)||(envsustain<0)) envfinish=1; + }; + return(out); + }; + if (inct>=1.0) out=envval[currentpoint]; + else out=envval[currentpoint-1]+(envval[currentpoint]-envval[currentpoint-1])*t; + + t+=inct; + if (t>=1.0){ + + if (currentpoint>=envpoints-1) envfinish=1; + else currentpoint++; + t=0.0; + inct=envdt[currentpoint]; + }; + + envoutval=out; + return (out); +}; + +/* + * Envelope Output (dB) + */ +REALTYPE Envelope::envout_dB(){ + REALTYPE out; + if (linearenvelope!=0) return (envout()); + + if ((currentpoint==1)&&((keyreleased==0)||(forcedrelase==0))) {//first point is always lineary interpolated + REALTYPE v1=dB2rap(envval[0]); + REALTYPE v2=dB2rap(envval[1]); + out=v1+(v2-v1)*t; + + t+=inct; + if (t>=1.0) { + t=0.0; + inct=envdt[2]; + currentpoint++; + out=v2; + }; + + if (out>0.001) envoutval=rap2dB(out); + else envoutval=-40.0; + } else out=dB2rap(envout()); + + return(out); +}; + +int Envelope::finished(){ + return(envfinish); +}; + diff --git a/src/Synth/Envelope.h b/src/Synth/Envelope.h @@ -0,0 +1,58 @@ +/* + ZynAddSubFX - a software synthesizer + + Envelope.h - Envelope implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef ENVELOPE_H +#define ENVELOPE_H + +#include <math.h> +#include "../globals.h" +#include "../Params/EnvelopeParams.h" + +class Envelope{ +public: + Envelope(EnvelopeParams *envpars,REALTYPE basefreq); + ~Envelope(); + void relasekey(); + REALTYPE envout(); + REALTYPE envout_dB(); + int finished();//returns 1 if the envelope is finished +private: + int envpoints; + int envsustain;//"-1" means disabled + REALTYPE envdt[MAX_ENVELOPE_POINTS];//millisecons + REALTYPE envval[MAX_ENVELOPE_POINTS];// [0.0 .. 1.0] + REALTYPE envstretch; + int linearenvelope; + + int currentpoint; //current envelope point (starts from 1) + int forcedrelase; + char keyreleased; //if the key was released + char envfinish; + REALTYPE t; // the time from the last point + REALTYPE inct;// the time increment + REALTYPE envoutval;//used to do the forced release +}; + + +#endif + + diff --git a/src/Synth/LFO.C b/src/Synth/LFO.C @@ -0,0 +1,119 @@ +/* + ZynAddSubFX - a software synthesizer + + LFO.C - LFO implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include "LFO.h" + + +LFO::LFO(LFOParams *lfopars){ + REALTYPE lfofreq=(pow(2,lfopars->Pfreq/127.0*10.0)-1.0)/12.0; + incx=fabs(lfofreq)*(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; + + if (lfopars->Pcontinous==0){ + if (lfopars->Pstartphase==0) x=RND; + else x=fmod((lfopars->Pstartphase-64.0)/127.0+1.0,1.0); + } else { + REALTYPE tmp=fmod(lfopars->time*incx,1.0); + x=fmod((lfopars->Pstartphase-64.0)/127.0+1.0+tmp,1.0); + }; + + //Limit the Frequency(or else...) + if (incx>0.49999999) incx=0.499999999; + + + lfornd=lfopars->Prandomness/127.0; + if (lfornd<0.0) lfornd=0.0; else if (lfornd>1.0) lfornd=1.0; + + switch (lfopars->fel){ + case 1:lfointensity=lfopars->Pintensity/127.0;break; + case 2:lfointensity=lfopars->Pintensity/127.0*4.0;break;//in octave + default:lfointensity=pow(2,lfopars->Pintensity/127.0*11.0)-1.0;//in centi + x-=0.25;//chance the starting phase + break; + }; + + amp1=(1-lfornd)+lfornd*RND; + amp2=(1-lfornd)+lfornd*RND; + lfotype=lfopars->PLFOtype; + lfodelay=lfopars->Pdelay/127.0*4.0;//0..4 sec +}; + +LFO::~LFO(){ +}; + +/* + * LFO out + */ +REALTYPE LFO::lfoout(){ + REALTYPE out; + switch (lfotype){ + case 1: //LFO_TRIANGLE + if ((x>0.0)&&(x<0.25)) out=4.0*x; + else if ((x>0.25)&&(x<0.75)) out=2-4*x; + else out=4.0*x-4.0; + break; + case 2: //LFO_SQUARE + if (x<0.5) out=-1; + else out=1; + break; + case 3: //LFO_RAMPUP + out=(x-0.5)*2.0; + break; + case 4: //LFO_RAMPDOWN + out=(0.5-x)*2.0; + break; + case 5: //LFO_EXP_DOWN 1 + out=pow(0.05,x)*2.0-1.0; + break; + case 6: //LFO_EXP_DOWN 2 + out=pow(0.001,x)*2.0-1.0; + break; + default:out=cos(x*2.0*PI);//LFO_SINE + }; + if ((lfotype==0)||(lfotype==1)) out*=lfointensity*(amp1+x*(amp2-amp1)); + else out*=lfointensity*amp2; + if (lfodelay<0.00001) { + x+=incx; + if (x>1) { + x-=1; + amp1=amp2; + amp2=(1-lfornd)+lfornd*RND; + }; + } + else lfodelay-=(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE; + return(out); +}; + +/* + * LFO out (for amplitude) + */ +REALTYPE LFO::amplfoout(){ + REALTYPE out; + out=1-lfointensity+lfoout()/2.0; + if (out<-1.0) out=-1.0; + else if (out>1.0) out=1.0; + return(out); +}; + diff --git a/src/Synth/LFO.h b/src/Synth/LFO.h @@ -0,0 +1,48 @@ +/* + ZynAddSubFX - a software synthesizer + + LFO.h - LFO implementation + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef LFO_H +#define LFO_H + +#include "../globals.h" +#include "../Params/LFOParams.h" + + +class LFO{ + public: + LFO(LFOParams *lfopars); + ~LFO(); + REALTYPE lfoout(); + REALTYPE amplfoout(); + private: + REALTYPE x; + REALTYPE incx; + REALTYPE amp1,amp2;// used for randomness + REALTYPE lfointensity; + REALTYPE lfornd; + REALTYPE lfodelay; + char lfotype; + +}; + + +#endif diff --git a/src/Synth/Makefile b/src/Synth/Makefile @@ -0,0 +1,14 @@ +include ../Makefile.inc + +objects=ADnote.o Envelope.o LFO.o OscilGen.o SUBnote.o Resonance.o + + +all: $(objects) + +-include ../Make.deps + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + diff --git a/src/Synth/OscilGen.C b/src/Synth/OscilGen.C @@ -0,0 +1,776 @@ +/* + ZynAddSubFX - a software synthesizer + + OscilGen.C - Waveform generator for ADnote + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <stdlib.h> +#include <math.h> +#include <stdio.h> + +#include "OscilGen.h" + +#include "../Misc/Util.h" + +OscilGen::OscilGen(FFTwrapper *fft_,Resonance *res_){ + int i; + + fft=fft_; + oscilFFTfreqs=new REALTYPE[OSCIL_SIZE]; + + res=res_; + oldbasefunc=0;oldbasepar=64;oldhmagtype=0;oldwaveshapingfunction=0;oldwaveshaping=64,oldnormalizemethod=0; + for (i=0;i<MAX_AD_HARMONICS;i++){ + hmag[i]=0.0; + hphase[i]=0.0; + Phmag[i]=64; + Phphase[i]=64; + }; + Phmag[0]=127; + Phmagtype=0; + Prand=64;//no randomness + + Pcurrentbasefunc=0; + Pbasefuncpar=64; + Pwaveshapingfunction=0; + Pwaveshaping=64; + Pnormalizemethod=0; + Pfiltertype=0; + Pfilterpar=64; + Pfilterbeforews=0; + Psatype=0; + Psapar=64; + + basefuncFFTfreqsQ=NULL; + basefuncFFTfreqs=NULL; + outoscilFFTfreqs=NULL; + + for (i=0;i<OSCIL_SIZE;i++) oscilFFTfreqs[i]=0.0; + oscilprepared=0; + oldfilterpars=0;oldsapars=0; +}; + +OscilGen::~OscilGen(){ + if (basefuncFFTfreqs!=NULL) delete [] basefuncFFTfreqs; + if (basefuncFFTfreqsQ!=NULL) delete [] basefuncFFTfreqsQ; + delete [] oscilFFTfreqs; +}; + +/* + * Base Functions - START + */ +REALTYPE OscilGen::basefunc_pulse(REALTYPE x,REALTYPE a){ + return((fmod(x,1.0)<a)?-1.0:1.0); +}; + +REALTYPE OscilGen::basefunc_saw(REALTYPE x,REALTYPE a){ + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + x=fmod(x,1); + if (x<a) return(x/a*2.0-1.0); + else return((1.0-x)/(1.0-a)*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_triangle(REALTYPE x,REALTYPE a){ + x=fmod(x+0.25,1); + a=1-a; + if (a<0.00001) a=0.00001; + if (x<0.5) x=x*4-1.0; + else x=(1.0-x)*4-1.0; + x/=-a; + if (x<-1.0) x=-1.0; + if (x>1.0) x=1.0; + return(x); +}; + +REALTYPE OscilGen::basefunc_power(REALTYPE x,REALTYPE a){ + x=fmod(x,1); + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + return(pow(x,exp((a-0.5)*10.0))*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_gauss(REALTYPE x,REALTYPE a){ + x=fmod(x,1)*2.0-1.0; + if (a<0.00001) a=0.00001; + return(exp(-x*x*(exp(a*8)+5.0))*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_diode(REALTYPE x,REALTYPE a){ + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + a=a*2.0-1.0; + x=cos((x+0.5)*2.0*PI)-a; + if (x<0.0) x=0.0; + return(x/(1.0-a)*2-1.0); +}; + +REALTYPE OscilGen::basefunc_abssine(REALTYPE x,REALTYPE a){ + x=fmod(x,1); + if (a<0.00001) a=0.00001; + else if (a>0.99999) a=0.99999; + return(sin(pow(x,exp((a-0.5)*5.0))*PI)*2.0-1.0); +}; + +REALTYPE OscilGen::basefunc_pulsesine(REALTYPE x,REALTYPE a){ + if (a<0.00001) a=0.00001; + x=(fmod(x,1)-0.5)*exp((a-0.5)*log(128)); + if (x<-0.5) x=-0.5; + else if (x>0.5) x=0.5; + x=sin(x*PI*2.0); + return(x); +}; + +REALTYPE OscilGen::basefunc_stretchsine(REALTYPE x,REALTYPE a){ + x=fmod(x+0.5,1)*2.0-1.0; + a=(a-0.5)*4;if (a>0.0) a*=2; + a=pow(3.0,a); + REALTYPE b=pow(fabs(x),a); + if (x<0) b=-b; + return(-sin(b*PI)); +}; + +REALTYPE OscilGen::basefunc_chirp(REALTYPE x,REALTYPE a){ + x=fmod(x,1.0)*2.0*PI; + a=(a-0.5)*4;if (a<0.0) a*=2.0; + a=pow(3.0,a); + return(sin(x/2.0)*sin(a*x*x)); +}; + +REALTYPE OscilGen::basefunc_absstretchsine(REALTYPE x,REALTYPE a){ + x=fmod(x+0.5,1)*2.0-1.0; + a=(a-0.5)*9; + a=pow(3.0,a); + REALTYPE b=pow(fabs(x),a); + if (x<0) b=-b; + return(-pow(sin(b*PI),2)); +}; + +REALTYPE OscilGen::basefunc_chebyshev(REALTYPE x,REALTYPE a){ + a=a*a*a*30.0+1.0; + return(cos(acos(x*2.0-1.0)*a)); +}; +/* + * Base Functions - END + */ + + +/* + * Get the base function + */ +void OscilGen::getbasefunction(REALTYPE *smps){ + int i; + REALTYPE par=(Pbasefuncpar+0.5)/128.0; + if (Pbasefuncpar==64) par=0.5; + switch (Pcurrentbasefunc){ + case 1:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_triangle(1.0*i/OSCIL_SIZE,par); + break; + case 2:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_pulse(1.0*i/OSCIL_SIZE,par); + break; + case 3:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_saw(1.0*i/OSCIL_SIZE,par); + break; + case 4:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_power(1.0*i/OSCIL_SIZE,par); + break; + case 5:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_gauss(1.0*i/OSCIL_SIZE,par); + break; + case 6:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_diode(1.0*i/OSCIL_SIZE,par); + break; + case 7:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_abssine(1.0*i/OSCIL_SIZE,par); + break; + case 8:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_pulsesine(1.0*i/OSCIL_SIZE,par); + break; + case 9:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_stretchsine(1.0*i/OSCIL_SIZE,par); + break; + case 10:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_chirp(1.0*i/OSCIL_SIZE,par); + break; + case 11:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_absstretchsine(1.0*i/OSCIL_SIZE,par); + break; + case 12:for (i=0;i<OSCIL_SIZE;i++) smps[i]=basefunc_chebyshev(1.0*i/OSCIL_SIZE,par); + break; + default:for (i=0;i<OSCIL_SIZE;i++) smps[i]=-sin(2.0*PI*i/OSCIL_SIZE); + }; +}; + +/* + * Filter the basefunction + */ +void OscilGen::oscilfilter(){ + if (Pfiltertype==0) return; + REALTYPE par=1.0-Pfilterpar/128.0; + REALTYPE max=0.0; + for (int i=0;i<OSCIL_SIZE/2-1;i++){ + REALTYPE gain=1.0; + switch(Pfiltertype){ + case 1: gain=pow(1.0-par*par*par,i);//lp + break; + case 2: gain=1.0-pow(1.0-par*par,i+1);//hp1 + break; + case 3: if (par<0.2) par=par*0.25+0.15; + gain=1.0-pow(1.0-par*par*0.999+0.001,i*0.05*i+1.0);//hp1b + gain*=gain*gain; + break; + case 4: gain=i+1-pow(2,(1.0-par)*7.5);//bp1 + gain=1.0/(1.0+gain*gain/(i+1.0)); + gain*=gain; + if (gain<1e-5) gain=1e-5; + break; + case 5: gain=i+1-pow(2,(1.0-par)*7.5);//bs1 + gain=pow(atan(gain/(i/10.0+1))/1.57,6); + break; + case 6: gain=(i+1>pow(2,(1.0-par)*10)?0.0:1.0);//lp2 + break; + case 7: gain=(i+1>pow(2,(1.0-par)*7)?1.0:0.0);//hp2 + if (Pfilterpar==0) gain=1.0; + break; + case 8: gain=(fabs(pow(2,(1.0-par)*7)-i)>i/2+1?0.0:1.0);//bp2 + break; + + case 9: gain=(fabs(pow(2,(1.0-par)*7)-i)<i/2+1?0.0:1.0);//bs2 + break; + case 10:gain=cos(par*par*PI/2.0*i);//cos + gain*=gain; + break; + }; + oscilFFTfreqs[OSCIL_SIZE-i-1]*=gain; + oscilFFTfreqs[i+1]*=gain; + REALTYPE tmp=oscilFFTfreqs[OSCIL_SIZE-i-1]*oscilFFTfreqs[OSCIL_SIZE-i-1]+ + oscilFFTfreqs[i+1]*oscilFFTfreqs[i+1]; + if (max<tmp) max=tmp; + }; + + if (max<1e-10) max=1.0; + for (int i=1;i<OSCIL_SIZE;i++) oscilFFTfreqs[i]/=max; +}; + +/* + * Change the base function + */ +void OscilGen::changebasefunction(){ + if (basefuncFFTfreqs!=NULL) { + delete(basefuncFFTfreqs); + basefuncFFTfreqs=NULL; + }; + if (basefuncFFTfreqs==NULL) basefuncFFTfreqs=new REALTYPE[OSCIL_SIZE]; + if (Pcurrentbasefunc!=0) { + // I use basefuncfreq for temporary store of the time-domain data + // because I don't wish "eat" too much memory with another array + getbasefunction(basefuncFFTfreqs); + fft->smps2freqs(basefuncFFTfreqs,NULL);//perform FFT + basefuncFFTfreqs[0]=0.0; + } else { + delete basefuncFFTfreqs; + basefuncFFTfreqs=NULL; + } + oscilprepared=0; + oldbasefunc=Pcurrentbasefunc; + oldbasepar=Pbasefuncpar; + +}; + +/* + * Waveshape + */ +void OscilGen::waveshape(){ + int i; + REALTYPE tmp; + + oldwaveshapingfunction=Pwaveshapingfunction; + oldwaveshaping=Pwaveshaping; + if (Pwaveshapingfunction==0) return; + + oscilFFTfreqs[0]=0.0;//remove the DC + //reduce the amplitude of the freqs near the nyquist + for (i=1;i<OSCIL_SIZE/8;i++) { + REALTYPE tmp=i/(OSCIL_SIZE/8.0); + oscilFFTfreqs[OSCIL_SIZE/2+i-1]*=tmp; + oscilFFTfreqs[OSCIL_SIZE/2-i+1]*=tmp; + }; + fft->freqs2smps(oscilFFTfreqs,NULL); + //now the oscilFFTfreqs contains *time-domain data* of samples + //I don't want to allocate another array for this + + //Normalize + REALTYPE max=0.0; + for (i=0;i<OSCIL_SIZE;i++) + if (max<fabs(oscilFFTfreqs[i])) max=fabs(oscilFFTfreqs[i]); + if (max<0.00001) max=1.0; + max=1.0/max;for (i=0;i<OSCIL_SIZE;i++) oscilFFTfreqs[i]*=max; + + //Do the waveshaping + waveshapesmps(OSCIL_SIZE,oscilFFTfreqs,Pwaveshapingfunction,Pwaveshaping); + + fft->smps2freqs(oscilFFTfreqs,NULL);//perform FFT +}; + +/* + * Adjust the spectrum + */ +void OscilGen::spectrumadjust(){ + if (Psatype==0) return; + REALTYPE par=Psapar/127.0; + switch(Psatype){ + case 1: par=1.0-par*2.0; + if (par>=0.0) par=pow(5.0,par); + else par=pow(8.0,par); + break; + case 2: par=pow(10.0,(1.0-par)*3.0)*0.00095; + break; + }; + REALTYPE max=0.0; + for (int i=0;i<OSCIL_SIZE/2-1;i++){ + REALTYPE tmp=pow(oscilFFTfreqs[OSCIL_SIZE-i-1],2)+pow(oscilFFTfreqs[i+1],2.0); + if (max<tmp) max=tmp; + }; + max=sqrt(max); + if (max<1e-8) max=1.0; + + for (int i=0;i<OSCIL_SIZE/2-1;i++){ + REALTYPE mag=sqrt(pow(oscilFFTfreqs[OSCIL_SIZE-i-1],2)+pow(oscilFFTfreqs[i+1],2.0))/max; + REALTYPE phase=atan2(oscilFFTfreqs[i+1],oscilFFTfreqs[OSCIL_SIZE-i-1]); + + + switch (Psatype){ + case 1: mag=pow(mag,par); + break; + case 2: if (mag<par) mag=0.0; + break; + }; + oscilFFTfreqs[OSCIL_SIZE-i-1]=mag*cos(phase); + oscilFFTfreqs[i+1]=mag*sin(phase); + }; + +}; + + +/* + * Prepare the Oscillator + */ +void OscilGen::prepare(){ + int i,j,k; + REALTYPE a,b,c,d,hmagnew; + if ((oldbasepar!=Pbasefuncpar)||(oldbasefunc!=Pcurrentbasefunc)) changebasefunction(); + + for (i=0;i<MAX_AD_HARMONICS;i++) hphase[i]=(Phphase[i]-64.0)/64.0*PI/(i+1); + + for (i=0;i<MAX_AD_HARMONICS;i++){ + hmagnew=1.0-fabs(Phmag[i]/64.0-1.0); + switch(Phmagtype){ + case 1:hmag[i]=exp(hmagnew*log(0.01)); break; + case 2:hmag[i]=exp(hmagnew*log(0.001));break; + case 3:hmag[i]=exp(hmagnew*log(0.0001));break; + case 4:hmag[i]=exp(hmagnew*log(0.00001));break; + default:hmag[i]=1.0-hmagnew; + break; + }; + + if (Phmag[i]<64) hmag[i]=-hmag[i]; + }; + + //remove the harmonics where Phmag[i]==64 + for (i=0;i<MAX_AD_HARMONICS;i++) if (Phmag[i]==64) hmag[i]=0.0; + + + for (i=0;i<OSCIL_SIZE;i++) oscilFFTfreqs[i]=0.0; + if (Pcurrentbasefunc==0) {//the sine case + for (i=0;i<MAX_AD_HARMONICS;i++){ + oscilFFTfreqs[i+1]=-hmag[i]*sin(hphase[i]*(i+1))/2.0; + oscilFFTfreqs[OSCIL_SIZE-i-1]=hmag[i]*cos(hphase[i]*(i+1))/2.0; + }; + } else { + for (j=0;j<MAX_AD_HARMONICS;j++){ + if (Phmag[j]==64) continue; + for (i=1;i<OSCIL_SIZE/2;i++){ + k=i*(j+1);if (k>OSCIL_SIZE/2) break; + a=basefuncFFTfreqs[i]; + b=basefuncFFTfreqs[OSCIL_SIZE-i]; + c=hmag[j]*cos(hphase[j]*k); + d=hmag[j]*sin(hphase[j]*k); + oscilFFTfreqs[k]+=a*c-b*d; + oscilFFTfreqs[OSCIL_SIZE-k]+=a*d+b*c; + }; + }; + + }; + + if (Pfilterbeforews==0){ + waveshape(); + oscilfilter(); + } else { + oscilfilter(); + waveshape(); + }; + + spectrumadjust(); + + REALTYPE sum=0; + for (j=1;j<OSCIL_SIZE/2;j++) { + REALTYPE term=oscilFFTfreqs[j]*oscilFFTfreqs[j]+oscilFFTfreqs[OSCIL_SIZE-j]*oscilFFTfreqs[OSCIL_SIZE-j]; + if (Pnormalizemethod==0) sum+=sqrt(term); + else sum+=term; + }; + if (sum<0.000001) sum=1.0; + if (Pnormalizemethod==1) sum=sqrt(sum)*2.0; + sum*=0.5; + for (j=1;j<OSCIL_SIZE;j++) oscilFFTfreqs[j]/=sum; + + oscilFFTfreqs[0]=0.0;//remove the DC + + if (ANTI_ALIAS==0) { + //Perform the IFFT in case of Antialiasing is disabled + REALTYPE *tmp=new REALTYPE[OSCIL_SIZE]; + for (i=0;i<OSCIL_SIZE;i++) tmp[i]=oscilFFTfreqs[i]; + fft->freqs2smps(tmp,oscilFFTfreqs); + //now the oscilFFTfreqs contains samples data in TIME-DOMAIN (despite it's name) + delete(tmp); + }; + oldhmagtype=Phmagtype; + oldnormalizemethod=Pnormalizemethod; + oscilprepared=1; +}; + +/* + * Get the oscillator function + */ +short int OscilGen::get(REALTYPE *smps,REALTYPE freqHz){ + return(this->get(smps,freqHz,0)); +}; + +/* + * Get the oscillator function + */ +short int OscilGen::get(REALTYPE *smps,REALTYPE freqHz,int resonance){ + int i; + int nyquist,outpos; + + if ((oldbasepar!=Pbasefuncpar)||(oldbasefunc!=Pcurrentbasefunc)||(oldhmagtype!=Phmagtype) + ||(oldwaveshaping!=Pwaveshaping)||(oldwaveshapingfunction!=Pwaveshapingfunction)) oscilprepared=0; + if (oldnormalizemethod!=Pnormalizemethod) oscilprepared=0; + if (oldfilterpars!=Pfiltertype*256+Pfilterpar+Pfilterbeforews*65536){ + oscilprepared=0; + oldfilterpars=Pfiltertype*256+Pfilterpar+Pfilterbeforews*65536; + }; + if (oldsapars!=Psatype*256+Psapar){ + oscilprepared=0; + oldsapars=Psatype*256+Psapar; + }; + + if (oscilprepared!=1) prepare(); + + outpos=(int)((RND*2.0-1.0)*(REALTYPE) OSCIL_SIZE*(Prand-64.0)/64.0); + outpos=(outpos+2*OSCIL_SIZE) % OSCIL_SIZE; + + if (ANTI_ALIAS==0) {//Anti-Aliasing OFF + for (i=0;i<OSCIL_SIZE;i++) smps[i]=oscilFFTfreqs[i]; + if (Prand!=64) return(outpos); + else return(0); + }; + + //Anti-Aliasing ON + outoscilFFTfreqs=new REALTYPE[OSCIL_SIZE]; + nyquist=(int)(0.5*SAMPLE_RATE/fabs(freqHz))+2; + if (nyquist>OSCIL_SIZE/2) nyquist=OSCIL_SIZE/2; + + for (i=0;i<OSCIL_SIZE;i++) outoscilFFTfreqs[i]=0.0; + + // Randomness (each harmonic), the block type is computed + // in ADnote by setting start position according to this setting + if ((Prand>64)&&(freqHz>=0.0)){ + REALTYPE rnd,angle,a,b,c,d; + rnd=PI*pow((Prand-64.0)/64.0,2.0); + for (i=1;i<nyquist-1;i++){//to Nyquist only for AntiAliasing + angle=rnd*i*RND; + a=oscilFFTfreqs[i]; + b=oscilFFTfreqs[OSCIL_SIZE-i]; + c=cos(angle); + d=sin(angle); + outoscilFFTfreqs[i]=a*c-b*d; + outoscilFFTfreqs[OSCIL_SIZE-i]=a*d+b*c; + }; + } else { + for (i=1;i<nyquist-1;i++) { + outoscilFFTfreqs[i]=oscilFFTfreqs[i]; + outoscilFFTfreqs[OSCIL_SIZE-i]=oscilFFTfreqs[OSCIL_SIZE-i]; + }; + }; + + if ((freqHz>0.1)&&(resonance!=0)) res->applyres(nyquist-1,outoscilFFTfreqs,freqHz); + + fft->freqs2smps(outoscilFFTfreqs,smps); + + for (i=0;i<OSCIL_SIZE;i++) smps[i]*=0.25;//correct the amplitude + + delete(outoscilFFTfreqs); + outoscilFFTfreqs=NULL; + if (Prand<64) return(outpos); + else return(0); +}; + + +/* + * Get the spectrum of the oscillator for the UI + */ +void OscilGen::getspectrum(int n, REALTYPE *spc,int what){ + if (n>OSCIL_SIZE/2) n=OSCIL_SIZE/2; + for (int i=1;i<n;i++){ + if (what==0){ + if (ANTI_ALIAS==0) spc[i-1]=0.0;//there is no spectrum available + else spc[i-1]=sqrt(oscilFFTfreqs[i]*oscilFFTfreqs[i]+ + oscilFFTfreqs[OSCIL_SIZE-i]*oscilFFTfreqs[OSCIL_SIZE-i]); + } else { + if (Pcurrentbasefunc==0) spc[i-1]=((i==1)?(1.0):(0.0)); + else spc[i-1]=sqrt(basefuncFFTfreqs[i]*basefuncFFTfreqs[i]+ + basefuncFFTfreqs[OSCIL_SIZE-i]*basefuncFFTfreqs[OSCIL_SIZE-i]); + }; + }; +} + + +/* + * Convert the oscillator as base function + */ +void OscilGen::useasbase(){ + int i; + + if (Pcurrentbasefunc==0) basefuncFFTfreqs=new REALTYPE[OSCIL_SIZE]; + + for (i=0;i<OSCIL_SIZE;i++) basefuncFFTfreqs[i]=oscilFFTfreqs[i]; + + oldbasefunc=Pcurrentbasefunc=127; + + prepare(); +}; + + +/* + * Get the base function for UI + */ +void OscilGen::getcurrentbasefunction(REALTYPE *smps){ + if (Pcurrentbasefunc!=0) { + for (int i=0;i<OSCIL_SIZE;i++) smps[i]=basefuncFFTfreqs[i]; + fft->freqs2smps(smps,NULL); + } else getbasefunction(smps);//the sine case +}; + + +/* + * Quantisize and store the base function frequencies (used to save basefunction to buffer) + */ +void OscilGen::savebasefuncQ(){ + int i; + short int data; + REALTYPE x,max; + max=0.0; + + if (basefuncFFTfreqsQ==NULL) + basefuncFFTfreqsQ=new unsigned short int[OSCIL_SIZE]; + for (i=0;i<OSCIL_SIZE;i++) basefuncFFTfreqsQ[i]=8192;//"8192"=0.0 + + if (Pcurrentbasefunc==0) return; + + for (i=1;i<OSCIL_SIZE;i++) + if (max<fabs(basefuncFFTfreqs[i])) max=fabs(basefuncFFTfreqs[i]); + if (max<0.00000001) max=1.0; + + for (i=1;i<OSCIL_SIZE/2;i++) { + //Cosine Component + x=basefuncFFTfreqs[i]/max; + if (fabs(x)<0.00001) data=0;// -100dB + else { + data=(short int) ((1.0+rap2dB(fabs(x))/100.0)*8191.0); + if (x<0.0) data=-data; + }; + basefuncFFTfreqsQ[i*2-1]=data+8192; + + //Sine Component + if (i!=(OSCIL_SIZE/2-1)) { + x=basefuncFFTfreqs[OSCIL_SIZE-i]/max; + if (fabs(x)<0.00001) data=0;// -100dB + else { + data=(short int) ((1.0+rap2dB(fabs(x))/100.0)*8191.0); + if (x<0.0) data=-data; + }; + basefuncFFTfreqsQ[i*2]=data+8192; + }; + }; +}; + +/* + * Load the base function frequencies from quantised data (used to load basefunction from buffer) + */ +void OscilGen::loadbasefuncQ(){ + short int data,i; + REALTYPE x; + + if (basefuncFFTfreqs==NULL) basefuncFFTfreqs=new REALTYPE[OSCIL_SIZE]; + for (i=0;i<OSCIL_SIZE;i++) basefuncFFTfreqs[i]=0.0; + if (basefuncFFTfreqsQ==NULL) return; + + if (Pcurrentbasefunc==0) basefuncFFTfreqs=new REALTYPE[OSCIL_SIZE]; + + for (i=0;i<OSCIL_SIZE;i++) basefuncFFTfreqs[i]=0.0;; + + + for (i=1;i<OSCIL_SIZE/2;i++) { + //Cosine Component + data=basefuncFFTfreqsQ[i*2-1]; + if (data==8192) x=0.0; + else { + x=dB2rap((fabs(data-8192.0)/8192-1.0)*100.0); + if (data<8192) x=-x; + }; + basefuncFFTfreqs[i]=x; + + //Sine Component + data=basefuncFFTfreqsQ[i*2]; + if (data==8192) x=0.0; + else { + x=dB2rap((fabs(data-8192.0)/8192-1.0)*100.0); + if (data<8192) x=-x; + }; + basefuncFFTfreqs[OSCIL_SIZE-i]=x; + + }; + + delete basefuncFFTfreqsQ; + basefuncFFTfreqsQ=NULL; + oldbasefunc=Pcurrentbasefunc=127; + oldbasepar=Pbasefuncpar; +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void OscilGen::saveloadbuf(Buffer *buf){ + unsigned char npar,n,nharmonic,tmp; + unsigned short int nh,tmpw; + + int custombasefuncloaded=0; +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Oscil parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + if (buf->getmode()==0){ + for (nharmonic=0;nharmonic<MAX_AD_HARMONICS;nharmonic++){ + Phmag[nharmonic]=64; + Phphase[nharmonic]=64; + }; + }; + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Oscil parameters + case 0x80: buf->rwbytepar(n,&Phmagtype); + break; + case 0x81: if (buf->getmode()!=0){ + for (nharmonic=0;nharmonic<MAX_AD_HARMONICS;nharmonic++){ + if (Phmag[nharmonic]!=64) { + buf->rwbytepar(n,&nharmonic); + buf->rwbyte(&Phmag[nharmonic]); + buf->rwbyte(&Phphase[nharmonic]); + }; + }; + } else { + buf->rwbytepar(n,&nharmonic); + if (nharmonic<MAX_AD_HARMONICS){//for safety + buf->rwbyte(&Phmag[nharmonic]); + buf->rwbyte(&Phphase[nharmonic]); + } else { + buf->rwbyte(&tmp); + buf->rwbyte(&tmp); + }; + + }; + break; + case 0x82: buf->rwbytepar(n,&Pcurrentbasefunc); + break; + case 0x83: buf->rwbytepar(n,&Pbasefuncpar); + break; + case 0x84: buf->rwbytepar(n,&Prand); + break; + case 0x85: buf->rwbytepar(n,&Pwaveshaping); + break; + case 0x86: buf->rwbytepar(n,&Pwaveshapingfunction); + break; + case 0x87: if (buf->getmode()!=0){ + if (Pcurrentbasefunc==127){ + savebasefuncQ(); + for (nh=0;nh<OSCIL_SIZE;nh++){ + if (basefuncFFTfreqsQ[nh]!=8192) { + buf->rwbyte(&n); + buf->rwword(&nh); + buf->rwword(&basefuncFFTfreqsQ[nh]); + }; + }; + }; + } else { + buf->rwword(&nh); + if (nh<OSCIL_SIZE){//for safety + if (basefuncFFTfreqsQ==NULL) { + basefuncFFTfreqsQ=new unsigned short int[OSCIL_SIZE]; + for (int tmp=0;tmp<OSCIL_SIZE;tmp++) basefuncFFTfreqsQ[tmp]=8192;//"8192"=0.0 + }; + buf->rwword(&basefuncFFTfreqsQ[nh]); + custombasefuncloaded=1; + } else { + buf->rwword(&tmpw); + }; + + }; + break; + case 0x88: buf->rwbytepar(n,&Pnormalizemethod); + break; + case 0x89: buf->rwbytepar(n,&Pfiltertype); + break; + case 0x8A: buf->rwbytepar(n,&Pfilterpar); + break; + case 0x8B: buf->rwbytepar(n,&Pfilterbeforews); + break; + case 0x8C: buf->rwbytepar(n,&Psatype); + break; + case 0x8D: buf->rwbytepar(n,&Psapar); + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + } else { + if (custombasefuncloaded!=0) { + loadbasefuncQ(); + }; + prepare(); + }; +}; + + + + + + diff --git a/src/Synth/OscilGen.h b/src/Synth/OscilGen.h @@ -0,0 +1,136 @@ +/* + ZynAddSubFX - a software synthesizer + + OscilGen.h - Waveform generator for ADnote + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef OSCIL_GEN_H +#define OSCIL_GEN_H + +#include "../globals.h" +#include "../Misc/Buffer.h" +#include "Resonance.h" +#include "../DSP/FFTwrapper.h" + +class OscilGen{ + public: + OscilGen(FFTwrapper *fft_,Resonance *res_); + ~OscilGen(); + + //computes the full spectrum of oscil from harmonics,phases and basefunc + void prepare(); + + //do the antialiasing(cut off higher freqs.),apply randomness and do a IFFT + short get(REALTYPE *smps,REALTYPE freqHz);//returns where should I start getting samples, used in block type randomness + short get(REALTYPE *smps,REALTYPE freqHz,int resonance); + //if freqHz is smaller than 0, return the "un-randomized" sample for UI + + void getbasefunction(REALTYPE *smps); + + //called by UI + void getspectrum(int n,REALTYPE *spc,int what);//what=0 pt. oscil,1 pt. basefunc + void getcurrentbasefunction(REALTYPE *smps); + void useasbase();//convert oscil to base function + void saveloadbuf(Buffer *buf); + + + //Parameters + + /* + The hmag and hphase starts counting from 0, so the first harmonic(1) has the index 0, + 2-nd harmonic has index 1, ..the 128 harminic has index 127 + */ + unsigned char Phmag[MAX_AD_HARMONICS],Phphase[MAX_AD_HARMONICS];//the MIDI parameters for mag. and phases + + + /*The Type of magnitude: + 0 - Linear + 1 - dB scale (-40) + 2 - dB scale (-60) + 3 - dB scale (-80) + 4 - dB scale (-100)*/ + unsigned char Phmagtype; + + unsigned char Pcurrentbasefunc;//The base function used - 0=sin, 1=... + unsigned char Pbasefuncpar;//the parameter of the base function + /*the Randomness: + 64=no randomness + 63..0 - block type randomness - 0 is maximum + 65..127 - each harmonic randomness - 127 is maximum*/ + unsigned char Prand; + unsigned char Pwaveshaping,Pwaveshapingfunction; + unsigned char Pnormalizemethod; + unsigned char Pfiltertype,Pfilterpar; + unsigned char Pfilterbeforews; + unsigned char Psatype,Psapar;//spectrum adjust + + REALTYPE hmag[MAX_AD_HARMONICS],hphase[MAX_AD_HARMONICS];//the magnituides and the phases of the sine/nonsine harmonics + //this is public because I get it from interface and show to the user + private: + FFTwrapper *fft; + //computes the basefunction and make the FFT; newbasefunc<0 = same basefunc + void changebasefunction(); + //Waveshaping + void waveshape(); + + //Filter the oscillator accotding to Pfiltertype and Pfilterpar + void oscilfilter(); + + //Adjust the spectrum + void spectrumadjust(); + + //Base function saveto/loadfrom quantised data + void savebasefuncQ(); + void loadbasefuncQ(); + + //Basic/base functions (Functiile De Baza) + REALTYPE basefunc_pulse(REALTYPE x,REALTYPE a); + REALTYPE basefunc_saw(REALTYPE x,REALTYPE a); + REALTYPE basefunc_triangle(REALTYPE x,REALTYPE a); + REALTYPE basefunc_power(REALTYPE x,REALTYPE a); + REALTYPE basefunc_gauss(REALTYPE x,REALTYPE a); + REALTYPE basefunc_diode(REALTYPE x,REALTYPE a); + REALTYPE basefunc_abssine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_pulsesine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_stretchsine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_chirp(REALTYPE x,REALTYPE a); + REALTYPE basefunc_absstretchsine(REALTYPE x,REALTYPE a); + REALTYPE basefunc_chebyshev(REALTYPE x,REALTYPE a); + + //Internal Data + unsigned char oldbasefunc,oldbasepar,oldhmagtype,oldwaveshapingfunction,oldwaveshaping,oldnormalizemethod; + int oldfilterpars,oldsapars; + /* + The frequencies of wavefroms are stored like this: + c[0],c[1],....,c[OSCIL_SIZE/2],s[OSCIL_SIZE/2-1],...,s[2],s[1] + c[N] is the cosine component and the s[N] is the sine component in the frequency domain + This way of storing of frequencies is similar to the FFTW package. + */ + REALTYPE *basefuncFFTfreqs;//Base Function Frequencies + REALTYPE *oscilFFTfreqs;//Oscillator Frequencies - this is different than the hamonics set-up by the user, it may contains time-domain data if the antialiasing is turned off + int oscilprepared;//1 if the oscil is prepared, 0 if it is not prepared and is need to call ::prepare() before ::get() + REALTYPE *outoscilFFTfreqs; + + unsigned short int *basefuncFFTfreqsQ; + Resonance *res; + +}; + + +#endif diff --git a/src/Synth/Resonance.C b/src/Synth/Resonance.C @@ -0,0 +1,231 @@ +/* + ZynAddSubFX - a software synthesizer + + Resonance.C - Resonance + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <math.h> +#include <stdlib.h> +#include "Resonance.h" + + +#include <stdio.h> + +Resonance::Resonance(){ + Penabled=0; + PmaxdB=20; + Pcenterfreq=64;//1 kHz + Poctavesfreq=64; + Pgain=5; + Pprotectthefundamental=0; + ctlcenter=1.0; + ctlbw=1.0; + for (int i=0;i<N_RES_POINTS;i++) Prespoints[i]=64; +}; + +Resonance::~Resonance(){ +}; + + +/* + * Set a point of resonance function with a value + */ +void Resonance::setpoint(int n,unsigned char p){ + if ((n<0)||(n>=N_RES_POINTS)) return; + Prespoints[n]=p; +}; + +/* + * Apply the resonance to FFT data + */ +void Resonance::applyres(int n,REALTYPE *fftdata,REALTYPE freq){ + if (Penabled==0) return;//if the resonance is disabled + REALTYPE sum=0.0, + l1=log(getfreqx(0.0)*ctlcenter), + l2=log(2.0)*getoctavesfreq()*ctlbw; + + for (int i=0;i<N_RES_POINTS;i++) if (sum<Prespoints[i]) sum=Prespoints[i]; + if (sum<1.0) sum=1.0; + + for (int i=1;i<n;i++){ + REALTYPE x=(log(freq*i)-l1)/l2;//compute where the n-th hamonics fits to the graph + if (x<0.0) x=0.0; + + x*=N_RES_POINTS; + REALTYPE dx=x-floor(x);x=floor(x); + int kx1=(int)x; if (kx1>=N_RES_POINTS) kx1=N_RES_POINTS-1; + int kx2=kx1+1;if (kx2>=N_RES_POINTS) kx2=N_RES_POINTS-1; + REALTYPE y=(Prespoints[kx1]*(1.0-dx)+Prespoints[kx2]*dx)/127.0-sum/127.0; + + y=pow(10.0,(y*PmaxdB+Pgain)/20.0); + + if ((Pprotectthefundamental!=0)&&(i==1)) y=pow(10.0,Pgain/20.0); + + fftdata[i]*=y; + fftdata[OSCIL_SIZE-i]*=y; + }; +}; + +/* + * Smooth the resonance function + */ +void Resonance::smooth(){ + REALTYPE old=Prespoints[0]; + for (int i=0;i<N_RES_POINTS;i++){ + old=old*0.4+Prespoints[i]*0.6; + Prespoints[i]=(int) old; + }; + old=Prespoints[N_RES_POINTS-1]; + for (int i=N_RES_POINTS-1;i>0;i--){ + old=old*0.4+Prespoints[i]*0.6; + Prespoints[i]=(int) old+1; + if (Prespoints[i]>127) Prespoints[i]=127; + }; +}; + +/* + * Randomize the resonance function + */ +void Resonance::randomize(int type){ + int r=(int)(RND*127.0); + for (int i=0;i<N_RES_POINTS;i++){ + Prespoints[i]=r; + if ((RND<0.1)&&(type==0)) r=(int)(RND*127.0); + if ((RND<0.3)&&(type==1)) r=(int)(RND*127.0); + if (type==2) r=(int)(RND*127.0); + }; + smooth(); +}; + +/* + * Interpolate the peaks + */ +void Resonance::interpolatepeaks(int type){ + int x1=0,y1=Prespoints[0]; + for (int i=1;i<N_RES_POINTS;i++){ + if ((Prespoints[i]!=64)||(i+1==N_RES_POINTS)){ + int y2=Prespoints[i]; + for (int k=0;k<i-x1;k++){ + float x=(float) k/(i-x1); + if (type==0) x=(1-cos(x*PI))*0.5; + Prespoints[x1+k]=(int)(y1*(1.0-x)+y2*x); + }; + x1=i; + y1=y2; + }; + }; +}; + +/* + * Get the frequency from x, where x is [0..1]; x is the x coordinate + */ +REALTYPE Resonance::getfreqx(REALTYPE x){ + if (x>1.0) x=1.0; + REALTYPE octf=pow(2.0,getoctavesfreq()); + return(getcenterfreq()/sqrt(octf)*pow(octf,x)); +}; + +/* + * Get the x coordinate from frequency (used by the UI) + */ +REALTYPE Resonance::getfreqpos(REALTYPE freq){ + return((log(freq)-log(getfreqx(0.0)))/log(2.0)/getoctavesfreq()); +}; + +/* + * Get the center frequency of the resonance graph + */ +REALTYPE Resonance::getcenterfreq(){ + return(10000.0*pow(10,-(1.0-Pcenterfreq/127.0)*2.0)); +}; + +/* + * Get the number of octave that the resonance functions applies to + */ +REALTYPE Resonance::getoctavesfreq(){ + return(0.25+10.0*Poctavesfreq/127.0); +}; + +void Resonance::sendcontroller(MidiControllers ctl,REALTYPE par){ + if (ctl==C_resonance_center) ctlcenter=par; + else ctlbw=par; +}; + + +/* + * Save or load the parameters to/from the buffer + */ +void Resonance::saveloadbuf(Buffer *buf){ + unsigned char npar,n,tmp; + +#ifdef DEBUG_BUFFER + fprintf(stderr,"\n( Resonance parameters) \n"); +#endif + + tmp=0xfe; + buf->rwbyte(&tmp);//if tmp!=0xfe error + + + for (n=0x80;n<0xf0;n++){ + if (buf->getmode()==0) { + buf->rwbyte(&npar); + n=0;//force a loop until the end of parameters (0xff) + } else npar=n; + if (npar==0xff) break; + + switch(npar){ + //Resonance parameters + case 0x80: buf->rwbytepar(n,&Penabled); + break; + case 0x81: buf->rwbytepar(n,&PmaxdB); + break; + case 0x82: buf->rwbytepar(n,&Pcenterfreq); + break; + case 0x83: buf->rwbytepar(n,&Poctavesfreq); + break; + case 0x84: buf->rwbytepar(n,&Pgain); + break; + case 0x85: buf->rwbytepar(n,&Pprotectthefundamental); + break; + case 0xA0: if (buf->getmode()!=0){ + if ((buf->getminimal()==0) || (Penabled!=0)){ + unsigned short int tmp2=N_RES_POINTS; + buf->rwbyte(&npar); + buf->rwword(&tmp2); + for (int i=0;i<N_RES_POINTS;i++) buf->rwbyte(&Prespoints[i]); + }; + } else { + unsigned short int tmp2; + buf->rwword(&tmp2); + for (int i=0;i<tmp2;i++) + if (i<N_RES_POINTS) buf->rwbyte(&Prespoints[i]); + else buf->rwbyte(&tmp); + + + }; + break; + }; + }; + + + if (buf->getmode()!=0) { + unsigned char tmp=0xff; + buf->rwbyte(&tmp); + }; +}; + diff --git a/src/Synth/Resonance.h b/src/Synth/Resonance.h @@ -0,0 +1,60 @@ +/* + ZynAddSubFX - a software synthesizer + + Resonance.h - Resonance + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef RESONANCE_H +#define RESONANCE_H + +#include "../globals.h" +#include "../Misc/Util.h" + +#define N_RES_POINTS 256 + +class Resonance{ + public: + Resonance(); + ~Resonance(); + void setpoint(int n,unsigned char p); + void applyres(int n,REALTYPE *fftdata,REALTYPE freq); + void smooth(); + void interpolatepeaks(int type); + void randomize(int type); + void saveloadbuf(Buffer *buf); + REALTYPE getfreqpos(REALTYPE freq); + REALTYPE getfreqx(REALTYPE x); + REALTYPE getcenterfreq(); + REALTYPE getoctavesfreq(); + void sendcontroller(MidiControllers ctl,REALTYPE par); + + //parameters + unsigned char Penabled; //if the ressonance is enabled + unsigned char Prespoints[N_RES_POINTS]; //how many points define the resonance function + unsigned char PmaxdB; //how many dB the signal may be amplified + unsigned char Pcenterfreq,Poctavesfreq; //the center frequency of the res. func., and the number of octaves + unsigned char Pgain; //how the signal is amplified + unsigned char Pprotectthefundamental; //the fundamental (1-st harmonic) is not damped, even it resonance function is low + //controllers + REALTYPE ctlcenter;//center frequency(relative) + REALTYPE ctlbw;//bandwidth(relative) + + private: +}; + +#endif diff --git a/src/Synth/SUBnote.C b/src/Synth/SUBnote.C @@ -0,0 +1,419 @@ +/* + ZynAddSubFX - a software synthesizer + + SUBnote.C - The "subtractive" synthesizer + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include "../globals.h" +#include "SUBnote.h" +#include "../Misc/Util.h" + +SUBnote::SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote){ + ready=0; + + tmpsmp=new REALTYPE[SOUND_BUFFER_SIZE]; + tmprnd=new REALTYPE[SOUND_BUFFER_SIZE]; + + pars=parameters; + ctl=ctl_; + portamento=portamento_; + NoteEnabled=ON; + volume=pow(0.1,3.0*(1.0-pars->PVolume/96.0));//-60 dB .. 0 dB + volume*=VelF(velocity,pars->PAmpVelocityScaleFunction); + if (pars->PPanning!=0) panning=pars->PPanning/127.0; + else panning=RND; + numstages=pars->Pnumstages; + stereo=pars->Pstereo; + start=pars->Pstart; + firsttick=1; + int pos[MAX_SUB_HARMONICS]; + + if (pars->Pfixedfreq==0) basefreq=freq; + else { + basefreq=440.0; + int fixedfreqET=pars->PfixedfreqET; + if (fixedfreqET!=0) {//if the frequency varies according the keyboard note + REALTYPE tmp=(midinote-69.0)/12.0*(pow(2.0,(fixedfreqET-1)/63.0)-1.0); + if (fixedfreqET<=64) basefreq*=pow(2.0,tmp); + else basefreq*=pow(3.0,tmp); + }; + + }; + REALTYPE detune=getdetune(pars->PDetuneType,pars->PCoarseDetune,pars->PDetune); + basefreq*=pow(2.0,detune/1200.0);//detune + basefreq*=ctl->pitchwheel.relfreq;//pitch wheel + + //global filter + GlobalFilterCenterPitch=pars->GlobalFilter->getfreq()+//center freq + (pars->PGlobalFilterVelocityScale/127.0*6.0)* //velocity sensing + (VelF(velocity,pars->PGlobalFilterVelocityScaleFunction)-1); + + GlobalFilterL=NULL;GlobalFilterR=NULL; + GlobalFilterEnvelope=NULL; + + //select only harmonics that desire to compute + numharmonics=0; + for (int n=0;n<MAX_SUB_HARMONICS;n++){ + if (pars->Phmag[n]==0)continue; + if (n*basefreq>SAMPLE_RATE/2.0) break;//remove the freqs above the Nyquist freq + pos[numharmonics++]=n; + }; + + if (numharmonics==0) { + NoteEnabled=OFF; + return; + }; + + + lfilter=new bpfilter[numstages*numharmonics]; + if (stereo!=0) rfilter=new bpfilter[numstages*numharmonics]; + + //how much the amplitude is normalised (because the harmonics) + REALTYPE reduceamp=0.0; + + for (int n=0;n<numharmonics;n++){ + + REALTYPE freq=basefreq*(pos[n]+1); + + //the bandwidth is not absolute(Hz); it is relative to frequency + REALTYPE bw=pow(10,(pars->Pbandwidth-127.0)/127.0*4)*numstages; + + //Bandwidth Scale + bw*=pow(1000/freq,(pars->Pbwscale-64.0)/64.0*3.0); + + //Relative BandWidth + bw*=pow(100,(pars->Phrelbw[pos[n]]-64.0)/64.0); + + if (bw>25.0) bw=25.0; + + //try to keep same amplitude on all freqs and bw. (empirically) + REALTYPE gain=sqrt(1500.0/(bw*freq)); + + REALTYPE hmagnew=1.0-pars->Phmag[pos[n]]/127.0; + REALTYPE hgain; + + switch(pars->Phmagtype){ + case 1:hgain=exp(hmagnew*log(0.01)); break; + case 2:hgain=exp(hmagnew*log(0.001));break; + case 3:hgain=exp(hmagnew*log(0.0001));break; + case 4:hgain=exp(hmagnew*log(0.00001));break; + default:hgain=1.0-hmagnew; + }; + gain*=hgain; + reduceamp+=hgain; + + for (int nph=0;nph<numstages;nph++){ + REALTYPE amp=1.0; + if (nph==0) amp=gain; + initfilter(lfilter[nph+n*numstages],freq,bw,amp,hgain); + if (stereo!=0) initfilter(rfilter[nph+n*numstages],freq,bw,amp,hgain); + }; + }; + + if (reduceamp<0.001) reduceamp=1.0; + volume/=reduceamp; + + oldpitchwheel=0; + oldbandwidth=64; + if (pars->Pfixedfreq==0) initparameters(basefreq); + else initparameters(basefreq/440.0*freq); + + oldamplitude=newamplitude; + ready=1; +}; + +SUBnote::~SUBnote(){ + if (NoteEnabled!=OFF) KillNote(); + delete [] tmpsmp; + delete [] tmprnd; +}; + +/* + * Kill the note + */ +void SUBnote::KillNote(){ + if (NoteEnabled!=OFF){ + delete [] lfilter; + lfilter=NULL; + if (stereo!=0) delete [] rfilter; + rfilter=NULL; + delete(AmpEnvelope); + if (FreqEnvelope!=NULL) delete(FreqEnvelope); + if (BandWidthEnvelope!=NULL) delete(BandWidthEnvelope); + NoteEnabled=OFF; + }; + +}; + + +/* + * Compute the filters coefficients + */ +void SUBnote::computefiltercoefs(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE gain){ + if (freq>SAMPLE_RATE/2.0-200.0) { + freq=SAMPLE_RATE/2.0-200.0; + }; + + REALTYPE omega=2.0*PI*freq/SAMPLE_RATE; + REALTYPE sn=sin(omega);REALTYPE cs=cos(omega); + REALTYPE alpha=sn*sinh(LOG_2/2.0*bw*omega/sn); + + if (alpha>1) alpha=1; + if (alpha>bw) alpha=bw; + + filter.b0=alpha/(1.0+alpha)*filter.amp*gain; + filter.b2=-alpha/(1.0+alpha)*filter.amp*gain; + filter.a1=-2.0*cs/(1.0+alpha); + filter.a2=(1.0-alpha)/(1.0+alpha); + +}; + + +/* + * Initialise the filters + */ +void SUBnote::initfilter(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE amp,REALTYPE mag){ + filter.xn1=0.0;filter.xn2=0.0; + + if (start==0) { + filter.yn1=0.0; + filter.yn2=0.0; + } else { + REALTYPE a=0.1*mag;//empirically + REALTYPE p=RND*2.0*PI; + if (start==1) a*=RND; + filter.yn1=a*cos(p); + filter.yn2=a*cos(p+freq*2.0*PI/SAMPLE_RATE); + + //correct the error of computation the start amplitude + //at very high frequencies + if (freq>SAMPLE_RATE*0.96) { + filter.yn1=0.0; + filter.yn2=0.0; + + }; + }; + + filter.amp=amp; + filter.freq=freq; + filter.bw=bw; + computefiltercoefs(filter,freq,bw,1.0); +}; + +/* + * Do the filtering + */ +void SUBnote::filter(bpfilter &filter,REALTYPE *smps){ + int i; + REALTYPE out; + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + out=smps[i] * filter.b0 + filter.b2 * filter.xn2 + -filter.a1 * filter.yn1 - filter.a2 * filter.yn2; + filter.xn2=filter.xn1; + filter.xn1=smps[i]; + filter.yn2=filter.yn1; + filter.yn1=out; + smps[i]=out; + + }; +}; + +/* + * Init Parameters + */ +void SUBnote::initparameters(REALTYPE freq){ + AmpEnvelope=new Envelope(pars->AmpEnvelope,freq); + if (pars->PFreqEnvelopeEnabled!=0) FreqEnvelope=new Envelope(pars->FreqEnvelope,freq); + else FreqEnvelope=NULL; + if (pars->PBandWidthEnvelopeEnabled!=0) BandWidthEnvelope=new Envelope(pars->BandWidthEnvelope,freq); + else BandWidthEnvelope=NULL; + if (pars->PGlobalFilterEnabled!=0){ + globalfiltercenterq=pars->GlobalFilter->getq(); + GlobalFilterL=new Filter(pars->GlobalFilter); + if (stereo!=0) GlobalFilterR=new Filter(pars->GlobalFilter); + GlobalFilterEnvelope=new Envelope(pars->GlobalFilterEnvelope,freq); + GlobalFilterFreqTracking=pars->GlobalFilter->getfreqtracking(basefreq); + }; + computecurrentparameters(); +}; + + +/* + * Compute Parameters of SUBnote for each tick + */ +void SUBnote::computecurrentparameters(){ + if ((FreqEnvelope!=NULL)||(BandWidthEnvelope!=NULL)|| + (oldpitchwheel!=ctl->pitchwheel.data)|| + (oldbandwidth!=ctl->bandwidth.data)|| + (portamento!=0)){ + REALTYPE envfreq=1.0; + REALTYPE envbw=1.0; + REALTYPE gain=1.0; + + if (FreqEnvelope!=NULL) { + envfreq=FreqEnvelope->envout()/1200; + envfreq=pow(2.0,envfreq); + }; + envfreq*=ctl->pitchwheel.relfreq;//pitch wheel + if (portamento!=0) {//portamento is used + envfreq*=ctl->portamento.freqrap; + if (ctl->portamento.used==0){//the portamento has finished + portamento=0;//this note is no longer "portamented" + }; + }; + + if (BandWidthEnvelope!=NULL) { + envbw=BandWidthEnvelope->envout(); + envbw=pow(2,envbw); + }; + envbw*=ctl->bandwidth.relbw;//bandwidth controller + + REALTYPE tmpgain=1.0/sqrt(envbw*envfreq); + + for (int n=0;n<numharmonics;n++){ + for (int nph=0;nph<numstages;nph++) { + if (nph==0) gain=tmpgain;else gain=1.0; + computefiltercoefs( lfilter[nph+n*numstages], + lfilter[nph+n*numstages].freq*envfreq, + lfilter[nph+n*numstages].bw*envbw,gain); + }; + }; + if (stereo!=0) + for (int n=0;n<numharmonics;n++){ + for (int nph=0;nph<numstages;nph++) { + if (nph==0) gain=tmpgain;else gain=1.0; + computefiltercoefs( rfilter[nph+n*numstages], + rfilter[nph+n*numstages].freq*envfreq, + rfilter[nph+n*numstages].bw*envbw,gain); + }; + }; + oldbandwidth=ctl->bandwidth.data; + oldpitchwheel=ctl->pitchwheel.data; + }; + newamplitude=volume*AmpEnvelope->envout_dB()*2.0; + + //Filter + if (GlobalFilterL!=NULL){ + REALTYPE globalfilterpitch=GlobalFilterCenterPitch+GlobalFilterEnvelope->envout(); + REALTYPE filterfreq=globalfilterpitch+ctl->filtercutoff.relfreq+GlobalFilterFreqTracking; + filterfreq=GlobalFilterL->getrealfreq(filterfreq); + + GlobalFilterL->setfreq_and_q(filterfreq,globalfiltercenterq*ctl->filterq.relq); + if (GlobalFilterR!=NULL) GlobalFilterR->setfreq_and_q(filterfreq,globalfiltercenterq*ctl->filterq.relq); + }; + +}; + +/* + * Note Output + */ +int SUBnote::noteout(REALTYPE *outl,REALTYPE *outr){ + int i; + + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + outl[i]=denormalkillbuf[i]; + outr[i]=denormalkillbuf[i]; + }; + + if (NoteEnabled==OFF) return(0); + + //left channel + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmprnd[i]=RND*2.0-1.0; + for (int n=0;n<numharmonics;n++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpsmp[i]=tmprnd[i]; + for (int nph=0;nph<numstages;nph++) + filter(lfilter[nph+n*numstages],tmpsmp); + for (i=0;i<SOUND_BUFFER_SIZE;i++) outl[i]+=tmpsmp[i]; + }; + + if (GlobalFilterL!=NULL) GlobalFilterL->filterout(&outl[0]); + + //right channel + if (stereo!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmprnd[i]=RND*2.0-1.0; + for (int n=0;n<numharmonics;n++){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpsmp[i]=tmprnd[i]; + for (int nph=0;nph<numstages;nph++) + filter(rfilter[nph+n*numstages],tmpsmp); + for (i=0;i<SOUND_BUFFER_SIZE;i++) outr[i]+=tmpsmp[i]; + }; + if (GlobalFilterR!=NULL) GlobalFilterR->filterout(&outr[0]); + } else for (i=0;i<SOUND_BUFFER_SIZE;i++) outr[i]=outl[i]; + + if (firsttick!=0){ + int n=10;if (n>SOUND_BUFFER_SIZE) n=SOUND_BUFFER_SIZE; + for (i=0;i<n;i++) { + REALTYPE ampfadein=0.5-0.5*cos((REALTYPE) i/(REALTYPE) n*PI); + outl[i]*=ampfadein; + outr[i]*=ampfadein; + }; + firsttick=0; + }; + + if (ABOVE_AMPLITUDE_THRESHOLD(oldamplitude,newamplitude)){ + // Amplitude interpolation + for (i=0;i<SOUND_BUFFER_SIZE;i++){ + REALTYPE tmpvol=INTERPOLATE_AMPLITUDE(oldamplitude + ,newamplitude,i,SOUND_BUFFER_SIZE); + outl[i]*=tmpvol*panning; + outr[i]*=tmpvol*(1.0-panning); + }; + } else { + for (i=0;i<SOUND_BUFFER_SIZE;i++) { + outl[i]*=newamplitude*panning; + outr[i]*=newamplitude*(1.0-panning); + }; + }; + + oldamplitude=newamplitude; + computecurrentparameters(); + + // Check if the note needs to be computed more + if (AmpEnvelope->finished()!=0){ + for (i=0;i<SOUND_BUFFER_SIZE;i++) {//fade-out + REALTYPE tmp=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE; + outl[i]*=tmp; + outr[i]*=tmp; + }; + KillNote(); + }; + return(1); +}; + +/* + * Relase Key (Note Off) + */ +void SUBnote::relasekey(){ + AmpEnvelope->relasekey(); + if (FreqEnvelope!=NULL) FreqEnvelope->relasekey(); + if (BandWidthEnvelope!=NULL) BandWidthEnvelope->relasekey(); + if (GlobalFilterEnvelope!=NULL) GlobalFilterEnvelope->relasekey(); +}; + +/* + * Check if the note is finished + */ +int SUBnote::finished(){ + if (NoteEnabled==OFF) return(1); + else return(0); +}; + diff --git a/src/Synth/SUBnote.h b/src/Synth/SUBnote.h @@ -0,0 +1,98 @@ +/* + ZynAddSubFX - a software synthesizer + + SUBnote.h - The subtractive synthesizer + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#ifndef SUB_NOTE_H +#define SUB_NOTE_H + +#include "../globals.h" +#include "../Params/SUBnoteParameters.h" +#include "../Params/Controller.h" +#include "Envelope.h" +#include "../DSP/Filter.h" + +class SUBnote{ + public: + SUBnote(SUBnoteParameters *parameters,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote); + ~SUBnote(); + int noteout(REALTYPE *outl,REALTYPE *outr);//note output,return 0 if the note is finished + void relasekey(); + int finished(); + + int ready; //if I can get the sampledata + + private: + + void computecurrentparameters(); + void initparameters(REALTYPE freq); + void KillNote(); + + SUBnoteParameters *pars; + + //parameters + int stereo; + int numstages;//number of stages of filters + int numharmonics;//number of harmonics (after the too higher hamonics are removed) + int start;//how the harmonics start + REALTYPE basefreq; + REALTYPE panning; + Envelope *AmpEnvelope; + Envelope *FreqEnvelope; + Envelope *BandWidthEnvelope; + + Filter *GlobalFilterL,*GlobalFilterR; + + Envelope *GlobalFilterEnvelope; + + //internal values + ONOFFTYPE NoteEnabled; + int firsttick,portamento; + REALTYPE volume,oldamplitude,newamplitude; + + REALTYPE GlobalFilterCenterPitch;//octaves + REALTYPE GlobalFilterFreqTracking; + + struct bpfilter{ + REALTYPE freq,bw,amp; //filter parameters + REALTYPE a1,a2,b0,b2;//filter coefs. b1=0 + REALTYPE xn1,xn2,yn1,yn2; //filter internal values + }; + + void initfilter(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE amp,REALTYPE mag); + void computefiltercoefs(bpfilter &filter,REALTYPE freq,REALTYPE bw,REALTYPE gain); + void filter(bpfilter &filter,REALTYPE *smps); + + bpfilter *lfilter,*rfilter; + + REALTYPE *tmpsmp; + REALTYPE *tmprnd;//this is filled with random numbers + + Controller *ctl; + int oldpitchwheel,oldbandwidth; + REALTYPE globalfiltercenterq; + +}; + + + + +#endif + diff --git a/src/UI/ADnoteUI.fl b/src/UI/ADnoteUI.fl @@ -0,0 +1,1731 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include "../Params/ADnoteParameters.h"} {public +} + +decl {\#include "../Synth/OscilGen.h"} {public +} + +decl {\#include "../Misc/Util.h"} {public +} + +decl {\#include "../Misc/Master.h"} {public +} + +decl {\#include "ResonanceUI.h"} {public +} + +decl {\#include <FL/Fl_Box.H>} {public +} + +decl {\#include <FL/Fl_Group.H>} {public +} + +decl {\#include <math.h>} {} + +decl {\#include <stdio.h>} {} + +decl {\#include <stdlib.h>} {} + +decl {\#include <string.h>} {} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include "EnvelopeUI.h"} {public +} + +decl {\#include "LFOUI.h"} {public +} + +decl {\#include "FilterUI.h"} {public +} + +class ADSpectrum {: {public Fl_Box} +} { + Function {ADSpectrum(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {oscil=NULL;} {} + } + Function {init(OscilGen *oscil_,int oscbase_,Master *master_)} {} { + code {oscil=oscil_; +oscbase=oscbase_; +master=master_;} {} + } + Function {draw()} {} { + code {int ox=x(),oy=y(),lx=w(),ly=h(),i; +const int maxdb=60;//must be multiple of 10 +int GX=2; +int n=lx/GX-1; +if (n>OSCIL_SIZE/2) n=OSCIL_SIZE/2; + +REALTYPE x; +REALTYPE spc[n]; +for (i=0;i<n;i++) spc[i]=0.0; + +pthread_mutex_lock(&master->mutex); +if (oscbase==0) oscil->getspectrum(n,spc,0); + else oscil->getspectrum(n,spc,1); +pthread_mutex_unlock(&master->mutex); + +//normalize +REALTYPE max=0; +for (i=0;i<n;i++){ + x=fabs(spc[i]); + if (max<x) max=x; +} +if (max<0.000001) max=1.0; +max=max*1.05; + +//draw + +if (this->active_r()) fl_color(this->parent()->selection_color()); + else fl_color(this->parent()->color()); +if ((ANTI_ALIAS==0)&&(oscbase==0)) fl_color(this->parent()->color()); +fl_line_style(FL_DOT); + +for (i=1;i<maxdb/10;i++){ + int ky=(int)((REALTYPE)i*ly*10.0/maxdb)/2; + ky*=2; + fl_line(ox,oy+ky-1,ox+lx-2,oy+ky-1); +}; + +for (i=2;i<n;i++){ + int tmp=i*GX-2; + if (i%10==1) fl_line_style(0); + else fl_line_style(FL_DOT); + fl_line(ox+tmp,oy+2,ox+tmp,oy+ly-2); +} + +if (this->active_r()) fl_color(this->parent()->labelcolor()); + else fl_color(this->parent()->color()); +fl_line_style(0); + +//draws the spectrum +for (i=0;i<n;i++){ + int tmp=i*GX+2; + x=spc[i]/max; + + if (x>dB2rap(-maxdb)) x=rap2dB(x)/maxdb+1; + else x=0; + + int val=(int) ((ly-2)*x); + if (val>0) fl_line(ox+tmp,oy+ly-2-val,ox+tmp,oy+ly-2); +};} {} + } + decl {OscilGen *oscil;} {} + decl {int oscbase;} {} + decl {Master *master;} {} +} + +class ADOscilloscope {: {public Fl_Box} +} { + Function {ADOscilloscope(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {oscil=NULL; +phase=64; +oscbase=0;} {} + } + Function {init(OscilGen *oscil_,Master *master_)} {} { + code {oscil=oscil_; +master=master_;} {} + } + Function {init(OscilGen *oscil_,int oscbase_,Master *master_)} {} { + code {oscil=oscil_; +oscbase=oscbase_; +master=master_;} {} + } + Function {init(OscilGen *oscil_,int oscbase_,int phase_,Master *master_)} {} { + code {oscil=oscil_; +oscbase=oscbase_; +phase=phase_; +master=master_;} {} + } + Function {draw()} {} { + code {int ox=x(),oy=y(),lx=w(),ly=h()-1,i; +REALTYPE smps[OSCIL_SIZE]; +pthread_mutex_lock(&master->mutex); +if (oscbase==0) oscil->get(smps,-1.0); + else oscil->getcurrentbasefunction(smps); +pthread_mutex_unlock(&master->mutex); + +//normalize +REALTYPE max=0; +for (i=0;i<OSCIL_SIZE;i++) + if (max<fabs(smps[i])) max=fabs(smps[i]); +//fprintf(stderr,"%.4f\\n",max); +if (max<0.00001) max=1.0; +max=-max*1.05; + +//draw +fl_line_style(FL_DASH); +if (this->active_r()) fl_color(this->parent()->labelcolor()); + else fl_color(this->parent()->color()); +int GX=16;if (lx<GX*3) GX=-1; +for (i=1;i<GX;i++){ + int tmp=(int)(lx/(REALTYPE)GX*i); + fl_line(ox+tmp,oy+2,ox+tmp,oy+ly-2); +}; +int GY=8;if (ly<GY*3) GY=-1; +for (i=1;i<GY;i++){ + int tmp=(int)(ly/(REALTYPE)GY*i); + fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); +}; + +//draw the function +fl_line_style(0,1); +fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); +if (this->active_r()) fl_color(this->parent()->selection_color()); + else fl_color(this->parent()->labelcolor()); +int lw=1; +//if ((lx<135)||(ly<135)) lw=1; +fl_line_style(0,lw); +int ph=(int)((phase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE); +for (i=1;i<lx;i++){ + int k1=(int)((REALTYPE)OSCIL_SIZE*(i-1)/lx)+ph; + int k2=(int)((REALTYPE)OSCIL_SIZE*i/lx)+ph; + REALTYPE y1=smps[k1%OSCIL_SIZE]/max; + REALTYPE y2=smps[k2%OSCIL_SIZE]/max; + fl_line(i-1+ox,(int)(y1*ly/2.0)+oy+ly/2,i+ox,(int)(y2*ly/2.0)+oy+ly/2); +};} {} + } + decl {OscilGen *oscil;} {} + decl {int oscbase;} {} + decl {int phase;} {public + } + decl {Master *master;} {} +} + +class ADOscilharmonic {: {public Fl_Group} +} { + Function {make_window()} {private + } { + Fl_Window harmonic { + private xywh {421 154 90 225} hide + class Fl_Group + } { + Fl_Slider mag { + callback {int x=64; +if (Fl::event_button1()) x=127-(int)o->value(); + else o->value(x); +if (x==64) o->selection_color(0); + else o->selection_color(222); + +pthread_mutex_lock(&master->mutex); + oscil->Phmag[n]=x; + oscil->prepare(); +pthread_mutex_unlock(&master->mutex); + +display->redraw(); +oldosc->redraw();} + xywh {0 15 15 115} type {Vert Knob} box FLAT_BOX selection_color 222 labelcolor 0 maximum 127 step 1 value 64 + code0 {o->value(127-oscil->Phmag[n]);} + code1 {if (oscil->Phmag[n]==64) o->selection_color(0);} + } + Fl_Slider phase { + callback {int x=64; +if (Fl::event_button1()) x=(int)o->value(); + else o->value(x); + +pthread_mutex_lock(&master->mutex); + oscil->Phphase[n]=x; + oscil->prepare(); +pthread_mutex_unlock(&master->mutex); + +display->redraw(); +oldosc->redraw();} + xywh {0 135 15 75} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 + code0 {o->value(oscil->Phphase[n]);} + } + Fl_Box {} { + xywh {15 70 5 5} box FLAT_BOX color 45 + } + Fl_Box {} { + xywh {15 170 5 5} box FLAT_BOX color 45 + } + Fl_Box {} { + label 01 + xywh {0 210 20 15} labelfont 1 labelsize 9 align 20 + code0 {char tmp[10];snprintf(tmp,10,"%d",n+1);o->label(strdup(tmp));} + } + Fl_Box {} { + label 01 + xywh {0 0 20 15} labelfont 1 labelsize 9 align 20 + code0 {char tmp[10];snprintf(tmp,10,"%d",n+1);o->label(strdup(tmp));} + } + } + } + Function {ADOscilharmonic(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {n=0; +oscil=NULL; +display=NULL;} {} + } + Function {init(OscilGen *oscil_,int n_,Fl_Group *display_,Fl_Widget *oldosc_, Master *master_)} {} { + code {oscil=oscil_; +n=n_; +display=display_; +master=master_; +oldosc=oldosc_; +make_window(); +end(); +harmonic->show();} {} + } + Function {~ADOscilharmonic()} {} { + code {harmonic->hide(); +delete(harmonic);} {} + } + decl {OscilGen *oscil;} {} + decl {Fl_Group *display;} {} + decl {int n;} {} + decl {Fl_Widget *oldosc;} {} + decl {Master *master;} {} +} + +class ADOscilEditor {} { + Function {make_window()} {} { + Fl_Window osceditUI { + label {ADsynth Oscillator Editor} + xywh {41 111 750 590} hide + } { + Fl_Group oscildisplaygroup { + xywh {15 5 360 300} box ENGRAVED_FRAME + } { + Fl_Group {} {open + xywh {20 85 350 190} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 + code0 {ADOscilloscope *osc=new ADOscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {osc->init(oscil,master);} + } {} + Fl_Box {} { + label Oscillator + xywh {130 10 110 20} box FLAT_BOX labelfont 1 + } + Fl_Value_Slider {} { + label rnd + callback {oscil->Prand=(int)o->value()+64; +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Oscilator Phase Randomness: smaller than 0 is "group", larger than 0 is for each harmonic} xywh {180 285 175 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 + code0 {o->value(oscil->Prand-64);} + } + Fl_Group {} {open + xywh {20 30 350 50} box THIN_DOWN_BOX color 32 selection_color 218 labelcolor 63 + code0 {ADSpectrum *spc=new ADSpectrum(o->x(),o->y(),o->w(),o->h(),"");} + code1 {spc->init(oscil,0,master);} + } {} + } + Fl_Box {} { + label {Base Func.} + xywh {505 15 110 20} box FLAT_BOX labelfont 1 + } + Fl_Group basefuncdisplaygroup { + xywh {375 5 360 300} box ENGRAVED_FRAME + } { + Fl_Group {} {open + xywh {380 85 350 190} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 + code0 {ADOscilloscope *osc=new ADOscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {osc->init(oscil,1,master);} + } {} + Fl_Choice {} { + label {Base Func.} + callback {oscil->Pcurrentbasefunc=(int) o->value(); + +basefuncdisplaygroup->redraw(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + xywh {445 280 90 20} down_box BORDER_BOX labelsize 12 textsize 12 + code0 {o->value(oscil->Pcurrentbasefunc);} + } { + menuitem {} { + label Sine + xywh {10 10 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Triangle + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Pulse + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Saw + xywh {40 40 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Power + xywh {50 50 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Gauss + xywh {50 50 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Diode + xywh {60 60 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label AbsSine + xywh {70 70 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label PulseSine + xywh {80 80 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label StrchSine + xywh {90 90 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Chirp + xywh {100 100 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label AbsStrSine + xywh {102 102 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Chebyshev + xywh {112 112 100 20} labelfont 1 labelsize 12 + } + } + Fl_Box {} { + label {Base Func.} + xywh {490 10 110 20} box FLAT_BOX labelfont 1 + } + Fl_Value_Slider {} { + label {par.} + callback {oscil->Pbasefuncpar=(int)o->value()+64; +basefuncdisplaygroup->redraw(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Base Function Parameter} xywh {550 285 175 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 + code0 {o->value(oscil->Pbasefuncpar-64);} + } + Fl_Group {} {open + xywh {380 30 350 50} box THIN_DOWN_BOX color 32 selection_color 218 labelcolor 63 + code0 {ADSpectrum *spc=new ADSpectrum (o->x(),o->y(),o->w(),o->h(),"");} + code1 {spc->init(oscil,1,master);} + } {} + } + Fl_Choice {} { + label {Mag.Type} + callback {oscil->Phmagtype=(int) o->value(); +basefuncdisplaygroup->redraw(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + xywh {80 280 65 20} down_box BORDER_BOX labelsize 12 textsize 12 + code0 {o->value(oscil->Phmagtype);} + } { + menuitem {} { + label Linear + xywh {0 0 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-40dB} + xywh {10 10 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-60dB} + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-80dB} + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-100dB} + xywh {40 40 100 20} labelfont 1 labelsize 12 + } + } + Fl_Button {} { + label {Use as base} + callback {oscil->useasbase(); +if (autoclearbutton->value()){ + for (int i=0;i<MAX_AD_HARMONICS;i++){ + h[i]->mag->value(64); + oscil->Phmag[i]=64; + h[i]->phase->value(64); + oscil->Phphase[i]=64; + }; + oscil->Phmag[0]=127; + h[0]->mag->value(0); + wshbutton->value(0); + wshbutton->do_callback(); + fltbutton->value(0); + fltbutton->do_callback(); + sabutton->value(0); + sabutton->do_callback(); +}; + +pthread_mutex_lock(&master->mutex); + for (int i=0;i<MAX_AD_HARMONICS;i++){ + if (oscil->Phmag[i]==64) h[i]->mag->selection_color(0); + else h[i]->mag->selection_color(222); + }; + oscil->prepare(); +pthread_mutex_unlock(&master->mutex); + +oscildisplaygroup->redraw(); +basefuncdisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Use this Oscillator as base function} xywh {15 310 85 20} box THIN_UP_BOX labelfont 1 labelsize 12 + } + Fl_Button {} { + label Close + callback {osceditUI->hide();} + xywh {678 557 69 28} box THIN_UP_BOX + } + Fl_Button {} { + label Clear + callback {for (int i=0;i<MAX_AD_HARMONICS;i++){ + h[i]->mag->value(64); + oscil->Phmag[i]=64; + h[i]->phase->value(64); + oscil->Phphase[i]=64; +}; +oscil->Phmag[0]=127; +h[0]->mag->value(0); + +for (int i=0;i<MAX_AD_HARMONICS;i++){ + if (oscil->Phmag[i]==64) h[i]->mag->selection_color(0); + else h[i]->mag->selection_color(222); +}; + +//harmonics->redraw(); + +pthread_mutex_lock(&master->mutex); + oscil->prepare(); +pthread_mutex_unlock(&master->mutex); + +oscildisplaygroup->redraw(); +oldosc->redraw();} + xywh {680 335 50 20} box THIN_UP_BOX labelfont 1 labelsize 12 + } + Fl_Group {} { + xywh {145 305 230 30} box ENGRAVED_BOX + } { + Fl_Choice wshbutton { + label {Wsh.} + callback {oscil->Pwaveshapingfunction=(int) o->value(); +basefuncdisplaygroup->redraw(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Waveshaping function} xywh {175 310 55 20} down_box BORDER_BOX labelsize 10 textsize 10 + code0 {o->value(oscil->Pwaveshapingfunction);} + } { + menuitem {} { + label None + xywh {25 25 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Atan + xywh {35 35 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Asym1 + xywh {45 45 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Pow + xywh {55 55 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Sine + xywh {65 65 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Qnts + xywh {75 75 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Zigzg + xywh {85 85 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Lmt + xywh {95 95 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LmtU + xywh {105 105 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LmtL + xywh {115 115 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label ILmt + xywh {127 127 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Clip + xywh {137 137 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Asym2 + xywh {85 85 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Pow2 + xywh {95 95 100 20} labelfont 1 labelsize 10 + } + } + Fl_Value_Slider {} { + callback {oscil->Pwaveshaping=(int)o->value()+64; +//basefuncdisplaygroup->redraw(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Waveshaping Parameter} xywh {230 315 140 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 + code0 {o->value(oscil->Pwaveshaping-64);} + } + } + Fl_Light_Button autoclearbutton { + label {Clr.} + tooltip {Auto clear when using the oscillator as base function} xywh {105 310 35 20} box THIN_UP_BOX value 1 labelfont 1 labelsize 10 + } + Fl_Light_Button {} { + label {RMS normalize} + callback {oscil->Pnormalizemethod=(int) o->value();} + tooltip {Normalize type (harmonic's sum/RMS) of the oscillator} xywh {680 360 65 30} box THIN_UP_BOX value 1 labelfont 1 labelsize 10 align 148 + code0 {o->value(oscil->Pnormalizemethod);} + } + Fl_Group {} { + xywh {375 305 160 30} box ENGRAVED_BOX + } { + Fl_Choice fltbutton { + label Filter + callback {oscil->Pfiltertype=(int) o->value(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Oscillator's filter type} xywh {405 310 50 20} down_box BORDER_BOX labelsize 10 textsize 10 + code0 {o->value(oscil->Pfiltertype);} + } { + menuitem {} { + label None + xywh {35 35 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LP1 + xywh {45 45 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HP1a + xywh {55 55 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HP1b + xywh {65 65 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label BP1 + xywh {75 75 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label BS1 + xywh {85 85 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LP2 + xywh {55 55 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HP2 + xywh {65 65 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label BP2 + xywh {65 65 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label BS2 + xywh {75 75 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Cos + xywh {75 75 100 20} labelfont 1 labelsize 10 + } + } + Fl_Dial {} { + callback {oscil->Pfilterpar=(int)o->value(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Oscillator's filter parameter} xywh {460 310 20 20} maximum 127 step 1 + code0 {o->value(oscil->Pfilterpar);} + class WidgetPDial + } + Fl_Check_Button {} { + label preF + callback {oscil->Pfilterbeforews=(int)o->value(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Apply the filter before the waveshaping} xywh {490 310 35 20} down_box DOWN_BOX labelsize 10 align 24 + code0 {o->value(oscil->Pfilterbeforews);} + } + } + Fl_Scroll _this_has_to_be_the_last { + xywh {15 335 660 250} type HORIZONTAL box ENGRAVED_BOX + } { + Fl_Pack harmonics {open + xywh {20 340 650 225} type HORIZONTAL + code0 {for (int i=0;i<MAX_AD_HARMONICS;i++){h[i]=new ADOscilharmonic(0,0,20,o->h(),"");h[i]->init(oscil,i,oscildisplaygroup,oldosc,master);}} + } {} + } + Fl_Group {} { + xywh {535 305 120 30} box ENGRAVED_BOX + } { + Fl_Choice sabutton { + label {Sp.adj.} + callback {oscil->Psatype=(int) o->value(); +oscildisplaygroup->redraw(); +oldosc->redraw();} open + tooltip {Oscillator's spectrum adjust} xywh {575 310 50 20} down_box BORDER_BOX labelsize 10 textsize 10 + code0 {o->value(oscil->Psatype);} + } { + menuitem {} { + label None + xywh {45 45 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Pow + xywh {55 55 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Thrs + xywh {65 65 100 20} labelfont 1 labelsize 10 + } + } + Fl_Dial {} { + callback {oscil->Psapar=(int)o->value(); +oscildisplaygroup->redraw(); +oldosc->redraw();} + tooltip {Oscillator's spectrum adjust parameter} xywh {630 310 20 20} maximum 127 step 1 + code0 {o->value(oscil->Psapar);} + class WidgetPDial + } + } + } + } + Function {ADOscilEditor(OscilGen *oscil_,Fl_Widget *oldosc_,Master *master_)} {} { + code {oscil=oscil_; +oldosc=oldosc_; +master=master_; +make_window(); +osceditUI->show();} {} + } + Function {~ADOscilEditor()} {} { + code {osceditUI->hide(); +for (int i=0;i<MAX_AD_HARMONICS;i++) delete (h[i]); +delete (osceditUI);} {} + } + decl {OscilGen *oscil;} {} + decl {Fl_Widget *oldosc;} {} + decl {ADOscilharmonic *h[MAX_AD_HARMONICS];} {} + decl {Master *master;} {} +} + +class ADvoicelistitem {: {public Fl_Group} +} { + Function {make_window()} {private + } { + Fl_Window ADnoteVoiceListItem { + private xywh {335 489 615 27} hide + class Fl_Group + } { + Fl_Group voicelistitemgroup { + private xywh {50 0 570 25} box FLAT_BOX + code0 {if (pars->VoicePar[nvoice].Enabled==0) o->deactivate();} + } { + Fl_Value_Slider voicevolume { + callback {pars->VoicePar[nvoice].PVolume=(int)o->value();} + tooltip Volume xywh {90 5 115 20} type {Horz Knob} box FLAT_BOX labelsize 8 align 5 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PVolume);} + } + Fl_Check_Button voiceresonanceenabled { + callback {pars->VoicePar[nvoice].Presonance=(int)o->value();} + tooltip {Resonance On/Off} xywh {245 7 15 17} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 12 align 4 + code0 {o->value(pars->VoicePar[nvoice].Presonance);} + } + Fl_Value_Slider voicelfofreq { + callback {pars->VoicePar[nvoice].FreqLfo->Pintensity=(int)o->value();} + tooltip {Frequency LFO amount} xywh {500 5 115 20} type {Horz Knob} box FLAT_BOX labelsize 8 align 5 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].FreqLfo->Pintensity);} + } + Fl_Dial voicepanning { + callback {pars->VoicePar[nvoice].PPanning=(int) o->value();} + tooltip {Panning (leftmost is Random)} xywh {215 5 20 20} box ROUND_UP_BOX labelsize 11 align 4 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PPanning);} + class WidgetPDial + } + Fl_Group voiceoscil {open + xywh {60 5 30 20} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 + code0 {osc=new ADOscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {osc->init(pars->VoicePar[nvoice].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master);} + code2 {if (pars->VoicePar[nvoice].Pextoscil != -1) {osc->init(pars->VoicePar[pars->VoicePar[nvoice].Pextoscil].OscilSmp,master);}} + } {} + Fl_Value_Output detunevalueoutput { + callback {o->value(getdetune((pars->VoicePar[nvoice].PDetuneType==0)?(pars->GlobalPar.PDetuneType) : (pars->VoicePar[nvoice].PDetuneType),0,pars->VoicePar[nvoice].PDetune));} + xywh {265 5 45 20} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10 + code0 {o->value(getdetune(pars->VoicePar[nvoice].PDetuneType,0,pars->VoicePar[nvoice].PDetune));} + } + Fl_Slider voicedetune { + callback {pars->VoicePar[nvoice].PDetune=(int)o->value()+8192; +detunevalueoutput->do_callback();} + tooltip {Fine Detune (cents)} xywh {315 5 185 20} type {Horz Knob} box FLAT_BOX minimum -8192 maximum 8191 step 1 + code0 {o->value(pars->VoicePar[nvoice].PDetune-8192);} + } + Fl_Box noiselabel { + label N + callback {if (pars->VoicePar[nvoice].Type==0) { + o->hide(); + voiceresonanceenabled->activate(); + detunevalueoutput->activate(); + voicedetune->activate(); + voicelfofreq->activate(); + voiceoscil->activate(); +} else { + o->show(); + voiceresonanceenabled->deactivate(); + detunevalueoutput->deactivate(); + voicedetune->deactivate(); + voicelfofreq->deactivate(); + voiceoscil->deactivate(); +};} + xywh {65 5 20 20} labelfont 1 labelsize 16 labelcolor 7 + code0 {if (pars->VoicePar[nvoice].Type==0) o->hide();} + } + } + Fl_Check_Button voiceenabled { + label 01 + callback {pars->VoicePar[nvoice].Enabled=(int)o->value(); +if (o->value()==0) voicelistitemgroup->deactivate(); +else voicelistitemgroup->activate(); +o->redraw();} + private xywh {30 5 20 20} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 4 + code0 {char tmp[10];snprintf(tmp,10,"%d",nvoice);o->label(strdup(tmp));} + code1 {o->value(pars->VoicePar[nvoice].Enabled);} + } + } + } + Function {ADvoicelistitem(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {nvoice=0; +pars=NULL;} {} + } + Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_)} {} { + code {pars=parameters; +nvoice=nvoice_; +master=master_; +make_window(); +ADnoteVoiceListItem->show(); +end();} {} + } + Function {refreshlist()} {} { + code {voiceenabled->value(pars->VoicePar[nvoice].Enabled); +voiceresonanceenabled->value(pars->VoicePar[nvoice].Presonance); +voicevolume->value(pars->VoicePar[nvoice].PVolume); +voicedetune->value(pars->VoicePar[nvoice].PDetune-8192); +voicepanning->value(pars->VoicePar[nvoice].PPanning); +voicelfofreq->value(pars->VoicePar[nvoice].FreqLfo->Pintensity); +if (pars->VoicePar[nvoice].Pextoscil != -1) { + osc->init(pars->VoicePar[pars->VoicePar[nvoice].Pextoscil].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master); +} else + osc->init(pars->VoicePar[nvoice].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master); +if (pars->VoicePar[nvoice].Enabled==0) voicelistitemgroup->deactivate(); + else voicelistitemgroup->activate(); +detunevalueoutput->do_callback(); +noiselabel->do_callback(); +ADnoteVoiceListItem->redraw();} {} + } + Function {~ADvoicelistitem()} {} { + code {ADnoteVoiceListItem->hide(); +delete(ADnoteVoiceListItem);} {} + } + decl {ADnoteParameters *pars;} {} + decl {int nvoice;} {} + decl {ADOscilloscope *osc;} {} + decl {Master *master;} {} +} + +class ADvoiceUI {: {public Fl_Group} +} { + Function {make_window()} {} { + Fl_Window ADnoteVoiceParameters { + label Voice + xywh {110 101 765 525} hide + class Fl_Group + } { + Fl_Group voiceparametersgroup { + xywh {0 0 765 525} box THIN_UP_BOX color 48 + code0 {if (pars->VoicePar[nvoice].Enabled==0) o->deactivate();} + } { + Fl_Group voicemodegroup { + xywh {5 5 755 515} + } { + Fl_Group voiceFMparametersgroup { + label MODULATOR + xywh {530 5 230 515} box THIN_UP_FRAME color 48 labeltype EMBOSSED_LABEL labelfont 1 labelsize 18 align 17 + code0 {if (pars->VoicePar[nvoice].PFMEnabled==0) o->deactivate();} + } { + Fl_Group modfrequency { + label {Mod.FREQUENCY} + xywh {535 220 220 145} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Group voiceFMfreqenvgroup { + label {ADSynth Modulator - Frequency Envelope} + xywh {540 290 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->VoicePar[nvoice].FMFreqEnvelope);} + code1 {if (pars->VoicePar[nvoice].PFMFreqEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFMFreqEnvelopeEnabled=(int)o->value(); +if (o->value()==0) voiceFMfreqenvgroup->deactivate(); +else voiceFMfreqenvgroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {545 295 50 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->VoicePar[nvoice].PFMFreqEnvelopeEnabled);} + } + Fl_Counter {} { + label {Coarse Det.} + callback {int k=(int) o->value(); +if (k<0) k+=1024; +pars->VoicePar[nvoice].PFMCoarseDetune = k+ + (pars->VoicePar[nvoice].PFMCoarseDetune/1024)*1024;} + tooltip {Coarse Detune} xywh {540 270 60 15} labelsize 11 align 1 minimum -64 maximum 63 step 1 textfont 1 textsize 12 + code0 {int k=pars->VoicePar[nvoice].PFMCoarseDetune%1024;} + code1 {if (k>=512) k-=1024;} + code2 {o->value(k);} + code3 {o->lstep(10);} + } + Fl_Text_Display {} { + xywh {600 270 50 15} labelsize 12 textsize 12 + } + Fl_Counter {} { + label Oct + callback {int k=(int) o->value(); +if (k<0) k+=16; +pars->VoicePar[nvoice].PFMCoarseDetune = k*1024+ + pars->VoicePar[nvoice].PFMCoarseDetune%1024;} + tooltip Octave xywh {660 270 45 15} type Simple labelsize 10 align 5 minimum -8 maximum 7 step 1 textfont 1 textsize 12 + code0 {int k=pars->VoicePar[nvoice].PFMCoarseDetune/1024;} + code1 {if (k>=8) k-=16;} + code2 {o->value(k);} + } + Fl_Counter {} { + label Type + callback {pars->VoicePar[nvoice].PFMDetuneType=(int) o->value(); +fmdetunevalueoutput->do_callback();} + tooltip {The way of how the detune is computed (0 for Default)} xywh {710 270 40 15} type Simple labelsize 10 align 5 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(0,N_DETUNE_TYPES);} + code1 {o->value(pars->VoicePar[nvoice].PFMDetuneType);} + } + Fl_Slider {} { + callback {pars->VoicePar[nvoice].PFMDetune=(int)o->value()+8192; +fmdetunevalueoutput->do_callback();} + tooltip {Fine Detune (cents)} xywh {590 245 160 10} type {Horz Knob} box FLAT_BOX minimum -8192 maximum 8191 step 1 + code0 {o->value(pars->VoicePar[nvoice].PFMDetune-8192);} + } + Fl_Value_Output fmdetunevalueoutput { + label Detune + callback {o->value(getdetune((pars->VoicePar[nvoice].PFMDetuneType==0)?(pars->GlobalPar.PDetuneType) : (pars->VoicePar[nvoice].PFMDetuneType),0,pars->VoicePar[nvoice].PFMDetune));} + xywh {540 245 45 13} labelsize 8 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 8 + code0 {o->value(getdetune(pars->VoicePar[nvoice].PFMDetuneType,0,pars->VoicePar[nvoice].PFMDetune));} + } + } + Fl_Group {} { + label {Mod.AMPLITUDE} + xywh {535 60 220 160} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Value_Slider {} { + label Vol + callback {pars->VoicePar[nvoice].PFMVolume=(int)o->value();} + tooltip Volume xywh {540 80 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PFMVolume);} + } + Fl_Value_Slider {} { + label {V.Sns} + callback {pars->VoicePar[nvoice].PFMVelocityScaleFunction=(int) o->value();} + tooltip {Velocity Sensing Function (rightmost to disable)} xywh {540 100 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PFMVelocityScaleFunction);} + } + Fl_Group voiceFMampenvgroup { + label {ADSynth Modulator - Amplitude Envelope} open + xywh {540 145 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->VoicePar[nvoice].FMAmpEnvelope);} + code1 {if (pars->VoicePar[nvoice].PFMAmpEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFMAmpEnvelopeEnabled=(int)o->value(); +if (o->value()==0) voiceFMampenvgroup->deactivate(); +else voiceFMampenvgroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {545 150 50 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->VoicePar[nvoice].PFMAmpEnvelopeEnabled);} + } + Fl_Value_Slider {} { + label {F.Damp} + callback {pars->VoicePar[nvoice].PFMVolumeDamp=(int) o->value()+64;} + tooltip {Modulator Damp at Higher frequency} xywh {540 120 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 minimum -64 maximum 63 step 1 + code0 {o->value(pars->VoicePar[nvoice].PFMVolumeDamp-64);} + } + } + Fl_Group modoscil { + xywh {535 365 220 150} + } { + Fl_Group fmoscil {open + xywh {535 405 220 110} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 + code0 {oscFM=new ADOscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {int nv=nvoice; if (pars->VoicePar[nvoice].PextFMoscil>=0) nv=pars->VoicePar[nvoice].PextFMoscil;} + code2 {oscFM->init(pars->VoicePar[nv].FMSmp,0,pars->VoicePar[nvoice].PFMoscilphase,master);} + } {} + Fl_Box {} { + label {Modullator Oscillator} + xywh {535 365 155 20} labelfont 1 align 20 + } + Fl_Button changeFMoscilbutton { + label Change + callback {if (oscedit!=NULL) delete(oscedit); + +int nv=nvoice; +if (pars->VoicePar[nvoice].PextFMoscil>=0) nv=pars->VoicePar[nvoice].PextFMoscil; + +oscedit=new ADOscilEditor(pars->VoicePar[nv].FMSmp,fmoscil,master);} + xywh {700 370 55 15} box THIN_UP_BOX labelfont 1 labelsize 12 + code0 {if (pars->VoicePar[nvoice].PextFMoscil>=0) o->labelcolor(FL_BLUE);} + } + Fl_Counter {} { + label {Ext.} + callback {pars->VoicePar[nvoice].PextFMoscil=(int)o->value(); +if ((int) o->value() != -1) { + oscFM->init(pars->VoicePar[(int) o->value()].FMSmp,master); + changeFMoscilbutton->labelcolor(FL_BLUE); +} else { + oscFM->init(pars->VoicePar[nvoice].FMSmp,master); + changeFMoscilbutton->labelcolor(FL_BLACK); +}; +voiceFMparametersgroup->redraw();} + tooltip {External Oscillator ( -1 for internal)} xywh {570 385 81 20} type Simple labelfont 1 labelsize 12 align 4 minimum -1 maximum 127 step 1 value -1 textfont 1 + code0 {o->bounds(-1,nvoice-1);} + code1 {o->value(pars->VoicePar[nvoice].PextFMoscil);} + } + Fl_Slider {} { + label Phase + callback {pars->VoicePar[nvoice].PFMoscilphase=64-(int)o->value(); +oscFM->phase=64-(int) o->value(); +fmoscil->redraw();} + xywh {665 395 65 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 + code0 {o->value(64-pars->VoicePar[nvoice].PFMoscilphase);} + } + } + Fl_Counter {} { + label {Ext. Mod.} + callback {pars->VoicePar[nvoice].PFMVoice=(int)o->value(); +if ((int) o->value() != -1) { + modoscil->deactivate(); + modfrequency->deactivate(); +} else { + modoscil->activate(); + modfrequency->activate(); +}; +voiceFMparametersgroup->redraw();} + tooltip {External Modulator voice ( -1 for internal)} xywh {640 40 70 20} type Simple align 5 minimum -1 maximum 127 step 1 value -1 textfont 1 + code0 {o->bounds(-1,nvoice-1);} + code1 {o->value(pars->VoicePar[nvoice].PFMVoice);} + code2 {if ((int) o->value() != -1) {modoscil->deactivate();modfrequency->deactivate();}} + } + } + Fl_Choice {} { + label {Type:} + callback {pars->VoicePar[nvoice].PFMEnabled=(int)o->value(); +if (o->value()==0) voiceFMparametersgroup->deactivate(); +else voiceFMparametersgroup->activate(); +o->redraw();} + xywh {535 40 80 20} down_box BORDER_BOX align 5 + code0 {o->value(pars->VoicePar[nvoice].PFMEnabled);} + } { + menuitem {} { + label OFF + xywh {40 40 100 20} labelfont 1 + } + menuitem {} { + label MORPH + xywh {50 50 100 20} labelfont 1 + } + menuitem {} { + label RING + xywh {60 60 100 20} labelfont 1 + } + menuitem {} { + label PM + xywh {70 70 100 20} labelfont 1 + } + menuitem {} { + label FM + xywh {80 80 100 20} labelfont 1 + } + menuitem {} { + label PITCH + xywh {90 90 100 20} labelfont 1 deactivate + } + } + Fl_Group {} { + label FREQUENCY + xywh {5 250 525 120} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Group voicefreqenvgroup { + label {ADSynth Voice - Frequency Envelope} open + xywh {10 290 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->VoicePar[nvoice].FreqEnvelope);} + code1 {if (pars->VoicePar[nvoice].PFreqEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFreqEnvelopeEnabled=(int)o->value(); +if (o->value()==0) voicefreqenvgroup->deactivate(); +else voicefreqenvgroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {15 295 50 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->VoicePar[nvoice].PFreqEnvelopeEnabled);} + } + Fl_Group voicefreqlfogroup { + label {Frequency LFO} open + xywh {215 290 230 70} box FLAT_BOX color 47 align 144 + code0 {o->init(pars->VoicePar[nvoice].FreqLfo);} + code1 {if (pars->VoicePar[nvoice].PFreqLfoEnabled==0) o->deactivate();} + class LFOUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFreqLfoEnabled=(int)o->value(); +if (o->value()==0) voicefreqlfogroup->deactivate(); +else voicefreqlfogroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {220 295 55 10} down_box DOWN_BOX labelfont 1 labelsize 12 align 24 + code0 {o->value(pars->VoicePar[nvoice].PFreqLfoEnabled);} + } + Fl_Counter {} { + label Oct + callback {int k=(int) o->value(); +if (k<0) k+=16; +pars->VoicePar[nvoice].PCoarseDetune = k*1024+ + pars->VoicePar[nvoice].PCoarseDetune%1024;} + tooltip Octave xywh {480 315 45 20} type Simple labelsize 10 align 4 minimum -8 maximum 7 step 1 textfont 1 textsize 12 + code0 {int k=pars->VoicePar[nvoice].PCoarseDetune/1024;} + code1 {if (k>=8) k-=16;} + code2 {o->value(k);} + } + Fl_Counter {} { + label Type + callback {pars->VoicePar[nvoice].PDetuneType=(int) o->value(); +detunevalueoutput->do_callback();} + tooltip {The way of how the detune is computed (0 for Default)} xywh {485 340 40 15} type Simple labelsize 10 align 4 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(0,N_DETUNE_TYPES);} + code1 {o->value(pars->VoicePar[nvoice].PDetuneType);} + } + Fl_Counter {} { + label {Coarse Det.} + callback {int k=(int) o->value(); +if (k<0) k+=1024; +pars->VoicePar[nvoice].PCoarseDetune = k+ + (pars->VoicePar[nvoice].PCoarseDetune/1024)*1024;} + tooltip {Coarse Detune} xywh {465 270 60 20} labelsize 11 align 1 minimum -64 maximum 63 step 1 textfont 1 textsize 12 + code0 {int k=pars->VoicePar[nvoice].PCoarseDetune%1024;} + code1 {if (k>=512) k-=1024;} + code2 {o->value(k);} + code3 {o->lstep(10);} + } + Fl_Text_Display {} { + xywh {465 290 60 15} labelsize 12 textsize 12 + } + Fl_Slider {} { + callback {pars->VoicePar[nvoice].PDetune=(int)o->value()+8192; +detunevalueoutput->do_callback();} + tooltip {Fine Detune (cents)} xywh {58 272 392 13} type {Horz Knob} box FLAT_BOX minimum -8192 maximum 8191 step 1 + code0 {o->value(pars->VoicePar[nvoice].PDetune-8192);} + } + Fl_Value_Output detunevalueoutput { + label Detune + callback {o->value(getdetune((pars->VoicePar[nvoice].PDetuneType==0)?(pars->GlobalPar.PDetuneType) : (pars->VoicePar[nvoice].PDetuneType),0,pars->VoicePar[nvoice].PDetune));} + xywh {10 272 45 15} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10 + code0 {o->value(getdetune(pars->VoicePar[nvoice].PDetuneType,0,pars->VoicePar[nvoice].PDetune));} + } + Fl_Check_Button {} { + label 440Hz + callback {int x=(int) o->value(); +pars->VoicePar[nvoice].Pfixedfreq=x; +if (x==0) fixedfreqetdial->deactivate(); + else fixedfreqetdial->activate();} + tooltip {Set the voice base frequency to 440Hz} xywh {345 253 55 15} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(pars->VoicePar[nvoice].Pfixedfreq);} + } + Fl_Dial fixedfreqetdial { + label {Eq.T.} + callback {pars->VoicePar[nvoice].PfixedfreqET=(int) o->value();} + tooltip {How the frequency varies acording to the keyboard (leftmost for fixed frequency)} xywh {405 255 15 15} box ROUND_UP_BOX labelsize 10 align 8 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PfixedfreqET);} + code1 {if (pars->VoicePar[nvoice].Pfixedfreq==0) o->deactivate();} + class WidgetPDial + } + } + Fl_Group voiceoscil { + xywh {80 375 445 145} box THIN_DOWN_BOX color 32 selection_color 71 labelcolor 179 + code0 {osc=new ADOscilloscope(o->x(),o->y(),o->w(),o->h(),"");} + code1 {int nv=nvoice; if (pars->VoicePar[nvoice].Pextoscil>=0) nv=pars->VoicePar[nvoice].Pextoscil;} + code2 {osc->init(pars->VoicePar[nv].OscilSmp,0,pars->VoicePar[nvoice].Poscilphase,master);} + } {} + Fl_Button changevoiceoscilbutton { + label Change + callback {if (oscedit!=NULL) delete(oscedit); + +int nv=nvoice; +if (pars->VoicePar[nvoice].Pextoscil>=0) nv=pars->VoicePar[nvoice].Pextoscil; + +oscedit=new ADOscilEditor(pars->VoicePar[nv].OscilSmp,voiceoscil,master);} + xywh {5 475 65 20} box THIN_UP_BOX labelfont 1 labelsize 12 + code0 {if (pars->VoicePar[nvoice].Pextoscil>=0) o->labelcolor(FL_BLUE);} + } + Fl_Box {} { + label {Voice Oscillator} + xywh {5 375 75 35} labelfont 1 align 128 + } + Fl_Slider {} { + label Phase + callback {pars->VoicePar[nvoice].Poscilphase=64-(int)o->value(); +osc->phase=64-(int) o->value(); +voiceoscil->redraw();} + xywh {10 420 65 10} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum -64 maximum 63 step 1 + code0 {o->value(64-pars->VoicePar[nvoice].Poscilphase);} + } + Fl_Counter {} { + label {Ext. Oscil.} + callback {pars->VoicePar[nvoice].Pextoscil=(int)o->value(); +if ((int) o->value() != -1) { + osc->init(pars->VoicePar[(int) o->value()].OscilSmp,master); + changevoiceoscilbutton->labelcolor(FL_BLUE); +} else { + osc->init(pars->VoicePar[nvoice].OscilSmp,master); + changevoiceoscilbutton->labelcolor(FL_BLACK); +}; + +voiceparametersgroup->redraw(); +voiceonbutton->redraw();} + tooltip {External Oscillator ( -1 for internal)} xywh {5 450 70 20} type Simple labelsize 12 align 5 minimum -1 maximum 127 step 1 value -1 textfont 1 + code0 {o->bounds(-1,nvoice-1);} + code1 {o->value(pars->VoicePar[nvoice].Pextoscil);} + } + Fl_Check_Button {} { + label {R.} + callback {pars->VoicePar[nvoice].Presonance=(int) o->value();} + tooltip {Resonance On/Off} xywh {210 5 35 35} box THIN_UP_BOX down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(pars->VoicePar[nvoice].Presonance);} + } + } + Fl_Group {} { + label AMPLITUDE + xywh {5 40 240 210} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Value_Slider {} { + label Vol + callback {pars->VoicePar[nvoice].PVolume=(int)o->value();} + tooltip Volume xywh {10 60 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PVolume);} + } + Fl_Value_Slider {} { + label {V.Sns} + callback {pars->VoicePar[nvoice].PAmpVelocityScaleFunction=(int) o->value();} + tooltip {Velocity Sensing Function (rightmost to disable)} xywh {10 80 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PAmpVelocityScaleFunction);} + } + Fl_Group voiceampenvgroup { + label {ADSynth Voice - Amplitude Envelope} open + xywh {10 105 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->VoicePar[nvoice].AmpEnvelope);} + code1 {if (pars->VoicePar[nvoice].PAmpEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Dial {} { + label Pan + callback {pars->VoicePar[nvoice].PPanning=(int) o->value();} + tooltip {Panning (leftmost is Random)} xywh {210 60 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PPanning);} + class WidgetPDial + } + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PAmpEnvelopeEnabled=(int)o->value(); +if (o->value()==0) voiceampenvgroup->deactivate(); +else voiceampenvgroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {15 110 50 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->VoicePar[nvoice].PAmpEnvelopeEnabled);} + } + Fl_Group voiceamplfogroup { + label {Amplitude LFO} open + xywh {10 175 230 70} box FLAT_BOX color 47 align 144 + code0 {o->init(pars->VoicePar[nvoice].AmpLfo);} + code1 {if (pars->VoicePar[nvoice].PAmpLfoEnabled==0) o->deactivate();} + class LFOUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PAmpLfoEnabled=(int)o->value(); +if (o->value()==0) voiceamplfogroup->deactivate(); +else voiceamplfogroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {15 180 55 10} down_box DOWN_BOX labelfont 1 labelsize 12 align 24 + code0 {o->value(pars->VoicePar[nvoice].PAmpLfoEnabled);} + } + Fl_Check_Button {} { + label Minus + callback {pars->VoicePar[nvoice].PVolumeminus=(int)o->value();} + xywh {10 45 50 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->VoicePar[nvoice].PVolumeminus);} + } + } + Fl_Group voicefiltergroup { + label FILTER + xywh {245 5 285 245} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + code0 {if (pars->VoicePar[nvoice].PFilterEnabled==0) o->deactivate();} + } { + Fl_Group {} { + label {ADsynth Voice - Filter} open + xywh {250 30 275 75} box FLAT_BOX color 50 align 144 + code0 {o->init(pars->VoicePar[nvoice].VoiceFilter,NULL,NULL);} + class FilterUI + } {} + Fl_Group voicefilterenvgroup { + label {ADSynth Voice - Filter Envelope} open + xywh {250 105 275 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->VoicePar[nvoice].FilterEnvelope);} + code1 {if (pars->VoicePar[nvoice].PFilterEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFilterEnvelopeEnabled=(int)o->value(); +if (o->value()==0) voicefilterenvgroup->deactivate(); +else voicefilterenvgroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {255 110 55 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->VoicePar[nvoice].PFilterEnvelopeEnabled);} + } + Fl_Group voicefilterlfogroup { + label {Filter LFO} open + xywh {250 175 230 70} box FLAT_BOX color 47 align 144 + code0 {o->init(pars->VoicePar[nvoice].FilterLfo);} + code1 {if (pars->VoicePar[nvoice].PFilterLfoEnabled==0) o->deactivate();} + class LFOUI + } {} + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFilterLfoEnabled=(int)o->value(); +if (o->value()==0) voicefilterlfogroup->deactivate(); +else voicefilterlfogroup->activate(); +o->redraw();} + tooltip {Forced Relase} xywh {255 180 55 10} down_box DOWN_BOX labelfont 1 labelsize 12 align 24 + code0 {o->value(pars->VoicePar[nvoice].PFilterLfoEnabled);} + } + } + Fl_Group {} { + label 01 + xywh {5 5 55 35} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 30 align 16 + code0 {char tmp[10];snprintf(tmp,10,"%d",nvoice);o->label(strdup(tmp));} + } {} + Fl_Choice {} { + callback {int x=(int) o->value(); +pars->VoicePar[nvoice].Type=x; +if (x==0) voicemodegroup->activate(); + else voicemodegroup->deactivate(); +noiselabel->do_callback();} + tooltip {Oscillator Type (sound/noise)} xywh {5 500 65 20} down_box BORDER_BOX labelsize 11 textfont 1 textsize 11 + code0 {o->value(pars->VoicePar[nvoice].Type);} + code1 {if (pars->VoicePar[nvoice].Type!=0) voicemodegroup->deactivate();} + } { + menuitem {} { + label Sound + xywh {5 5 100 20} labelfont 1 labelsize 13 + } + menuitem {} { + label NOISE + xywh {15 15 100 20} labelfont 1 labelsize 13 labelcolor 1 + } + } + Fl_Check_Button bypassfiltercheckbutton { + label {Bypass Global F.} + callback {pars->VoicePar[nvoice].Pfilterbypass=(int)o->value();} + xywh {425 10 100 20} down_box DOWN_BOX labelfont 1 labelsize 10 align 148 + code0 {o->value(pars->VoicePar[nvoice].Pfilterbypass);} + } + Fl_Group {} { + xywh {115 5 95 35} box THIN_UP_BOX + } { + Fl_Value_Slider {} { + label Delay + callback {pars->VoicePar[nvoice].PDelay=(int)o->value();} + tooltip Volume xywh {120 21 84 12} type {Horz Knob} box FLAT_BOX labelsize 12 align 5 maximum 127 step 1 + code0 {o->value(pars->VoicePar[nvoice].PDelay);} + } + } + Fl_Check_Button {} { + label Enable + callback {pars->VoicePar[nvoice].PFilterEnabled=(int)o->value(); +if (o->value()==0) voicefiltergroup->deactivate(); +else voicefiltergroup->activate(); +o->redraw(); +bypassfiltercheckbutton->redraw();} + tooltip {Enable Filter} xywh {250 15 60 15} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(pars->VoicePar[nvoice].PFilterEnabled);} + } + Fl_Box noiselabel { + label {White Noise} + callback {if (pars->VoicePar[nvoice].Type==0) o->hide(); else o->show();} + xywh {150 415 300 65} labelfont 1 labelsize 50 labelcolor 7 + code0 {if (pars->VoicePar[nvoice].Type==0) o->hide(); else o->show();} + } + } + Fl_Check_Button voiceonbutton { + label On + callback {pars->VoicePar[nvoice].Enabled=(int)o->value(); +if (o->value()==0) voiceparametersgroup->deactivate(); +else voiceparametersgroup->activate(); +o->redraw();} + xywh {60 5 55 35} box THIN_UP_BOX down_box DOWN_BOX labelfont 1 labelsize 16 + code0 {o->value(pars->VoicePar[nvoice].Enabled);} + } + } + } + Function {ADvoiceUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {nvoice=0; +pars=NULL; +oscedit=NULL;} {} + } + Function {init(ADnoteParameters *parameters,int nvoice_,Master *master_)} {} { + code {pars=parameters; +nvoice=nvoice_; +master=master_; +make_window(); +end(); +ADnoteVoiceParameters->show();} {} + } + Function {~ADvoiceUI()} {} { + code {ADnoteVoiceParameters->hide(); +hide(); +if (oscedit!=NULL) { + delete(oscedit); +}; +delete (ADnoteVoiceParameters);} {} + } + decl {int nvoice;} {} + decl {ADnoteParameters *pars;} {} + decl {ADOscilEditor *oscedit;} {} + decl {ADOscilloscope *osc;} {} + decl {ADOscilloscope *oscFM;} {} + decl {Master *master;} {} +} + +class ADnoteUI {} { + Function {make_window()} {private + } { + Fl_Window ADnoteGlobalParameters { + label {ADsynth Global Parameters of the Instrument} selected + xywh {112 194 535 405} hide + } { + Fl_Group {} { + label FREQUENCY + xywh {5 255 525 115} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Group {} { + label {ADSynth Global - Frequency Envelope} open + xywh {10 295 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->GlobalPar.FreqEnvelope);} + class EnvelopeUI + } {} + Fl_Counter {} { + label Oct + callback {int k=(int) o->value(); +if (k<0) k+=16; +pars->GlobalPar.PCoarseDetune = k*1024+ + pars->GlobalPar.PCoarseDetune%1024;} + tooltip Octave xywh {480 320 45 20} type Simple labelsize 10 align 4 minimum -8 maximum 7 step 1 textfont 1 textsize 12 + code0 {int k=pars->GlobalPar.PCoarseDetune/1024;} + code1 {if (k>=8) k-=16;} + code2 {o->value(k);} + } + Fl_Counter {} { + label Type + callback {pars->GlobalPar.PDetuneType=(int) o->value(); +detunevalueoutput->do_callback();} + tooltip {The way of how the detune is computed (Default)} xywh {485 345 40 15} type Simple labelsize 10 align 4 minimum 1 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(1,N_DETUNE_TYPES);} + code1 {o->value(pars->GlobalPar.PDetuneType);} + } + Fl_Counter {} { + label {C.det} + callback {int k=(int) o->value(); +if (k<0) k+=1024; +pars->GlobalPar.PCoarseDetune = k+ + (pars->GlobalPar.PCoarseDetune/1024)*1024;} + tooltip {Coarse Detune} xywh {465 270 60 20} labelsize 10 align 5 minimum -64 maximum 63 step 1 textfont 1 textsize 12 + code0 {int k=pars->GlobalPar.PCoarseDetune%1024;} + code1 {if (k>=512) k-=1024;} + code2 {o->value(k);} + code3 {o->lstep(10);} + } + Fl_Text_Display {} { + xywh {465 290 60 15} labelsize 12 textsize 12 + } + Fl_Group {} { + label {Frequency LFO} open + xywh {215 295 230 70} box FLAT_BOX color 47 align 144 + code0 {o->init(pars->GlobalPar.FreqLfo);} + class LFOUI + } {} + Fl_Slider {} { + callback {pars->GlobalPar.PDetune=(int)o->value()+8192; +detunevalueoutput->do_callback();} + tooltip {Fine Detune (cents)} xywh {60 275 390 15} type {Horz Knob} box FLAT_BOX minimum -8192 maximum 8191 step 1 + code0 {o->value(pars->GlobalPar.PDetune-8192);} + } + Fl_Value_Output detunevalueoutput { + label Detune + callback {o->value(getdetune(pars->GlobalPar.PDetuneType,0,pars->GlobalPar.PDetune));} + xywh {12 275 45 15} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10 + code0 {o->value(getdetune(pars->GlobalPar.PDetuneType,0,pars->GlobalPar.PDetune));} + } + } + Fl_Group {} { + label AMPLITUDE + xywh {5 5 240 250} box THIN_UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Value_Slider {} { + label Vol + callback {pars->GlobalPar.PVolume=(int)o->value();} + tooltip Volume xywh {10 30 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PVolume);} + } + Fl_Value_Slider {} { + label {V.Sns} + callback {pars->GlobalPar.PAmpVelocityScaleFunction=(int) o->value();} + tooltip {Velocity Sensing Function (rightmost to disable)} xywh {10 50 160 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PAmpVelocityScaleFunction);} + } + Fl_Dial {} { + label Pan + callback {pars->GlobalPar.PPanning=(int) o->value();} + tooltip {Panning (leftmost is Random)} xywh {210 25 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PPanning);} + class WidgetPDial + } + Fl_Dial {} { + label {P.Str.} + callback {pars->GlobalPar.PPunchStrength=(int) o->value();} + tooltip {Punch Strength} xywh {125 227 25 25} box ROUND_UP_BOX labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PPunchStrength);} + class WidgetPDial + } + Fl_Dial {} { + label {P.t.} + callback {pars->GlobalPar.PPunchTime=(int) o->value();} + tooltip {Punch Time (duration)} xywh {155 227 25 25} box ROUND_UP_BOX labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PPunchTime);} + class WidgetPDial + } + Fl_Dial {} { + label {P.Stc.} + callback {pars->GlobalPar.PPunchStretch=(int) o->value();} + tooltip {Punch Stretch} xywh {185 227 25 25} box ROUND_UP_BOX labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PPunchStretch);} + class WidgetPDial + } + Fl_Dial {} { + label {P.Vel.} + callback {pars->GlobalPar.PPunchVelocitySensing=(int) o->value();} + tooltip {Punch Velocity Sensing} xywh {215 227 25 25} box ROUND_UP_BOX labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->GlobalPar.PPunchVelocitySensing);} + class WidgetPDial + } + Fl_Group {} { + label {ADSynth Global - Amplitude Envelope} open + xywh {10 75 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->GlobalPar.AmpEnvelope);} + class EnvelopeUI + } {} + Fl_Group {} { + label {Amplitude LFO} open + xywh {10 145 230 70} box FLAT_BOX color 47 align 144 + code0 {o->init(pars->GlobalPar.AmpLfo);} + class LFOUI + } {} + } + Fl_Group {} { + label FILTER + xywh {245 5 285 250} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + } { + Fl_Group {} { + label {ADSynth Global - Filter Envelope} open + xywh {250 110 275 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->GlobalPar.FilterEnvelope);} + class EnvelopeUI + } {} + Fl_Group {} { + label {Filter LFO} open + xywh {250 180 230 70} box FLAT_BOX color 47 align 144 + code0 {o->init(pars->GlobalPar.FilterLfo);} + class LFOUI + } {} + Fl_Group {} { + label {ADsynth Global - Filter} open + xywh {250 35 275 75} box FLAT_BOX color 50 align 144 + code0 {o->init(pars->GlobalPar.GlobalFilter,&pars->GlobalPar.PFilterVelocityScale,&pars->GlobalPar.PFilterVelocityScaleFunction);} + class FilterUI + } {} + } + Fl_Check_Button {} { + label Stereo + callback {pars->GlobalPar.PStereo=(int) o->value();} + xywh {5 220 80 35} box ENGRAVED_BOX down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(pars->GlobalPar.PStereo);} + } + Fl_Button {} { + label {Show Voice List} + callback {for (int i=0;i<NUM_VOICES;i++){ + voicelistitem[i]->refreshlist(); +} +ADnoteVoiceList->show();} + xywh {180 375 125 25} + } + Fl_Button {} { + label {Show Voice Parameters} + callback {ADnoteVoice->show();} + xywh {5 375 170 25} labelfont 1 + } + Fl_Button {} { + label Close + callback {ADnoteGlobalParameters->hide();} + xywh {430 375 100 25} box THIN_UP_BOX + } + Fl_Button {} { + label Resonance + callback {resui->resonancewindow->redraw(); +resui->resonancewindow->show();} + tooltip Resonance xywh {309 375 86 25} box THIN_UP_BOX + } + } + Fl_Window ADnoteVoiceList { + label {ADsynth Voices list} + xywh {32 266 650 260} hide + } { + Fl_Text_Display {} { + label {No.} + xywh {10 15 30 10} box NO_BOX labelfont 1 labelsize 13 + } + Fl_Text_Display {} { + label Vol + xywh {145 15 30 10} box NO_BOX labelfont 1 labelsize 13 + } + Fl_Text_Display {} { + label Detune + xywh {384 15 25 10} box NO_BOX labelfont 1 labelsize 13 + } + Fl_Text_Display {} { + label Pan + xywh {210 15 30 10} box NO_BOX labelfont 1 labelsize 13 + } + Fl_Text_Display {} { + label {Vib. Depth} + xywh {560 15 30 10} box NO_BOX labelfont 1 labelsize 13 + } + Fl_Text_Display {} { + label {R.} + xywh {245 15 25 10} box NO_BOX labelfont 1 labelsize 13 + } + Fl_Button {} { + label {Hide Voice List} + callback {ADnoteVoiceList->hide();} + xywh {255 237 125 20} + } + Fl_Scroll {} {open + xywh {0 15 640 220} type VERTICAL box THIN_UP_BOX + } { + Fl_Pack {} {open + xywh {0 20 620 210} + code0 {for (int i=0;i<NUM_VOICES;i++){voicelistitem[i]=new ADvoicelistitem(0,0,620,25,"");voicelistitem[i]->init(pars,i,master);}} + } {} + } + } + Fl_Window ADnoteVoice { + label {ADsynth Voice Parameters} + xywh {53 58 765 560} hide + } { + Fl_Group advoice { + xywh {0 0 760 525} box BORDER_BOX + code0 {o->init(pars,nvoice,master);} + code1 {o->show();} + class ADvoiceUI + } {} + Fl_Counter currentvoicecounter { + label {Current Voice} + callback {nvoice=(int)o->value(); +advoice->hide(); +ADnoteVoice->remove(advoice); +delete advoice; +advoice=new ADvoiceUI(0,0,765,525); +ADnoteVoice->add(advoice); +advoice->init(pars,nvoice,master); +advoice->show(); +ADnoteVoice->redraw();} + xywh {5 530 130 25} type Simple labelfont 1 align 8 minimum 0 maximum 0 step 1 textfont 1 textsize 18 + code0 {o->bounds(0,NUM_VOICES-1);} + } + Fl_Button {} { + label {Close Window} + callback {ADnoteVoice->hide();} + xywh {300 530 195 25} box THIN_UP_BOX labelfont 1 + } + Fl_Button {} { + label Copy + callback {pthread_mutex_lock(&master->mutex); + pars->copypastevoice(nvoice,0); +pthread_mutex_unlock(&master->mutex);} + tooltip {Copy the voice to clipboard} xywh {655 530 50 20} box THIN_UP_BOX + } + Fl_Button {} { + label Paste + callback {pthread_mutex_lock(&master->mutex); + pars->copypastevoice(nvoice,1); +pthread_mutex_unlock(&master->mutex); + +currentvoicecounter->do_callback();} + tooltip {Paste the voice from the clipboard} xywh {710 530 50 20} box THIN_UP_BOX + } + } + } + Function {ADnoteUI(ADnoteParameters *parameters,Master *master_)} {} { + code {pars=parameters; +master=master_; +nvoice=0; +resui=new ResonanceUI(pars->GlobalPar.Reson); +make_window();} {} + } + Function {~ADnoteUI()} {} { + code {ADnoteVoiceList->hide(); +ADnoteGlobalParameters->hide(); +ADnoteVoice->hide(); +delete(ADnoteVoiceList); +delete(ADnoteGlobalParameters); +delete(ADnoteVoice); +delete(resui);} {} + } + decl {ADnoteParameters *pars;} {} + decl {ResonanceUI *resui;} {} + decl {Master *master;} {} + decl {int nvoice;} {} + decl {ADvoicelistitem *voicelistitem[NUM_VOICES];} {} +} diff --git a/src/UI/BankUI.fl b/src/UI/BankUI.fl @@ -0,0 +1,299 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <string.h>} {public +} + +decl {\#include <FL/Fl_Button.H>} {public +} + +decl {\#include <FL/Fl_File_Chooser.H>} {public +} + +decl {\#include "../Misc/Master.h"} {public +} + +decl {\#include "../Misc/Bank.h"} {public +} + +class BankProcess_ {} { + Function {process()} {return_type {virtual void} + } {} + decl {Bank *bank;} {public + } +} + +class BankSlot {: {public Fl_Button,BankProcess_} +} { + Function {BankSlot(int x,int y, int w, int h, const char *label=0):Fl_Button(x,y,w,h,label)} {} { + code {what=NULL; +whatslot=NULL; +nslot=0;} {} + } + Function {handle(int event)} {return_type int + } { + code {if (what==NULL) return(0); +if (Fl::event_inside(this)){ + *what=0;*whatslot=nslot; + if ((event==FL_RELEASE)&&(Fl::event_button()==1))*what=1; + if ((event==FL_RELEASE)&&(Fl::event_button()==3))*what=2; + if (event==FL_PUSH) highlight=1; +}else highlight=0; + +int tmp=Fl_Button::handle(event); +if ((*what!=0) && Fl::event_inside(this)) (bp->*fnc)(); +return(tmp);} {} + } + Function {init(int nslot_, int *what_, int *whatslot_,void (BankProcess_:: *fnc_)(void),BankProcess_ *bp_,Bank *bank_)} {} { + code {nslot=nslot_; +what=what_; +whatslot=whatslot_; +fnc=fnc_; +bp=bp_; +bank=bank_; +box(FL_THIN_UP_BOX); +align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_CLIP); +highlight=0; +refresh();} {} + } + Function {refresh()} {} { + code {if (bank->emptyslot(nslot)) color(46); + else color(51); +label(bank->getnamenumbered(nslot));} {} + } + decl {int *what,*whatslot,nslot,highlight;} {} + decl {void (BankProcess_:: *fnc)(void);} {} + decl {BankProcess_ *bp;} {} +} + +class BankUI {: {public BankProcess_} +} { + Function {make_window()} {} { + Fl_Window bankuiwindow { + label Bank + xywh {16 205 770 430} hide + code0 {o->label(bank->bankfiletitle);} + code1 {if (bank->bankfiletitle==NULL) o->label ("Choose a bank to use by pressing the 'Load/Use Bank from file...' button or choose 'New Bank...' to make a new bank.");} + } { + Fl_Button {} { + label Close + callback {bankuiwindow->hide();} + xywh {543 402 72 24} box THIN_UP_BOX + } + Fl_Pack {} { + xywh {6 6 150 375} box BORDER_BOX + code0 {o->box(FL_NO_BOX);} + code1 {for (int i=0;i<25;i++){bs[i]=new BankSlot (0,0,o->w(),15," ");bs[i]->init(i,&what,&slot,&BankProcess_::process,(BankProcess_ *)this,bank);};} + } {} + Fl_Pack {} { + xywh {159 6 150 375} box BORDER_BOX + code0 {o->box(FL_NO_BOX);} + code1 {for (int i=25;i<50;i++){bs[i]=new BankSlot (0,0,o->w(),15," ");bs[i]->init(i,&what,&slot,&BankProcess_::process,(BankProcess_ *)this,bank);};} + } {} + Fl_Pack {} { + xywh {312 6 150 375} box BORDER_BOX + code0 {o->box(FL_NO_BOX);} + code1 {for (int i=50;i<75;i++){bs[i]=new BankSlot (0,0,o->w(),15," ");bs[i]->init(i,&what,&slot,&BankProcess_::process,(BankProcess_ *)this,bank);};} + } {} + Fl_Pack {} { + xywh {465 6 150 375} box BORDER_BOX + code0 {o->box(FL_NO_BOX);} + code1 {for (int i=75;i<100;i++){bs[i]=new BankSlot (0,0,o->w(),15," ");bs[i]->init(i,&what,&slot,&BankProcess_::process,(BankProcess_ *)this,bank);};} + } {} + Fl_Pack {} { + xywh {618 6 150 420} box BORDER_BOX + code0 {o->box(FL_NO_BOX);} + code1 {for (int i=100;i<128;i++){bs[i]=new BankSlot (0,0,o->w(),15," ");bs[i]->init(i,&what,&slot,&BankProcess_::process,(BankProcess_ *)this,bank);};} + } {} + Fl_Group {} {open + xywh {6 384 321 42} box ENGRAVED_BOX + } { + Fl_Light_Button writebutton { + label WRITE + callback {if (o->value()>0.5) mode=2} + xywh {117 390 99 30} type Radio box PLASTIC_UP_BOX down_box THIN_DOWN_BOX selection_color 1 labeltype ENGRAVED_LABEL labelfont 1 labelsize 18 + code0 {if (bank->locked()) o->deactivate();} + } + Fl_Light_Button readbutton { + label READ + callback {if (o->value()>0.5) mode=1;} + xywh {12 390 99 30} type Radio box PLASTIC_UP_BOX down_box THIN_DOWN_BOX selection_color 101 labeltype ENGRAVED_LABEL labelfont 1 labelsize 18 + code0 {o->value(1);} + } + Fl_Light_Button clearbutton { + label CLEAR + callback {if (o->value()>0.5) mode=3;} + xywh {222 390 99 30} type Radio box PLASTIC_UP_BOX down_box THIN_DOWN_BOX selection_color 0 labeltype ENGRAVED_LABEL labelfont 1 labelsize 18 + code0 {if (bank->locked()) o->deactivate();} + } + } + Fl_Button loadusebankfile { + label {Load/Use Bank from file...} + callback {const char *filename; +filename=fl_file_chooser("Load and use Bank from file:","(*.bnk_zyn)",NULL,0); +if (filename==NULL) return; +if (bank->loadfilebank(filename)==2) + fl_alert("Error: Could not load the bank from the file.."); +for (int i=0;i<128;i++) bs[i]->refresh(); +refreshmainwindow();} + xywh {336 387 105 39} box PLASTIC_UP_BOX labelfont 1 labelsize 12 align 128 + } + Fl_Button {} { + label {Save Bank...} + callback {char *filename; +\#define EXT ".bnk_zyn" +filename=fl_file_chooser("Save Bank to file and use it:","(*"EXT")",NULL,0); +if (filename==NULL) return; +filename=fl_filename_setext(filename,EXT); +\#undef EXT + +if (filename==NULL) return; +int result=bank->savefilebank(filename,0); +if (result==1) { + if (fl_ask("The file exists. \\nOverwrite it?")){ + result=bank->savefilebank(filename,1); + } else return; + +}; +if (result!=0) fl_alert("Error: Could not save the bank to the file.."); + +refreshmainwindow();} + xywh {444 387 93 18} box PLASTIC_UP_BOX labelfont 1 labelsize 12 align 128 + } + Fl_Button {} { + label {New Bank...} + callback {char *filename; +\#define EXT ".bnk_zyn" +filename=fl_file_chooser("New empty Bank:","(*"EXT")",NULL,0); +if (filename==NULL) return; +filename=fl_filename_setext(filename,EXT); +\#undef EXT + +if (filename==NULL) return; +int result=bank->newfilebank(filename,0); +if (result==1) { + if (fl_ask("The file exists. \\nOverwrite it?")){ + result=bank->newfilebank(filename,1); + } else return; + +}; +if (result!=0) fl_alert("Error: Could not save the bank to the file.."); +for (int i=0;i<128;i++) bs[i]->refresh(); +refreshmainwindow();} + xywh {444 408 93 18} box PLASTIC_UP_BOX labelfont 1 labelsize 12 align 128 + } + Fl_Check_Button {} { + label {auto close} + callback {config.cfg.BankUIAutoClose=(int) o->value();} + tooltip {automatically close the bank window if the instrument is loaded} xywh {545 385 65 15} down_box DOWN_BOX labelsize 10 + code0 {o->value(config.cfg.BankUIAutoClose);} + } + } + } + Function {BankUI(Master *master_,int *npart_)} {} { + code {fnc=&BankProcess_::process; +master=master_; +npart=npart_; +bank=&master_->bank; +what=0; +make_window(); +mode=1;} {} + } + Function {~BankUI()} {return_type virtual + } { + code {bankuiwindow->hide(); +delete(bankuiwindow);} {} + } + Function {show()} {} { + code {bankuiwindow->show();} {} + } + Function {init(Fl_Valuator *cbwig_)} {} { + code {cbwig=cbwig_;} {} + } + Function {process()} {return_type void + } { + code {int slot=this->slot; + +if ((what==2)&&(bank->emptyslot(slot)==0)) {//Rename slot + const char *tmp=fl_input("Slot (instrument) name:",(const char *)bank->getname(slot)); + if (tmp!=NULL) bank->setname(slot,tmp); + bs[slot]->refresh(); +}; + +if ((what==1)&&(mode==2)){//save(write) to slot + if (!bank->emptyslot(slot)) + if (!fl_ask("Overwrite the slot no. %d ?",slot+1)) goto nooverwriteslot; + pthread_mutex_lock(&master->mutex); + slbuf.changemode(1); + slbuf.changeminimal(1); + master->part[*npart]->saveloadbuf(&slbuf,2); + bank->setname(slot,(char *)master->part[*npart]->Pname); + bank->savetoslot(slot,(char *)master->part[*npart]->Pname,&slbuf); + pthread_mutex_unlock(&master->mutex); + + bs[slot]->refresh(); + mode=1;readbutton->value(1);writebutton->value(0); + nooverwriteslot:; +}; + + +if ((what==1)&&(mode==1)&&(!bank->emptyslot(slot))){//Reads from slot + pthread_mutex_lock(&master->mutex); + instrumentdefaultsbuf.changemode(0); + master->part[*npart]->saveloadbuf(&instrumentdefaultsbuf,1); + bank->loadfromslot(slot,&slbuf); + slbuf.changemode(0); + master->part[*npart]->saveloadbuf(&slbuf,1); + pthread_mutex_unlock(&master->mutex); + if (master->part[*npart]->disablekitloading==0){ + snprintf((char *)master->part[*npart]->Pname,PART_MAX_NAME_LEN + ,bank->getname(slot)); + } else { + snprintf((char *)master->part[*npart]->kit[0].Pname,PART_MAX_NAME_LEN + ,bank->getname(slot)); + }; + cbwig->do_callback(); + + if (config.cfg.BankUIAutoClose!=0) + bankuiwindow->hide(); + +}; + +if ((what==1)&&(mode==3)&&(!bank->emptyslot(slot))){//Clears the slot + if (fl_ask("Clear the slot no. %d ?",slot+1)){ + bank->clearslot(slot); + bs[slot]->refresh(); + }; +};} {selected + } + } + Function {refreshmainwindow()} {} { + code {bankuiwindow->label(bank->bankfiletitle); +mode=1;readbutton->value(1);writebutton->value(0);clearbutton->value(0); +if (bank->locked()){ + writebutton->deactivate(); + clearbutton->deactivate(); +} else { + writebutton->activate(); + clearbutton->activate(); +};} {} + } + decl {BankSlot *bs[128];} {} + decl {int slot,what;//"what"=what button is pressed} {} + decl {int mode,*npart;} {} + decl {Master *master;} {} + decl {void (BankProcess_::* fnc)(void);} {} + decl {Fl_Valuator *cbwig;} {public + } +} diff --git a/src/UI/ConfigUI.fl b/src/UI/ConfigUI.fl @@ -0,0 +1,252 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <math.h>} {public +} + +decl {\#include <stdlib.h>} {selected public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include "../Misc/Util.h"} {public +} + +decl {\#include "../Misc/Dump.h"} {public +} + +decl {extern Dump dump;} {public +} + +class ConfigUI {} { + Function {make_window()} {} { + Fl_Window configwindow { + label {ZynAddSubFX Settings} + xywh {41 80 500 290} hide + } { + Fl_Button {} { + label OK + callback {configwindow->hide();} + xywh {70 255 100 20} box THIN_UP_BOX + } + Fl_Group {} { + label {Sample Rate} + xywh {5 25 165 30} box ENGRAVED_FRAME + } { + Fl_Choice {} { + callback {if ((int)o->value()==0) samplerateinput->activate(); + else samplerateinput->deactivate(); + +int samplerates[7]={44100,16000,22050,32000,44100,48000,96000}; +config.cfg.SampleRate=samplerates[(int)o->value()]; + +setsamplerateinput();} + xywh {10 30 85 20} down_box BORDER_BOX textsize 10 + code0 {o->value(getsamplerateorder());} + } { + menuitem {} { + label Custom + xywh {0 0 100 20} labelfont 1 + } + menuitem {} { + label 16000Hz + xywh {20 20 100 20} labelfont 1 + } + menuitem {} { + label 22050Hz + xywh {10 10 100 20} labelfont 1 + } + menuitem {} { + label 32000Hz + xywh {20 20 100 20} labelfont 1 + } + menuitem {} { + label 44100Hz + xywh {30 30 100 20} labelfont 1 + } + menuitem {} { + label 48000Hz + xywh {40 40 100 20} labelfont 1 + } + menuitem {} { + label 96000Hz + xywh {50 50 100 20} labelfont 1 + } + } + Fl_Input samplerateinput { + callback {char *tmp; +config.cfg.SampleRate=strtoul(o->value(),&tmp,10);} + xywh {105 30 60 20} type Int textfont 1 + code0 {setsamplerateinput();} + code1 {if (getsamplerateorder()!=0) o->deactivate();} + } + } + Fl_Input {} { + label {Buffer Size} + callback {char *tmp; +config.cfg.SoundBufferSize=strtoul(o->value(),&tmp,10);} + tooltip {Internal Sound Buffer Size (samples)} xywh {180 30 60 20} type Int labelsize 12 align 129 textfont 1 + code0 {char *tmpbuf=new char[100];o->cut(0,o->maximum_size());} + code1 {snprintf(tmpbuf,100,"%d",config.cfg.SoundBufferSize);o->insert(tmpbuf);} + code2 {delete(tmpbuf);} + } + Fl_Light_Button {} { + label {Swap Stereo } + callback {config.cfg.SwapStereo=(int) o->value();} + xywh {10 60 85 20} box THIN_UP_BOX labelsize 11 + code0 {o->value(config.cfg.SwapStereo);} + } + Fl_Choice {} { + label OscilSize + callback {config.cfg.OscilSize=128<<o->value();} + tooltip {ADSynth Oscillator Size (samples)} xywh {165 60 75 20} down_box BORDER_BOX labelfont 1 labelsize 12 textsize 10 + code0 {o->value( (int) (log(config.cfg.OscilSize/128.0-1.0)/log(2)) +1);} + } { + menuitem {} { + label 128 + xywh {15 15 100 20} labelfont 1 + } + menuitem {} { + label 256 + xywh {25 25 100 20} labelfont 1 + } + menuitem {} { + label 512 + xywh {35 35 100 20} labelfont 1 + } + menuitem {} { + label 1024 + xywh {35 35 100 20} labelfont 1 + } + menuitem {} { + label 2048 + xywh {45 45 100 20} labelfont 1 + } + menuitem {} { + label 4096 + xywh {45 45 100 20} labelfont 1 + } + menuitem {} { + label 8192 + xywh {55 55 100 20} labelfont 1 + } + menuitem {} { + label 16384 + xywh {65 65 100 20} labelfont 1 + } + } + Fl_Box {} { + label {The settings has effect only after ZynAddSubFX is restarted.} + xywh {10 210 235 30} labelfont 1 labelsize 12 align 128 + } + Fl_Box {} { + label {Read the Readme.txt for other settings} + xywh {5 190 240 20} labelfont 1 labelsize 12 align 128 + } + Fl_Group {} { + xywh {5 95 230 85} box ENGRAVED_BOX + } { + Fl_File_Input {} { + label {Dump File} + callback {snprintf(config.cfg.DumpFile,config.maxstringsize,"%s",o->value());} + xywh {10 140 220 35} align 5 + code0 {o->insert(config.cfg.DumpFile);} + } + Fl_Check_Button {} { + label {Dump notes} + callback {config.cfg.DumpNotesToFile=(int) o->value(); +dump.startnow();//this has effect only if this option was disabled} + xywh {10 100 100 20} down_box DOWN_BOX + code0 {o->value(config.cfg.DumpNotesToFile);} + } + } + Fl_Group {} { + xywh {250 15 245 275} box ENGRAVED_FRAME + } { + Fl_Box {} { + label {Note: Not all the following settings are used (this depends on the operating system, etc..)} + xywh {255 25 235 45} labelfont 1 labelsize 12 align 128 + } + Fl_Group {} { + label Linux + xywh {255 95 235 115} box ENGRAVED_BOX labelfont 1 labelsize 16 align 5 + } { + Fl_File_Input {} { + label {OSS Sequencer Device (/dev/...)} + callback {snprintf(config.cfg.LinuxOSSSeqInDev,config.maxstringsize,"%s",o->value());} + xywh {260 165 225 35} align 5 + code0 {o->insert(config.cfg.LinuxOSSSeqInDev);} + } + Fl_File_Input {} { + label {OSS Wave Out Device (/dev/...)} + callback {snprintf(config.cfg.LinuxOSSWaveOutDev,config.maxstringsize,"%s",o->value());} + xywh {260 115 225 35} align 5 + code0 {o->insert(config.cfg.LinuxOSSWaveOutDev);} + } + } + Fl_Group {} { + label Windows + xywh {255 235 235 50} box ENGRAVED_BOX labelfont 1 labelsize 16 align 5 + } { + Fl_Counter {} { + label {Midi In Dev} + callback {config.cfg.WindowsMidiInId=(int) o->value(); +midiinputnamebox->label(config.winmididevices[config.cfg.WindowsMidiInId].name);} + xywh {265 255 65 20} type Simple labelsize 12 align 1 minimum 0 maximum 100 step 1 + code0 {o->maximum(config.winmidimax-1);} + code1 {o->value(config.cfg.WindowsMidiInId);} + } + Fl_Box midiinputnamebox { + label {Midi input device name} + xywh {335 245 150 35} labelfont 1 labelsize 12 align 212 + code0 {o->label(config.winmididevices[config.cfg.WindowsMidiInId].name);} + } + } + } + Fl_Check_Button {} { + label Append + callback {config.cfg.DumpAppend=(int) o->value();} + xywh {150 100 80 20} down_box DOWN_BOX + code0 {o->value(config.cfg.DumpAppend);} + } + } + } + Function {ConfigUI()} {} { + code {make_window();} {} + } + Function {getsamplerateorder()} {return_type int + } { + code {int smpr=config.cfg.SampleRate; +int order=0; +switch(smpr){ + case 16000:order=1;break; + case 22050:order=2;break; + case 32000:order=3;break; + case 44100:order=4;break; + case 48000:order=5;break; + case 96000:order=6;break; + default:order=0;break; +}; +return(order);} {} + } + Function {setsamplerateinput()} {return_type void + } { + code {char *tmpbuf=new char[100]; +samplerateinput->cut(0,samplerateinput->maximum_size()); +snprintf(tmpbuf,100,"%d",config.cfg.SampleRate); +samplerateinput->insert(tmpbuf); +delete (tmpbuf);} {} + } + Function {show()} {} { + code {configwindow->show();} {} + } +} diff --git a/src/UI/EffUI.fl b/src/UI/EffUI.fl @@ -0,0 +1,1216 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <string.h>} {public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include "EnvelopeUI.h"} {public +} + +decl {\#include "../Misc/Util.h"} {public +} + +decl {\#include "../Effects/EffectMgr.h"} {public +} + +class EQGraph {: {public Fl_Box} +} { + Function {EQGraph(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {eff=NULL; +maxdB=30;} {} + } + Function {init(EffectMgr *eff_)} {} { + code {eff=eff_; +oldx=-1; +khzval=-1;} {} + } + Function {draw_freq_line(REALTYPE freq,int type)} {} { + code {fl_color(FL_GRAY); +REALTYPE freqx=getfreqpos(freq); +switch(type){ + case 0:if (active_r()) fl_color(FL_WHITE); + else fl_color(205,205,205); + fl_line_style(FL_SOLID); + break; + case 1:fl_line_style(FL_DOT);break; + case 2:fl_line_style(FL_DASH);break; +}; + + +if ((freqx>0.0)&&(freqx<1.0)) + fl_line(x()+(int) (freqx*w()),y(), + x()+(int) (freqx*w()),y()+h());} {} + } + Function {draw()} {} { + code {int ox=x(),oy=y(),lx=w(),ly=h(),i,iy,oiy; +REALTYPE freqx; + +if (active_r()) fl_color(0,70,150); + else fl_color(80,120,160); +fl_rectf(ox,oy,lx,ly); + + +//draw the lines +fl_color(FL_GRAY); + +fl_line_style(FL_SOLID); +fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); + +freqx=getfreqpos(1000.0); +if ((freqx>0.0)&&(freqx<1.0)) + fl_line(ox+(int) (freqx*lx),oy, + ox+(int) (freqx*lx),oy+ly); + +for (i=1;i<10;i++){ + if(i==1){ + draw_freq_line(i*100.0,0); + draw_freq_line(i*1000.0,0); + }else + if (i==5){ + draw_freq_line(i*10.0,2); + draw_freq_line(i*100.0,2); + draw_freq_line(i*1000.0,2); + }else{ + draw_freq_line(i*10.0,1); + draw_freq_line(i*100.0,1); + draw_freq_line(i*1000.0,1); + }; +}; + +draw_freq_line(10000.0,0); +draw_freq_line(20000.0,1); + + +fl_line_style(FL_DOT); +int GY=6;if (ly<GY*3) GY=-1; +for (i=1;i<GY;i++){ + int tmp=(int)(ly/(REALTYPE)GY*i); + fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); +}; + + +//draw the frequency response +if (active_r()) fl_color(FL_YELLOW); + else fl_color(200,200,80); +fl_line_style(FL_SOLID); +oiy=getresponse(ly,getfreqx(0.0)); +for (i=1;i<lx;i++){ + REALTYPE frq=getfreqx(i/(REALTYPE) lx); + if (frq>SAMPLE_RATE/2) break; + iy=getresponse(ly,frq); + if ((oiy>=0) && (oiy<ly) && + (iy>=0) && (iy<ly) ) + fl_line(ox+i-1,oy+ly-oiy,ox+i,oy+ly-iy); + oiy=iy; +};} {} + } + Function {getresponse(int maxy,REALTYPE freq)} {return_type int + } { + code {REALTYPE dbresp=eff->getEQfreqresponse(freq); +int idbresp=(int) ((dbresp/maxdB+1.0)*maxy/2.0); + + +//fprintf(stderr,"%.5f\\n",(dbresp/maxdB+1.0)*maxy/2.0); + + +return(idbresp);} {} + } + Function {getfreqx(REALTYPE x)} {return_type REALTYPE + } { + code {if (x>1.0) x=1.0; +return(20.0*pow(1000.0,x));} {} + } + Function {getfreqpos(REALTYPE freq)} {return_type REALTYPE + } { + code {if (freq<0.00001) freq=0.00001; +return(log(freq/20.0)/log(1000.0));} {} + } + decl {int oldx,oldy;} {} + decl {REALTYPE khzval;} {public + } + decl {EffectMgr *eff;} {} + decl {int maxdB;} {} +} + +class EffUI {: {public Fl_Group} +} { + Function {EffUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {eff=NULL;} {} + } + Function {~EffUI()} {} { + code {effwindow->hide(); +hide(); +delete (effwindow);} {} + } + Function {make_null_window()} {} { + Fl_Window effnullwindow { + xywh {287 379 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Text_Display {} { + label {No Effect} + xywh {120 35 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 labelcolor 43 align 8 + } + } + } + Function {make_reverb_window()} {} { + Fl_Window effreverbwindow { + xywh {328 433 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Text_Display {} { + label {Reverb } + xywh {275 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {10 15 90 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {Cathedral 1} + xywh {10 10 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Cathedral 2} + xywh {20 20 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Cathedral 3} + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Hall 1} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Hall 2} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Room 1} + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Room 2} + xywh {70 70 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label Basement + xywh {80 80 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label Tunnel + xywh {90 90 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Echoed 1} + xywh {100 100 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Echoed 2} + xywh {110 110 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Very Long 1} + xywh {120 120 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Very Long 2} + xywh {130 130 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Choice {} { + label Type + callback {eff->seteffectpar(10,(int) o->value());} + xywh {110 15 75 15} down_box BORDER_BOX color 14 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->geteffectpar(10));} + } { + menuitem {} { + label Random + xywh {20 20 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label Freeverb + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Dial {} { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + code1 {if (eff->insertion!=0) o->label("D/W");} + class WidgetPDial + } + Fl_Dial {} { + label Pan + callback {eff->seteffectpar(1,(int) o->value());} + xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(1));} + class WidgetPDial + } + Fl_Dial {} { + label Time + callback {eff->seteffectpar(2,(int) o->value());} + xywh {80 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(2));} + class WidgetPDial + } + Fl_Dial {} { + label {I.del} + callback {eff->seteffectpar(3,(int) o->value());} + xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(3));} + class WidgetPDial + } + Fl_Dial {} { + label {I.delfb} + callback {eff->seteffectpar(4,(int) o->value());} + xywh {155 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(4));} + class WidgetPDial + } + Fl_Dial {} { + label {R.delay} + callback {eff->seteffectpar(5,(int) o->value());} + xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 deactivate + code0 {o->value(eff->geteffectpar(5));} + class WidgetPDial + } + Fl_Dial {} { + label {E/R} + callback {eff->seteffectpar(6,(int) o->value());} + xywh {235 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 deactivate + code0 {o->value(eff->geteffectpar(6));} + class WidgetPDial + } + Fl_Dial {} { + label LPF + callback {eff->seteffectpar(7,(int) o->value());} + xywh {270 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(7));} + class WidgetPDial + } + Fl_Dial {} { + label HPF + callback {eff->seteffectpar(8,(int) o->value());} + xywh {305 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(8));} + class WidgetPDial + } + Fl_Dial {} { + label Damp + callback {eff->seteffectpar(9,(int) o->value());} + xywh {340 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 minimum 64 maximum 127 step 1 + code0 {o->value(eff->geteffectpar(9));} + class WidgetPDial + } + Fl_Dial {} { + label {R.S.} + callback {int x=64; +if (Fl::event_button1()) x=(int)o->value(); + else o->value(x); +eff->seteffectpar(11,x);} + tooltip RoomSize xywh {190 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 8 align 8 minimum 1 maximum 127 step 1 + code0 {o->value(eff->geteffectpar(11));} + class WidgetPDial + } + } + } + Function {make_echo_window()} {} { + Fl_Window effechowindow { + xywh {82 542 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {11 15 95 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {Echo 1} + xywh {20 20 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Echo 2} + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Echo 3} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Simple Echo} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label Canyon + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Panning Echo 1} + xywh {70 70 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Panning Echo 2} + xywh {80 80 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Panning Echo 3} + xywh {90 90 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Feedback Echo} + xywh {100 100 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label Echo + xywh {295 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Dial {} { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + code1 {if (eff->insertion!=0) o->label("D/W");} + class WidgetPDial + } + Fl_Dial {} { + label Pan + callback {eff->seteffectpar(1,(int) o->value());} + xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(1));} + class WidgetPDial + } + Fl_Dial {} { + label Delay + callback {eff->seteffectpar(2,(int) o->value());} + xywh {80 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(2));} + class WidgetPDial + } + Fl_Dial {} { + label {LRdl.} + callback {eff->seteffectpar(3,(int) o->value());} + xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(3));} + class WidgetPDial + } + Fl_Dial {} { + label {LRc.} + callback {eff->seteffectpar(4,(int) o->value());} + xywh {155 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(4));} + class WidgetPDial + } + Fl_Dial {} { + label {Fb.} + callback {eff->seteffectpar(5,(int) o->value());} + xywh {195 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(5));} + class WidgetPDial + } + Fl_Dial {} { + label Damp + callback {eff->seteffectpar(6,(int) o->value());} + xywh {235 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(6));} + class WidgetPDial + } + } + } + Function {make_chorus_window()} {} { + Fl_Window effchoruswindow { + xywh {210 263 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {10 15 90 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {Chorus 1} + xywh {20 20 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Chorus 2} + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Chorus 3} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Celeste 1} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Celeste 2} + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Flange 1} + xywh {70 70 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Flange 2} + xywh {80 80 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Flange 3} + xywh {90 90 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Flange 4} + xywh {100 100 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Flange 5} + xywh {110 110 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label Chorus + xywh {265 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Dial {} { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + code1 {if (eff->insertion!=0) o->label("D/W");} + class WidgetPDial + } + Fl_Dial {} { + label Pan + callback {eff->seteffectpar(1,(int) o->value());} + xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(1));} + class WidgetPDial + } + Fl_Dial {} { + label Freq + callback {eff->seteffectpar(2,(int) o->value());} + xywh {85 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(2));} + class WidgetPDial + } + Fl_Dial {} { + label Rnd + callback {eff->seteffectpar(3,(int) o->value());} + xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(3));} + class WidgetPDial + } + Fl_Dial {} { + label {St.df} + callback {eff->seteffectpar(5,(int) o->value());} + xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(5));} + class WidgetPDial + } + Fl_Dial {} { + label Dpth + callback {eff->seteffectpar(6,(int) o->value());} + xywh {235 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(6));} + class WidgetPDial + } + Fl_Dial {} { + label Delay + callback {eff->seteffectpar(7,(int) o->value());} + xywh {270 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(7));} + class WidgetPDial + } + Fl_Dial {} { + label Fb + callback {eff->seteffectpar(8,(int) o->value());} + xywh {305 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(8));} + class WidgetPDial + } + Fl_Dial {} { + label {L/R} + callback {eff->seteffectpar(9,(int) o->value());} + xywh {340 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(9));} + class WidgetPDial + } + Fl_Check_Button {} { + label Flange + callback {eff->seteffectpar(10,(int) o->value());} + xywh {120 10 55 20} box THIN_UP_BOX down_box DOWN_BOX color 230 labelfont 1 labelsize 10 hide deactivate + code0 {o->value(eff->geteffectpar(10));} + } + Fl_Check_Button {} { + label Substract + callback {eff->seteffectpar(11,(int) o->value());} + xywh {185 10 70 20} box THIN_UP_BOX down_box DOWN_BOX color 230 labelfont 1 labelsize 10 + code0 {o->value(eff->geteffectpar(11));} + } + Fl_Choice {} { + label {LFO type} + callback {eff->seteffectpar(4,(int) o->value());} + tooltip {LFO function} xywh {155 50 40 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 130 textsize 8 + code0 {o->value(eff->geteffectpar(4));} + } { + menuitem {} { + label SINE + xywh {15 15 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label TRI + xywh {25 25 100 20} labelfont 1 labelsize 10 + } + } + } + } + Function {make_phaser_window()} {} { + Fl_Window effphaserwindow { + xywh {277 263 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {10 15 90 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {Phaser 1} + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Phaser 2} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Phaser 3} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Phaser 4} + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Phaser 5} + xywh {70 70 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Phaser 6} + xywh {80 80 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label Phaser + xywh {275 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Dial {} { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + code1 {if (eff->insertion!=0) o->label("D/W");} + class WidgetPDial + } + Fl_Dial {} { + label Pan + callback {eff->seteffectpar(1,(int) o->value());} + xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(1));} + class WidgetPDial + } + Fl_Dial {} { + label Freq + callback {eff->seteffectpar(2,(int) o->value());} + xywh {85 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(2));} + class WidgetPDial + } + Fl_Dial {} { + label Rnd + callback {eff->seteffectpar(3,(int) o->value());} + xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(3));} + class WidgetPDial + } + Fl_Dial {} { + label {St.df} + callback {eff->seteffectpar(5,(int) o->value());} + xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(5));} + class WidgetPDial + } + Fl_Dial {} { + label Dpth + callback {eff->seteffectpar(6,(int) o->value());} + xywh {235 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(6));} + class WidgetPDial + } + Fl_Dial {} { + label Fb + callback {eff->seteffectpar(7,(int) o->value());} + xywh {270 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(7));} + class WidgetPDial + } + Fl_Dial {} { + label {L/R} + callback {eff->seteffectpar(9,(int) o->value());} + xywh {345 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(9));} + class WidgetPDial + } + Fl_Check_Button {} { + label Substract + callback {eff->seteffectpar(10,(int) o->value());} + xywh {185 10 70 20} box THIN_UP_BOX down_box DOWN_BOX color 230 labelfont 1 labelsize 10 + code0 {o->value(eff->geteffectpar(10));} + } + Fl_Choice {} { + label {LFO type} + callback {eff->seteffectpar(4,(int) o->value());} + tooltip {LFO function} xywh {155 50 40 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 130 textsize 8 + code0 {o->value(eff->geteffectpar(4));} + } { + menuitem {} { + label SINE + xywh {15 15 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label TRI + xywh {25 25 100 20} labelfont 1 labelsize 10 + } + } + Fl_Counter {} { + label Stages + callback {eff->seteffectpar(8,(int) o->value());} + xywh {305 55 35 15} type Simple labelfont 1 labelsize 12 minimum 0 maximum 127 step 1 + code0 {o->range(1,MAX_PHASER_STAGES);} + code1 {o->value(eff->geteffectpar(8));} + } + Fl_Dial {} { + label Phase + callback {eff->seteffectpar(11,(int) o->value());} + xywh {155 10 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 maximum 127 + code0 {o->value(eff->geteffectpar(11));} + class WidgetPDial + } + } + } + Function {make_alienwah_window()} {} { + Fl_Window effalienwahwindow { + xywh {230 283 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {10 15 90 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {Alienwah 1} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Alienwah 2} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Alienwah 3} + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Alienwah 4} + xywh {70 70 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label AlienWah + xywh {245 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Dial {} { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + code1 {if (eff->insertion!=0) o->label("D/W");} + class WidgetPDial + } + Fl_Dial {} { + label Pan + callback {eff->seteffectpar(1,(int) o->value());} + xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(1));} + class WidgetPDial + } + Fl_Dial {} { + label Freq + callback {eff->seteffectpar(2,(int) o->value());} + xywh {85 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(2));} + class WidgetPDial + } + Fl_Dial {} { + label Rnd + callback {eff->seteffectpar(3,(int) o->value());} + xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(3));} + class WidgetPDial + } + Fl_Dial {} { + label {St.df} + callback {eff->seteffectpar(5,(int) o->value());} + xywh {200 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(5));} + class WidgetPDial + } + Fl_Dial {} { + label Dpth + callback {eff->seteffectpar(6,(int) o->value());} + xywh {235 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(6));} + class WidgetPDial + } + Fl_Dial {} { + label Fb + callback {eff->seteffectpar(7,(int) o->value());} + xywh {270 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(7));} + class WidgetPDial + } + Fl_Dial {} { + label {L/R} + callback {eff->seteffectpar(9,(int) o->value());} + xywh {345 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(9));} + class WidgetPDial + } + Fl_Choice {} { + label {LFO type} + callback {eff->seteffectpar(4,(int) o->value());} + tooltip {LFO function} xywh {155 50 40 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 130 textsize 8 + code0 {o->value(eff->geteffectpar(4));} + } { + menuitem {} { + label SINE + xywh {15 15 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label TRI + xywh {25 25 100 20} labelfont 1 labelsize 10 + } + } + Fl_Counter {} { + label Delay + callback {eff->seteffectpar(8,(int) o->value());} + xywh {305 55 35 15} type Simple labelfont 1 labelsize 12 minimum 0 maximum 127 step 1 + code0 {o->range(1,MAX_ALIENWAH_DELAY);} + code1 {o->value(eff->geteffectpar(8));} + } + Fl_Dial {} { + label Phase + callback {eff->seteffectpar(10,(int) o->value());} + xywh {160 5 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(10));} + class WidgetPDial + } + } + } + Function {make_distorsion_window()} {} { + Fl_Window effdistorsionwindow {selected + xywh {87 411 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {11 15 95 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {Overdrive 1} + xywh {20 20 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Overdrive 2} + xywh {30 30 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {A. Exciter 1} + xywh {40 40 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {A. Exciter 2} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label {Guitar Amp} + xywh {50 50 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + menuitem {} { + label Quantisize + xywh {60 60 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label Distortion + xywh {230 10 10 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Dial {} { + label Vol + callback {eff->seteffectpar(0,(int) o->value());} + xywh {10 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + code1 {if (eff->insertion!=0) o->label("D/W");} + class WidgetPDial + } + Fl_Dial {} { + label Pan + callback {eff->seteffectpar(1,(int) o->value());} + xywh {45 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(1));} + class WidgetPDial + } + Fl_Dial {} { + label {LRc.} + callback {eff->seteffectpar(2,(int) o->value());} + xywh {80 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(2));} + class WidgetPDial + } + Fl_Dial {} { + label Drive + callback {eff->seteffectpar(3,(int) o->value());} + xywh {120 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 when 4 maximum 127 + code0 {o->value(eff->geteffectpar(3));} + class WidgetPDial + } + Fl_Dial {} { + label Level + callback {eff->seteffectpar(4,(int) o->value());} + xywh {155 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(4));} + class WidgetPDial + } + Fl_Dial {} { + label LPF + callback {eff->seteffectpar(7,(int) o->value());} + xywh {285 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(7));} + class WidgetPDial + } + Fl_Dial {} { + label HPF + callback {eff->seteffectpar(8,(int) o->value());} + xywh {320 40 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(8));} + class WidgetPDial + } + Fl_Choice {} { + label Type + callback {eff->seteffectpar(5,(int) o->value());} + xywh {190 50 60 20} box UP_BOX down_box BORDER_BOX labelfont 1 labelsize 12 align 2 textsize 10 + code0 {o->value(eff->geteffectpar(5));} + } { + menuitem {} { + label Atan + xywh {55 55 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Asym1 + xywh {65 65 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Pow + xywh {75 75 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Sine + xywh {85 85 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Qnts + xywh {95 95 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Zigzg + xywh {105 105 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Lmt + xywh {115 115 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LmtU + xywh {125 125 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LmtL + xywh {135 135 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label ILmt + xywh {147 147 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Clip + xywh {157 157 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Asym2 + xywh {75 75 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Pow2 + xywh {85 85 100 20} labelfont 1 labelsize 10 + } + } + Fl_Check_Button {} { + label {Neg.} + callback {eff->seteffectpar(6,(int) o->value());} + xywh {260 55 15 15} down_box DOWN_BOX labelfont 1 labelsize 12 align 2 + code0 {o->value(eff->geteffectpar(6));} + } + Fl_Check_Button {} { + label {St.} + callback {eff->seteffectpar(9,(int) o->value());} + tooltip Stereo xywh {355 60 15 15} down_box DOWN_BOX labelfont 1 labelsize 12 align 2 + code0 {o->value(eff->geteffectpar(9));} + } + Fl_Check_Button {} { + label PF + callback {eff->seteffectpar(10,(int) o->value());} + tooltip {Applies the filters(before or after) the distorsion} xywh {355 44 15 15} down_box DOWN_BOX labelfont 1 labelsize 12 align 1 + code0 {o->value(eff->geteffectpar(10));} + } + } + } + Function {make_eq_window()} {} { + Fl_Window effeqwindow { + xywh {248 307 380 95} box PLASTIC_UP_BOX color 221 labelfont 1 hide + class Fl_Group + } { + Fl_Choice {} { + label Preset + callback {eff->changepreset((int)o->value()); +cbwidget->do_callback();} + xywh {11 15 54 15} down_box BORDER_BOX color 14 selection_color 0 labelfont 1 labelsize 10 labelcolor 0 align 5 textfont 1 textsize 10 textcolor 7 hide + code0 {o->value(eff->getpreset());} + } { + menuitem {} { + label {EQ 1} + xywh {20 20 100 20} labelfont 1 labelsize 10 labelcolor 7 + } + } + Fl_Text_Display {} { + label EQ + xywh {320 10 15 20} box NO_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 26 align 8 + } + Fl_Dial {} { + label Gain + callback {eff->seteffectpar(0,(int) o->value()); +eqgraph->redraw();} + xywh {10 35 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 maximum 127 + code0 {o->value(eff->geteffectpar(0));} + class WidgetPDial + } + Fl_Counter bandcounter { + label {B.} + callback {eqband=(int) o->value(); +int npb=eqband*5+10; + +int type=eff->geteffectpar(npb); +typechoice->value(type); + +if (type>6) gaindial->activate(); + else gaindial->deactivate(); + +if (type==0) bandgroup->deactivate(); +else bandgroup->activate(); + +int freq=eff->geteffectpar(npb+1); +freqdial->value(freq); + +int gain=eff->geteffectpar(npb+2); +gaindial->value(gain); + +int q=eff->geteffectpar(npb+3); +qdial->value(q); + +int dbl=eff->geteffectpar(npb+4); +stagescounter->value(dbl);} + tooltip {Band no.} xywh {240 20 45 15} type Simple labelfont 1 labelsize 12 align 1 minimum 0 maximum 1 step 1 textfont 1 textsize 12 + code0 {o->bounds(0,MAX_EQ_BANDS-1);} + } + Fl_Group bandgroup { + xywh {245 40 130 50} box ENGRAVED_FRAME + code0 {if (eff->geteffectpar(10)==0) o->deactivate();} + } { + Fl_Dial freqdial { + label Freq + callback {int np=eqband*5+11; +eff->seteffectpar(np,(int) o->value()); +eqgraph->redraw();} + xywh {250 50 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 when 3 maximum 127 + code0 {o->value(eff->geteffectpar(11));} + class WidgetPDial + } + Fl_Dial gaindial { + label Gain + callback {int np=eqband*5+12; +eff->seteffectpar(np,(int) o->value()); +eqgraph->redraw();} + xywh {280 50 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 when 3 maximum 127 step 1 + code0 {o->value(eff->geteffectpar(12));} + code1 {if (eff->geteffectpar(10)<6) o->deactivate();} + class WidgetPDial + } + Fl_Dial qdial { + label Q + callback {int np=eqband*5+13; +eff->seteffectpar(np,(int) o->value()); +eqgraph->redraw();} + xywh {310 50 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 when 3 maximum 127 + code0 {o->value(eff->geteffectpar(13));} + code1 {//if (eff->geteffectpar(10)>=7) o->deactivate();} + class WidgetPDial + } + Fl_Counter stagescounter { + label {St.} + callback {int np=eqband*5+14; +eff->seteffectpar(np,(int) o->value()); +eqgraph->redraw();} + tooltip {Additional filter stages} xywh {340 60 30 15} type Simple labelfont 1 labelsize 10 minimum 1 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(0,MAX_FILTER_STAGES-1);} + code1 {o->value(eff->geteffectpar(14));} + } + } + Fl_Choice typechoice { + label {T.} + callback {int np=eqband*5+10; +eff->seteffectpar(np,(int) o->value()); +bandcounter->do_callback(); +eqgraph->redraw();} + tooltip Type xywh {290 20 40 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 when 6 textsize 10 + code0 {o->value(eff->geteffectpar(10));} + } { + menuitem {} { + label OFF + xywh {0 0 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Lp1 + xywh {10 10 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Hp1 + xywh {20 20 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Lp2 + xywh {30 30 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Hp2 + xywh {40 40 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Bp2 + xywh {50 50 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label N2 + xywh {60 60 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Pk + xywh {80 80 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LSh + xywh {70 70 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HSh + xywh {80 80 100 20} labelfont 1 labelsize 10 + } + } + Fl_Box eqgraph { + xywh {45 10 190 75} box BORDER_BOX color 178 + code0 {o->init(eff);} + class EQGraph + } + } + } + Function {init(EffectMgr *eff_,Fl_Widget *cbwidget_)} {} { + code {eff=eff_; +cbwidget=cbwidget_; +switch(eff->geteffect()){ + case 1:make_reverb_window(); + effwindow=effreverbwindow; + break; + case 2:make_echo_window(); + effwindow=effechowindow; + break; + case 3:make_chorus_window(); + effwindow=effchoruswindow; + break; + case 4:make_phaser_window(); + effwindow=effphaserwindow; + break; + case 5:make_alienwah_window(); + effwindow=effalienwahwindow; + break; + case 6:make_distorsion_window(); + effwindow=effdistorsionwindow; + break; + case 7:make_eq_window(); + effwindow=effeqwindow; + eqband=0; + break; + default:make_null_window(); + effwindow=effnullwindow; + break; +}; + +end(); +effwindow->position(this->parent()->x(),this->parent()->y());} {} + } + decl {EffectMgr *eff;} {} + decl {Fl_Group *effwindow;} {} + decl {Fl_Widget *cbwidget;} {} + decl {int eqband;} {} +} diff --git a/src/UI/EnvelopeUI.fl b/src/UI/EnvelopeUI.fl @@ -0,0 +1,700 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include <FL/Fl_Group.H>} {public +} + +decl {\#include "../Params/EnvelopeParams.h"} {public +} + +decl {\#include <FL/Fl_Box.H>} {public +} + +decl {\#include <FL/fl_draw.H>} {public +} + +decl {\#include <FL/fl_ask.H>} {public +} + +class EnvelopeFreeEdit {: {public Fl_Box} +} { + Function {EnvelopeFreeEdit(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {env=NULL; +pair=NULL;} {} + } + Function {init(EnvelopeParams *env_)} {} { + code {env=env_; +oldx=-1; +currentpoint=-1; +cpx=0; +lastpoint=-1;} {} + } + Function {setpair(Fl_Box *pair_)} {} { + code {pair=pair_;} {} + } + Function {getpointx(int n)} {return_type int + } { + code {int lx=w()-10; +int npoints=env->Penvpoints; + +float sum=0; +for (int i=1;i<npoints;i++) sum+=env->getdt(i)+1; + +float sumbefore=0;//the sum of all points before the computed point +for (int i=1;i<=n;i++) sumbefore+=env->getdt(i)+1; + +return((int) (sumbefore/(REALTYPE) sum*lx));} {} + } + Function {getpointy(int n)} {return_type int + } { + code {int ly=h()-10; + +return((int) ((1.0-env->Penvval[n]/127.0)*ly));} {} + } + Function {getnearest(int x,int y)} {return_type int + } { + code {int lx=w()-10; +int ly=h()-10; +x-=5;y-=5; + +int nearestpoint=0; +int nearestval=1000000;//a big value +for (int i=0;i<env->Penvpoints;i++){ + int distance=abs(x-getpointx(i))+abs(y-getpointy(i)); + if (distance<nearestval) { + nearestpoint=i; + nearestval=distance; + }; +}; +return(nearestpoint);} {} + } + Function {draw()} {private + } { + code {int ox=x(),oy=y(),lx=w(),ly=h(); +if (env->Pfreemode==0) env->converttofree(); +int npoints=env->Penvpoints; + +if (active_r()) fl_color(FL_BLACK); + else fl_color(90,90,90); +if (!active_r()) currentpoint=-1; + +fl_rectf(ox,oy,lx,ly); + +ox+=5;oy+=5;lx-=10;ly-=10; + +//draw the lines +fl_color(FL_GRAY); + +fl_line_style(FL_SOLID); +fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); + +//draws the evelope points and lines +Fl_Color alb=FL_WHITE; +if (!active_r()) alb=fl_rgb_color(180,180,180); +fl_color(alb); +int oldxx=0,xx=0,oldyy=0,yy=getpointy(0); +fl_rectf(ox-3,oy+yy-3,6,6); +for (int i=1;i<npoints;i++){ + oldxx=xx;oldyy=yy; + xx=getpointx(i);yy=getpointy(i); + if (i==currentpoint) fl_color(FL_RED); + else fl_color(alb); + fl_line(ox+oldxx,oy+oldyy,ox+xx,oy+yy); + fl_rectf(ox+xx-3,oy+yy-3,6,6); +}; + +//draw the last moved point point (if exists) +if (lastpoint>=0){ + fl_color(FL_CYAN); + fl_rectf(ox+getpointx(lastpoint)-5,oy+getpointy(lastpoint)-5,10,10); +}; + +//draw the sustain position +if (env->Penvsustain>0){ + fl_color(FL_YELLOW); + xx=getpointx(env->Penvsustain); + fl_line(ox+xx,oy+0,ox+xx,oy+ly); +}; + +//Show the envelope duration and the current line duration +fl_font(FL_HELVETICA|FL_BOLD,10); +float time=0.0; +if (currentpoint<=0){ + fl_color(alb); + for (int i=1;i<npoints;i++) time+=env->getdt(i); +} else { + fl_color(255,0,0); + time=env->getdt(currentpoint); +}; +char tmpstr[20]; +if (time<1000.0) snprintf((char *)&tmpstr,20,"%.1fms\\0",time); + else snprintf((char *)&tmpstr,20,"%.2fs\\0",time/1000.0); +fl_draw(tmpstr,ox+lx-20,oy+ly-10,20,10,FL_ALIGN_RIGHT,NULL,0);} {} + } + Function {handle(int event)} {return_type int + } { + code {int x_=Fl::event_x()-x(); +int y_=Fl::event_y()-y(); + +if (event==FL_PUSH) { + currentpoint=getnearest(x_,y_); + cpx=x_; + cpdt=env->Penvdt[currentpoint]; + lastpoint=currentpoint; + redraw(); + if (pair!=NULL) pair->redraw(); +}; + +if (event==FL_RELEASE){ + currentpoint=-1; + redraw(); + if (pair!=NULL) pair->redraw(); +}; + +if ((event==FL_DRAG)&&(currentpoint>=0)){ + int ny=127-(int) (y_*127.0/h()); + if (ny<0) ny=0;if (ny>127) ny=127; + env->Penvval[currentpoint]=ny; + + int dx=(int)((x_-cpx)*0.1); + int newdt=cpdt+dx; + if (newdt<0) newdt=0;if (newdt>127) newdt=127; + if (currentpoint!=0) env->Penvdt[currentpoint]=newdt; + else env->Penvdt[currentpoint]=0; + + redraw(); + if (pair!=NULL) pair->redraw(); +}; + + +return(1);} {} + } + decl {Fl_Box *pair;} {} + decl {EnvelopeParams *env;} {} + decl {int oldx,oldy;} {} + decl {int currentpoint,cpx,cpdt;} {} + decl {int lastpoint;} {public + } +} + +class EnvelopeUI {: {public Fl_Group} +} { + Function {EnvelopeUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {env=NULL;} {} + } + Function {~EnvelopeUI()} {} { + code {envwindow->hide(); +hide(); +freemodeeditwindow->hide(); +delete (envwindow); +delete (freemodeeditwindow);} {} + } + Function {make_freemode_edit_window()} {} { + Fl_Window freemodeeditwindow { + label Envelope + xywh {132 455 575 180} hide + } { + Fl_Box freeedit { + label Envelope + xywh {5 5 565 145} box FLAT_BOX color 0 + code0 {o->init(env);} + class EnvelopeFreeEdit + } + Fl_Button {} { + label {Add point} + callback {int curpoint=freeedit->lastpoint; +if (curpoint<0) return; +//if (curpoint>=env->Penvpoints-1) return; +if (env->Penvpoints>=MAX_ENVELOPE_POINTS) return; + +for (int i=env->Penvpoints;i>=curpoint+1;i--){ + env->Penvdt[i]=env->Penvdt[i-1]; + env->Penvval[i]=env->Penvval[i-1]; +}; + +if (curpoint==0) { + env->Penvdt[1]=64; +}; + +env->Penvpoints++; +if (curpoint<=env->Penvsustain) env->Penvsustain++; + +freeedit->lastpoint+=1; +freeedit->redraw(); +envfree->redraw(); + +sustaincounter->value(env->Penvsustain); +sustaincounter->maximum(env->Penvpoints-2);} + xywh {115 155 80 20} box THIN_UP_BOX + code0 {if (env->Pfreemode==0) o->hide();} + } + Fl_Button {} { + label {Delete point} + callback {int curpoint=freeedit->lastpoint; +if (curpoint<1) return; +if (curpoint>=env->Penvpoints-1) return; +if (env->Penvpoints<=3) return; + +for (int i=curpoint+1;i<env->Penvpoints;i++){ + env->Penvdt[i-1]=env->Penvdt[i]; + env->Penvval[i-1]=env->Penvval[i]; +}; + +env->Penvpoints--; + +if (curpoint<=env->Penvsustain) env->Penvsustain--; + + +freeedit->lastpoint-=1; +freeedit->redraw(); +envfree->redraw(); + +sustaincounter->value(env->Penvsustain); +sustaincounter->maximum(env->Penvpoints-2);} + xywh {200 155 80 20} box THIN_UP_BOX + code0 {if (env->Pfreemode==0) o->hide();} + } + Fl_Light_Button freemodebutton { + label FreeMode + callback {reinit(); + +freeedit->lastpoint=-1; +freeedit->redraw();} + tooltip {Enable or disable the freemode} xywh {10 155 95 25} box PLASTIC_UP_BOX + } + Fl_Check_Button {} { + label frcR + callback {env->Pforcedrelase=(int)o->value();} + tooltip {Forced Relase} xywh {410 165 40 15} down_box DOWN_BOX labelsize 11 + code0 {o->value(env->Pforcedrelase);} + code1 {if (env->Pfreemode==0) o->hide();} + } + Fl_Dial {} { + label {Str.} + callback {env->Penvstretch=(int)o->value();} + tooltip {Envelope stretch (on lower notes make the envelope longer)} xywh {380 155 25 25} box ROUND_UP_BOX labelsize 11 align 4 maximum 127 step 1 + code0 {o->value(env->Penvstretch);} + code1 {if (env->Pfreemode==0) o->hide();} + class WidgetPDial + } + Fl_Button {} { + label Close + callback {freemodeeditwindow->hide();} + xywh {510 155 60 25} box THIN_UP_BOX + } + Fl_Check_Button {} { + label L + callback {env->Plinearenvelope=(int)o->value();} + tooltip {Linear Envelope} xywh {410 151 30 15} down_box DOWN_BOX labelsize 11 + code0 {o->value(env->Plinearenvelope);} + code1 {if (env->Pfreemode==0) o->hide();} + code2 {if (env->Envmode>2) o->hide();} + } + Fl_Counter sustaincounter { + label Sust + callback {env->Penvsustain=(int) o->value(); +freeedit->redraw(); +envfree->redraw();} + tooltip {Sustain (0 is disabled)} xywh {315 155 40 15} type Simple labelsize 12 align 4 minimum 0 maximum 127 step 1 + code0 {o->value(env->Penvsustain);} + code1 {if (env->Pfreemode==0) o->hide();} + code2 {o->maximum(env->Penvpoints-2);} + } + } + } + Function {make_ADSR_window()} {} { + Fl_Window envADSR { + xywh {440 55 205 70} color 50 labelfont 1 hide + class Fl_Group + } { + Fl_Group {} { + label {Amplitude Envelope} + xywh {0 0 205 70} box PLASTIC_UP_BOX color 223 labeltype ENGRAVED_LABEL labelsize 11 align 17 + } { + Fl_Dial {} { + label {A.dt} + callback {env->PA_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Attack time} xywh {5 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {D.dt} + callback {env->PD_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Decay time} xywh {40 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PD_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {R.dt} + callback {env->PR_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Release time} xywh {110 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {S.val} + callback {env->PS_val=(int)o->value(); +freeedit->redraw();} + tooltip {Sustain value} xywh {75 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PS_val);} + class WidgetPDial + } + Fl_Check_Button {} { + label frcR + callback {env->Pforcedrelase=(int)o->value();} + tooltip {Forced Relase} xywh {180 35 20 15} down_box DOWN_BOX labelsize 11 align 6 + code0 {o->value(env->Pforcedrelase);} + } + Fl_Dial {} { + label Stretch + callback {env->Penvstretch=(int)o->value();} + tooltip {Envelope stretch (on lower notes makes the envelope longer)} xywh {145 25 25 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->Penvstretch);} + class WidgetPDial + } + Fl_Button {} { + label Edit + callback {freemodeeditwindow->show();} + tooltip {Envelope window} xywh {160 5 40 15} box PLASTIC_UP_BOX labelfont 1 labelsize 10 + } + Fl_Check_Button {} { + label L + callback {env->Plinearenvelope=(int)o->value();} + tooltip {The evelope is linear} xywh {180 20 15 15} down_box DOWN_BOX labelsize 11 align 4 + code0 {o->value(env->Plinearenvelope);} + } + } + } + } + Function {make_ASR_window()} {} { + Fl_Window envASR { + xywh {433 172 210 70} hide + class Fl_Group + } { + Fl_Group {} { + label {Frequency Envelope} + xywh {0 0 210 70} box PLASTIC_UP_BOX color 223 labeltype ENGRAVED_LABEL labelsize 11 align 17 + } { + Fl_Dial {} { + label {A.val} + callback {env->PA_val=(int)o->value(); +freeedit->redraw();} + tooltip {Starting value} xywh {5 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_val);} + class WidgetPDial + } + Fl_Dial {} { + label {A.dt} + callback {env->PA_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Attack time} xywh {40 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {R.val} + callback {env->PR_val=(int)o->value(); +freeedit->redraw();} + tooltip {Release value} xywh {110 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_val);} + class WidgetPDial + } + Fl_Dial {} { + label {R.dt} + callback {env->PR_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Release time} xywh {75 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_dt);} + class WidgetPDial + } + Fl_Dial {} { + label Stretch + callback {env->Penvstretch=(int)o->value();} + tooltip {Envelope stretch (on lower notes makes the envelope longer)} xywh {145 25 25 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->Penvstretch);} + class WidgetPDial + } + Fl_Check_Button {} { + label frcR + callback {env->Pforcedrelase=(int)o->value();} + tooltip {Forced release} xywh {180 25 15 25} down_box DOWN_BOX labelsize 11 align 6 + code0 {o->value(env->Pforcedrelase);} + } + } + Fl_Button {} { + label Edit + callback {freemodeeditwindow->show();} + tooltip {Envelope window} xywh {165 5 40 15} box PLASTIC_UP_BOX labelfont 1 labelsize 10 + } + } + } + Function {make_ADSRfilter_window()} {} { + Fl_Window envADSRfilter { + xywh {406 296 275 70} color 50 labelfont 1 hide + class Fl_Group + } { + Fl_Group {} { + label {Filter Envelope} selected + xywh {0 0 275 70} box PLASTIC_UP_BOX color 223 labeltype ENGRAVED_LABEL labelsize 11 align 17 + } { + Fl_Dial {} { + label {A.val} + callback {env->PA_val=(int)o->value(); +freeedit->redraw();} + tooltip {Starting value} xywh {5 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_val);} + class WidgetPDial + } + Fl_Dial {} { + label {A.dt} + callback {env->PA_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Attack time} xywh {40 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {D.val} + callback {env->PD_val=(int)o->value(); +freeedit->redraw();} + tooltip {decay value} xywh {75 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PD_val);} + class WidgetPDial + } + Fl_Dial {} { + label {D.dt} + callback {env->PD_dt=(int)o->value(); +freeedit->redraw();} + tooltip {decay time} xywh {110 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PD_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {R.dt} + callback {env->PR_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Release time} xywh {145 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {R.val} + callback {env->PR_val=(int)o->value(); +freeedit->redraw();} + tooltip {Release value} xywh {180 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_val);} + class WidgetPDial + } + Fl_Dial {} { + label Stretch + callback {env->Penvstretch=(int)o->value();} + tooltip {Envelope stretch (on lower notes makes the envelope longer)} xywh {215 25 25 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->Penvstretch);} + class WidgetPDial + } + Fl_Check_Button {} { + label frcR + callback {env->Pforcedrelase=(int)o->value();} + tooltip {Forced Relase} xywh {250 30 15 20} down_box DOWN_BOX labelsize 11 align 6 + code0 {o->value(env->Pforcedrelase);} + } + Fl_Button {} { + label Edit + callback {freemodeeditwindow->show();} + xywh {230 5 40 15} box PLASTIC_UP_BOX labelfont 1 labelsize 10 + } + } + } + } + Function {make_ASRbw_window()} {} { + Fl_Window envASRbw { + xywh {431 279 210 70} hide + class Fl_Group + } { + Fl_Group {} { + label {BandWidth Envelope} + xywh {0 0 210 70} box PLASTIC_UP_BOX color 223 labeltype ENGRAVED_LABEL labelsize 11 align 17 + } { + Fl_Dial {} { + label {A.val} + callback {env->PA_val=(int)o->value(); +freeedit->redraw();} + tooltip {Starting value} xywh {5 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_val);} + class WidgetPDial + } + Fl_Dial {} { + label {A.dt} + callback {env->PA_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Attack time} xywh {40 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PA_dt);} + class WidgetPDial + } + Fl_Dial {} { + label {R.val} + callback {env->PR_val=(int)o->value(); +freeedit->redraw();} + tooltip {Release value} xywh {110 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_val);} + class WidgetPDial + } + Fl_Dial {} { + label {R.dt} + callback {env->PR_dt=(int)o->value(); +freeedit->redraw();} + tooltip {Release time} xywh {75 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->PR_dt);} + class WidgetPDial + } + Fl_Dial {} { + label Stretch + callback {env->Penvstretch=(int)o->value();} + tooltip {Envelope stretch (on lower notes makes the envelope longer)} xywh {145 25 25 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(env->Penvstretch);} + class WidgetPDial + } + Fl_Check_Button {} { + label frcR + callback {env->Pforcedrelase=(int)o->value();} + tooltip {Forced release} xywh {180 25 15 25} down_box DOWN_BOX labelsize 11 align 6 + code0 {o->value(env->Pforcedrelase);} + } + } + Fl_Button {} { + label Edit + callback {freemodeeditwindow->show();} + xywh {165 5 40 15} box PLASTIC_UP_BOX labelfont 1 labelsize 10 + } + } + } + Function {make_free_window()} {} { + Fl_Window envfree { + xywh {289 383 205 70} color 50 labelfont 1 hide resizable + class Fl_Group + } { + Fl_Group envfreegroup { + label {Amplitude Envelope} + xywh {0 0 205 70} box PLASTIC_UP_BOX color 223 labeltype ENGRAVED_LABEL labelsize 11 align 17 resizable + } { + Fl_Box freeeditsmall { + label Envelope + callback {envfree->redraw();} + xywh {5 20 195 45} box FLAT_BOX color 0 resizable + code0 {o->init(env);} + class EnvelopeFreeEdit + } + Fl_Button {} { + label Edit + callback {freemodeeditwindow->show();} + xywh {160 5 40 15} box PLASTIC_UP_BOX labelfont 1 labelsize 10 + } + } + } + } + Function {init(EnvelopeParams *env_)} {} { + code {env=env_; + +if (env->Pfreemode==0){ + switch(env->Envmode){ + case(1): + case(2): + make_ADSR_window(); + envwindow=envADSR; + break; + case(3): + make_ASR_window(); + envwindow=envASR; + break; + case(4): + make_ADSRfilter_window(); + envwindow=envADSRfilter; + break; + case(5): + make_ASRbw_window(); + envwindow=envASRbw; + break; + default: + break; + }; +}else{ + make_free_window(); + envwindow=envfree; + if (env->Envmode==3) envfreegroup->label("Frequency Envelope"); + if (env->Envmode==4) envfreegroup->label("Filter Envelope"); + if (env->Envmode==5) envfreegroup->label("Bandwidth Envelope"); +}; +end(); + +envwindow->resize(this->x(),this->y(),this->w(),this->h()); + +make_freemode_edit_window(); +freemodeeditwindow->label(this->label()); + +if (env->Pfreemode!=0){ + freeeditsmall->setpair(freeedit); + freeedit->setpair(freeeditsmall); +};} {} + } + Function {reinit()} {} { + code {if (env->Pfreemode!=0){ + int answer=fl_ask("Disable the free mode of the Envelope?"); + if (env->Pfreemode!=0) freemodebutton->value(1); + else freemodebutton->value(0); + if (answer==0) return; +}; + +if (env->Pfreemode==0) env->Pfreemode=1; + else env->Pfreemode=0; + +hide(); +int winx=freemodeeditwindow->x(); +int winy=freemodeeditwindow->y(); + +freemodeeditwindow->hide(); +delete (freemodeeditwindow); +envwindow->hide(); +Fl_Group *par=envwindow->parent(); +par->hide(); +par->remove(envwindow); +delete (envwindow); + + +init(env); +par->add(envwindow); +par->end(); +envwindow->show(); +par->redraw(); + +par->show(); +show(); +freemodeeditwindow->position(winx,winy); +freemodeeditwindow->show(); + +if (env->Pfreemode!=0) freemodebutton->value(1); + else freemodebutton->value(0);} {} + } + decl {EnvelopeParams *env;} {} + decl {Fl_Group *envwindow;} {} +} diff --git a/src/UI/FilterUI.fl b/src/UI/FilterUI.fl @@ -0,0 +1,547 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include <FL/Fl_Group.H>} {public +} + +decl {\#include "../Params/FilterParams.h"} {public +} + +decl {\#include <FL/Fl_Box.H>} {public +} + +decl {\#include <FL/fl_draw.H>} {public +} + +decl {\#include <FL/fl_ask.H>} {public +} + +class FormantFilterGraph {: {public Fl_Box} +} { + Function {FormantFilterGraph(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {pars=NULL; +nvowel=NULL; +nformant=NULL; +graphpoints=NULL;} {} + } + Function {init(FilterParams *pars_,int *nvowel_,int *nformant_)} {} { + code {pars=pars_; +nvowel=nvowel_; +nformant=nformant_; +oldx=-1; +graphpoints=new REALTYPE [w()];} {} + } + Function {draw_freq_line(REALTYPE freq,int type)} {} { + code {REALTYPE freqx=pars->getfreqpos(freq); +switch(type){ + case 0:fl_line_style(FL_SOLID);break; + case 1:fl_line_style(FL_DOT);break; + case 2:fl_line_style(FL_DASH);break; +}; + + +if ((freqx>0.0)&&(freqx<1.0)) + fl_line(x()+(int) (freqx*w()),y(), + x()+(int) (freqx*w()),y()+h());} {} + } + Function {draw()} {open + } { + code {int maxdB=30; +int ox=x(),oy=y(),lx=w(),ly=h(),i,ix,iy,oiy; +REALTYPE freqx; + +fl_color(FL_BLACK); +fl_rectf(ox,oy,lx,ly); + + +//draw the lines +fl_color(FL_GRAY); + +fl_line_style(FL_SOLID); +//fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); + +freqx=pars->getfreqpos(1000.0); +if ((freqx>0.0)&&(freqx<1.0)) + fl_line(ox+(int) (freqx*lx),oy, + ox+(int) (freqx*lx),oy+ly); + +for (i=1;i<10;i++){ + if(i==1){ + draw_freq_line(i*100.0,0); + draw_freq_line(i*1000.0,0); + }else + if (i==5){ + draw_freq_line(i*100.0,2); + draw_freq_line(i*1000.0,2); + }else{ + draw_freq_line(i*100.0,1); + draw_freq_line(i*1000.0,1); + }; +}; + +draw_freq_line(10000.0,0); +draw_freq_line(20000.0,1); + +fl_line_style(FL_DOT); +int GY=10;if (ly<GY*3) GY=-1; +for (i=1;i<GY;i++){ + int tmp=(int)(ly/(REALTYPE)GY*i); + fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); +}; + +fl_color(FL_YELLOW); +fl_font(FL_HELVETICA,10); +if (*nformant<pars->Pnumformants){ + draw_freq_line(pars->getformantfreq(pars->Pvowels[*nvowel].formants[*nformant].freq),2); + +//show some information (like current formant frequency,amplitude) + char tmpstr[20]; + + snprintf(tmpstr,20,"%.2f kHz",pars->getformantfreq(pars->Pvowels[*nvowel].formants[*nformant].freq)*0.001); + fl_draw(tmpstr,ox+1,oy+1,40,12,FL_ALIGN_LEFT,NULL,0); + + snprintf(tmpstr,20,"%d dB",(int)( rap2dB(1e-9 + pars->getformantamp(pars->Pvowels[*nvowel].formants[*nformant].amp)) + pars->getgain() )); + fl_draw(tmpstr,ox+1,oy+15,40,12,FL_ALIGN_LEFT,NULL,0); + +}; + +//draw the data + +fl_color(FL_RED); +fl_line_style(FL_SOLID); + +pars->formantfilterH(*nvowel,lx,graphpoints); + +oiy=(int) ((graphpoints[0]/maxdB+1.0)*ly/2.0); +for (i=1;i<lx;i++){ + int iy=(int) ((graphpoints[i]/maxdB+1.0)*ly/2.0); + if ((iy>=0)&&(oiy>=0)&&(iy<ly)&&(oiy<lx)) + fl_line(ox+i-1,oy+ly-oiy,ox+i,oy+ly-iy); + oiy=iy; +};} {} + } + Function {~FormantFilterGraph()} {} { + code {delete(graphpoints);} {} + } + decl {FilterParams *pars;} {} + decl {int oldx,oldy;} {} + decl {int *nvowel,*nformant;} {} + decl {REALTYPE *graphpoints;} {} +} + +class FilterUI {: {public Fl_Group} +} { + Function {FilterUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {pars=NULL; +velsnsamp=NULL; +velsns=NULL; +nvowel=0;nformant=0;nseqpos=0;} {} + } + Function {~FilterUI()} {} { + code {filterui->hide(); +formantparswindow->hide(); +hide(); +delete (filterui); +delete (formantparswindow);} {} + } + Function {make_window()} {} { + Fl_Window filterui { + xywh {365 269 275 75} color 50 labelfont 1 + class Fl_Group visible + } { + Fl_Group filterparamswindow { + label {Filter Parameters} + xywh {0 0 275 75} box PLASTIC_UP_BOX color 183 labeltype ENGRAVED_LABEL labelsize 11 align 17 + } { + Fl_Choice analogfiltertypechoice { + label FilterType + callback {pars->Ptype=(int)o->value();} + tooltip {The Filter type} xywh {10 50 50 15} down_box BORDER_BOX labelsize 10 align 5 textsize 10 + code1 {o->value(pars->Ptype);} + } { + menuitem {} { + label LPF1 + xywh {40 40 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HPF1 + xywh {50 50 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LPF2 + xywh {60 60 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HPF2 + xywh {70 70 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label BPF2 + xywh {82 82 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label NF2 + xywh {94 94 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label PkF2 + xywh {104 104 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label LSh2 + xywh {114 114 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label HSh2 + xywh {124 124 100 20} labelfont 1 labelsize 10 + } + } + Fl_Choice svfiltertypechoice { + label FilterType + callback {pars->Ptype=(int)o->value();} + tooltip {The Filter type} xywh {10 50 50 15} down_box BORDER_BOX labelsize 10 align 5 textsize 10 + code1 {o->value(pars->Ptype);} + } { + menuitem {} { + label 1LPF + xywh {134 134 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label 1HPF + xywh {144 144 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label 1BPF + xywh {154 154 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label 1NF + xywh {164 164 100 20} labelfont 1 labelsize 10 + } + } + Fl_Choice {} { + label Category + callback {switchcategory((int)o->value());} + tooltip {The Category of the Filter (Analog/Formantic/etc.)} xywh {10 20 60 15} down_box BORDER_BOX labelsize 10 align 5 textsize 10 + code0 {o->value(pars->Pcategory);} + } { + menuitem {} { + label Analog + xywh {50 50 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label Formant + xywh {60 60 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label StVarF + xywh {70 70 100 20} labelfont 1 labelsize 10 + } + } + Fl_Dial cfreqdial { + label {C.Freq} + callback {pars->Pfreq=(int)o->value();} + tooltip {Center Frequency of the Filter or the base position in the vowel's sequence} xywh {75 25 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pfreq);} + class WidgetPDial + } + Fl_Dial {} { + label Q + callback {pars->Pq=(int)o->value(); +formantfiltergraph->redraw();} + tooltip {Filter resonance or bandwidth} xywh {110 25 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pq);} + class WidgetPDial + } + Fl_Dial {} { + label {freq.tr.} + callback {pars->Pfreqtrack=(int) o->value();} + tooltip {Filter frequency tracking (left is negative, middle is 0, and right is positive)} xywh {215 25 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pfreqtrack);} + class WidgetPDial + } + Fl_Counter stcounter { + label {St.} + callback {pars->Pstages=(int)o->value(); +formantfiltergraph->redraw();} + tooltip {Additional filter stages (in order to increase dB/oct. value and the order of the filter)} xywh {225 5 40 15} type Simple labelsize 10 align 4 minimum 1 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(0,MAX_FILTER_STAGES-1);} + code1 {o->value(pars->Pstages);} + } + Fl_Dial vsnsadial { + label {V.SnsA.} + callback {if (velsnsamp!=NULL) *velsnsamp=(int)o->value();} + tooltip {Velocity sensing amount of the Filter} xywh {145 25 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + class WidgetPDial + } + Fl_Dial vsnsdial { + label {V.Sns.} + callback {if (velsns!=NULL) *velsns=(int)o->value();} + tooltip {Velocity Sensing Function of the Filter} xywh {180 25 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + class WidgetPDial + } + Fl_Dial gaindial { + label gain + callback {pars->Pgain=(int)o->value(); +formantfiltergraph->redraw();} + tooltip {Filter output gain/damp} xywh {250 35 20 20} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pgain);} + class WidgetPDial + } + } + Fl_Button editbutton { + label Edit + callback {formantparswindow->show();} + xywh {15 40 50 25} box PLASTIC_UP_BOX labelfont 1 labelsize 12 + } + } + } + Function {make_formant_window()} {} { + Fl_Window formantparswindow { + label {Formant Filter Parameters} + xywh {41 226 710 205} hide + } { + Fl_Group {} { + xywh {485 47 105 113} box THIN_UP_BOX + } { + Fl_Counter {} { + label {Formant } + callback {nformant=(int) o->value(); +update_formant_window(); +formantfiltergraph->redraw();} + xywh {545 80 40 15} type Simple labelfont 1 labelsize 10 align 4 minimum 0 maximum 127 step 1 textsize 10 + code0 {o->bounds(0,FF_MAX_FORMANTS-1);} + code1 {o->value(nformant);} + } + Fl_Counter {} { + label {Vowel no.} + callback {nvowel=(int) o->value(); +update_formant_window(); +formantfiltergraph->redraw();} + xywh {545 55 40 20} type Simple labelfont 1 labelsize 10 align 4 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(0,FF_MAX_VOWELS-1);} + code1 {o->value(nvowel);} + } + Fl_Group formantparsgroup { + xywh {490 105 95 50} box ENGRAVED_FRAME + } { + Fl_Dial formant_freq_dial { + label freq + callback {pars->Pvowels[nvowel].formants[nformant].freq=(int) o->value(); +formantfiltergraph->redraw();} + tooltip {Formant frequency} xywh {495 115 25 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + class WidgetPDial + } + Fl_Dial formant_q_dial { + label Q + callback {pars->Pvowels[nvowel].formants[nformant].q=(int) o->value(); +formantfiltergraph->redraw();} + tooltip {Formant's Q} xywh {525 115 24 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + class WidgetPDial + } + Fl_Dial formant_amp_dial { + label amp + callback {pars->Pvowels[nvowel].formants[nformant].amp=(int) o->value(); +formantfiltergraph->redraw();} + tooltip {Formant amplitude} xywh {555 115 24 25} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + class WidgetPDial + } + } + } + Fl_Group {} { + xywh {590 47 100 113} box THIN_UP_BOX + } { + Fl_Counter {} { + label {Seq.Size} + callback {pars->Psequencesize=(int) o->value(); +update_formant_window();} + xywh {595 62 55 20} type Simple labelfont 1 labelsize 10 align 5 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(1,FF_MAX_SEQUENCE-1);} + code1 {o->value(pars->Psequencesize);} + } + Fl_Counter {} { + label {S.Pos.} + callback {nseqpos=(int) o->value(); +update_formant_window();} + tooltip {Current position from the sequence} xywh {595 97 40 15} type Simple labelfont 1 labelsize 10 align 9 minimum 0 maximum 127 step 1 textsize 10 + code0 {o->bounds(0,FF_MAX_SEQUENCE-2);} + code1 {o->value(nseqpos);} + } + Fl_Counter vowel_counter { + label Vowel + callback {pars->Psequence[nseqpos].nvowel=(int) o->value();} + xywh {640 97 40 15} type Simple labelsize 10 align 1 minimum 0 maximum 127 step 1 textsize 11 + code0 {o->bounds(0,FF_MAX_VOWELS-1);} + } + Fl_Check_Button {} { + label {Neg.Input} + callback {pars->Psequencereversed=(int) o->value();} + tooltip {Negate the input from LFO/envelopes/etc.} xywh {625 132 60 20} down_box DOWN_BOX labelsize 10 + code0 {o->value(pars->Psequencereversed);} + } + Fl_Dial {} { + label Strch + callback {pars->Psequencestretch=(int) o->value();} + tooltip {Sequence Stretch} xywh {595 130 25 25} box ROUND_UP_BOX labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->Psequencestretch);} + class WidgetPDial + } + } + Fl_Counter {} { + label {Num.Formants} + callback {pars->Pnumformants=(int) o->value(); +update_formant_window(); + +formantfiltergraph->redraw();} + xywh {485 15 65 20} type Simple labelfont 1 labelsize 11 align 5 minimum 0 maximum 127 step 1 + code0 {o->bounds(1,FF_MAX_FORMANTS);} + code1 {o->value(pars->Pnumformants);} + } + Fl_Dial {} { + label {Fr.Sl.} + callback {pars->Pformantslowness=(int) o->value();} + tooltip {Formant's Slowness (Morphing)} xywh {565 15 25 25} box ROUND_UP_BOX labelfont 1 labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->Pformantslowness);} + class WidgetPDial + } + Fl_Value_Output centerfreqvo { + label {C.f.} + callback {o->value(pars->getcenterfreq()/1000.0);} + tooltip {Center Frequency (kHz)} xywh {515 164 33 18} when 3 minimum 1 maximum 10 step 0.01 value 1 textfont 1 + code0 {o->value(pars->getcenterfreq()/1000.0);} + } + Fl_Value_Output octavesfreqvo { + label {Oct.} + callback {o->value(pars->getoctavesfreq());} + tooltip {No. of octaves} xywh {515 182 33 18} when 3 minimum 1 maximum 127 step 1 value 5 textfont 1 + code0 {o->value(pars->getoctavesfreq());} + } + Fl_Slider {} { + callback {pars->Pcenterfreq=(int)o->value(); +centerfreqvo->do_callback(); +formantfiltergraph->redraw();} + xywh {551 167 84 15} type {Horz Knob} box FLAT_BOX maximum 127 + code0 {o->value(pars->Pcenterfreq);} + } + Fl_Slider {} { + callback {pars->Poctavesfreq=(int)o->value(); +octavesfreqvo->do_callback(); +formantfiltergraph->redraw();} + xywh {551 185 84 15} type {Horz Knob} box FLAT_BOX maximum 127 + code0 {o->value(pars->Poctavesfreq);} + } + Fl_Box formantfiltergraph { + xywh {5 5 475 195} box BORDER_BOX + code0 {o->init(pars,&nvowel,&nformant);} + class FormantFilterGraph + } + Fl_Dial {} { + label {Vw.Cl.} + callback {pars->Pvowelclearness=(int) o->value();} + tooltip {Vowel "clearness" (how the mixed vowels are avoided)} xywh {600 15 25 25} box ROUND_UP_BOX labelfont 1 labelsize 11 align 1 maximum 127 step 1 + code0 {o->value(pars->Pvowelclearness);} + class WidgetPDial + } + Fl_Button {} { + label Close + callback {formantparswindow->hide();} + xywh {645 180 60 25} box THIN_UP_BOX + } + } + } + Function {update_formant_window()} {} { + code {formant_freq_dial->value(pars->Pvowels[nvowel].formants[nformant].freq); +formant_q_dial->value(pars->Pvowels[nvowel].formants[nformant].q); +formant_amp_dial->value(pars->Pvowels[nvowel].formants[nformant].amp); +if (nformant<pars->Pnumformants) formantparsgroup->activate(); + else formantparsgroup->deactivate(); + +if (nseqpos<pars->Psequencesize) vowel_counter->activate(); + else vowel_counter->deactivate(); + + +vowel_counter->value(pars->Psequence[nseqpos].nvowel);} {} + } + Function {init(FilterParams *filterpars_,unsigned char *velsnsamp_,unsigned char *velsns_)} {} { + code {pars=filterpars_; +velsnsamp=velsnsamp_; +velsns=velsns_; + +make_window(); +end(); +make_formant_window(); + + +filterui->resize(this->x(),this->y(),this->w(),this->h()); + + +if (velsnsamp==NULL){ + vsnsadial->deactivate(); + vsnsadial->value(127); + } else vsnsadial->value(*velsnsamp); + +if (velsns==NULL){ + vsnsdial->deactivate(); + vsnsdial->value(127); + } else vsnsdial->value(*velsns); + +switchcategory(pars->Pcategory); + + +formantparswindow->label(this->label()); + +update_formant_window();} {} + } + Function {switchcategory(int newcat)} {} { + code {if (pars->Pcategory!=newcat){ + pars->Pgain=64; + gaindial->value(64); + analogfiltertypechoice->value(0); + analogfiltertypechoice->do_callback(); + svfiltertypechoice->value(0); + svfiltertypechoice->do_callback(); +}; +pars->Pcategory=newcat; + +if ((newcat==0)||(newcat==2)) { + if (newcat==0) { + analogfiltertypechoice->show(); + svfiltertypechoice->hide(); + } else { + svfiltertypechoice->show(); + analogfiltertypechoice->hide(); + }; + editbutton->hide(); + formantparswindow->hide(); + cfreqdial->label("C.freq"); +} else { + analogfiltertypechoice->hide(); + svfiltertypechoice->hide(); + editbutton->show(); + cfreqdial->label("BS.pos"); +}; + +filterparamswindow->redraw();} {selected + } + } + decl {FilterParams *pars;} {} + decl {unsigned char *velsnsamp,*velsns;} {} + decl {int nvowel,nformant,nseqpos;} {} +} diff --git a/src/UI/LFOUI.fl b/src/UI/LFOUI.fl @@ -0,0 +1,146 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0103 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include <FL/Fl_Group.H>} {public +} + +decl {\#include "../Params/LFOParams.h"} {public +} + +decl {\#include <FL/Fl_Box.H>} {public +} + +decl {\#include <FL/fl_draw.H>} {public +} + +decl {\#include <FL/fl_ask.H>} {public +} + +class LFOUI {: {public Fl_Group} +} { + Function {LFOUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {pars=NULL;} {} + } + Function {~LFOUI()} {} { + code {lfoui->hide(); +hide(); +delete (lfoui);} {} + } + Function {make_window()} {} { + Fl_Window lfoui { + xywh {354 365 231 70} color 50 labelfont 1 hide + class Fl_Group + } { + Fl_Group lfoparamswindow { + label LFO + xywh {0 0 230 70} box PLASTIC_UP_BOX color 223 labeltype ENGRAVED_LABEL labelsize 11 align 17 + } { + Fl_Dial {} { + label {Freq.} + callback {pars->Pfreq=(int)o->value();} + tooltip {LFO Frequency} xywh {5 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pfreq);} + class WidgetPDial + } + Fl_Dial {} { + label Depth + callback {pars->Pintensity=(int)o->value();} + tooltip {LFO Amount} xywh {40 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pintensity);} + class WidgetPDial + } + Fl_Dial {} { + label Delay + callback {pars->Pdelay=(int)o->value();} + tooltip {LFO delay} xywh {110 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pdelay);} + class WidgetPDial + } + Fl_Dial {} { + label Start + callback {pars->Pstartphase=(int)o->value();} + tooltip {LFO Startphase (leftmost is Random)} xywh {75 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Pstartphase);} + class WidgetPDial + } + Fl_Dial {} { + label RND + callback {pars->Prandomness=(int)o->value();} + tooltip {LFO Randomness} xywh {145 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->Prandomness);} + class WidgetPDial + } + Fl_Choice {} { + label Type + callback {pars->PLFOtype=(int)o->value();} + tooltip {LFO function} xywh {180 35 45 15} down_box BORDER_BOX labelsize 10 align 2 textsize 8 + code0 {o->value(pars->PLFOtype);} + } { + menuitem {} { + label SINE + xywh {20 20 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label TRI + xywh {30 30 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label SQR + xywh {30 30 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {R.up} + xywh {40 40 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {R.dn} + xywh {50 50 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label E1dn + xywh {60 60 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label E2dn + xywh {70 70 100 20} labelfont 1 labelsize 10 + } + } + Fl_Check_Button {} { + label {Cnt.} + callback {pars->Pcontinous=(int)o->value();} + tooltip {Continous LFO} xywh {180 15 40 15} down_box DOWN_BOX labelsize 11 + code0 {o->value(pars->Pcontinous);} + } + } + } + } + Function {init(LFOParams *lfopars_)} {} { + code {pars=lfopars_; + +make_window(); +end(); + +lfoui->resize(this->x(),this->y(),this->w(),this->h()); + +lfoparamswindow->label(this->label());} {selected + } + } + decl {LFOParams *pars;} {} +} diff --git a/src/UI/Makefile b/src/UI/Makefile @@ -0,0 +1,36 @@ +include ../Makefile.inc + +%.cc : %.fl + fluid -c $< + +objects=WidgetPDial.o EnvelopeUI.o LFOUI.o FilterUI.o VirKeyboard.o ConfigUI.o\ + SUBnoteUI.o ResonanceUI.o ADnoteUI.o EffUI.o BankUI.o \ + PartUI.o MicrotonalUI.o SeqUI.o MasterUI.o + + +all: $(objects) + +WidgetPDial.o: WidgetPDial.fl WidgetPDial.cc WidgetPDial.h +EnvelopeUI.o: EnvelopeUI.fl EnvelopeUI.cc EnvelopeUI.h +LFOUI.o: LFOUI.fl LFOUI.cc LFOUI.h +FilterUI.o: FilterUI.fl FilterUI.cc FilterUI.h + +ResonanceUI.o: ResonanceUI.fl ResonanceUI.cc ResonanceUI.h +ADnoteUI.o:ADnoteUI.fl ADnoteUI.cc ADnoteUI.h +SUBnoteUI.o:SUBnoteUI.fl SUBnoteUI.cc SUBnoteUI.h + +EffUI.o: EffUI.fl EffUI.cc EffUI.h +BankUI.o: BankUI.fl BankUI.cc BankUI.h +PartUI.o: PartUI.fl PartUI.cc PartUI.h + +VirKeyboard.o: VirKeyboard.fl VirKeyboard.cc VirKeyboard.h +ConfigUI.o: ConfigUI.fl ConfigUI.cc ConfigUI.h +MicrotonalUI.o: MicrotonalUI.fl MicrotonalUI.cc MicrotonalUI.h +SeqUI.o: SeqUI.fl SeqUI.cc SeqUI.h +MasterUI.o: MasterUI.fl MasterUI.cc MasterUI.h + +.PHONY : clean +clean: + rm -f $(objects) + rm -f makeinclude.deps + rm -f *.h *.cc diff --git a/src/UI/MasterUI.fl b/src/UI/MasterUI.fl @@ -0,0 +1,1167 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <string.h>} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include "ADnoteUI.h"} {public +} + +decl {\#include "SUBnoteUI.h"} {public +} + +decl {\#include "EffUI.h"} {public +} + +decl {\#include "VirKeyboard.h"} {public +} + +decl {\#include "ConfigUI.h"} {public +} + +decl {\#include "BankUI.h"} {public +} + +decl {\#include "PartUI.h"} {public +} + +decl {\#include "MicrotonalUI.h"} {public +} + +decl {\#include "SeqUI.h"} {public +} + +decl {\#include "../Misc/Master.h"} {public +} + +decl {\#include "../Misc/Part.h"} {public +} + +decl {\#include "../Misc/Util.h"} {public +} + +decl {\#include "../globals.h"} {public +} + +class VUMeter {: {public Fl_Box} +} { + Function {VUMeter(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {master=NULL; +npart=-1;} {} + } + Function {init(Master *master_,int part_)} {} { + code {//the "part_" parameters sets the part (if it is >=0), else it sets the master +master=master_; +label(NULL); +npart=part_;} {} + } + Function {draw_master()} {} { + code {\#define MIN_DB (-48) +int ox=x(); int oy=y(); int lx=w(); int ly=h(); + +pthread_mutex_lock(&master->mutex); +REALTYPE dbl=rap2dB(master->vuoutpeakl); +REALTYPE dbr=rap2dB(master->vuoutpeakr); +REALTYPE maxdbl=rap2dB(master->vumaxoutpeakl); +REALTYPE maxdbr=rap2dB(master->vumaxoutpeakr); +int clipped=master->vuclipped; +pthread_mutex_unlock(&master->mutex); + +dbl=(MIN_DB-dbl)/MIN_DB; +if (dbl<0.0) dbl=0.0; + else if (dbl>1.0)dbl=1.0; + +dbr=(MIN_DB-dbr)/MIN_DB; +if (dbr<0.0) dbr=0.0; + else if (dbr>1.0) dbr=1.0; + +\#define VULENX (lx-35) +\#define VULENY (ly/2-3) + +dbl*=VULENX;dbr*=VULENX; + +int idbl=(int) dbl; +int idbr=(int) dbr; + +//draw the vu-meter lines +fl_rectf(ox,oy,idbr,VULENY,0,200,255); +fl_rectf(ox,oy+ly/2,idbl,VULENY,0,200,255); +fl_rectf(ox+idbr,oy,VULENX-idbr,VULENY,0,0,0); +fl_rectf(ox+idbl,oy+ly/2,VULENX-idbl,VULENY,0,0,0); + +//draw the scales +REALTYPE tmp=VULENX*1.0/MIN_DB; +for (int i=1;i<1-MIN_DB;i++){ + int tx=VULENX+(int) (tmp*i); + fl_rectf(ox+tx,oy,1,VULENY+ly/2,0,160,200); + if (i%5==0) fl_rectf(ox+tx,oy,1,VULENY+ly/2,0,230,240); + if (i%10==0) fl_rectf(ox+tx-1,oy,2,VULENY+ly/2,0,225,255); +}; + +//draw the red box if clipping has occured +if (clipped==0) fl_rectf(ox+VULENX+2,oy+1,lx-VULENX-3,ly-4,0,0,10); + else fl_rectf(ox+VULENX+2,oy+1,lx-VULENX-3,ly-4,250,10,10); + +//draw the maxdB +fl_font(FL_HELVETICA|FL_BOLD,10); +fl_color(255,255,255); +char tmpstr[10]; +if ((maxdbl>MIN_DB-20)){ + snprintf((char *)&tmpstr,10,"%ddB\\0",(int)maxdbr); + fl_draw(tmpstr,ox+VULENX+1,oy+1,lx-VULENX-1,VULENY,FL_ALIGN_RIGHT,NULL,0); +}; +if ((maxdbr>MIN_DB-20)){ + snprintf((char *)&tmpstr,10,"%ddB\\0",(int)maxdbl); + fl_draw(tmpstr,ox+VULENX+1,oy+ly/2+1,lx-VULENX-1,VULENY,FL_ALIGN_RIGHT,NULL,0); +};} {} + } + Function {draw_part()} {} { + code {\#define MIN_DB (-48) +int ox=x(); int oy=y(); int lx=w(); int ly=h(); + +if (!active_r()){ + pthread_mutex_lock(&master->mutex); + int fakedb=master->fakepeakpart[npart]; + pthread_mutex_unlock(&master->mutex); + fl_rectf(ox,oy,lx,ly,140,140,140); + if (fakedb>0){ + fakedb=(int)(fakedb/255.0*ly)+4; + fl_rectf(ox+2,oy+ly-fakedb,lx-4,fakedb,0,0,0); + }; + + return; +}; + +//draw the vu lines +pthread_mutex_lock(&master->mutex); + REALTYPE db=rap2dB(master->vuoutpeakpart[npart]); +pthread_mutex_unlock(&master->mutex); + +db=(MIN_DB-db)/MIN_DB; +if (db<0.0) db=0.0; + else if (db>1.0) db=1.0; + +db*=ly-2; + +int idb=(int) db; + +fl_rectf(ox,oy+ly-idb,lx,idb,0,200,255); +fl_rectf(ox,oy,lx,ly-idb,0,0,0); + + +//draw the scales +REALTYPE tmp=ly*1.0/MIN_DB; + for (int i=1;i<1-MIN_DB;i++){ + int ty=ly+(int) (tmp*i); + if (i%5==0) fl_rectf(ox,oy+ly-ty,lx,1,0,160,200); + if (i%10==0) fl_rectf(ox,oy+ly-ty,lx,1,0,230,240); +};} {} + } + Function {draw()} {} { + code {if (npart>=0) draw_part(); + else draw_master();} {} + } + Function {tickdraw(VUMeter *o)} {return_type {static void} + } { + code {o->redraw();} {} + } + Function {tick(void *v)} {return_type {static void} + } { + code {tickdraw((VUMeter *) v); +Fl::add_timeout(1.0/25.0,tick,v);//25 fps} {} + } + Function {handle(int event)} {return_type int + } { + code {switch(event){ + case FL_SHOW: + tick(this); + break; + case FL_HIDE: + Fl::remove_timeout(tick,this); + break; + case FL_PUSH: + if (npart>=0) break; + pthread_mutex_lock(&master->mutex); + master->vuresetpeaks(); + pthread_mutex_unlock(&master->mutex); + break; +}; +return(1);} {} + } + decl {Master *master;} {} + decl {int npart;} {} +} + +class SysEffSend {: {public WidgetPDial} +} { + Function {SysEffSend(int x,int y, int w, int h, const char *label=0):WidgetPDial(x,y,w,h,label)} {} { + code {master=NULL; +neff1=0; +neff2=0;} {} + } + Function {init(Master *master_,int neff1_,int neff2_)} {} { + code {neff1=neff1_; +neff2=neff2_; +master=master_; +minimum(0); +maximum(127); +step(1); +labelfont(1); +labelsize(10); +align(FL_ALIGN_TOP); + +value(master->Psysefxsend[neff1][neff2]); +char tmp[20];snprintf(tmp,20,"%d->%d",neff1,neff2);this->label(strdup(tmp));} {} + } + Function {~SysEffSend()} {} { + code {hide();} {} + } + Function {handle(int event)} {return_type int + } { + code {if ((event==FL_PUSH) || (event==FL_DRAG)){ + master->setPsysefxsend(neff1,neff2,(int) value()); +}; + +return(WidgetPDial::handle(event));} {} + } + decl {Master *master;} {} + decl {int neff1;} {} + decl {int neff2;} {} +} + +class Panellistitem {: {public Fl_Group} +} { + Function {make_window()} {private + } { + Fl_Window panellistitem { + private xywh {315 213 70 260} hide + class Fl_Group + } { + Fl_Group panellistitemgroup { + private xywh {0 20 70 240} box PLASTIC_THIN_UP_BOX + code0 {if (master->part[npart]->Penabled==0) o->deactivate();} + } { + Fl_Group {} { + xywh {45 65 15 110} box ENGRAVED_FRAME + } { + Fl_Box {} { + label {V U} + xywh {45 65 15 110} box FLAT_BOX color 0 selection_color 75 labelcolor 55 align 128 + code0 {o->init(master,npart);} + class VUMeter + } + } + Fl_Button partname { + label { } + callback {if ((int)bankui->cbwig->value()!=npart){ + bankui->cbwig->value(npart); + bankui->cbwig->do_callback(); +}; +bankui->show();} + xywh {5 27 60 30} box THIN_DOWN_BOX down_box FLAT_BOX labelfont 1 labelsize 10 align 208 + } + Fl_Slider partvolume { + callback {master->part[npart]->setPvolume((int) o->value());} + xywh {10 65 30 110} type {Vert Knob} box FLAT_BOX minimum 127 maximum 0 step 1 value 127 + code0 {o->value(master->part[npart]->Pvolume);} + } + Fl_Dial partpanning { + callback {master->part[npart]->setPpanning((int) o->value());} + xywh {20 180 30 30} maximum 127 step 1 + code0 {o->value(master->part[npart]->Ppanning);} + class WidgetPDial + } + Fl_Counter partrcv { + callback {master->part[npart]->Prcvchn=(int) o->value();} + xywh {15 215 40 15} type Simple minimum 0 maximum 16 step 1 + code0 {o->bounds(0,NUM_MIDI_CHANNELS-1);} + code1 {o->value(master->part[npart]->Prcvchn);} + } + Fl_Button {} { + label edit + callback {if ((int)bankui->cbwig->value()!=npart){ + bankui->cbwig->value(npart); + bankui->cbwig->do_callback(); +};} + xywh {15 235 40 20} box PLASTIC_UP_BOX labelsize 10 + } + } + Fl_Check_Button partenabled { + label 01 + callback {pthread_mutex_lock(&master->mutex); + master->partonoff(npart,(int) o->value()); +pthread_mutex_unlock(&master->mutex); + +if ((int) o->value()==0) panellistitemgroup->deactivate(); + else { + panellistitemgroup->activate(); + if ((int)bankui->cbwig->value()!=npart){ + bankui->cbwig->value(npart); + bankui->cbwig->do_callback(); + }; +}; + +o->redraw();} + private xywh {5 0 45 20} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 24 + code0 {char tmp[10];snprintf(tmp,10,"%d",npart);o->label(strdup(tmp));} + code1 {o->value(master->part[npart]->Penabled);} + } + } + } + Function {Panellistitem(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {npart=0; +master=NULL; +bankui=NULL;} {} + } + Function {init(Master *master_, int npart_,BankUI *bankui_)} {} { + code {npart=npart_; +master=master_; +bankui=bankui_; + +make_window(); +panellistitem->show(); +end();} {} + } + Function {refresh()} {} { + code {partenabled->value(master->part[npart]->Penabled); +if (master->part[npart]->Penabled!=0) panellistitemgroup->activate(); + else panellistitemgroup->deactivate(); + +partvolume->value(master->part[npart]->Pvolume); +partpanning->value(master->part[npart]->Ppanning); +partrcv->value(master->part[npart]->Prcvchn); + +partname->label((char *)master->part[npart]->Pname); + +if ((int)bankui->cbwig->value()!=npart) + panellistitemgroup->color(fl_rgb_color(160,160,160)); +else + panellistitemgroup->color(fl_rgb_color(50,190,240)); + +panellistitemgroup->redraw();} {} + } + Function {~Panellistitem()} {} { + code {panellistitem->hide(); +delete(panellistitem);} {} + } + decl {int npart;} {} + decl {Master *master;} {} + decl {BankUI *bankui;} {} +} + +class MasterUI {} { + Function {make_window()} {} { + Fl_Window masterwindow { + label zynaddsubfx + callback {\#ifdef VSTAUDIOOUT +fl_alert("ZynAddSubFX could not be closed this way, because it's a VST plugin. Please use the host aplication to close it."); +\#else +if (fl_ask("Exit and leave the unsaved data?")) *exitprogram=1; +\#endif} + xywh {149 197 390 465} hide + code0 {setfilelabel(NULL);} non_modal + } { + Fl_Menu_Bar mastermenu { + xywh {0 0 690 25} + } { + submenu {} { + label {&File} + xywh {0 0 100 20} + } { + menuitem {} { + label {&New Master...} + callback {if (fl_ask("Clear *ALL* the parameters ?")){ + delete microtonalui; + + pthread_mutex_lock(&master->mutex); + masterdefaultsbuf.changemode(0); + master->saveloadbuf(&masterdefaultsbuf); + master->microtonal.reset(); + pthread_mutex_unlock(&master->mutex); + + npartcounter->do_callback(); + syseffnocounter->do_callback(); + inseffnocounter->do_callback(); + masterkeyshiftcounter->value(master->Pkeyshift-64); + mastervolumedial->value(master->Pvolume); + globalfinedetuneslider->value(master->microtonal.Pglobalfinedetune); + microtonalui=new MicrotonalUI(&master->microtonal); + updatesendwindow(); + setfilelabel(NULL); +}; + +updatepanel();} + xywh {20 20 100 20} + } + menuitem {} { + label {&Open Master...} + callback {const char *filename; +filename=fl_file_chooser("Open:","(*.mas_zyn)",NULL,0); +if (filename==NULL) return; +int result=loadbufferfile(&slbuf,filename,0); +if (result==0) { + setfilelabel(filename); + slbuf.changemode(0); + delete microtonalui; + pthread_mutex_lock(&master->mutex); + + //clear all parameters, first + masterdefaultsbuf.changemode(0); + master->saveloadbuf(&masterdefaultsbuf); + master->part[0]->Penabled=0; + //load the data + master->saveloadbuf(&slbuf); + pthread_mutex_unlock(&master->mutex); + npartcounter->do_callback(); + syseffnocounter->do_callback(); + inseffnocounter->do_callback(); + masterkeyshiftcounter->value(master->Pkeyshift-64); + mastervolumedial->value(master->Pvolume); + globalfinedetuneslider->value(master->microtonal.Pglobalfinedetune); + microtonalui=new MicrotonalUI(&master->microtonal); + nrpnbutton->value(master->ctl.NRPN.receive); + updatesendwindow(); +} else { + if (result==4) fl_alert("Error: Could not load the file\\nbecause it is not a master file."); + else fl_alert("Error: Could not load the file."); +}; +updatepanel();} + xywh {10 10 100 20} + } + menuitem {} { + label {&Save Master As...} + callback {char *filename; +\#define EXT ".mas_zyn" +filename=fl_file_chooser("Save:","(*"EXT")",NULL,0); +if (filename==NULL) return; +filename=fl_filename_setext(filename,EXT); +\#undef EXT +slbuf.changemode(1); +slbuf.changeminimal(1);//MINIMAL +pthread_mutex_lock(&master->mutex); +master->saveloadbuf(&slbuf); +pthread_mutex_unlock(&master->mutex); +int result=savebufferfile(&slbuf,filename,0,0); +if (result==1) { + result=0; + if (fl_ask("The file exists. \\nOverwrite it?")) + result=savebufferfile(&slbuf,filename,1,0); +}; +if (result!=0) fl_alert("Error: Could not save the file."); + else setfilelabel(filename); + + +updatepanel();} + xywh {0 0 100 20} divider + } + menuitem {} { + label {&Load Scale Settings...} + callback {const char *filename; +filename=fl_file_chooser("Load:","(*.scl_zyn)",NULL,0); +if (filename==NULL) return; +int result=loadbufferfile(&slbuf,filename,2); +if (result==0) { + delete microtonalui; + + slbuf.changemode(0); + pthread_mutex_lock(&master->mutex); + master->microtonal.reset(); + master->microtonal.saveloadbuf(&slbuf); + pthread_mutex_unlock(&master->mutex); + + microtonalui=new MicrotonalUI(&master->microtonal); + + } else { + if (result==4) fl_alert("Error: Could not load the file\\nbecause it is not a scale file."); + else fl_alert("Error: Could not load the file."); + };} + xywh {35 35 100 20} + } + menuitem {} { + label {Save Scale Settings &As...} + callback {char *filename; +\#define EXT ".scl_zyn" +filename=fl_file_chooser("Save:","(*"EXT")",NULL,0); +if (filename==NULL) return; +filename=fl_filename_setext(filename,EXT); +\#undef EXT +slbuf.changemode(1); +slbuf.changeminimal(1);//MINIMAL +master->microtonal.saveloadbuf(&slbuf); +int result=savebufferfile(&slbuf,filename,0,2); +if (result==1) { + result=0; + if (fl_ask("The file exists. \\nOverwrite it?")) + result=savebufferfile(&slbuf,filename,1,2); +}; +if (result!=0) fl_alert("Error: Could not save the file.");} + xywh {25 25 100 20} + } + menuitem {} { + label {Show Scale Settings...} + callback {microtonalui->show();} + xywh {0 0 100 20} divider + } + menuitem {} { + label {&Settings...} + callback {configui->show();} + xywh {25 25 100 20} divider + } + menuitem {} { + label {&Copyright...} + callback {aboutwindow->show();} + xywh {15 15 100 20} divider + } + menuitem {} { + label {E&xit} + callback {masterwindow->do_callback();} + xywh {10 10 100 20} + } + } + submenu {} { + label {&Instrument} + xywh {10 10 100 20} + } { + menuitem {} { + label {&New Instrument...} + callback {if (fl_ask("Clear instrument's parameters ?")){ + int npart=(int)npartcounter->value(); + pthread_mutex_lock(&master->mutex); + instrumentdefaultsbuf.changemode(0); + master->part[npart]->disablekitloading=0; + master->part[npart]->saveloadbuf(&instrumentdefaultsbuf,1); + pthread_mutex_unlock(&master->mutex); + + npartcounter->do_callback(); +}; + +updatepanel();} + xywh {35 35 100 20} + } + menuitem {} { + label {&Load Instrument...} + callback {const char *filename; +filename=fl_file_chooser("Load:","(*.ins_zyn)",NULL,0); +if (filename==NULL) return; +int result=loadbufferfile(&slbuf,filename,1); +if (result==0) { + slbuf.changemode(0); + pthread_mutex_lock(&master->mutex); + int npart=(int)npartcounter->value(); + + //clear all instrument parameters, first + instrumentdefaultsbuf.changemode(0); + master->part[npart]->saveloadbuf(&instrumentdefaultsbuf,1); + //load the instr. parameters + master->part[npart]->saveloadbuf(&slbuf,1); + pthread_mutex_unlock(&master->mutex); + npartcounter->do_callback(); + } else { + if (result==4) fl_alert("Error: Could not load the file\\nbecause it is not an instrument file."); + else fl_alert("Error: Could not load the file."); + }; + +updatepanel();} + xywh {20 20 100 20} + } + menuitem {} { + label {&Save Instrument As...} + callback {char *filename; +\#define EXT ".ins_zyn" +filename=fl_file_chooser("Save:","(*"EXT")",NULL,0); +if (filename==NULL) return; +filename=fl_filename_setext(filename,EXT); +\#undef EXT +slbuf.changemode(1); +slbuf.changeminimal(1);//MINIMAL +int npart=(int)npartcounter->value(); +pthread_mutex_lock(&master->mutex); +master->part[npart]->saveloadbuf(&slbuf,1); +pthread_mutex_unlock(&master->mutex); +int result=savebufferfile(&slbuf,filename,0,1); +if (result==1) { + result=0; + if (fl_ask("The file exists. \\nOverwrite it?")) + result=savebufferfile(&slbuf,filename,1,1); +}; +if (result!=0) fl_alert("Error: Could not save the file."); + + +updatepanel();} + xywh {10 10 100 20} divider + } + menuitem {} { + label {Instrument Info...} + callback {partui->infowin->show();} + xywh {45 45 100 20} divider + } + menuitem {} { + label {Show Instr. &Bank...} + callback {bankui->show();} + xywh {0 0 100 20} divider + } + menuitem {} { + label {&Virtual Keyboard...} + callback {virkeyboard->show();} + xywh {10 10 100 20} + } + } + submenu recordmenu { + label {&Record} + xywh {0 0 100 20} + } { + menuitem {} { + label {&Choose WAV file...} + callback {char *filename; +recordbutton->deactivate(); +pausebutton->deactivate(); +pauselabel->deactivate(); +stopbutton->deactivate(); +filename=fl_file_chooser("Record to audio file:","(*.wav)",NULL,0); +if (filename==NULL) return; +fl_filename_setext(filename,".wav"); + +int result=master->HDDRecorder.preparefile(filename,0); +if (result==1) { + result=0; + if (fl_ask("The file exists. \\nOverwrite it?")) + master->HDDRecorder.preparefile(filename,1); +}; +if (result==0) recordbutton->activate(); + +if (result!=0) fl_alert("Error: Could not save the file.");} + xywh {0 0 100 20} + } + } + submenu {} { + label {&Sequencer} + xywh {0 0 100 20} + } { + menuitem {} { + label {Show &Sequencer...} + callback {sequi->show();} + xywh {0 0 100 20} + } + } + } + Fl_Dial mastervolumedial { + label {M.Vol} + callback {master->setPvolume((int) o->value());} + tooltip {Master Volume} xywh {5 30 30 30} box ROUND_UP_BOX labelfont 1 labelsize 12 align 130 maximum 127 step 1 + code0 {o->value(master->Pvolume);} + class WidgetPDial + } + Fl_Counter masterkeyshiftcounter { + label {Master KeyShift} + callback {master->setPkeyshift((int) o->value()+64);} + xywh {45 31 90 20} labelsize 12 minimum -64 maximum 64 step 1 + code0 {o->lstep(12);} + code1 {o->value(master->Pkeyshift-64);} + } + Fl_Button {} { + label {Panic!} + callback {virkeyboard->relaseallkeys(); +pthread_mutex_lock(&master->mutex); +master->shutup=1; +pthread_mutex_unlock(&master->mutex);} + xywh {293 29 92 31} box PLASTIC_UP_BOX color 231 labelfont 1 + } + Fl_Group partuigroup { + xywh {0 242 390 183} box ENGRAVED_FRAME + } { + Fl_Group partui { + xywh {4 245 383 175} box FLAT_BOX + code0 {o->init(master->part[0],master,0,bankui);} + code1 {o->show();} + class PartUI + } {} + } + Fl_Tabs {} { + xywh {0 80 390 160} + } { + Fl_Group {} { + label {System Effects} + xywh {0 100 390 140} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL labelsize 20 align 25 + } { + Fl_Counter syseffnocounter { + label {Sys.Effect No.} + callback {nsyseff=(int) o->value(); +sysefftype->value(master->sysefx[nsyseff]->geteffect()); +sysefftype->do_callback();} + xywh {5 120 80 20} type Simple labelfont 1 labelsize 11 align 1 minimum 0 maximum 127 step 1 textfont 1 + code0 {o->bounds(0,NUM_SYS_EFX-1);} + code1 {o->value(nsyseff);} + } + Fl_Choice sysefftype { + label EffType + callback {syseffectuigroup->remove(syseffectui); +delete syseffectui; +pthread_mutex_lock(&master->mutex); +master->sysefx[nsyseff]->changeeffect((int) o->value()); +pthread_mutex_unlock(&master->mutex); +syseffectui=new EffUI(0,0,765,525); +syseffectuigroup->add(syseffectui); +syseffectui->init(master->sysefx[nsyseff],sysefftype); +syseffectui->redraw();} + xywh {315 125 70 15} down_box BORDER_BOX labelsize 11 + code0 {o->value(master->sysefx[nsyseff]->geteffect());} + } { + menuitem {} { + label {No Effect} + xywh {10 10 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Reverb + xywh {20 20 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Echo + xywh {30 30 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Chorus + xywh {40 40 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Phaser + xywh {50 50 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label AlienWah + xywh {60 60 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Distortion + xywh {70 70 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label EQ + xywh {80 80 100 20} labelfont 1 labelsize 11 + } + } + Fl_Group syseffectuigroup { + xywh {5 140 380 95} box FLAT_BOX color 48 + } { + Fl_Group syseffectui { + xywh {5 140 380 95} + code0 {o->init(master->sysefx[nsyseff],sysefftype);} + class EffUI + } {} + } + Fl_Button {} { + label {Send to...} + callback {syseffsendwindow->show();} + xywh {95 120 75 20} box THIN_UP_BOX labelfont 1 labelsize 12 + } + Fl_Button {} { + label {Swap/Copy...} + callback {swapefftype=0;//system effect +swapwitheffectcounter->do_callback(); +swapeffwindow->show();} + xywh {200 125 70 15} box THIN_UP_BOX labelfont 1 labelsize 10 + } + } + Fl_Group {} { + label {Insertion Effects} + xywh {0 100 390 140} box ENGRAVED_FRAME labeltype EMBOSSED_LABEL labelsize 20 align 25 hide + } { + Fl_Button {} { + label {Swap/Copy...} + callback {swapefftype=1;//insert effect +swapwitheffectcounter->do_callback(); +swapeffwindow->show();} + xywh {200 125 70 15} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Counter inseffnocounter { + label {Ins.Effect No.} + callback {ninseff=(int) o->value(); +insefftype->value(master->insefx[ninseff]->geteffect()); +insefftype->do_callback(); +inseffpart->value(master->Pinsparts[ninseff]); +inseffpart->do_callback();} + xywh {5 120 80 20} type Simple labelfont 1 labelsize 11 align 1 minimum 0 maximum 127 step 1 textfont 1 + code0 {o->bounds(0,NUM_INS_EFX-1);} + code1 {o->value(ninseff);} + } + Fl_Counter inseffpart { + label {Eff.Part} + callback {master->Pinsparts[ninseff]=(int) o->value(); +if ((int) o->value()==-1){ + inseffectuigroup->deactivate(); + insefftype->deactivate(); + master->insefx[ninseff]->cleanup(); +} else { + inseffectuigroup->activate(); + insefftype->activate(); +};} + tooltip {Part where the effect is applied, -1 for disable, -2 to apply the effect to master} xywh {90 125 65 15} type Simple labelsize 11 align 5 minimum 0 maximum 127 step 1 + code0 {o->bounds(-2,NUM_MIDI_PARTS-1);} + code1 {o->value(master->Pinsparts[ninseff]);} + } + Fl_Choice insefftype { + label EffType + callback {inseffectuigroup->remove(inseffectui); +delete inseffectui; +pthread_mutex_lock(&master->mutex); +master->insefx[ninseff]->changeeffect((int) o->value()); +pthread_mutex_unlock(&master->mutex); +inseffectui=new EffUI(0,0,765,525); +inseffectuigroup->add(inseffectui); +inseffectui->init(master->insefx[ninseff],insefftype); +inseffectui->redraw();} + xywh {315 125 70 15} down_box BORDER_BOX labelsize 11 + code0 {o->value(master->insefx[ninseff]->geteffect());} + code1 {if (master->Pinsparts[ninseff]== -1) o->deactivate();} + } { + menuitem {} { + label {No Effect} + xywh {25 25 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Reverb + xywh {35 35 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Echo + xywh {45 45 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Chorus + xywh {55 55 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Phaser + xywh {60 60 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label AlienWah + xywh {70 70 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Distortion + xywh {80 80 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label EQ + xywh {90 90 100 20} labelfont 1 labelsize 11 + } + } + Fl_Group inseffectuigroup { + xywh {5 140 380 95} box FLAT_BOX color 48 + } { + Fl_Group inseffectui { + xywh {5 140 380 95} + code0 {o->init(master->insefx[ninseff],insefftype);} + code1 {if (master->Pinsparts[ninseff]== -1) o->deactivate();} + class EffUI + } {} + } + } + } + Fl_Button {} { + label Scales + callback {microtonalui->show();} + xywh {330 80 56 19} box PLASTIC_UP_BOX color 231 labeltype ENGRAVED_LABEL labelfont 1 + } + Fl_Group {} {selected + xywh {172 30 117 45} box ENGRAVED_BOX + } { + Fl_Button recordbutton { + label {Rec.} + callback {o->deactivate(); +recordmenu->deactivate(); +recordmenu->label("&Record(*)"); +stopbutton->activate(); +pausebutton->activate(); +pauselabel->activate(); +master->HDDRecorder.start(); +master->vuresetpeaks(); +mastermenu->redraw();} + tooltip {Start Recording} xywh {181 36 21 21} box ROUND_UP_BOX color 88 labelfont 1 labelsize 10 align 2 deactivate + } + Fl_Button stopbutton { + label Stop + callback {o->deactivate(); +master->HDDRecorder.stop(); +recordbutton->deactivate(); +pausebutton->deactivate(); +pauselabel->deactivate(); +recordmenu->activate(); +recordmenu->label("&Record"); +mastermenu->redraw();} + tooltip {Stop Recording and close the audio file} xywh {259 36 21 21} box THIN_UP_BOX color 4 labelfont 1 labelsize 10 align 2 deactivate + } + Fl_Button pausebutton { + label {@||} + callback {o->deactivate(); +master->HDDRecorder.pause(); +recordbutton->activate(); +mastermenu->redraw();} + tooltip {Pause Recording} xywh {220 36 21 21} box THIN_UP_BOX color 4 selection_color 4 labelfont 1 labelcolor 3 align 16 deactivate + } + Fl_Box pauselabel { + label Pause + xywh {214 56 30 15} labelfont 1 labelsize 10 deactivate + } + } + Fl_Group {} { + xywh {1 427 389 33} box ENGRAVED_FRAME + } { + Fl_Box {} { + label {VU-Meter} + xywh {4 430 384 30} box FLAT_BOX color 48 selection_color 75 + code0 {o->init(master,-1);} + class VUMeter + } + } + Fl_Check_Button nrpnbutton { + label NRPN + callback {master->ctl.NRPN.receive=(int) o->value();} + tooltip {Receive NRPNs} xywh {45 65 47 10} down_box DOWN_BOX labelsize 10 + code0 {o->value(master->ctl.NRPN.receive);} + } + Fl_Counter npartcounter { + callback {partuigroup->remove(partui); +delete partui; +partui=new PartUI(0,0,765,525); +partuigroup->add(partui); +partui->init(master->part[(int) o->value()],master,(int) o->value(),bankui); +partui->redraw(); +o->redraw(); +npart=(int) o->value(); + +updatepanel();} + tooltip {The part number} xywh {5 247 70 23} type Simple labelfont 1 minimum 0 maximum 127 step 1 textfont 1 + code0 {o->bounds(0,NUM_MIDI_PARTS-1);} + code1 {bankui->init(o);} + } + Fl_Button {} { + label vK + callback {virkeyboard->show();} + tooltip {Virtual Keyboard} xywh {292 80 35 19} box PLASTIC_UP_BOX color 231 labeltype ENGRAVED_LABEL labelfont 1 + } + Fl_Button {} { + label {R.D.} + callback {globalfinedetuneslider->value(64.0); +globalfinedetuneslider->do_callback();} + tooltip {Master fine detune reset} xywh {140 65 30 10} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Dial globalfinedetuneslider { + label {F.Det.} + callback {master->microtonal.Pglobalfinedetune=(int) o->value();} + tooltip {global fine detune} xywh {143 30 20 20} box ROUND_UP_BOX labelsize 10 align 130 maximum 127 step 1 value 64 + code0 {o->value(master->microtonal.Pglobalfinedetune);} + class WidgetPDial + } + Fl_Button {} { + label {Panel Window} + callback {updatepanel(); +panelwindow->show();} + tooltip {Panel Window} xywh {293 62 92 16} box PLASTIC_UP_BOX color 183 labelfont 1 labelsize 10 + } + } + Fl_Window aboutwindow { + label {Copyright...} + xywh {629 278 330 210} hide + } { + Fl_Box {} { + label {Copyright (c) 2002-2003 Nasca O. Paul} + xywh {5 35 320 25} labeltype EMBOSSED_LABEL labelsize 18 align 16 + } + Fl_Box {} { + label {This is free software; you may redistribute it and/or modify it under the terms of the +version 2 of the GNU General Public License as published by the Free Software Fundation. + This program comes with + ABSOLUTELY NO WARRANTY. + See the version 2 of the +GNU General Public License for details.} + xywh {0 60 325 115} labelfont 1 labelsize 12 align 144 + } + Fl_Button {} { + label {Close this window} + callback {aboutwindow->hide();} + xywh {80 180 180 25} box THIN_UP_BOX labelsize 12 + } + Fl_Box {} { + label ZynAddSubFX + xywh {5 5 325 30} labeltype EMBOSSED_LABEL labelfont 1 labelsize 24 labelcolor 0 align 16 + } + } + Fl_Window syseffsendwindow { + label {System Effects Send} + xywh {171 234 120 250} hide resizable + } { + Fl_Scroll {} {open + xywh {0 45 120 170} box FLAT_BOX resizable + code0 {for (int neff1=0;neff1<NUM_SYS_EFX;neff1++) for (int neff2=neff1+1;neff2<NUM_SYS_EFX;neff2++)} + code1 {{syseffsend[neff1][neff2]=new SysEffSend(o->x()+(neff2-1)*35,o->y()+15+neff1*50,30,30);syseffsend[neff1][neff2]->label("aaa");syseffsend[neff1][neff2]->init(master,neff1,neff2);};} + } {} + Fl_Button {} { + label Close + callback {syseffsendwindow->hide();} + xywh {25 220 80 25} box THIN_UP_BOX + } + Fl_Box {} { + label {Send system effect's output to other system effects} + xywh {5 5 110 35} labelsize 10 align 192 + } + } + Fl_Window swapeffwindow { + label {Swap/Copy effect} + xywh {581 329 205 100} hide modal + } { + Fl_Counter swapwitheffectcounter { + label {Swap with effect/Copy to:} + callback {if (swapefftype==0) o->maximum(NUM_SYS_EFX-1); + else o->maximum(NUM_INS_EFX-1);} + xywh {65 30 75 20} type Simple labelfont 1 labelsize 12 align 1 minimum 0 maximum 127 step 1 textfont 1 + } + Fl_Button {} { + label Swap + callback {int neff2=(int) swapwitheffectcounter->value(); +int tmp=0; +if (swapefftype==0) { + pthread_mutex_lock(&master->mutex); + master->swapcopyeffects(0,swapefftype,nsyseff,neff2); + pthread_mutex_unlock(&master->mutex); + tmp=nsyseff; + syseffnocounter->value(neff2);syseffnocounter->do_callback(); + syseffnocounter->value(tmp);syseffnocounter->do_callback(); + }else{ + pthread_mutex_lock(&master->mutex); + master->swapcopyeffects(0,swapefftype,ninseff,neff2); + pthread_mutex_unlock(&master->mutex); + tmp=ninseff; + inseffnocounter->value(neff2);inseffnocounter->do_callback(); + inseffnocounter->value(tmp);inseffnocounter->do_callback(); + }; +swapeffwindow->hide();} + xywh {15 60 55 25} box THIN_UP_BOX labelfont 1 + } + Fl_Button {} { + label Cancel + callback {swapeffwindow->hide();} + xywh {140 60 55 25} box THIN_UP_BOX labelfont 1 + } + Fl_Button {} { + label Copy + callback {pthread_mutex_lock(&master->mutex); +if (swapefftype==0) master->swapcopyeffects(1,swapefftype,nsyseff,(int) swapwitheffectcounter->value()); + else master->swapcopyeffects(1,swapefftype,ninseff,(int) swapwitheffectcounter->value()); +pthread_mutex_unlock(&master->mutex); +swapeffwindow->hide();} + xywh {75 60 55 25} box THIN_UP_BOX labelfont 1 + } + } + Fl_Window panelwindow { + label {ZynAddSubFX Panel} + xywh {4 20 632 635} hide + } { + Fl_Scroll {} {open + xywh {0 5 570 310} type HORIZONTAL box THIN_UP_BOX + } { + Fl_Pack {} {open + xywh {5 10 560 285} type HORIZONTAL + code0 {for (int i=0;i<NUM_MIDI_PARTS/2;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(master,i,bankui);}} + } {} + } + Fl_Scroll {} {open + xywh {0 320 570 310} type HORIZONTAL box THIN_UP_BOX + } { + Fl_Pack {} {open + xywh {5 325 560 285} type HORIZONTAL + code0 {for (int i=NUM_MIDI_PARTS/2;i<NUM_MIDI_PARTS;i++){panellistitem[i]=new Panellistitem(0,0,70,260,"");panellistitem[i]->init(master,i,bankui);}} + } {} + } + Fl_Button {} { + label Close + callback {panelwindow->hide(); +updatepanel();} + xywh {575 605 50 25} box THIN_UP_BOX + } + Fl_Button {} { + label Refresh + callback {updatepanel();} + xywh {575 570 55 25} box THIN_UP_BOX + } + } + } + Function {updatesendwindow()} {} { + code {for (int neff1=0;neff1<NUM_SYS_EFX;neff1++) + for (int neff2=neff1+1;neff2<NUM_SYS_EFX;neff2++) + syseffsend[neff1][neff2]->value(master->Psysefxsend[neff1][neff2]);} {} + } + Function {setfilelabel(const char *filename)} {} { + code {if (filename!=NULL) snprintf(&masterwindowlabel[0],100,"%s - ZynAddSubFX",fl_filename_name(filename)); + else snprintf(&masterwindowlabel[0],100,"ZynAddSubFX (c)2002-2003 Nasca O. Paul"); +masterwindowlabel[99]='\\0'; +masterwindow->label(&masterwindowlabel[0]);} {} + } + Function {updatepanel()} {} { + code {for (int npart=0;npart<NUM_MIDI_PARTS;npart++){ + panellistitem[npart]->refresh(); +};} {} + } + Function {MasterUI(Master *master_,int *exitprogram_)} {} { + code {master=master_; +exitprogram=exitprogram_; +ninseff=0; +nsyseff=0; +npart=0; + +for (int i=0;i<NUM_SYS_EFX;i++) + for (int j=0;j<NUM_SYS_EFX;j++) + syseffsend[i][j]=NULL; + +microtonalui=new MicrotonalUI(&master->microtonal); +virkeyboard=new VirKeyboard(master); +bankui=new BankUI(master,&npart); +configui=new ConfigUI(); +sequi=new SeqUI(master); + +make_window(); + +swapefftype=0;} {} + } + Function {~MasterUI()} {} { + code {masterwindow->hide(); +delete (masterwindow); +aboutwindow->hide(); +delete (aboutwindow); +syseffsendwindow->hide(); +delete(syseffsendwindow); + +delete (virkeyboard); +delete (microtonalui); +delete (bankui); +delete (configui); +delete (sequi);} {} + } + decl {Master *master;} {} + decl {MicrotonalUI *microtonalui;} {} + decl {SeqUI *sequi;} {} + decl {BankUI *bankui;} {} + decl {int ninseff,npart;} {} + decl {int nsyseff;} {} + decl {int *exitprogram;} {} + decl {SysEffSend *syseffsend[NUM_SYS_EFX][NUM_SYS_EFX];} {} + decl {VirKeyboard *virkeyboard;} {} + decl {ConfigUI *configui;} {} + decl {int swapefftype;} {} + decl {char masterwindowlabel[100];} {} + decl {Panellistitem *panellistitem[NUM_MIDI_PARTS];} {} +} diff --git a/src/UI/MicrotonalUI.fl b/src/UI/MicrotonalUI.fl @@ -0,0 +1,266 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0103 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <string.h>} {public +} + +decl {\#include <FL/Fl_File_Chooser.H>} {public +} + +decl {\#include <FL/fl_ask.H>} {public +} + +decl {\#include "../Misc/Microtonal.h"} {public +} + +class MicrotonalUI {} { + Function {make_window()} {} { + Fl_Window microtonaluiwindow { + label Scales + xywh {487 190 405 450} hide + } { + Fl_Group {} { + tooltip {Center where the note's freqs. are turned upside-down} xywh {249 2 155 45} box ENGRAVED_FRAME + } { + Fl_Check_Button {} { + label {Invert keys} + callback {microtonal->Pinvertupdown=(int) o->value(); +if (microtonal->Pinvertupdown==0) centerinvertcounter->deactivate(); + else centerinvertcounter->activate();} + tooltip {Turn upside-down the note frequencies} xywh {254 13 55 30} down_box DOWN_BOX labelfont 1 labelsize 12 align 148 + code0 {o->value(microtonal->Pinvertupdown);} + } + Fl_Counter centerinvertcounter { + label Center + callback {microtonal->Pinvertupdowncenter=(int) o->value();} + xywh {319 13 80 20} labelfont 1 labelsize 12 align 130 minimum 0 maximum 127 step 1 textfont 1 + code0 {o->lstep(microtonal->getoctavesize());} + code1 {o->value(microtonal->Pinvertupdowncenter);} + code2 {if (microtonal->Pinvertupdown==0) o->deactivate();} + } + } + Fl_Group microtonalgroup { + xywh {3 49 402 398} box ENGRAVED_FRAME + code0 {if (microtonal->Penabled==0) o->deactivate();} + } { + Fl_Button {} { + label Apply + callback {tuningsinput->do_callback(); +mappinginput->do_callback();} + tooltip {Retune the synth accorging to the inputs from "Tunnings" and "Keyboard Mappings"} xywh {8 413 95 28} box THIN_UP_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 18 + } + Fl_Value_Output octavesizeoutput { + label {nts./oct.} + callback {o->value(microtonal->getoctavesize());} + tooltip {Notes/Octave} xywh {150 421 35 17} labelsize 10 align 5 maximum 500 step 1 value 12 textfont 1 + code0 {o->value(microtonal->getoctavesize());} + } + Fl_Input nameinput { + label {Name:} + callback {snprintf((char *)microtonal->Pname,MICROTONAL_MAX_NAME_LEN,"%s",o->value());} + xywh {8 64 285 25} labelfont 1 labelsize 12 align 5 + code0 {o->insert((char *)microtonal->Pname);} + } + Fl_Input tuningsinput { + label {Tunings:} + callback {int err=microtonal->texttotunings(o->value()); +if (err>=0) fl_alert("Parse Error: The input may contain only numbers (like 232.59)\\n or divisions (like 121/64)."); +if (err==-2) fl_alert("Parse Error: The input is empty."); +octavesizeoutput->do_callback();} + xywh {8 144 182 264} type Multiline labelfont 1 labelsize 12 align 5 when 0 + code0 {updateTuningsInput();} + } + Fl_Input commentinput { + label {Comment:} + callback {snprintf((char *)microtonal->Pcomment,MICROTONAL_MAX_NAME_LEN,"%s",o->value());} + xywh {8 104 391 25} labelfont 1 labelsize 12 align 5 + code0 {o->insert((char *)microtonal->Pcomment);} + } + Fl_Counter {} { + label Shift + callback {microtonal->Pscaleshift=(int) o->value()+64;} + xywh {313 69 70 20} type Simple labelsize 12 align 1 minimum -63 maximum 64 step 1 textfont 1 + code0 {o->value(microtonal->Pscaleshift-64);} + } + Fl_Button {} { + label {Import .SCL file} + callback {const char *filename; +filename=fl_file_chooser("Open:","(*.scl)",NULL,0); +if (filename==NULL) return; +int result=microtonal->loadscl(filename); +if (result==0) { + updateTuningsInput(); + nameinput->cut(0,tuningsinput->maximum_size()); + nameinput->insert((char *)microtonal->Pname); + nameinput->position(0); + commentinput->cut(0,tuningsinput->maximum_size()); + commentinput->insert((char *)microtonal->Pname); + commentinput->position(0); + tuningsinput->position(0); + octavesizeoutput->do_callback(); + } else { + fl_alert("Error: Could not load the file."); + };} + tooltip {Inport Scala .scl file (tunnings)} xywh {243 411 84 15} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Group keymappinggroup { + label {Keyboard Mapping} open + xywh {193 144 206 264} box ENGRAVED_BOX labelfont 1 labelsize 12 + } { + Fl_Input mappinginput { + callback {microtonal->texttomapping(o->value()); +mapsizeoutput->do_callback(); +anotecounter->do_callback();} + xywh {250 147 146 258} type Multiline labelfont 1 labelsize 12 align 5 + code0 {updateMappingInput();} + } + Fl_Counter firstnotecounter { + label {First note} + callback {microtonal->Pfirstkey=(int) o->value();} + tooltip {First MIDI note number} xywh {199 195 42 18} type Simple labelsize 10 align 5 minimum 0 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->value(microtonal->Pfirstkey);} + } + Fl_Counter lastnotecounter { + label {Last note} + callback {microtonal->Plastkey=(int) o->value();} + tooltip {Last MIDI note number} xywh {199 225 42 18} type Simple labelsize 10 align 5 minimum 0 maximum 127 step 1 value 127 textfont 1 textsize 12 + code0 {o->value(microtonal->Plastkey);} + } + Fl_Counter middlenotecounter { + label {Midle note} + callback {microtonal->Pmiddlenote=(int) o->value();} + tooltip {Midle note (where scale degree 0 is mapped to)} xywh {199 267 42 18} type Simple labelsize 10 align 5 minimum 0 maximum 127 step 1 value 60 textfont 1 textsize 12 + code0 {o->value(microtonal->Pmiddlenote);} + } + Fl_Value_Output mapsizeoutput { + label {Map Size} + callback {o->value(microtonal->Pmapsize);} + xywh {201 382 44 20} labelsize 10 align 5 maximum 500 step 1 value 12 textfont 1 + code0 {o->value(microtonal->Pmapsize);} + } + } + Fl_Check_Button mappingenabledbutton { + label ON + callback {int x=(int) o->value(); +microtonal->Pmappingenabled=x; +if (x==0) keymappinggroup->deactivate(); + else keymappinggroup->activate(); +o->show();} + tooltip {Enable the Mapping (otherwise the mapping is linear)} xywh {198 150 48 21} box FLAT_BOX down_box DOWN_BOX labelfont 1 + code0 {o->value(microtonal->Pmappingenabled);} + code1 {if (microtonal->Pmappingenabled==0) keymappinggroup->deactivate();} + } + Fl_Button {} { + label {Import .kbm file} + callback {const char *filename; +filename=fl_file_chooser("Open:","(*.kbm)",NULL,0); +if (filename==NULL) return; +int result=microtonal->loadkbm(filename); +if (result==0) { + updateMappingInput(); + mappinginput->position(0); + mapsizeoutput->do_callback(); + firstnotecounter->value(microtonal->Pfirstkey); + lastnotecounter->value(microtonal->Plastkey); + middlenotecounter->value(microtonal->Pmiddlenote); + mapsizeoutput->do_callback(); + mappingenabledbutton->value(microtonal->Pmappingenabled); + mappingenabledbutton->do_callback(); + afreqinput->value(microtonal->PAfreq); + anotecounter->value(microtonal->PAnote); + anotecounter->do_callback(); + } else { + fl_alert("Error: Could not load the file."); + };} + tooltip {Inport Scala .kbm file (keyboard mapping)} xywh {243 428 84 16} box THIN_UP_BOX labelfont 1 labelsize 10 + } + } + Fl_Group {} { + xywh {108 2 140 45} box ENGRAVED_FRAME + } { + Fl_Counter anotecounter { + label {"A" Note} + callback {microtonal->PAnote=(int) o->value(); +if (microtonal->getnotefreq(microtonal->PAnote,0)<0.0) o->textcolor(FL_RED); + else o->textcolor(FL_BLACK); + +o->redraw();} + tooltip {The "A" note (the reference note for which freq. ("A" freq) is given)} xywh {173 17 65 20} labelfont 1 labelsize 10 align 129 minimum 0 maximum 127 step 1 value 69 textfont 1 textsize 11 + code0 {o->lstep(12);} + code1 {o->value(microtonal->PAnote);} + } + Fl_Value_Input afreqinput { + label {"A" Freq.} + callback {microtonal->PAfreq=o->value();} + tooltip {The freq. of "A" note (default=440.0)} xywh {118 17 45 20} labelfont 1 labelsize 10 align 1 minimum 1 maximum 20000 step 0.001 value 440 textfont 1 textsize 11 + code0 {o->value(microtonal->PAfreq);} + } + } + Fl_Button {} { + label Close + callback {microtonaluiwindow->hide();} + xywh {333 413 67 28} box THIN_UP_BOX + } + Fl_Check_Button {} { + label {Enable Microtonal} + callback {microtonal->Penabled=(int) o->value(); +if (microtonal->Penabled==0) microtonalgroup->deactivate(); + else microtonalgroup->activate();} + xywh {3 3 102 45} box PLASTIC_UP_BOX down_box DOWN_BOX labelfont 1 labelsize 12 align 148 + code0 {o->value(microtonal->Penabled);} + } + } + } + Function {updateTuningsInput()} {} { + code {char *tmpbuf=new char[100]; + +tuningsinput->cut(0,tuningsinput->maximum_size()); + +for (int i=0;i<microtonal->getoctavesize();i++){ + if (i!=0) tuningsinput->insert("\\n"); + microtonal->tuningtoline(i,tmpbuf,100); + tuningsinput->insert(tmpbuf); +}; + +delete(tmpbuf);} {} + } + Function {updateMappingInput()} {} { + code {char *tmpbuf=new char[100]; + +mappinginput->cut(0,tuningsinput->maximum_size()); + +for (int i=0;i<microtonal->Pmapsize;i++){ + if (i!=0) mappinginput->insert("\\n"); + if ((microtonal->Pmapping[i])==-1) + snprintf(tmpbuf,100,"x"); + else snprintf(tmpbuf,100,"%d",microtonal->Pmapping[i]); + mappinginput->insert(tmpbuf); +}; + +delete(tmpbuf);} {} + } + Function {MicrotonalUI(Microtonal *microtonal_)} {} { + code {microtonal=microtonal_; + +make_window();} {} + } + Function {~MicrotonalUI()} {} { + code {microtonaluiwindow->hide(); +delete(microtonaluiwindow);} {} + } + Function {show()} {} { + code {microtonaluiwindow->show();} {} + } + decl {Microtonal *microtonal;} {} +} diff --git a/src/UI/PartUI.fl b/src/UI/PartUI.fl @@ -0,0 +1,1047 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <string.h>} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include "EffUI.h"} {public +} + +decl {\#include "BankUI.h"} {public +} + +decl {\#include "ADnoteUI.h"} {public +} + +decl {\#include "SUBnoteUI.h"} {public +} + +decl {\#include "../Misc/Config.h"} {public +} + +decl {\#include "../Misc/Master.h"} {public +} + +decl {\#include "../Misc/Part.h"} {public +} + +class PartSysEffSend {: {public Fl_Group} +} { + Function {make_window()} {private + } { + Fl_Window syseffsend { + private xywh {584 83 90 35} hide + class Fl_Group + } { + Fl_Dial {} { + label 01 + callback {master->setPsysefxvol(npart,neff,(int) o->value());} + xywh {0 0 25 25} box ROUND_UP_BOX labelfont 1 labelsize 10 align 130 maximum 127 step 1 + code0 {o->size(25,25);} + code1 {o->value(master->Psysefxvol[neff][npart]);} + code2 {char tmp[10];snprintf(tmp,10,"%d",neff);o->label(strdup(tmp));} + class WidgetPDial + } + } + } + Function {PartSysEffSend(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {master=NULL; +neff=0; +npart=0;} {} + } + Function {init(Master *master_,int npart_,int neff_)} {} { + code {npart=npart_; +neff=neff_; +master=master_; +make_window(); +syseffsend->show(); +end();} {} + } + Function {~PartSysEffSend()} {} { + code {syseffsend->hide(); +delete(syseffsend);} {} + } + decl {Master *master;} {} + decl {int neff;} {} + decl {int npart;} {} +} + +class PartUI_ {} { + Function {showparameters(int kititem,int engine)} {return_type virtual + } {} +} + +class PartKitItem {: {public Fl_Group} +} { + Function {make_window()} {private + } { + Fl_Window partkititem { + private xywh {149 528 590 27} hide + class Fl_Group + } { + Fl_Group partkititemgroup { + private xywh {55 0 530 20} box FLAT_BOX + code0 {if (part->kit[n].Penabled==0) o->deactivate();} + } { + Fl_Counter minkcounter { + callback {part->kit[n].Pminkey=(int)o->value();} + xywh {225 0 55 15} type Simple minimum 0 maximum 128 step 1 + code0 {o->value(part->kit[n].Pminkey);} + } + Fl_Button {} { + label m + callback {if (part->lastnote>=0) minkcounter->value(part->lastnote); +minkcounter->do_callback(); +maxkcounter->do_callback();} + tooltip {set the minimum key to the last pressed key} xywh {285 3 15 12} box THIN_UP_BOX labelsize 10 + } + Fl_Button {} { + label M + callback {if (part->lastnote>=0) maxkcounter->value(part->lastnote); +maxkcounter->do_callback(); +minkcounter->do_callback();} + tooltip {set the maximum key to the last pressed key} xywh {315 3 15 12} box THIN_UP_BOX labelsize 10 + } + Fl_Button {} { + label R + callback {minkcounter->value(0); +minkcounter->do_callback(); +maxkcounter->value(127); +maxkcounter->do_callback();} + tooltip {reset the minimum key to 0 and maximum key to 127} xywh {300 3 15 12} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Button adeditbutton { + label edit + callback {partui->showparameters(n,0);} + xywh {420 0 40 15} box THIN_UP_BOX labelsize 12 + code0 {if (part->kit[n].Padenabled==0) o->deactivate();} + code1 {if (n==0) o->hide();} + } + Fl_Button subeditbutton { + label edit + callback {partui->showparameters(n,1);} + xywh {490 0 40 15} box THIN_UP_BOX labelsize 12 + code0 {if (part->kit[n].Psubenabled==0) o->deactivate();} + code1 {if (n==0) o->hide();} + } + Fl_Check_Button mutedcheck { + callback {part->kit[n].Pmuted=(int)o->value();} + private xywh {60 0 20 15} down_box DOWN_BOX labelfont 1 labelsize 12 align 4 + code0 {o->value(part->kit[n].Pmuted);} + } + Fl_Counter maxkcounter { + callback {part->kit[n].Pmaxkey=(int)o->value();} + xywh {335 0 55 15} type Simple minimum 0 maximum 128 step 1 + code0 {o->value(part->kit[n].Pmaxkey);} + } + Fl_Button labelbutton { + label {Bass Drum} + callback {const char *tmp=fl_input("Kit item name:",(const char *)part->kit[n].Pname); +if (tmp!=NULL) snprintf((char *)part->kit[n].Pname,PART_MAX_NAME_LEN,tmp);} + xywh {90 0 130 15} box THIN_DOWN_BOX down_box FLAT_BOX labelfont 1 labelsize 11 align 20 + code0 {o->label((char *)part->kit[n].Pname);} + } + Fl_Check_Button adcheck { + callback {part->kit[n].Padenabled=(int)o->value(); +if (part->kit[n].Padenabled!=0) adeditbutton->activate(); + else adeditbutton->deactivate();} + private xywh {400 0 20 15} down_box DOWN_BOX labelfont 1 labelsize 12 align 4 + code0 {o->value(part->kit[n].Padenabled);} + code1 {if (n==0) o->hide();} + } + Fl_Check_Button subcheck { + callback {part->kit[n].Psubenabled=(int)o->value(); +if (part->kit[n].Psubenabled!=0) subeditbutton->activate(); + else subeditbutton->deactivate();} + private xywh {470 0 20 15} down_box DOWN_BOX labelfont 1 labelsize 12 align 4 + code0 {o->value(part->kit[n].Psubenabled);} + code1 {if (n==0) o->hide();} + } + Fl_Counter sentdoeffectcounter { + callback {if (o->value()>=0.0) part->kit[n].Psendtoparteffect=(int)o->value(); + else part->kit[n].Psendtoparteffect=127;} + xywh {535 0 45 15} type Simple minimum -1 maximum 128 step 1 + code0 {o->bounds(-1,NUM_PART_EFX);} + code1 {o->value(part->kit[n].Psendtoparteffect);} + code2 {if (part->kit[n].Psendtoparteffect==127) o->value(-1);} + } + } + Fl_Check_Button enabledcheck { + label 01 + callback {int answer=1; +if (o->value()==0) answer=fl_ask("Delete the item?"); +if (answer!=0){ +pthread_mutex_lock(&master->mutex); + part->setkititemstatus(n,(int) o->value()); +pthread_mutex_unlock(&master->mutex); + +if (o->value()==0) partkititemgroup->deactivate(); +else partkititemgroup->activate(); +o->redraw(); +partui->showparameters(n,-1);//use to delete the ui, if it is not to item 0 +} else o->value(1);} + private xywh {30 0 20 15} down_box DOWN_BOX labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 4 + code0 {snprintf(label,10,"%d",n);o->label(strdup(label));} + code1 {o->value(part->kit[n].Penabled);} + code2 {if (n==0) o->deactivate();} + } + } + } + Function {PartKitItem(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {n=0; +part=NULL;} {} + } + Function {refresh()} {} { + code {enabledcheck->value(part->kit[n].Penabled); +if (part->kit[n].Penabled==0) partkititemgroup->deactivate(); +else partkititemgroup->activate(); + +mutedcheck->value(part->kit[n].Pmuted); +labelbutton->label((char *)part->kit[n].Pname); +minkcounter->value(part->kit[n].Pminkey); +maxkcounter->value(part->kit[n].Pmaxkey); +adcheck->value(part->kit[n].Padenabled); +adcheck->do_callback(); +subcheck->value(part->kit[n].Psubenabled); +subcheck->do_callback(); +sentdoeffectcounter->value(part->kit[n].Psendtoparteffect); + +this->redraw();} { + callback {int answer=1; +if (o->value()==0) answer=fl_ask("Delete the item?"); +if (answer!=0){ +pthread_mutex_lock(&master->mutex); + part->setkititemstatus(n,(int) o->value()); +pthread_mutex_unlock(&master->mutex); + +if (o->value()==0) partkititemgroup->deactivate(); +else partkititemgroup->activate(); +o->redraw(); +partui->showparameters(n,-1);//use to delete the ui, if it is not to item 0 +} else o->value(1);} + } + } + Function {init(Part *part_,int n_,Master *master_,PartUI_ *partui_)} {} { + code {part=part_; +n=n_; +partui=partui_; +master=master_; +make_window(); +//partkititem->show(); +end();} {} + } + Function {~PartKitItem()} {} { + code {partkititem->hide(); +delete(partkititem);} {} + } + decl {Part *part;} {} + decl {int n;} {} + decl {Master *master;} {} + decl {char label[10];} {} + decl {PartUI_ *partui;} {} +} + +class PartUI {: {public Fl_Group,PartUI_} +} { + Function {make_window()} {private + } { + Fl_Window partgroup { + private xywh {149 400 385 180} hide + class Fl_Group + } { + Fl_Group partgroupui { + xywh {0 0 385 180} + code0 {if (part->Penabled==0) o->deactivate();} + } { + Fl_Dial {} { + label Pan + callback {part->setPpanning((int) o->value());} + xywh {50 40 25 25} box ROUND_UP_BOX labelsize 12 maximum 127 step 1 + code0 {o->value(part->Ppanning);} + class WidgetPDial + } + Fl_Counter {} { + label KeyShift + callback {part->Pkeyshift=(int) o->value()+64;} + xywh {195 40 90 20} labelsize 12 minimum -64 maximum 64 step 1 + code0 {o->lstep(12);} + code1 {o->value(part->Pkeyshift-64);} + } + Fl_Counter {} { + label {Chn.Rcv.} + callback {part->Prcvchn=(int) o->value();} + tooltip {receive from Midi channel} xywh {295 55 85 20} type Simple labelfont 1 labelsize 12 minimum 0 maximum 127 step 1 + code0 {o->bounds(0,NUM_MIDI_CHANNELS-1);} + code1 {o->value(part->Prcvchn);} + } + Fl_Button {} { + label AllNotesOff + callback {part->AllNotesOff();} + xywh {300 30 80 20} box PLASTIC_UP_BOX labelfont 1 labelsize 12 + } + Fl_Group {} {open + xywh {1 81 165 70} box ENGRAVED_FRAME + } { + Fl_Check_Button adsynenabledcheck { + label ADsyn + callback {part->PADnoteenabled=(int) o->value(); +part->kit[0].Padenabled=part->PADnoteenabled;} + tooltip {enable/disable ADsynth} xywh {6 86 70 20} box PLASTIC_UP_BOX down_box DOWN_BOX color 222 selection_color 218 labelfont 1 labelsize 12 + code1 {o->value(part->PADnoteenabled);} + } + Fl_Button {} { + label {ADs edit} + callback {showparameters(0,0);} + xywh {6 106 70 24} box PLASTIC_UP_BOX color 222 selection_color 220 labelfont 1 labelsize 12 align 128 + } + Fl_Check_Button subsynenabledcheck { + label SUBsyn + callback {part->PSUBnoteenabled=(int) o->value(); +part->kit[0].Psubenabled=part->PSUBnoteenabled;} + tooltip {enable/disable SUBsynth} xywh {81 86 80 20} box PLASTIC_UP_BOX down_box DOWN_BOX color 222 selection_color 218 labelfont 1 labelsize 12 + code1 {o->value(part->PSUBnoteenabled);} + } + Fl_Button {} { + label {SUBs edit} + callback {showparameters(0,1);} + xywh {81 105 80 25} box PLASTIC_UP_BOX color 222 selection_color 220 labelfont 1 labelsize 12 align 128 + } + Fl_Button {} { + label {Instr.kit items edit} + callback {instrumentkitlist->show();} + xywh {5 130 155 18} box PLASTIC_UP_BOX color 238 selection_color 220 labeltype ENGRAVED_LABEL labelsize 12 align 128 + } + } + Fl_Scroll {} {open + xywh {166 91 125 60} box ENGRAVED_FRAME labelfont 1 labelsize 10 align 21 + } { + Fl_Pack {} {open + xywh {171 96 115 35} type HORIZONTAL + code0 {o->spacing(5);} + code1 {for (int i=0;i<NUM_SYS_EFX;i++){psyef[i]=new PartSysEffSend(0,0,25,35,"");psyef[i]->init(master,npart,i);}} + } {} + } + Fl_Button {} { + label {Grand Piano} + callback {int event=Fl::event_button(); +if (event==FL_RIGHT_MOUSE){ + const char *tmp=fl_input("Instrument name:",(const char *)part->Pname); + if (tmp!=NULL) snprintf((char *)part->Pname,PART_MAX_NAME_LEN,tmp); +} else { + if (event==FL_LEFT_MOUSE) bankui->show(); + else infowin->show(); +};} + tooltip {left mousebutton - to choose/save/.. from/to bank or right mousebutton to change the name or middle button to change the instrument information} xywh {155 5 135 20} box THIN_DOWN_BOX down_box FLAT_BOX labelfont 1 labelsize 12 align 20 + code0 {o->label((char *)part->Pname);} + } + Fl_Box {} { + label {To Sys.Efx.} + xywh {166 81 95 10} labelfont 1 labelsize 10 + } + Fl_Check_Button {} { + label NoteOn + callback {part->Pnoteon=(int) o->value();} + tooltip {set if the part receives NoteOn messages} xywh {0 155 65 20} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(part->Pnoteon);} + } + Fl_Counter minkcounter { + label {Min.k} + callback {part->Pminkey=(int) o->value(); +if (part->Pminkey>part->Pmaxkey) o->textcolor(FL_RED); + else o->textcolor(FL_BLACK);} + tooltip {Minimum key (that the part receives NoteOn messages)} xywh {295 125 40 15} type Simple labelfont 1 labelsize 10 minimum 0 maximum 127 step 1 textsize 10 + code0 {o->value(part->Pminkey);} + } + Fl_Counter maxkcounter { + label {Max.k} + callback {part->Pmaxkey=(int) o->value(); + +if (part->Pminkey>part->Pmaxkey) o->textcolor(FL_RED); + else o->textcolor(FL_BLACK);} + tooltip {Maximum key (that the part receives NoteOn messages)} xywh {340 125 40 15} type Simple labelfont 1 labelsize 10 minimum 0 maximum 127 step 1 textsize 10 + code0 {o->value(part->Pmaxkey);} + } + Fl_Dial {} { + label Volume + callback {part->setPvolume((int) o->value());} + tooltip {Part Volume} xywh {10 35 30 30} box ROUND_UP_BOX labelsize 12 maximum 127 step 1 + code0 {o->value(part->Pvolume);} + class WidgetPDial + } + Fl_Dial {} { + label {Vel.Ofs.} + callback {part->Pveloffs=(int) o->value();} + tooltip {Velocity Offset} xywh {135 40 25 25} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 + code0 {o->value(part->Pveloffs);} + class WidgetPDial + } + Fl_Dial {} { + label {Vel.Sns.} + callback {part->Pvelsns=(int) o->value();} + tooltip {Velocity Sensing Function} xywh {95 40 25 25} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 + code0 {o->value(part->Pvelsns);} + class WidgetPDial + } + Fl_Button {} { + label Controllers + callback {ctlwindow->show();} + xywh {295 90 85 30} box PLASTIC_UP_BOX labelfont 1 labelsize 12 + } + Fl_Check_Button {} { + label Poly + callback {part->Ppolymode=(int) o->value();} + tooltip {Part mode (mono/poly)} xywh {65 155 45 20} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(part->Ppolymode);} + } + Fl_Check_Button {} { + label Portamento + callback {part->ctl.portamento.portamento=(int) o->value();} + tooltip {Enable/Disable the portamento} xywh {115 155 85 20} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(part->ctl.portamento.portamento);} + } + Fl_Counter keylimitcounter { + label {K.lmt.} + callback {part->setkeylimit((int) o->value());} + tooltip {Key Limit (max notes that are alowed to play in this part)} xywh {210 155 70 20} type Simple labelfont 1 labelsize 10 align 8 minimum 0 maximum 127 step 1 + code0 {o->value(part->Pkeylimit);} + } + Fl_Button {} { + label PartFX + callback {partfx->show();} + xywh {300 5 80 20} box PLASTIC_UP_BOX labelfont 1 labelsize 16 + } + Fl_Button {} { + label i + callback {infowin->show();} + xywh {170 40 20 20} box THIN_UP_BOX labelfont 1 labelsize 12 + } + } + Fl_Check_Button {} { + label Enabled + callback {pthread_mutex_lock(&master->mutex); +master->partonoff(npart,(int) o->value()); +pthread_mutex_unlock(&master->mutex); +if (part->Penabled==0) partgroupui->deactivate(); + else partgroupui->activate();} + xywh {85 5 65 20} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(part->Penabled);} + } + Fl_Button {} { + label m + callback {if (part->lastnote>=0) minkcounter->value(part->lastnote); +minkcounter->do_callback(); +maxkcounter->do_callback();} + tooltip {set the minimum key to the last pressed key} xywh {315 153 15 12} box THIN_UP_BOX labelsize 10 + } + Fl_Button {} { + label M + callback {if (part->lastnote>=0) maxkcounter->value(part->lastnote); +maxkcounter->do_callback(); +minkcounter->do_callback();} + tooltip {set the maximum key to the last pressed key} xywh {345 153 15 12} box THIN_UP_BOX labelsize 10 + } + Fl_Button {} { + label R + callback {minkcounter->value(0); +minkcounter->do_callback(); +maxkcounter->value(127); +maxkcounter->do_callback();} + tooltip {reset the minimum key to 0 and maximum key to 127} xywh {330 153 15 12} box THIN_UP_BOX labelfont 1 labelsize 10 + } + } + Fl_Window ctlwindow { + label Controllers + private xywh {24 405 420 130} hide + } { + Fl_Check_Button {} { + label Expr + callback {part->ctl.expression.receive=(int) o->value();} + tooltip {Expression enable} xywh {125 55 45 20} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 + code0 {o->value(part->ctl.expression.receive);} + } + Fl_Dial {} { + label PanDpth + callback {part->ctl.panning.depth=(int) o->value();} + tooltip {Panning Depth} xywh {10 55 30 30} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.panning.depth);} + class WidgetPDial + } + Fl_Dial {} { + label FltCut + callback {part->ctl.filtercutoff.depth=(int) o->value();} + tooltip {Filter Cutoff depth} xywh {90 55 30 30} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.filtercutoff.depth);} + class WidgetPDial + } + Fl_Dial {} { + label FltQ + callback {part->ctl.filterq.depth=(int) o->value();} + tooltip {Filter Q depth} xywh {50 55 30 30} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.filterq.depth);} + class WidgetPDial + } + Fl_Dial {} { + label BwDpth + callback {part->ctl.bandwidth.depth=(int) o->value();} + tooltip {BandWidth depth} xywh {100 10 30 30} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.bandwidth.depth);} + class WidgetPDial + } + Fl_Dial {} { + label ModWh + callback {part->ctl.modwheel.depth=(int) o->value();} + tooltip {Modulation Wheel depth} xywh {55 10 30 30} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.modwheel.depth);} + class WidgetPDial + } + Fl_Counter {} { + label {PWheelB.Rng (cents)} + callback {part->ctl.pitchwheel.bendrange=(int) o->value();} + tooltip {Pitch Wheel Bend Range (cents)} xywh {135 15 110 20} labelsize 10 align 1 minimum -6400 maximum 6400 step 1 + code0 {o->value(part->ctl.pitchwheel.bendrange);} + code1 {o->lstep(100);} + } + Fl_Check_Button {} { + label FMamp + callback {part->ctl.fmamp.receive=(int) o->value();} + tooltip {FM amplitude enable} xywh {175 55 60 20} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 + code0 {o->value(part->ctl.fmamp.receive);} + } + Fl_Check_Button {} { + label Vol + callback {part->ctl.volume.receive=(int) o->value();} + tooltip {Volume enable} xywh {125 80 45 20} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 + code0 {o->value(part->ctl.volume.receive);} + } + Fl_Check_Button {} { + label Sustain + callback {part->ctl.sustain.receive=(int) o->value(); +if (part->ctl.sustain.receive==0) { + part->RelaseSustainedKeys(); + part->ctl.setsustain(0); +};} + tooltip {Sustain pedal enable} xywh {175 80 60 20} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 + code0 {o->value(part->ctl.sustain.receive);} + } + Fl_Button {} { + label Close + callback {ctlwindow->hide();} + xywh {300 105 95 20} box THIN_UP_BOX + } + Fl_Button {} { + label {Reset all controllers} + callback {part->SetController(C_resetallcontrollers,0);} + xywh {5 105 210 20} box THIN_UP_BOX + } + Fl_Group {} { + label Portamento open + xywh {250 15 120 85} box ENGRAVED_FRAME labelfont 1 labelsize 10 + } { + Fl_Check_Button {} { + label Rcv + callback {part->ctl.portamento.receive=(int) o->value();} + tooltip {Receive Portamento Controllers} xywh {255 20 40 20} box THIN_UP_BOX down_box DOWN_BOX labelsize 10 + code0 {o->value(part->ctl.portamento.receive);} + } + Fl_Dial {} { + label time + callback {part->ctl.portamento.time=(int) o->value();} + tooltip {Portamento time} xywh {255 60 25 25} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.portamento.time);} + class WidgetPDial + } + Fl_Counter {} { + label thresh + callback {part->ctl.portamento.pitchthresh=(int) o->value();} + tooltip {Minimum or max. difference of the notes in order to do the portamento (x 100 cents)} xywh {310 20 50 20} type Simple labelsize 10 minimum 0 maximum 127 step 1 + code0 {o->value(part->ctl.portamento.pitchthresh);} + } + Fl_Check_Button {} { + label {th.type} + callback {part->ctl.portamento.pitchthreshtype=(int) o->value();} + tooltip {Threshold type (min/max)} xywh {340 70 15 15} down_box DOWN_BOX labelsize 10 align 2 + code0 {o->value(part->ctl.portamento.pitchthreshtype);} + } + Fl_Box {} { + label {x100 cnt.} + xywh {310 50 55 15} labelsize 10 align 16 + } + Fl_Dial {} { + label {t.up/dn} + callback {int x=(int) o->value(); + +part->ctl.portamento.updowntimestretch=x;} selected + tooltip {Portamento time stretch (up/down)} xywh {285 60 25 25} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.portamento.updowntimestretch);} + class WidgetPDial + } + } + Fl_Group {} { + label Resonance open + xywh {370 15 45 85} box ENGRAVED_BOX labelfont 1 labelsize 10 + } { + Fl_Dial {} { + label BWdpth + callback {part->ctl.resonancebandwidth.depth=(int) o->value();} + tooltip {BandWidth controller depth} xywh {380 60 25 25} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.resonancebandwidth.depth);} + class WidgetPDial + } + Fl_Dial {} { + label CFdpth + callback {part->ctl.resonancecenter.depth=(int) o->value();} + tooltip {Center Frequency controller Depth} xywh {380 20 25 25} labelsize 10 maximum 127 step 1 + code0 {o->value(part->ctl.resonancecenter.depth);} + class WidgetPDial + } + } + Fl_Check_Button {} { + label {Exp MWh} + callback {part->ctl.modwheel.exponential=(int) o->value();} + tooltip {Exponential modulation wheel} xywh {10 15 40 25} down_box DOWN_BOX labelsize 10 align 148 + code0 {o->value(part->ctl.modwheel.exponential);} + } + } + Fl_Window partfx { + label {Part's Insert Effects} + private xywh {110 483 390 145} hide + } { + Fl_Counter inseffnocounter { + label {Ins.Effect No.} + callback {ninseff=(int) o->value(); +insefftype->value(part->partefx[ninseff]->geteffect()); +insefftype->do_callback(); + +int x=part->Pefxroute[ninseff]; +if (x==127) x=1; +sendtochoice->value(x);} + xywh {5 110 80 20} type Simple labelfont 1 labelsize 11 align 6 minimum 0 maximum 127 step 1 textfont 1 + code0 {o->bounds(0,NUM_PART_EFX-1);} + code1 {o->value(ninseff);} + } + Fl_Choice insefftype { + label EffType + callback {inseffectuigroup->remove(inseffectui); +delete inseffectui; +pthread_mutex_lock(part->mutex); +part->partefx[ninseff]->changeeffect((int) o->value()); +pthread_mutex_unlock(part->mutex); +inseffectui=new EffUI(0,0,765,525); +inseffectuigroup->add(inseffectui); +inseffectui->init(part->partefx[ninseff],insefftype); +inseffectui->redraw();} + xywh {95 110 70 15} down_box BORDER_BOX labelsize 11 align 6 + code0 {o->value(part->partefx[ninseff]->geteffect());} + } { + menuitem {} { + label {No Effect} + xywh {35 35 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Reverb + xywh {45 45 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Echo + xywh {55 55 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Chorus + xywh {65 65 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Phaser + xywh {70 70 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label AlienWah + xywh {80 80 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label Distortion + xywh {90 90 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label EQ + xywh {100 100 100 20} labelfont 1 labelsize 11 + } + } + Fl_Group inseffectuigroup { + xywh {5 5 380 100} box FLAT_BOX color 48 + } { + Fl_Group inseffectui { + xywh {5 5 380 95} + code0 {o->init(part->partefx[ninseff],insefftype);} + class EffUI + } {} + } + Fl_Button {} { + label Close + callback {partfx->hide();} + xywh {315 120 70 20} + } + Fl_Choice sendtochoice { + label {Send To.} + callback {int x=(int) o->value(); +if (x==1) x=127; +part->Pefxroute[ninseff]=x;} + xywh {175 110 80 15} down_box BORDER_BOX labelsize 11 align 6 + code0 {int x=part->Pefxroute[ninseff]; if (x==127) x=1;} + code1 {o->value(x);} + } { + menuitem {} { + label {Next Effect} + xywh {45 45 100 20} labelfont 1 labelsize 11 + } + menuitem {} { + label {Part Out} + xywh {55 55 100 20} labelfont 1 labelsize 11 + } + } + } + Fl_Window instrumentkitlist { + label {Instrument Kit} + xywh {70 61 590 370} hide + } { + Fl_Button {} { + label {Close Window} + callback {instrumentkitlist->hide();} + xywh {375 350 160 20} box THIN_UP_BOX + } + Fl_Scroll kitlist { + xywh {0 15 590 330} type VERTICAL box THIN_UP_BOX + code0 {if (part->Pkitmode==0) o->deactivate();} + } { + Fl_Pack {} { + xywh {0 20 590 320} + code0 {for (int i=0;i<NUM_KIT_ITEMS;i++){partkititem[i]=new PartKitItem(0,0,590,20,"");partkititem[i]->init(part,i,master,this);}} + } {} + } + Fl_Box {} { + label {No.} + xywh {5 0 25 15} labelfont 1 labelsize 12 align 18 + } + Fl_Box {} { + label {M.} + xywh {55 0 25 15} labelfont 1 labelsize 12 align 18 + } + Fl_Box {} { + label {Min.k} + xywh {235 0 40 15} labelfont 1 labelsize 12 align 18 + } + Fl_Box {} { + label {Max.k} + xywh {345 0 40 15} labelfont 1 labelsize 12 align 18 + } + Fl_Box {} { + label ADsynth + xywh {405 0 50 15} labelfont 1 labelsize 12 align 18 + } + Fl_Box {} { + label SUBsynth + xywh {475 0 60 15} labelfont 1 labelsize 12 align 18 + } + Fl_Button swapcopybutton { + label {Swap/Copy...} + callback {swapwindow->show();} + xywh {200 350 75 15} box THIN_UP_BOX labelfont 1 labelsize 10 + code0 {if (part->Pkitmode==0) o->deactivate();} + } + Fl_Check_Button protectthekitcheck { + label {Protect the kit} + callback {part->disablekitloading=(int) o->value();} + tooltip {Load only in the 0 item, and preserve other items intact when loading a instrument} xywh {110 350 90 10} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(part->disablekitloading);} + code1 {if (part->Pkitmode==0) o->deactivate();} + } + Fl_Choice {} { + label Mode + callback {part->Pkitmode=(int) o->value(); +if (part->Pkitmode==0) { + kitlist->deactivate(); + swapcopybutton->deactivate(); + protectthekitcheck->value(0); + protectthekitcheck->do_callback(); + protectthekitcheck->deactivate(); + } else { + kitlist->activate(); + swapcopybutton->activate(); + protectthekitcheck->activate(); +};} + xywh {35 350 70 15} down_box BORDER_BOX labelsize 12 textfont 1 textsize 12 + code0 {o->value(part->Pkitmode);} + } { + menuitem {} { + label OFF + xywh {0 0 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label MULTI + xywh {10 10 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label SINGLE + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + } + Fl_Check_Button {} { + label {Drum mode} + callback {part->Pdrummode=(int) o->value();} + xywh {285 350 70 15} down_box DOWN_BOX labelsize 11 + code0 {o->value(part->Pdrummode);} + } + Fl_Box {} { + label {FX.} + xywh {545 0 30 15} labelfont 1 labelsize 12 align 18 + } + } + Fl_Window swapwindow { + label {Swap/Copy item} + xywh {384 262 205 100} hide modal + } { + Fl_Counter swap2counter { + label to + xywh {110 20 75 20} type Simple labelfont 1 labelsize 12 align 1 minimum 0 maximum 127 step 1 value 1 textfont 1 + code0 {o->maximum(NUM_KIT_ITEMS);} + } + Fl_Button {} { + label Swap + callback {int item1=(int) swap1counter->value(); +int item2=(int) swap2counter->value(); + +pthread_mutex_lock(&master->mutex); + part->swapcopyitem(item1,item2,1); +pthread_mutex_unlock(&master->mutex); + +swapwindow->hide(); +showparameters(0,-1); + +for (int i=0;i<NUM_KIT_ITEMS;i++) partkititem[i]->refresh(); + +adsynenabledcheck->value(part->kit[0].Padenabled); +subsynenabledcheck->value(part->kit[0].Psubenabled);} + xywh {15 60 55 25} box THIN_UP_BOX labelfont 1 + } + Fl_Button {} { + label Copy + callback {int item1=(int) swap1counter->value(); +int item2=(int) swap2counter->value(); + +pthread_mutex_lock(&master->mutex); + part->swapcopyitem(item1,item2,0); +pthread_mutex_unlock(&master->mutex); + +swapwindow->hide(); +showparameters(0,-1); + +for (int i=0;i<NUM_KIT_ITEMS;i++) partkititem[i]->refresh(); + +adsynenabledcheck->value(part->kit[0].Padenabled); +subsynenabledcheck->value(part->kit[0].Psubenabled);} + xywh {75 60 55 25} box THIN_UP_BOX labelfont 1 + } + Fl_Button {} { + label Cancel + callback {swapwindow->hide();} + xywh {140 60 55 25} box THIN_UP_BOX labelfont 1 + } + Fl_Counter swap1counter { + label from + xywh {15 20 75 20} type Simple labelfont 1 labelsize 12 align 1 minimum 0 maximum 127 step 1 textfont 1 + code0 {o->maximum(NUM_KIT_ITEMS);} + } + } + Fl_Window infowin { + label {Instrument Info} + xywh {224 184 366 343} hide + } { + Fl_Input {} { + label {Author and Copyright} + callback {snprintf((char *)part->info.Pauthor,MAX_INFO_TEXT_SIZE,"%s",o->value());} + xywh {5 20 355 130} type Multiline align 5 + code0 {o->maximum_size(MAX_INFO_TEXT_SIZE);} + code1 {o->value((char *) &part->info.Pauthor);} + } + Fl_Input {} { + label Comments + callback {snprintf((char *)part->info.Pcomments,MAX_INFO_TEXT_SIZE,"%s",o->value());} + xywh {5 170 355 145} type Multiline align 5 + code0 {o->maximum_size(MAX_INFO_TEXT_SIZE);} + code1 {o->value((char *) &part->info.Pcomments);} + } + Fl_Button {} { + label Close + callback {infowin->hide();} + xywh {245 320 110 20} box THIN_UP_BOX + } + Fl_Choice {} { + label {Type:} + callback {part->info.Ptype=o->value();} + xywh {40 320 150 20} down_box BORDER_BOX labelfont 1 labelsize 12 textsize 11 + code0 {o->value(part->info.Ptype);} + } { + menuitem {} { + label {------------------------} + xywh {10 10 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Piano + xywh {0 0 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Chromatic Percussion} + xywh {10 10 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Organ + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Guitar + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Bass + xywh {40 40 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Solo Strings} + xywh {50 50 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Ensemble + xywh {60 60 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Brass + xywh {70 70 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Reed + xywh {80 80 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Pipe + xywh {90 90 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Synth Lead} + xywh {100 100 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Synth Pad} + xywh {110 110 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Synth Effects} + xywh {120 120 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Ethnic + xywh {130 130 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label Percussive + xywh {140 140 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Sound Effects} + xywh {150 150 100 20} labelfont 1 labelsize 12 + } + } + } + } + Function {PartUI(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {part=NULL; +adnoteui=NULL; +subnoteui=NULL; +lastkititem=-1;} {} + } + Function {init(Part *part_,Master *master_,int npart_,BankUI *bankui_)} {} { + code {bankui=bankui_; +part=part_; +npart=npart_; +master=master_; +ninseff=0; + +make_window(); +partgroup->position(this->parent()->x()+2,this->parent()->y()+2); +partgroup->show(); +end(); + + +if (config.ui.showinstrumentinfo!=0) infowin->show();} {} + } + Function {showparameters(int kititem,int engine)} {} { + code {if (engine==-1){//this is used if I want to clear the engine from the part + if (kititem==lastkititem) kititem=-1; + else kititem=lastkititem; +}; + +if (kititem!=lastkititem){ + if (adnoteui!=NULL) delete (adnoteui); + if (subnoteui!=NULL) delete (subnoteui); + adnoteui=NULL;subnoteui=NULL; + lastkititem=kititem; + + if (kititem>=NUM_KIT_ITEMS) return;//bad kit item + if (kititem<0) return; + + if (part->kit[kititem].adpars!=NULL) + adnoteui=new ADnoteUI(part->kit[kititem].adpars,master); + + if (part->kit[kititem].subpars!=NULL) + subnoteui=new SUBnoteUI(part->kit[kititem].subpars); +}; + + + +if ((engine==0)&&(adnoteui!=NULL)) adnoteui->ADnoteGlobalParameters->show(); +if ((engine==1)&&(subnoteui!=NULL)) subnoteui->SUBparameters->show();} {} + } + Function {~PartUI()} {} { + code {config.ui.showinstrumentinfo=infowin->visible(); + +if (adnoteui!=NULL) delete (adnoteui); +if (subnoteui!=NULL) delete (subnoteui); + +partgroup->hide(); +delete(partgroup); + +ctlwindow->hide(); +delete(ctlwindow); + +partfx->hide(); +delete(partfx); + +infowin->hide(); +delete(infowin); + +instrumentkitlist->hide(); +delete(instrumentkitlist);} {} + } + decl {Part *part;} {} + decl {Master *master;} {} + decl {BankUI *bankui;} {} + decl {ADnoteUI *adnoteui;} {} + decl {SUBnoteUI *subnoteui;} {} + decl {PartSysEffSend *psyef[NUM_SYS_EFX];} {} + decl {int npart;} {} + decl {int ninseff;} {} + decl {int lastkititem;} {} + decl {PartKitItem *partkititem[NUM_KIT_ITEMS];} {} +} diff --git a/src/UI/ResonanceUI.fl b/src/UI/ResonanceUI.fl @@ -0,0 +1,306 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <FL/Fl_Box.H>} {public +} + +decl {\#include <FL/fl_draw.H>} {public +} + +decl {\#include <FL/Fl_Value_Output.H>} {public +} + +decl {\#include <math.h>} {} + +decl {\#include <stdio.h>} {} + +decl {\#include <stdlib.h>} {} + +decl {\#include <string.h>} {} + +decl {\#include "../Synth/Resonance.h"} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +class ResonanceGraph {: {public Fl_Box} +} { + Function {ResonanceGraph(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {respar=NULL;} {} + } + Function {init(Resonance *respar_,Fl_Value_Output *khzvalue_,Fl_Value_Output *dbvalue_)} {} { + code {respar=respar_; +khzvalue=khzvalue_; +dbvalue=dbvalue_; +oldx=-1; +khzval=-1;} {} + } + Function {draw_freq_line(REALTYPE freq,int type)} {} { + code {REALTYPE freqx=respar->getfreqpos(freq); +switch(type){ + case 0:fl_line_style(FL_SOLID);break; + case 1:fl_line_style(FL_DOT);break; + case 2:fl_line_style(FL_DASH);break; +}; + + +if ((freqx>0.0)&&(freqx<1.0)) + fl_line(x()+(int) (freqx*w()),y(), + x()+(int) (freqx*w()),y()+h());} {} + } + Function {draw()} {} { + code {int ox=x(),oy=y(),lx=w(),ly=h(),i,ix,iy,oiy; +REALTYPE freqx; + +fl_color(FL_BLACK); +fl_rectf(ox,oy,lx,ly); + + +//draw the lines +fl_color(FL_GRAY); + +fl_line_style(FL_SOLID); +fl_line(ox+2,oy+ly/2,ox+lx-2,oy+ly/2); + +freqx=respar->getfreqpos(1000.0); +if ((freqx>0.0)&&(freqx<1.0)) + fl_line(ox+(int) (freqx*lx),oy, + ox+(int) (freqx*lx),oy+ly); + +for (i=1;i<10;i++){ + if(i==1){ + draw_freq_line(i*100.0,0); + draw_freq_line(i*1000.0,0); + }else + if (i==5){ + draw_freq_line(i*100.0,2); + draw_freq_line(i*1000.0,2); + }else{ + draw_freq_line(i*100.0,1); + draw_freq_line(i*1000.0,1); + }; +}; + +draw_freq_line(10000.0,0); +draw_freq_line(20000.0,1); + +fl_line_style(FL_DOT); +int GY=10;if (ly<GY*3) GY=-1; +for (i=1;i<GY;i++){ + int tmp=(int)(ly/(REALTYPE)GY*i); + fl_line(ox+2,oy+tmp,ox+lx-2,oy+tmp); +}; + + + +//draw the data +fl_color(FL_RED); +fl_line_style(FL_SOLID); +oiy=(int)(respar->Prespoints[0]/128.0*ly); +for (i=1;i<N_RES_POINTS;i++){ + ix=(int)(i*1.0/N_RES_POINTS*lx); + iy=(int)(respar->Prespoints[i]/128.0*ly); + fl_line(ox+ix-1,oy+ly-oiy,ox+ix,oy+ly-iy); + oiy=iy; +};} {} + } + Function {handle(int event)} {return_type int + } { + code {int x_=Fl::event_x()-x(); +int y_=Fl::event_y()-y(); +if ( (x_>=0)&&(x_<w()) && (y_>=0)&&(y_<h())){ + khzvalue->value(respar->getfreqx(x_*1.0/w())/1000.0); + dbvalue->value((1.0-y_*2.0/h())*respar->PmaxdB); +}; + +if ((event==FL_PUSH)||(event==FL_DRAG)){ + int leftbutton=1; + if (Fl::event_button()==FL_RIGHT_MOUSE) leftbutton=0; + if (x_<0) x_=0;if (y_<0) y_=0; + if (x_>=w()) x_=w();if (y_>=h()-1) y_=h()-1; + + if ((oldx<0)||(oldx==x_)){ + int sn=(int)(x_*1.0/w()*N_RES_POINTS); + int sp=127-(int)(y_*1.0/h()*127); + if (leftbutton!=0) respar->setpoint(sn,sp); + else respar->setpoint(sn,64); + } else { + int x1=oldx; + int x2=x_; + int y1=oldy; + int y2=y_; + if (oldx>x_){ + x1=x_;y1=y_; + x2=oldx;y2=oldy; + }; + for (int i=0;i<x2-x1;i++){ + int sn=(int)((i+x1)*1.0/w()*N_RES_POINTS); + REALTYPE yy=(y2-y1)*1.0/(x2-x1)*i; + int sp=127-(int)((y1+yy)/h()*127); + if (leftbutton!=0) respar->setpoint(sn,sp); + else respar->setpoint(sn,64); + }; + }; + + oldx=x_;oldy=y_; + redraw(); +} else oldx=-1; +return(1);} {} + } + decl {Fl_Value_Output *khzvalue;} {} + decl {Fl_Value_Output *dbvalue;} {} + decl {Resonance *respar;} {} + decl {int oldx,oldy;} {} + decl {REALTYPE khzval;} {public + } +} + +class ResonanceUI {} { + Function {make_window()} {} { + Fl_Window resonancewindow { + label Resonance + xywh {32 300 780 305} hide + } { + Fl_Value_Output khzvalue { + label kHz + xywh {480 264 45 18} align 8 minimum 0.001 maximum 48 step 0.01 textfont 1 + code0 {//this widget must be before the calling widgets} + } + Fl_Value_Output dbvalue { + label dB + xywh {480 282 45 18} align 8 minimum -150 maximum 150 step 0.1 textfont 1 + code0 {//this widget must be before the calling widgets} + } + Fl_Group {} { + xywh {6 5 768 256} box BORDER_BOX + code0 {rg=new ResonanceGraph(o->x(),o->y(),o->w(),o->h(),"");} + code1 {rg->init(respar,khzvalue,dbvalue);} + code2 {rg->show();} + } {} + Fl_Button {} { + label Close + callback {resonancewindow->hide();} + xywh {681 270 93 27} box THIN_UP_BOX + } + Fl_Button {} { + label Zero + callback {for (int i=0;i<N_RES_POINTS;i++) + respar->setpoint(i,64); +resonancewindow->redraw();} + tooltip {Clear the resonance function} xywh {556 264 66 15} box THIN_UP_BOX labelfont 1 + } + Fl_Button {} { + label Smooth + callback {respar->smooth(); +resonancewindow->redraw();} + tooltip {Smooth the resonance function} xywh {556 282 66 18} box THIN_UP_BOX labelfont 1 + } + Fl_Check_Button {} { + label Enable + callback {respar->Penabled=(int) o->value();} + xywh {6 270 78 27} box THIN_UP_BOX down_box DOWN_BOX + code0 {o->value(respar->Penabled);} + } + Fl_Roller {} { + callback {maxdbvo->value(o->value()); +respar->PmaxdB=(int) o->value();} + xywh {90 282 84 15} type Horizontal minimum 1 maximum 90 step 1 value 30 + } + Fl_Value_Output maxdbvo { + label {Max.} + callback {o->value(respar->PmaxdB);} + tooltip {The Maximum amplitude (dB)} xywh {126 264 24 18} minimum 1 maximum 127 step 1 value 30 textfont 1 + code0 {o->value(respar->PmaxdB);} + } + Fl_Box {} { + label dB + xywh {150 264 24 18} + } + Fl_Value_Output centerfreqvo { + label {C.f.} + callback {o->value(respar->getcenterfreq()/1000.0);} + tooltip {Center Frequency (kHz)} xywh {210 264 33 18} when 3 minimum 1 maximum 10 step 0.01 value 1 textfont 1 + code0 {o->value(respar->getcenterfreq()/1000.0);} + } + Fl_Value_Output octavesfreqvo { + label {Oct.} + callback {o->value(respar->getoctavesfreq());} + tooltip {No. of octaves} xywh {210 282 33 18} when 3 minimum 1 maximum 127 step 1 value 30 textfont 1 + code0 {o->value(respar->getoctavesfreq());} + } + Fl_Value_Slider {} { + label {Amplification(dB)} + callback {respar->Pgain=(int) o->value();} + xywh {318 282 108 15} type {Horz Knob} box FLAT_BOX labelfont 1 labelsize 12 align 5 maximum 60 step 1 + code0 {o->value(respar->Pgain);} + } + Fl_Button {} { + label RND2 + callback {respar->randomize(1); +resonancewindow->redraw();} + tooltip {Randomize the resonance function} xywh {631 276 42 12} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Button {} { + label RND1 + callback {respar->randomize(0); +resonancewindow->redraw();} + tooltip {Randomize the resonance function} xywh {631 264 42 12} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Button {} { + label RND3 + callback {respar->randomize(2); +resonancewindow->redraw();} + tooltip {Randomize the resonance function} xywh {631 288 42 12} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Check_Button {} { + label {P.1st} + callback {respar->Pprotectthefundamental=(int) o->value();} + tooltip {Protect the fundamental frequency (do not damp the first harmonic)} xywh {430 285 45 15} down_box DOWN_BOX labelsize 10 + code0 {o->value(respar->Pprotectthefundamental);} + } + Fl_Button {} { + label InterpP + callback {int type; +if (Fl::event_button()==FL_LEFT_MOUSE) type=0; + else type=1; +respar->interpolatepeaks(type); +resonancewindow->redraw();} + tooltip {Interpolate the peaks} xywh {430 265 46 15} box THIN_UP_BOX labelfont 1 labelsize 10 + } + Fl_Dial {} { + label {C.f.} + callback {respar->Pcenterfreq=(int)o->value(); +centerfreqvo->do_callback(); +rg->redraw();} + xywh {245 265 30 30} box ROUND_UP_BOX labelsize 10 maximum 127 step 1 + code0 {o->value(respar->Pcenterfreq);} + class WidgetPDial + } + Fl_Dial {} { + label {Oct.} + callback {respar->Poctavesfreq=(int)o->value(); +octavesfreqvo->do_callback(); +rg->redraw();} selected + xywh {280 265 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(respar->Poctavesfreq);} + class WidgetPDial + } + } + } + Function {ResonanceUI(Resonance *respar_)} {} { + code {respar=respar_; +make_window();} {} + } + Function {~ResonanceUI()} {} { + code {resonancewindow->hide();} {} + } + decl {Resonance *respar;} {public + } + decl {ResonanceGraph *rg;} {} +} diff --git a/src/UI/SUBnoteUI.fl b/src/UI/SUBnoteUI.fl @@ -0,0 +1,382 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <string.h>} {public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {\#include "EnvelopeUI.h"} {public +} + +decl {\#include "FilterUI.h"} {public +} + +decl {\#include "../Misc/Util.h"} {public +} + +decl {\#include "../Params/SUBnoteParameters.h"} {public +} + +class SUBnoteharmonic {: {public Fl_Group} +} { + Function {make_window()} {private + } { + Fl_Window harmonic { + xywh {329 403 90 225} hide + class Fl_Group + } { + Fl_Slider mag { + callback {int x=0; +if (Fl::event_button1()) x=127-(int)o->value(); + else o->value(127-x); +pars->Phmag[n]=x; +if (pars->Phmag[n]==0) o->selection_color(0); + else o->selection_color(222);} + tooltip {harmonic's magnitude} xywh {0 15 10 115} type {Vert Knob} box FLAT_BOX selection_color 222 labelcolor 0 maximum 127 step 1 value 127 + code0 {o->value(127-pars->Phmag[n]);} + code1 {if (pars->Phmag[n]==0) o->selection_color(0);} + } + Fl_Slider bw { + callback {int x=64; +if (Fl::event_button1()) x=127-(int)o->value(); + else o->value(x); +pars->Phrelbw[n]=x;} + tooltip {harmonic's bandwidth} xywh {0 135 10 75} type {Vert Knob} box FLAT_BOX selection_color 222 maximum 127 step 1 value 64 + code0 {o->value(127-pars->Phrelbw[n]);} + } + Fl_Box {} { + xywh {10 170 5 5} box FLAT_BOX color 45 + code0 {if (n+1==MAX_SUB_HARMONICS) o->hide();} + } + Fl_Box {} { + label 01 + xywh {0 210 10 15} labelfont 1 labelsize 9 align 20 + code0 {char tmp[10];snprintf(tmp,10,"%d",n+1);o->label(strdup(tmp));} + } + Fl_Box {} { + label 01 + xywh {0 0 10 15} labelfont 1 labelsize 9 align 20 + code0 {char tmp[10];snprintf(tmp,10,"%d",n+1);o->label(strdup(tmp));} + } + } + } + Function {SUBnoteharmonic(int x,int y, int w, int h, const char *label=0):Fl_Group(x,y,w,h,label)} {} { + code {n=0;} {} + } + Function {init(SUBnoteParameters *pars_,int n_)} {} { + code {pars=pars_; +n=n_; +make_window(); +harmonic->show(); +end();} {} + } + decl {SUBnoteParameters *pars;} {} + decl {int n;} {} + Function {~SUBnoteharmonic()} {} { + code {harmonic->hide(); +hide(); +delete(harmonic);} {} + } +} + +class SUBnoteUI {} { + Function {make_window()} {} { + Fl_Window SUBparameters { + label {SUBsynth Parameters} + xywh {4 225 735 390} hide + } { + Fl_Scroll {} { + xywh {5 140 435 245} type HORIZONTAL box THIN_UP_BOX + } { + Fl_Pack harmonics {open + xywh {10 145 425 235} type HORIZONTAL + code0 {for (int i=0;i<MAX_SUB_HARMONICS;i++){h[i]=new SUBnoteharmonic(0,0,15,o->h(),"");h[i]->init(pars,i);}} + } {} + } + Fl_Button {} { + label Close + callback {SUBparameters->hide();} + xywh {590 365 140 20} box THIN_UP_BOX labelfont 1 labelsize 12 + } + Fl_Group {} { + label AMPLITUDE + xywh {5 5 215 135} box THIN_UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 + } { + Fl_Value_Slider {} { + label Vol + callback {pars->PVolume=(int)o->value();} + tooltip Volume xywh {10 25 140 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->PVolume);} + } + Fl_Value_Slider {} { + label {V.Sns} + callback {pars->PAmpVelocityScaleFunction=(int) o->value();} + tooltip {Velocity Sensing Function (rightmost to disable)} xywh {10 45 140 15} type {Horz Knob} box FLAT_BOX labelsize 12 align 8 maximum 127 step 1 + code0 {o->value(pars->PAmpVelocityScaleFunction);} + } + Fl_Dial {} { + label Pan + callback {pars->PPanning=(int) o->value();} + tooltip {Panning (leftmost is Random)} xywh {185 20 30 30} box ROUND_UP_BOX labelsize 11 maximum 127 step 1 + code0 {o->value(pars->PPanning);} + class WidgetPDial + } + Fl_Group {} { + label {SUBsynth - Amplitude Envelope} open + xywh {10 65 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->AmpEnvelope);} + class EnvelopeUI + } {} + } + Fl_Group {} { + xywh {495 325 235 35} box THIN_UP_FRAME + } { + Fl_Counter {} { + label {Filter Stages} + callback {pars->Pnumstages=(int) o->value();} + tooltip {How many times the noise is filtered} xywh {515 340 45 15} type Simple labelfont 1 labelsize 10 align 1 minimum 1 maximum 5 step 1 textsize 10 + code0 {o->value(pars->Pnumstages);} + } + Fl_Choice {} { + label {Mag.Type} + callback {pars->Phmagtype=(int) o->value();} + xywh {585 340 65 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 textsize 12 + code0 {o->value(pars->Phmagtype);} + } { + menuitem {} { + label Linear + xywh {20 20 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-40dB} + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-60dB} + xywh {40 40 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-80dB} + xywh {50 50 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {-100dB} + xywh {60 60 100 20} labelfont 1 labelsize 12 + } + } + Fl_Choice {} { + label Start + callback {pars->Pstart=(int) o->value();} open + xywh {670 340 50 15} down_box BORDER_BOX labelfont 1 labelsize 10 align 1 textsize 12 + code0 {o->value(pars->Pstart);} + } { + menuitem {} { + label Zero + xywh {30 30 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label RND + xywh {40 40 100 20} labelfont 1 labelsize 12 + } + menuitem {} { + label {Max.} + xywh {50 50 100 20} labelfont 1 labelsize 12 + } + } + } + Fl_Group freqsettingsui { + label FREQUENCY + xywh {440 5 290 135} box THIN_UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 + } { + Fl_Group freqenvelopegroup { + label {SUBsynth - Frequency Envelope} open + xywh {445 65 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->FreqEnvelope);} + code1 {if (pars->PFreqEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Check_Button {} { + label Enabled + callback {pars->PFreqEnvelopeEnabled=o->value(); +if (o->value()==0) freqenvelopegroup->deactivate(); + else freqenvelopegroup->activate(); +o->show(); +freqsettingsui->redraw();} + xywh {445 68 55 15} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->PFreqEnvelopeEnabled);} + } + Fl_Counter {} { + label Oct + callback {int k=(int) o->value(); +if (k<0) k+=16; +pars->PCoarseDetune = k*1024+ + pars->PCoarseDetune%1024;} + tooltip Octave xywh {680 95 45 20} type Simple labelsize 10 align 4 minimum -8 maximum 7 step 1 textfont 1 textsize 12 + code0 {int k=pars->PCoarseDetune/1024;} + code1 {if (k>=8) k-=16;} + code2 {o->value(k);} + } + Fl_Counter {} { + label Type + callback {pars->PDetuneType=(int) o->value(); +detunevalueoutput->do_callback();} + tooltip {The way of how the detune is computed} xywh {685 120 40 15} type Simple labelsize 10 align 4 minimum 1 maximum 127 step 1 textfont 1 textsize 12 + code0 {o->bounds(1,N_DETUNE_TYPES);} + code1 {o->value(pars->PDetuneType);} + } + Fl_Counter {} { + label {Coarse Det.} + callback {int k=(int) o->value(); +if (k<0) k+=1024; +pars->PCoarseDetune = k+ + (pars->PCoarseDetune/1024)*1024;} + tooltip {Coarse Detune} xywh {665 50 60 20} labelsize 11 align 1 minimum -64 maximum 63 step 1 textfont 1 textsize 12 + code0 {int k=pars->PCoarseDetune%1024;} + code1 {if (k>=512) k-=1024;} + code2 {o->value(k);} + code3 {o->lstep(10);} + } + Fl_Text_Display {} { + xywh {665 70 60 15} labelsize 12 textsize 12 + } + Fl_Slider {} { + callback {pars->PDetune=(int)o->value()+8192; +detunevalueoutput->do_callback();} + tooltip {Fine Detune (cents)} xywh {495 25 230 15} type {Horz Knob} box FLAT_BOX minimum -8192 maximum 8191 step 1 + code0 {o->value(pars->PDetune-8192);} + } + Fl_Value_Output detunevalueoutput { + label Detune + callback {o->value(getdetune(pars->PDetuneType,0,pars->PDetune));} + xywh {448 25 45 15} labelsize 10 align 5 minimum -5000 maximum 5000 step 0.01 textfont 1 textsize 10 + code0 {o->value(getdetune(pars->PDetuneType,0,pars->PDetune));} + } + Fl_Check_Button {} { + label 440Hz + callback {int x=(int) o->value(); +pars->Pfixedfreq=x; +if (x==0) fixedfreqetdial->deactivate(); + else fixedfreqetdial->activate();} + tooltip {set the base frequency to 440Hz} xywh {555 45 50 15} down_box DOWN_BOX labelfont 1 labelsize 11 + code0 {o->value(pars->Pfixedfreq);} + } + Fl_Dial fixedfreqetdial { + label {Eq.T.} + callback {pars->PfixedfreqET=(int) o->value();} + tooltip {How the frequency varies acording to the keyboard (leftmost for fixed frequency)} xywh {610 45 15 15} box ROUND_UP_BOX labelsize 10 align 8 maximum 127 step 1 + code0 {o->value(pars->PfixedfreqET);} + code1 {if (pars->Pfixedfreq==0) o->deactivate();} + class WidgetPDial + } + } + Fl_Check_Button {} { + label Stereo + callback {pars->Pstereo=(int) o->value();} + xywh {440 325 55 35} box THIN_UP_BOX down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->Pstereo);} + } + Fl_Button {} { + label Clear + callback {for (int i=0;i<MAX_SUB_HARMONICS;i++){ + h[i]->mag->value(127); + pars->Phmag[i]=0; + h[i]->bw->value(64); + pars->Phrelbw[i]=64; +}; +pars->Phmag[0]=127; +h[0]->mag->value(0); +SUBparameters->redraw();} + tooltip {Clear the harmonics} xywh {445 365 70 20} box THIN_UP_BOX labelfont 1 labelsize 12 + } + Fl_Group bandwidthsettingsui { + label BANDWIDTH + xywh {220 5 220 135} box THIN_UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 align 17 + } { + Fl_Group bandwidthenvelopegroup { + label {SUBsynth - BandWidth Envelope} open + xywh {225 65 205 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->BandWidthEnvelope);} + code1 {if (pars->PBandWidthEnvelopeEnabled==0) o->deactivate();} + class EnvelopeUI + } {} + Fl_Check_Button {} { + label Enabled + callback {pars->PBandWidthEnvelopeEnabled=o->value(); +if (o->value()==0) bandwidthenvelopegroup->deactivate(); + else bandwidthenvelopegroup->activate(); +o->show(); +bandwidthsettingsui->redraw();} + xywh {225 67 55 15} down_box DOWN_BOX labelfont 1 labelsize 10 + code0 {o->value(pars->PBandWidthEnvelopeEnabled);} + } + Fl_Value_Slider {} { + label {Band Width} + callback {pars->Pbandwidth=(int) o->value();} + xywh {225 40 115 15} type {Horz Knob} box FLAT_BOX labelsize 10 align 1 maximum 127 step 1 + code0 {o->value(pars->Pbandwidth);} + } + Fl_Value_Slider {} { + label {B.Width Scale} + callback {pars->Pbwscale=(int) o->value()+64;} + tooltip {How much I increase the BandWidth according to lower/higher harmonics} xywh {345 40 90 15} type {Horz Knob} box FLAT_BOX labelsize 10 align 1 minimum -64 maximum 63 step 1 + code0 {o->value(pars->Pbwscale-64);} + } + } + Fl_Group globalfiltergroup { + label FILTER + xywh {440 140 290 185} box THIN_UP_FRAME labeltype EMBOSSED_LABEL labelfont 1 labelsize 16 align 17 + code0 {if (pars->PGlobalFilterEnabled==0) o->deactivate();} + } { + Fl_Group {} { + label {SUBsynth - Filter Envelope} open + xywh {445 250 275 70} box FLAT_BOX color 51 align 144 + code0 {o->init(pars->GlobalFilterEnvelope);} + class EnvelopeUI + } {} + Fl_Group {} { + label {SUBsynthl - Filter} open selected + xywh {445 170 275 75} box FLAT_BOX color 50 align 144 + code0 {o->init(pars->GlobalFilter,&pars->PGlobalFilterVelocityScale,&pars->PGlobalFilterVelocityScaleFunction);} + class FilterUI + } {} + } + Fl_Check_Button {} { + label Enabled + callback {pars->PGlobalFilterEnabled=o->value(); +if (o->value()==0) globalfiltergroup->deactivate(); + else globalfiltergroup->activate(); +o->show(); +globalfiltergroup->redraw();} + xywh {445 145 85 20} down_box DOWN_BOX labelfont 1 labelsize 12 + code0 {o->value(pars->PGlobalFilterEnabled);} + } + } + } + Function {SUBnoteUI(SUBnoteParameters *parameters)} {} { + code {pars=parameters; +make_window();} {} + } + Function {~SUBnoteUI()} {} { + code {for (int i=0;i<MAX_SUB_HARMONICS;i++) delete (h[i]); +SUBparameters->hide(); +delete(SUBparameters);} {} + } + decl {SUBnoteParameters *pars;} {} + decl {SUBnoteharmonic *h[MAX_SUB_HARMONICS];} {} +} diff --git a/src/UI/SeqUI.fl b/src/UI/SeqUI.fl @@ -0,0 +1,80 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include "../globals.h"} {public +} + +decl {\#include "../Misc/Master.h"} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +class SeqUI {open +} { + Function {make_window()} {open + } { + Fl_Window seqwin { + label {Sequencer - ZynAddSubFX} open + xywh {104 235 239 100} visible + } { + Fl_Group {} { + label Recorder + xywh {10 20 100 65} box ENGRAVED_BOX labelfont 1 + } { + Fl_Button recordbutton { + label {Rec.} + callback {o->deactivate(); +stopbutton_rec->activate(); +master->seq.startrec();} + tooltip {Start Recording} xywh {20 30 30 30} box ROUND_UP_BOX color 88 labelfont 1 labelsize 16 align 2 + } + Fl_Button stopbutton_rec { + label Stop + callback {o->deactivate(); +recordbutton->activate(); + +master->seq.stoprec();} + tooltip {Stop Recording} xywh {65 29 30 31} box THIN_UP_BOX color 4 labelfont 1 labelsize 16 align 2 deactivate + } + } + Fl_Group {} { + label Player + xywh {120 20 100 65} box ENGRAVED_BOX labelfont 1 + } { + Fl_Button playbutton { + label Play + callback {o->deactivate(); +stopbutton_play->activate(); + +master->seq.startplay();} + tooltip {Start Playing} xywh {130 30 30 30} box DIAMOND_UP_BOX color 79 labelfont 1 labelsize 16 align 2 + } + Fl_Button stopbutton_play { + label Stop + callback {o->deactivate(); +playbutton->activate(); + +master->seq.stopplay();} selected + tooltip {Stop Playing} xywh {175 29 30 31} box THIN_UP_BOX color 4 labelfont 1 labelsize 16 align 2 deactivate + } + } + } + } + Function {SeqUI(Master *master_)} {open + } { + code {master=master_; + +make_window();} {} + } + decl {Master *master} {} + Function {show()} {open + } { + code {seqwin->show();} {} + } +} diff --git a/src/UI/VirKeyboard.fl b/src/UI/VirKeyboard.fl @@ -0,0 +1,385 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0104 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2002-2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <stdlib.h>} {selected public +} + +decl {\#include <FL/fl_draw.H>} {public +} + +decl {\#include <FL/Fl_Box.H>} {public +} + +decl {\#include "../globals.h"} {public +} + +decl {\#include "../Misc/Master.h"} {public +} + +decl {\#include "../Input/MidiIn.h"} {public +} + +decl {\#include "WidgetPDial.h"} {public +} + +decl {const int keyspos[12]={0,-1,1,-2,2,3,-4,4,-5,5,-6,6};} {} + +decl {const int keysoct1[]={'q','2','w','3','e','r','5','t','6','y','7','u','i','9','o','0','p','[','=',']','\\\\',FL_Enter,0};} {} + +decl {const int keysoct2[]={'z','s','x','d','c','v','g','b','h','n','j','m',',','l','.',';','/',0};} {} + +class VirKeys {: {public Fl_Box} +} { + decl {static const int N_OCT=6;} {} + decl {static const int SIZE_WHITE=14;} {} + decl {static const int SIZE_BLACK=8;} {} + Function {VirKeys(int x,int y, int w, int h, const char *label=0):Fl_Box(x,y,w,h,label)} {} { + code {master=NULL;} {} + } + Function {init(Master *master_)} {} { + code {master=master_; +for (int i=0;i<N_OCT*12+1;i++) pressed[i]=0; +midich=0; +midivel=100; +midioct=2; + +keyoct1=3; +keyoct2=2; +rndvelocity=0;} {} + } + Function {draw()} {} { + code {int ox=x(),oy=y(),lx=w(),ly=h()-1,i; + +if (damage()!=1){ + fl_color(250,240,230); + fl_rectf(ox,oy,lx,ly); + + fl_color(FL_BLACK); + fl_line(ox,oy,ox+lx,oy); + fl_line(ox,oy+ly,ox+lx,oy+ly); + for (i=0;i<N_OCT*7+1;i++){ + fl_line(ox+i*SIZE_WHITE,oy,ox+i*SIZE_WHITE,oy+ly); + int ik=i%7; + if ((ik==1)||(ik==2)||(ik==4)||(ik==5)||(ik==6)) + fl_rectf(ox+i*SIZE_WHITE-SIZE_BLACK/2,oy, + SIZE_BLACK+1,ly*3/5); + }; +}; + + +for (i=0;i<N_OCT*12;i++){ + // if (pressed[i]==0) continue; + + int noct=i/12; + int kv=keyspos[i%12]; + + if (kv>=0){//white keys + if (pressed[i]==0) fl_color(250,240,230); + else fl_color(FL_BLUE); + fl_rectf(ox+(kv+7*noct)*SIZE_WHITE+3,oy+ly*3/5+2, + SIZE_WHITE-4,ly*2/5-3); + } else {//black keys + kv=keyspos[(i+1)%12]; + if (pressed[i]==0) fl_color(FL_BLACK); + else fl_color(FL_BLUE); + fl_rectf(ox+(kv+7*noct)*SIZE_WHITE-SIZE_BLACK/2+2,oy+2, + SIZE_BLACK-3,ly*3/5-5); + }; +};} {} + } + Function {handle(int event)} {return_type int + } { + code {int i; +int ly=h(); +int x_=Fl::event_x()-x(); +int y_=Fl::event_y()-y(); +if ( (x_<0)&&(x_>w()) && (y_<0)&&(y_>h())){ + return(0); +}; + + +if ((event==FL_PUSH)||(event==FL_DRAG)||(event==FL_RELEASE)){ + int kpos=-1; + + if (y_>ly*3/5){//white keys + int pos=x_/SIZE_WHITE; + if (pos<0) return(1); + for (i=0;i<12;i++) { + if (pos%7==keyspos[i]) { + kpos=pos/7*12+i; + break; + }; + }; + } else {//black keys + int pos=(x_+SIZE_WHITE/2)/SIZE_WHITE; + if (pos<0) return(1); + for (i=1;i<12;i++) { + if (pos%7==-keyspos[i]) { + kpos=pos/7*12+i; + break; + }; + }; + }; + + if (((event==FL_PUSH)||(event==FL_DRAG))&& + (Fl::event_shift()==0)) { + presskey(kpos,1,1); + }; + + if ((event==FL_PUSH)&&(Fl::event_shift()!=0)) { + if (pressed[kpos]==0) presskey(kpos,0,1); + else relasekey(kpos,1); + }; + if ((event==FL_RELEASE)&&(Fl::event_shift()==0)) + relaseallkeys(1); + take_focus(); +}; + +if ((event==FL_KEYDOWN)||(event==FL_KEYUP)){ + int key=Fl::event_key(); + int kpos=-1; + for (i=0;keysoct1[i]!=0;i++) if (key==keysoct1[i]) kpos=i+12*keyoct1; + for (i=0;keysoct2[i]!=0;i++) if (key==keysoct2[i]) kpos=i+12*keyoct2; + + if (kpos==-1) return(0); + if (event==FL_KEYDOWN) presskey(kpos,0,2); + else relasekey(kpos,2); +}; + +return(1);} {} + } + Function {presskey(int nk,int exclusive,int type)} {} { + code {if (nk>=N_OCT*12) return; +if ((nk<0)&&(exclusive==0)) { + relaseallkeys(type); + return; +}; +if (pressed[nk]!=0) return;//the key is already pressed + +if (exclusive!=0) relaseallkeys(type); +pressed[nk]=type; + +damage(1); +float vel=midivel; +if (rndvelocity!=0){ + vel=midivel*(127.0-rndvelocity)/127.0+RND*rndvelocity; +}; + +pthread_mutex_lock(&master->mutex); + master->NoteOn(midich,nk+midioct*12,(int)vel); +pthread_mutex_unlock(&master->mutex);} {} + } + Function {relasekey(int nk,int type)} {} { + code {if ((nk<0)||(nk>=N_OCT*12)) return; +if (pressed[nk]==0) return;//the key is not pressed +if ((type!=0)&&(pressed[nk]!=type)) return; + +pressed[nk]=0; + + +damage(1); + +pthread_mutex_lock(&master->mutex); + master->NoteOff(midich,nk+12*midioct); +pthread_mutex_unlock(&master->mutex);} {} + } + Function {relaseallkeys(int type)} {} { + code {for (int i=0;i<N_OCT*12;i++) relasekey(i,type);} {} + } + decl {Master *master;} {} + decl {int pressed[N_OCT*12+1];} {} + decl {unsigned char midich;} {public + } + decl {unsigned char midivel;} {public + } + decl {char midioct,keyoct1,keyoct2;} {public + } + decl {unsigned char rndvelocity;} {public + } +} + +class VirKeyboard {} { + Function {make_window()} {} { + Fl_Window virkeyboardwindow { + label {Virtual Keyboard - ZynAddSubFX} + callback {relaseallkeys(); +virkeyboardwindow->hide();} + xywh {46 407 650 130} hide + } { + Fl_Box virkeys { + label Keyboard + xywh {10 10 590 80} box FLAT_BOX color 17 + code0 {o->init(master);} + class VirKeys + } + Fl_Counter {} { + label {"qwer.." Oct} + callback {relaseallkeys(); +virkeys->keyoct1=(int) o->value(); +virkeys->take_focus();} + tooltip {keys "q2w3er5t6y..." octave} xywh {380 95 45 15} type Simple labelsize 10 align 4 when 6 minimum 0 maximum 5 step 1 textfont 1 textsize 10 + code0 {o->value(virkeys->keyoct1);} + } + Fl_Counter {} { + label {"zxcv.." Oct} + callback {relaseallkeys(); +virkeys->keyoct2=(int) o->value(); +virkeys->take_focus();} + tooltip {keys "zsxdcvgbh..." octave} xywh {380 110 45 15} type Simple labelsize 10 align 4 when 6 minimum 0 maximum 5 step 1 textfont 1 textsize 10 + code0 {o->value(virkeys->keyoct2);} + } + Fl_Counter {} { + label {Ch.} + callback {relaseallkeys(); +virkeys->midich=(int) o->value(); +virkeys->take_focus();} + tooltip {Midi Channel} xywh {30 100 55 20} type Simple labelsize 12 align 4 when 6 minimum 0 maximum 15 step 1 textfont 1 textsize 12 + code0 {o->value(virkeys->midich);} + } + Fl_Value_Slider {} { + label Vel + callback {virkeys->midivel=(int) o->value(); +virkeys->take_focus();} + tooltip Velocity xywh {90 105 105 15} type {Horz Knob} box FLAT_BOX labelsize 10 align 5 minimum 1 maximum 127 step 1 + code0 {o->value(virkeys->midivel);} + } + Fl_Counter {} { + label {Oct.} + callback {relaseallkeys(); +virkeys->midioct=(int) o->value(); +virkeys->take_focus();} + tooltip {Midi Octave} xywh {255 100 55 20} type Simple labelsize 12 align 4 when 6 minimum 0 maximum 5 step 1 textfont 1 textsize 12 + code0 {o->value(virkeys->midioct);} + } + Fl_Button {} { + label Close + callback {relaseallkeys(); +virkeyboardwindow->hide();} + xywh {545 105 55 20} box THIN_UP_BOX + } + Fl_Value_Slider {} { + label Cval + callback {int ctl=midictl; + +pthread_mutex_lock(&master->mutex); + master->SetController(virkeys->midich,ctl,(int) o->value()); +pthread_mutex_unlock(&master->mutex); +virkeys->take_focus();} + tooltip {Controller value} xywh {605 10 15 115} type {Vert Fill} box ENGRAVED_BOX selection_color 229 labelsize 8 align 5 minimum 127 maximum 0 step 1 value 64 textsize 7 + } + Fl_Choice {} { + label Controller + callback {switch((int) o->value()+1){ + case 1: midictl=C_modwheel; break; + case 2: midictl=C_volume; break; + case 3: midictl=C_panning; break; + case 4: midictl=C_expression; break; + case 5: midictl=C_sustain; break; + case 6: midictl=C_portamento; break; + case 7: midictl=C_filterq; break; + case 8: midictl=C_filtercutoff; break; + case 9: midictl=C_bandwidth; break; + case 10: midictl=C_fmamp; break; + case 11: midictl=C_resonance_center; break; + case 12: midictl=C_resonance_bandwidth; break; + default: midictl=C_NULL; break; + +}; + + + +virkeys->take_focus();} + xywh {435 105 100 15} down_box BORDER_BOX labelsize 10 align 5 when 6 textfont 1 textsize 10 + code0 {midictl=C_bandwidth;o->value(8);} + } { + menuitem {} { + label {01: Mod.Wheel} + xywh {0 0 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {07: Volume} + xywh {10 10 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {10: Panning} + xywh {20 20 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {11: Expression} + xywh {30 30 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {64: Sustain} + xywh {40 40 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {65: Portamento} + xywh {50 50 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {71: Filter Q} + xywh {60 60 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {74: Filter Freq.} + xywh {70 70 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {75: Bandwidth} + xywh {80 80 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {76: FM Gain} + xywh {90 90 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {77: Res. c. freq} + xywh {100 100 100 20} labelfont 1 labelsize 10 + } + menuitem {} { + label {78: Res. bw.} + xywh {110 110 100 20} labelfont 1 labelsize 10 + } + } + Fl_Roller pitchwheelroller { + label Pwh + callback {pthread_mutex_lock(&master->mutex); + master->SetController(virkeys->midich,C_pitchwheel,-(int) o->value()); +pthread_mutex_unlock(&master->mutex); +virkeys->take_focus();} + tooltip {Pitch Wheel} xywh {625 10 20 95} box PLASTIC_UP_BOX labelsize 8 align 1 when 3 minimum -8192 maximum 8192 step 64 + } + Fl_Button {} { + label R + callback {pitchwheelroller->value(0); +pitchwheelroller->do_callback();} + tooltip {Reset Pitch Bend} xywh {625 110 20 15} box THIN_UP_BOX labelfont 1 + } + Fl_Dial {} { + label Vrnd + callback {virkeys->rndvelocity=(int) o->value();} + tooltip {Velocity Randomness} xywh {205 105 20 20} box ROUND_UP_BOX labelsize 10 align 129 maximum 127 step 1 + code0 {o->value(virkeys->rndvelocity);} + class WidgetPDial + } + } + } + Function {VirKeyboard(Master *master_)} {} { + code {master=master_; +midictl=75; +make_window();} {} + } + Function {show()} {} { + code {virkeyboardwindow->show();} {} + } + Function {relaseallkeys()} {} { + code {virkeys->relaseallkeys(0);} {} + } + decl {Master *master;} {} + decl {int midictl;} {} +} diff --git a/src/UI/WidgetPDial.fl b/src/UI/WidgetPDial.fl @@ -0,0 +1,123 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0103 +header_name {.h} +code_name {.cc} +decl {//Copyright (c) 2003 Nasca Octavian Paul} {} + +decl {//License: GNU GPL version 2} {} + +decl {\#include <FL/Fl_Dial.H>} {public +} + +decl {\#include <FL/fl_draw.H>} {public +} + +decl {\#include <stdio.h>} {public +} + +decl {\#include <math.h>} {public +} + +class WidgetPDial {: {public Fl_Dial} +} { + Function {WidgetPDial(int x,int y, int w, int h, const char *label=0):Fl_Dial(x,y,w,h,label)} {} { + code {oldvalue=0.0;} {} + } + Function {handle(int event)} {return_type int + } { + code {switch (event){ +case FL_PUSH:oldvalue=value(); +case FL_DRAG: + int my=-(Fl::event_y()-y()-h()/2); + + double dragsize=200.0; + if (Fl::event_state(FL_BUTTON1)==0) dragsize*=10; + double v=oldvalue+my/dragsize*(maximum()-minimum()); + if (v<minimum()) v=minimum(); + else if (v>maximum()) v=maximum(); + + value(v); + value_damage(); + do_callback(); + return(1); + break; +}; +return(0);} {selected + } + } + Function {drawgradient(int cx,int cy,int sx,double m1,double m2)} {return_type void + } { + code {for (int i=(int)(m1*sx);i<(int)(m2*sx);i++){ + double tmp=1.0-pow(i*1.0/sx,2.0); + pdialcolor(140+(int) (tmp*90),140+(int)(tmp*90),140+(int) (tmp*100)); + fl_arc(cx+sx/2-i/2,cy+sx/2-i/2,i,i,0,360); +};} {} + } + Function {draw()} {} { + code {int cx=x(),cy=y(),sx=w(),sy=h(); + + +//clears the button face +pdialcolor(190,190,200); +fl_pie(cx-1,cy-1,sx+2,sy+2,0,360); + +//Draws the button face (gradinet) +drawgradient(cx,cy,sx,0.5,1.0); + +double val=(value()-minimum())/(maximum()-minimum()); + +//draws the scale +pdialcolor(220,220,250); +double a1=angle1(),a2=angle2(); +for (int i=0;i<12;i++){ + double a=-i/12.0*360.0-val*(a2-a1)-a1; + fl_pie(cx,cy,sx,sy,a+270-3,a+3+270); +}; + +drawgradient(cx,cy,sx,0.0,0.75); + +//draws the value +double a=-(a2-a1)*val-a1; + + + + + +//draws the max and min points +pdialcolor(0,100,200); +int xp=(int)(cx+sx/2.0+sx/2.0*sin(angle1()/180.0*3.141592)); +int yp=(int)(cy+sy/2.0+sy/2.0*cos(angle1()/180.0*3.141592)); +fl_pie(xp-2,yp-2,4,4,0,360); + +xp=(int)(cx+sx/2.0+sx/2.0*sin(angle2()/180.0*3.141592)); +yp=(int)(cy+sy/2.0+sy/2.0*cos(angle2()/180.0*3.141592)); +fl_pie(xp-2,yp-2,4,4,0,360); + + + + + +fl_push_matrix(); + + fl_translate(cx+sx/2,cy+sy/2); + fl_rotate(a-90.0); + + fl_translate(sx/2,0); + + + fl_begin_polygon(); + pdialcolor(0,0,0); + fl_vertex(-10,-4); + fl_vertex(-10,4); + fl_vertex(0,0); + fl_end_polygon(); + + +fl_pop_matrix();} {} + } + Function {pdialcolor(int r,int g,int b)} {} { + code {if (active_r()) fl_color(r,g,b); + else fl_color(160-(160-r)/3,160-(160-b)/3,160-(160-b)/3);} {} + } + decl {double oldvalue;} {} +} diff --git a/src/default.bnk_zyn b/src/default.bnk_zyn Binary files differ. diff --git a/src/globals.h b/src/globals.h @@ -0,0 +1,206 @@ +/* + ZynAddSubFX - a software synthesizer + + globals.h - it contains program settings and the program capabilities + like number of parts, of effects + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + + +#ifndef GLOBALS_H +#define GLOBALS_H + +//What float type I use for internal sampledata +#define REALTYPE float + +// Sampling rate +extern int SAMPLE_RATE; + +/* + * The size of a sound buffer (or the granularity) + * All internal transfer of sound data use buffer of this size + * All parameters are constant during this period of time, exception + * some parameters(like amplitudes) which are linear interpolated. + * If you increase this you'll ecounter big latencies, but if you + * decrease this the CPU requirements gets high. + */ +extern int SOUND_BUFFER_SIZE; + + +/* + * The size of ADnote Oscillator + * Decrease this => poor quality + * Increase this => CPU requirements gets high (only at start of the note) + */ +extern int OSCIL_SIZE; + + +/* + * The number of harmonics of additive synth + * This must be smaller than OSCIL_SIZE/2 + */ +#define MAX_AD_HARMONICS 128 + + +/* + * The number of harmonics of substractive + */ +#define MAX_SUB_HARMONICS 64 + +/* + * Number of parts + */ +#define NUM_MIDI_PARTS 16 + +/* + * Number of Midi channes + */ +#define NUM_MIDI_CHANNELS 16 + +/* + * The number of voices of additive synth for a single note + */ +#define NUM_VOICES 8 + +/* + * The poliphony (notes) + */ +#define POLIPHONY 60 + +/* + * The antialiasing and other parameters that depents on IFFT on each + * note on command(see OscilGen). 1 for enabled and 0 for disabled + */ +#define ANTI_ALIAS 1 + + +/* + * Number of system effects + */ +#define NUM_SYS_EFX 4 + + +/* + * Number of insertion effects + */ +#define NUM_INS_EFX 8 + +/* + * Number of part's insertion effects + */ +#define NUM_PART_EFX 3 + +/* + * Maximum number of the instrument on a part + */ +#define NUM_KIT_ITEMS 16 + + +/* + * How is applied the velocity sensing + */ +#define VELOCITY_MAX_SCALE 8.0 + +/* + * The maximum length of instrument's name + */ +#define PART_MAX_NAME_LEN 30 + +/* + * The maximum number of bands of the equaliser + */ +#define MAX_EQ_BANDS 8 +#if (MAX_EQ_BANDS>=20) +#error "Too many EQ bands in globals.h" +#endif + + +/* + * Maximum filter stages + */ +#define MAX_FILTER_STAGES 5 + +/* + * Formant filter (FF) limits + */ +#define FF_MAX_VOWELS 6 +#define FF_MAX_FORMANTS 12 +#define FF_MAX_SEQUENCE 8 + + + +#define LOG_2 0.693147181 +#define PI 3.1415926536 +#define LOG_10 2.302585093 + +/* + * The threshold for the amplitude interpolation used if the amplitude + * is changed (by LFO's or Envelope's). If the change of the amplitude + * is below this, the amplitude is not interpolated + */ +#define AMPLITUDE_INTERPOLATION_THRESHOLD 0.0001 + +/* + * How the amplitude threshold is computed + */ +#define ABOVE_AMPLITUDE_THRESHOLD(a,b) ( ( 2.0*fabs( (b) - (a) ) / \ + ( fabs( (b) + (a) + 0.0000000001) ) ) > AMPLITUDE_INTERPOLATION_THRESHOLD ) + +/* + * Interpolate Amplitude + */ +#define INTERPOLATE_AMPLITUDE(a,b,x,size) ( (a) + \ + ( (b) - (a) ) * (REALTYPE)(x) / (REALTYPE) (size) ) + + +/* + * dB + */ +#define dB2rap(dB) ((exp((dB)*LOG_10/20.0))) +#define rap2dB(rap) ((20*log(rap)/LOG_10)) + +/* + * The random generator (0.0..1.0) + */ +#define RND (rand()/(RAND_MAX+1.0)) + +enum ONOFFTYPE{OFF=0,ON=1}; + +enum MidiControllers{C_NULL=0,C_pitchwheel=1000,C_expression=11,C_panning=10, + C_filtercutoff=74,C_filterq=71,C_bandwidth=75,C_modwheel=1,C_fmamp=76, + C_volume=7,C_sustain=64,C_allnotesoff=123,C_allsoundsoff=120,C_resetallcontrollers=121, + C_portamento=65,C_resonance_center=77,C_resonance_bandwidth=78, + + C_dataentryhi=0x06,C_dataentrylo=0x26,C_nrpnhi=99,C_nrpnlo=98}; + + +//is like i=(int)(floor(f)) +#ifdef ASM_F2I_YES +#define F2I(f,i) __asm__ __volatile__ ("fistpl %0" : "=m" (i) : "t" (f-0.49999999) : "st") ; +#else +#define F2I(f,i) (i)=((f>0) ? ( (int)(f) ) :( (int)(f-1.0) )); +#endif + + + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#endif + diff --git a/src/main.C b/src/main.C @@ -0,0 +1,577 @@ +/* + ZynAddSubFX - a software synthesizer + + main.c - Main file of the synthesizer + Copyright (C) 2002-2003 Nasca Octavian Paul + Author: Nasca Octavian Paul + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License (version 2) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include <time.h> + +#include <unistd.h> +#include <pthread.h> + +#ifdef OS_LINUX +#include <getopt.h> +#elif OS_WINDOIWS +#include <winbase.h> +#include <windows.h> +#endif + +#include "Misc/Master.h" +#include "Misc/Util.h" +#include "Misc/Dump.h" +extern Dump dump; + +#ifdef ALSAMIDIIN +#include "Input/ALSAMidiIn.h" +#endif + +#ifdef OSSMIDIIN +#include "Input/OSSMidiIn.h" +#endif + +#if (defined(NONEMIDIIN)||defined(VSTMIDIIN)) +#include "Input/NULLMidiIn.h" +#endif + +#ifdef WINMIDIIN +#include "Input/WINMidiIn.h" +#endif + + +#include "UI/MasterUI.h" + +MasterUI *ui; +pthread_t thr1,thr2,thr3; +Master *master; +int swaplr=0;//1 for left-right swapping + +#ifdef JACKAUDIOOUT +#include "Output/JACKaudiooutput.h" +#elif PAAUDIOOUT +#include "Output/PAaudiooutput.h" +#elif OSSAUDIOOUT +#include "Output/OSSaudiooutput.h" +OSSaudiooutput *audioout; +#endif + +MidiIn *Midi; +int Pexitprogram=0;//if the UI set this to 1, the program will exit + +/* + * Try to get the realtime priority + */ +void set_realtime(){ +#ifdef OS_LINUX + sched_param sc; + + sc.sched_priority=50; + int err=sched_setscheduler(0,SCHED_FIFO,&sc); +// if (err==0) printf("Real-time"); +#endif +}; + +/* + * Midi input thread + */ +#if !(defined(WINMIDIIN)||defined(VSTMIDIIN)) +void *thread1(void *arg){ + MidiCmdType cmdtype; + unsigned char cmdchan,note,vel; + int cmdparams[MP_MAX_BYTES]; + + set_realtime(); + while (Pexitprogram==0){ + Midi->getmidicmd(cmdtype,cmdchan,cmdparams); + note=cmdparams[0]; + vel=cmdparams[1]; + + pthread_mutex_lock(&master->mutex); + + if (cmdtype==MidiNoteON) master->NoteOn(cmdchan,note,vel); + if (cmdtype==MidiNoteOFF) master->NoteOff(cmdchan,note); + if (cmdtype==MidiController) master->SetController(cmdchan,cmdparams[0],cmdparams[1]); + + pthread_mutex_unlock(&master->mutex); + }; + + return(0); +}; +#endif + +/* + * Wave output thread (if is not compiled for JACK, Portaudio and VST) + */ +#if !(defined(JACKAUDIOOUT)||defined(PAAUDIOOUT)||defined(VSTAUDIOOUT)) + +void *thread2(void *arg){ + REALTYPE outputl[SOUND_BUFFER_SIZE]; + REALTYPE outputr[SOUND_BUFFER_SIZE]; + + set_realtime(); + while (Pexitprogram==0){ + pthread_mutex_lock(&master->mutex); + master->AudioOut(outputl,outputr); + pthread_mutex_unlock(&master->mutex); + +#ifndef NONEAUDIOOUT + audioout->OSSout(outputl,outputr); +#endif + +/** / int i,x,x2; + REALTYPE xx,xx2; + + short int xsmps[SOUND_BUFFER_SIZE*2]; + for (i=0;i<SOUND_BUFFER_SIZE;i++){//output to stdout + xx=-outputl[i]*32767; + xx2=-outputr[i]*32767; + if (xx<-32768) xx=-32768; + if (xx>32767) xx=32767; + if (xx2<-32768) xx2=-32768; + if (xx2>32767) xx2=32767; + x=(short int) xx; + x2=(short int) xx2; + xsmps[i*2]=x;xsmps[i*2+1]=x2; + }; + write(1,&xsmps,SOUND_BUFFER_SIZE*2*2); + + /**/ + }; + return(0); +}; +#endif + +/* + * User Interface thread + */ + + +void *thread3(void *arg){ + ui->masterwindow->show(); + while (Pexitprogram==0) Fl::wait(); + return(0); +}; + + +/* + * Program initialisation + */ + + +void initprogram(){ +#ifndef JACKAUDIOOUT + fprintf(stderr,"\nSample Rate = \t\t%d\n",SAMPLE_RATE); +#endif + fprintf(stderr,"Sound Buffer Size = \t%d samples\n",SOUND_BUFFER_SIZE); + fprintf(stderr,"Internal latency = \t%.1f ms\n",SOUND_BUFFER_SIZE*1000.0/SAMPLE_RATE); + fprintf(stderr,"ADsynth Oscil.Size = \t%d samples\n",OSCIL_SIZE); + + fflush(stderr); + srand(time(NULL)); + denormalkillbuf=new REALTYPE [SOUND_BUFFER_SIZE]; + for (int i=0;i<SOUND_BUFFER_SIZE;i++) denormalkillbuf[i]=(RND-0.5)*1e-16; + + master=new Master(); + master->swaplr=swaplr; + +#ifdef OSSAUDIOOUT + audioout=new OSSaudiooutput(); +#elif JACKAUDIOOUT + JACKaudiooutputinit(master); +#elif PAAUDIOOUT + PAaudiooutputinit(master); +#endif + +#ifdef ALSAMIDIIN + Midi=new ALSAMidiIn(); +#endif +#ifdef OSSMIDIIN + Midi=new OSSMidiIn(); +#endif +#if (defined(NONEMIDIIN)||(defined(VSTMIDIIN))) + Midi=new NULLMidiIn(); +#endif + ui=new MasterUI(master,&Pexitprogram); +}; + +/* + * Program exit + */ +void exitprogram(){ + pthread_mutex_lock(&master->mutex); +#ifdef OSSAUDIOOUT + delete(audioout); +#endif +#ifdef JACKAUDIOOUT + JACKfinish(); +#endif +#ifdef PAAUDIOOUT + PAfinish(); +#endif + + delete(Midi); + delete(ui); + delete(denormalkillbuf); + +// pthread_mutex_unlock(&master->mutex); + delete(master); +}; + +#ifdef OS_WINDOWS +#define ARGSIZE 100 + char winoptarguments[ARGSIZE]; + char getopt(int argc, char *argv[], const char *shortopts, int *index){ + winoptarguments[0]=0; + char result=0; + + if (*index>=argc) return(-1); + + if (strlen(argv[*index])==2) + if (argv[*index][0]=='-') { + result=argv[*index][1]; + if (*index+1<argc) { + snprintf(winoptarguments,ARGSIZE,"%s",argv[*index+1]); + }; + }; + (*index)++; + return(result); + }; + int opterr=0; +#undef ARGSIZE + +#endif + +#ifndef VSTAUDIOOUT +int main(int argc, char *argv[]){ + int loadfile=0,noui=0; + fprintf(stderr,"\nZynAddSubFX - Copyright (c) 2002-2003 Nasca Octavian Paul\n"); + fprintf(stderr,"This program is free software (GNU GPL v.2) and \n it comes with ABSOLUTELY NO WARRANTY.\n\n"); +#ifdef OS_LINUX + if (argc==1) fprintf(stderr,"Try 'zynaddsubfx --help' for command-line options.\n"); +#else + if (argc==1) fprintf(stderr,"Try 'zynaddsubfx -h' for command-line options.\n"); +#endif + /* Get the settings from the Config*/ + SAMPLE_RATE=config.cfg.SampleRate; + SOUND_BUFFER_SIZE=config.cfg.SoundBufferSize; + OSCIL_SIZE=config.cfg.OscilSize; + swaplr=config.cfg.SwapStereo; + + /* Parse command-line options */ +#ifdef OS_LINUX + struct option opts[]={ + {"load",2,NULL,'l'}, + {"sample-rate",2,NULL,'r'}, + {"buffer-size",2,NULL,'b'}, + {"oscil-size",2,NULL,'o'}, + {"dump",2,NULL,'D'}, + {"swap",2,NULL,'S'}, + {"no-gui",2,NULL,'U'}, + {"help",2,NULL,'h'}, + {0,0,0,0} + }; +#endif + opterr=0; + int option_index=0,opt,exitwithhelp=0; + while (1){ +#ifdef OS_LINUX + opt=getopt_long(argc,argv,"l:r:b:o:hSDU",opts,&option_index); + char *optarguments=optarg; +#else + opt=getopt(argc,argv,"l:r:b:o:hSDU",&option_index); + char *optarguments=&winoptarguments[0]; +#endif + + if (opt==-1) break; + + int tmp; + switch(opt){ + case 'h':exitwithhelp=1; + break; + case 'U':noui=1; + break; + case 'l':tmp=0; + if (optarguments!=NULL) { + tmp=loadbufferfile(&slbuf,optarguments,0); + if (tmp!=0) { + fprintf(stderr,"ERROR:Could not load file %s .\n",optarguments); + exit(1); + }; + loadfile=1; + }; + break; + case 'r':tmp=0; + if (optarguments!=NULL) tmp=atoi(optarguments); + if (tmp>=4000) { + SAMPLE_RATE=tmp; + } else { + fprintf(stderr,"ERROR:Incorrect sample rate %s .\n",optarguments); + exit(1); + }; + break; + case 'b':tmp=0; + if (optarguments!=NULL) tmp=atoi(optarguments); + if (tmp>=2) { + SOUND_BUFFER_SIZE=tmp; + } else { + fprintf(stderr,"ERROR:Incorrect buffer size %s .\n",optarguments); + exit(1); + }; + break; + case 'o':tmp=0; + if (optarguments!=NULL) tmp=atoi(optarguments); + OSCIL_SIZE=tmp; + if (OSCIL_SIZE<MAX_AD_HARMONICS*2) OSCIL_SIZE=MAX_AD_HARMONICS*2; + OSCIL_SIZE=(int) pow(2,ceil(log (OSCIL_SIZE-1.0)/log(2.0))); + if (tmp!=OSCIL_SIZE) fprintf(stderr,"\nOSCIL_SIZE is wrong (must me 2^n) or too small. Adjusting to %d.\n",OSCIL_SIZE); + break; + case 'S':swaplr=1; + break; + case 'D':dump.startnow(); + break; + case '?':fprintf(stderr,"ERROR:Bad option or parameter.\n\n"); + exitwithhelp=1; + break; + }; + }; + + if (exitwithhelp!=0) { + fprintf(stderr,"Usage: zynaddsubfx [OPTION]\n\n"); + fprintf(stderr," -h , --help \t\t\t\t display command-line help and exit\n"); + fprintf(stderr," -l file, --load=FILE\t\t\t loads a .mas-zyn file\n"); + fprintf(stderr," -r SR, --sample-rate=SR\t\t set the sample rate SR\n"); + fprintf(stderr," -b BS, --buffer-size=SR\t\t set the buffer size (granularity)\n"); + fprintf(stderr," -o OS, --oscil-size=OS\t\t set the ADsynth oscil. size\n"); + fprintf(stderr," -S , --swap\t\t\t\t swap Left <--> Right\n"); + fprintf(stderr," -D , --dump\t\t\t\t Dumps midi note ON/OFF commands\n"); + fprintf(stderr," -U , --no-gui\t\t\t\t Run ZynAddSubFX without user interface\n"); + +#ifdef OS_WINDOWS + fprintf(stderr,"\nWARNING: On Windows systems, only short comandline parameters works.\n"); + fprintf(stderr," eg. instead '--buffer-size=512' use '-b 512'\n"); +#endif + fprintf(stderr,"\n\n"); + return(0); + }; + + //--------- + + initprogram(); + + if (loadfile!=0){ + slbuf.changemode(0); + master->part[0]->Penabled=0; + master->saveloadbuf(&slbuf); + }; + +#if !(defined(NONEMIDIIN)||defined(WINMIDIIN)||defined(VSTMIDIIN)) + pthread_create(&thr1,NULL,thread1,NULL); +#endif + +#if !(defined(JACKAUDIOOUT)||defined(PAAUDIOOUT)||defined(VSTAUDIOOUT)) + pthread_create(&thr2,NULL,thread2,NULL); +#endif + +/* not working....yet. +//drop the suid-root permisions +#if !(defined(JACKAUDIOOUT)||defined(PAAUDIOOUT)||defined(VSTAUDIOOUT)|| (defined (WINMIDIIN)) ) + setuid(getuid()); + seteuid(getuid()); +#endif +*/ + if (noui==0) pthread_create(&thr3,NULL,thread3,NULL); + +#ifdef WINMIDIIN + InitWinMidi(master); +#endif + + while (Pexitprogram==0){ +#ifdef OS_LINUX + usleep(100000); +#elif OS_WINDOWS + Sleep(100); +#endif + }; + +#ifdef WINMIDIIN + StopWinMidi(); +#endif + + exitprogram(); + return(0); +}; + + +#else + +#include "Output/VSTaudiooutput.h" + +#define main main_plugin +extern "C" __declspec(dllexport) AEffect *main_plugin(audioMasterCallback audioMaster); + +int instances=-1; + +AEffect *main (audioMasterCallback audioMaster){ +// if (audioMaster(0,audioMasterVersion,0,0,0,0)!=0) { +// return(0); +// }; + + if (instances==-1){ + Midi=new NULLMidiIn(); + denormalkillbuf=new REALTYPE [SOUND_BUFFER_SIZE]; + for (int i=0;i<SOUND_BUFFER_SIZE;i++) denormalkillbuf[i]=(RND-0.5)*1e-16; + instances=0; + }; + + if (instances!=0) return(0);//don't allow multiple instances + + AudioEffect *sintetizator=new VSTSynth(audioMaster); + + return sintetizator->getAeffect(); +}; + +void* hInstance; +BOOL WINAPI DllMain (HINSTANCE hInst,DWORD dwReason,LPVOID lpvReserved){ + hInstance=hInst; + return(1); +}; + +void *thread(void *arg){ + VSTSynth *vs=(VSTSynth *) arg; + +/* FILE *a=fopen("aaaa1","a"); + fprintf(a,"%lx %lx %lx -i=%d\n",vs,0,vs->vmaster,instances); + fflush(a);fclose(a); +*/ + + vs->ui=new MasterUI(vs->vmaster,&vs->Pexitprogram); + +/* a=fopen("aaaa1","a"); + fprintf(a,"%lx %lx %lx\n",vs,vs->ui->master,vs->vmaster); + fflush(a);fclose(a); +*/ + + vs->ui->masterwindow->show(); + +/* a=fopen("aaaa1","a"); + fprintf(a,"%lx %lx %lx\n",vs,vs->ui,vs->vmaster); + fflush(a);fclose(a); +*/ + + while (vs->Pexitprogram==0) Fl::wait(0.01); + + delete(vs->ui); + Fl::wait(0.01); + +/* a=fopen("aaaa1","a"); + fprintf(a,"EXIT\n"); + fflush(a);fclose(a); +*/ + + + pthread_exit(0); + return(0); +}; + +//Parts of the VSTSynth class +VSTSynth::VSTSynth (audioMasterCallback audioMaster):AudioEffectX(audioMaster,1,0){ + instances++; + + if (audioMaster){ + setNumInputs(0); + setNumOutputs(2); + setUniqueID('zasfx'); + canProcessReplacing(); +// hasVu(false); +// hasClip(false); + + isSynth(true); + + }; + + + SAMPLE_RATE=config.cfg.SampleRate; + SOUND_BUFFER_SIZE=config.cfg.SoundBufferSize; + OSCIL_SIZE=config.cfg.OscilSize; + swaplr=config.cfg.SwapStereo; + this->Pexitprogram=0; + + this->vmaster=new Master(); + this->vmaster->swaplr=swaplr; + + +// FILE *a=fopen("aaaa0","a"); +// fprintf(a,"%lx %lx %lx\n",this,this->ui,this->ui->masterwindow); +// fflush(a);fclose(a); + + pthread_create(&this->thr,NULL,thread,this); + +// suspend(); + +}; + + + +VSTSynth::~VSTSynth(){ + this->Pexitprogram=1; + + Sleep(200);//wait the thread to finish + +// pthread_mutex_lock(&vmaster->mutex); + + + delete(this->vmaster); + + instances--; +}; + +long VSTSynth::processEvents(VstEvents *events){ + for (int i=0;i<events->numEvents;i++){ +// FILE *a=fopen("events","a"); +// fprintf(a,"%lx\n",events->events[i]->type); +// fflush(a);fclose(a); + + if ((events->events[i])->type != kVstMidiType) continue; + VstMidiEvent *ev= (VstMidiEvent*) events->events[i]; + char *data=ev->midiData; + int status=data[0]/16; + int cmdchan=data[0]&0x0f; + int cntl; + + pthread_mutex_lock(&vmaster->mutex); + switch(status){ + case 0x8:vmaster->NoteOff(cmdchan,data[1]&0x7f); + break; + case 0x9:if (data[2]==0) vmaster->NoteOff(cmdchan,data[1]&0x7f); + else vmaster->NoteOn(cmdchan,data[1]&0x7f,data[2]&0x7f); + break; + case 0xB: cntl=Midi->getcontroller(data[1]&0x7f); + vmaster->SetController(cmdchan,cntl,data[2]&0x7f); + break; + case 0xC: vmaster->SetController(cmdchan,C_pitchwheel,data[1]&0x7f+(data[2]&0x7f)*128); + break; + }; + pthread_mutex_unlock(&vmaster->mutex); + + }; +}; +#endif + diff --git a/src/zynaddsubfx_gcc.def b/src/zynaddsubfx_gcc.def @@ -0,0 +1,3 @@ +LIBRARY ZYNADDSUBFX +DESCRIPTION 'ZynAddSubFX for VST' +EXPORTS main=main_plugin