// // Plug-in: "MDA JX10" v1.1 // // Copyright(c)1999-2001 Paul Kellett (maxim digital audio) // #include "mdaJX10.h" #include <stdio.h> #include <stdlib.h> //rand() #include <math.h> AudioEffect *createEffectInstance(audioMasterCallback audioMaster) { return new mdaJX10(audioMaster); } mdaJX10Program::mdaJX10Program() { param[0] = 0.00f; //OSC Mix param[1] = 0.25f; //OSC Tune param[2] = 0.50f; //OSC Fine param[3] = 0.00f; //OSC Mode param[4] = 0.35f; //OSC Rate param[5] = 0.50f; //OSC Bend param[6] = 1.00f; //VCF Freq param[7] = 0.15f; //VCF Reso param[8] = 0.75f; //VCF <Env param[9] = 0.00f; //VCF <LFO param[10] = 0.50f; //VCF <Vel param[11] = 0.00f; //VCF Att param[12] = 0.30f; //VCF Dec param[13] = 0.00f; //VCF Sus param[14] = 0.25f; //VCF Rel param[15] = 0.00f; //ENV Att param[16] = 0.50f; //ENV Dec param[17] = 1.00f; //ENV Sus param[18] = 0.30f; //ENV Rel param[19] = 0.81f; //LFO Rate param[20] = 0.50f; //Vibrato param[21] = 0.00f; //Noise - not present in original patches param[22] = 0.50f; //Octave param[23] = 0.50f; //Tuning strcpy (name, "Empty Patch"); } mdaJX10::mdaJX10(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, NPROGS, NPARAMS) { LvzInt32 i=0; Fs = 44100.0f; programs = new mdaJX10Program[NPROGS]; if(programs) { fillpatch(i++, "5th Sweep Pad", 1.0f, 0.37f, 0.25f, 0.3f, 0.32f, 0.5f, 0.9f, 0.6f, 0.12f, 0.0f, 0.5f, 0.9f, 0.89f, 0.9f, 0.73f, 0.0f, 0.5f, 1.0f, 0.71f, 0.81f, 0.65f, 0.0f, 0.5f, 0.5f); fillpatch(i++, "Echo Pad [SA]", 0.88f, 0.51f, 0.5f, 0.0f, 0.49f, 0.5f, 0.46f, 0.76f, 0.69f, 0.1f, 0.69f, 1.0f, 0.86f, 0.76f, 0.57f, 0.3f, 0.8f, 0.68f, 0.66f, 0.79f, 0.13f, 0.25f, 0.45f, 0.5f); fillpatch(i++, "Space Chimes [SA]", 0.88f, 0.51f, 0.5f, 0.16f, 0.49f, 0.5f, 0.49f, 0.82f, 0.66f, 0.08f, 0.89f, 0.85f, 0.69f, 0.76f, 0.47f, 0.12f, 0.22f, 0.55f, 0.66f, 0.89f, 0.34f, 0.0f, 1.0f, 0.5f); fillpatch(i++, "Solid Backing", 1.0f, 0.26f, 0.14f, 0.0f, 0.35f, 0.5f, 0.3f, 0.25f, 0.7f, 0.0f, 0.63f, 0.0f, 0.35f, 0.0f, 0.25f, 0.0f, 0.5f, 1.0f, 0.3f, 0.81f, 0.5f, 0.5f, 0.5f, 0.5f); fillpatch(i++, "Velocity Backing [SA]", 0.41f, 0.5f, 0.79f, 0.0f, 0.08f, 0.32f, 0.49f, 0.01f, 0.34f, 0.0f, 0.93f, 0.61f, 0.87f, 1.0f, 0.93f, 0.11f, 0.48f, 0.98f, 0.32f, 0.81f, 0.5f, 0.0f, 0.5f, 0.5f); fillpatch(i++, "Rubber Backing [ZF]", 0.29f, 0.76f, 0.26f, 0.0f, 0.18f, 0.76f, 0.35f, 0.15f, 0.77f, 0.14f, 0.54f, 0.0f, 0.42f, 0.13f, 0.21f, 0.0f, 0.56f, 0.0f, 0.32f, 0.2f, 0.58f, 0.22f, 0.53f, 0.5f); fillpatch(i++, "808 State Lead", 1.0f, 0.65f, 0.24f, 0.4f, 0.34f, 0.85f, 0.65f, 0.63f, 0.75f, 0.16f, 0.5f, 0.0f, 0.3f, 0.0f, 0.25f, 0.17f, 0.5f, 1.0f, 0.03f, 0.81f, 0.5f, 0.0f, 0.68f, 0.5f); fillpatch(i++, "Mono Glide", 0.0f, 0.25f, 0.5f, 1.0f, 0.46f, 0.5f, 0.51f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.3f, 0.0f, 0.25f, 0.37f, 0.5f, 1.0f, 0.38f, 0.81f, 0.62f, 0.0f, 0.5f, 0.5f); fillpatch(i++, "Detuned Techno Lead", 0.84f, 0.51f, 0.15f, 0.45f, 0.41f, 0.42f, 0.54f, 0.01f, 0.58f, 0.21f, 0.67f, 0.0f, 0.09f, 1.0f, 0.25f, 0.2f, 0.85f, 1.0f, 0.3f, 0.83f, 0.09f, 0.4f, 0.49f, 0.5f); fillpatch(i++, "Hard Lead [SA]", 0.71f, 0.75f, 0.53f, 0.18f, 0.24f, 1.0f, 0.56f, 0.52f, 0.69f, 0.19f, 0.7f, 1.0f, 0.14f, 0.65f, 0.95f, 0.07f, 0.91f, 1.0f, 0.15f, 0.84f, 0.33f, 0.0f, 0.49f, 0.5f); fillpatch(i++, "Bubble", 0.0f, 0.25f, 0.43f, 0.0f, 0.71f, 0.48f, 0.23f, 0.77f, 0.8f, 0.32f, 0.63f, 0.4f, 0.18f, 0.66f, 0.14f, 0.0f, 0.38f, 0.65f, 0.16f, 0.48f, 0.5f, 0.0f, 0.67f, 0.5f); fillpatch(i++, "Monosynth", 0.62f, 0.26f, 0.51f, 0.79f, 0.35f, 0.54f, 0.64f, 0.39f, 0.51f, 0.65f, 0.0f, 0.07f, 0.52f, 0.24f, 0.84f, 0.13f, 0.3f, 0.76f, 0.21f, 0.58f, 0.3f, 0.0f, 0.36f, 0.5f); fillpatch(i++, "Moogcury Lite", 0.81f, 1.0f, 0.21f, 0.78f, 0.15f, 0.35f, 0.39f, 0.17f, 0.69f, 0.4f, 0.62f, 0.0f, 0.47f, 0.19f, 0.37f, 0.0f, 0.5f, 0.2f, 0.33f, 0.38f, 0.53f, 0.0f, 0.12f, 0.5f); fillpatch(i++, "Gangsta Whine", 0.0f, 0.51f, 0.52f, 0.96f, 0.44f, 0.5f, 0.41f, 0.46f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.25f, 0.15f, 0.5f, 1.0f, 0.32f, 0.81f, 0.49f, 0.0f, 0.83f, 0.5f); fillpatch(i++, "Higher Synth [ZF]", 0.48f, 0.51f, 0.22f, 0.0f, 0.0f, 0.5f, 0.5f, 0.47f, 0.73f, 0.3f, 0.8f, 0.0f, 0.1f, 0.0f, 0.07f, 0.0f, 0.42f, 0.0f, 0.22f, 0.21f, 0.59f, 0.16f, 0.98f, 0.5f); fillpatch(i++, "303 Saw Bass", 0.0f, 0.51f, 0.5f, 0.83f, 0.49f, 0.5f, 0.55f, 0.75f, 0.69f, 0.35f, 0.5f, 0.0f, 0.56f, 0.0f, 0.56f, 0.0f, 0.8f, 1.0f, 0.24f, 0.26f, 0.49f, 0.0f, 0.07f, 0.5f); fillpatch(i++, "303 Square Bass", 0.75f, 0.51f, 0.5f, 0.83f, 0.49f, 0.5f, 0.55f, 0.75f, 0.69f, 0.35f, 0.5f, 0.14f, 0.49f, 0.0f, 0.39f, 0.0f, 0.8f, 1.0f, 0.24f, 0.26f, 0.49f, 0.0f, 0.07f, 0.5f); fillpatch(i++, "Analog Bass", 1.0f, 0.25f, 0.2f, 0.81f, 0.19f, 0.5f, 0.3f, 0.51f, 0.85f, 0.09f, 0.0f, 0.0f, 0.88f, 0.0f, 0.21f, 0.0f, 0.5f, 1.0f, 0.46f, 0.81f, 0.5f, 0.0f, 0.27f, 0.5f); fillpatch(i++, "Analog Bass 2", 1.0f, 0.25f, 0.2f, 0.72f, 0.19f, 0.86f, 0.48f, 0.43f, 0.94f, 0.0f, 0.8f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.61f, 1.0f, 0.32f, 0.81f, 0.5f, 0.0f, 0.27f, 0.5f); fillpatch(i++, "Low Pulses", 0.97f, 0.26f, 0.3f, 0.0f, 0.35f, 0.5f, 0.8f, 0.4f, 0.52f, 0.0f, 0.5f, 0.0f, 0.77f, 0.0f, 0.25f, 0.0f, 0.5f, 1.0f, 0.3f, 0.81f, 0.16f, 0.0f, 0.0f, 0.5f); fillpatch(i++, "Sine Infra-Bass", 0.0f, 0.25f, 0.5f, 0.65f, 0.35f, 0.5f, 0.33f, 0.76f, 0.53f, 0.0f, 0.5f, 0.0f, 0.3f, 0.0f, 0.25f, 0.0f, 0.55f, 0.25f, 0.3f, 0.81f, 0.52f, 0.0f, 0.14f, 0.5f); fillpatch(i++, "Wobble Bass [SA]", 1.0f, 0.26f, 0.22f, 0.64f, 0.82f, 0.59f, 0.72f, 0.47f, 0.34f, 0.34f, 0.82f, 0.2f, 0.69f, 1.0f, 0.15f, 0.09f, 0.5f, 1.0f, 0.07f, 0.81f, 0.46f, 0.0f, 0.24f, 0.5f); fillpatch(i++, "Squelch Bass", 1.0f, 0.26f, 0.22f, 0.71f, 0.35f, 0.5f, 0.67f, 0.7f, 0.26f, 0.0f, 0.5f, 0.48f, 0.69f, 1.0f, 0.15f, 0.0f, 0.5f, 1.0f, 0.07f, 0.81f, 0.46f, 0.0f, 0.24f, 0.5f); fillpatch(i++, "Rubber Bass [ZF]", 0.49f, 0.25f, 0.66f, 0.81f, 0.35f, 0.5f, 0.36f, 0.15f, 0.75f, 0.2f, 0.5f, 0.0f, 0.38f, 0.0f, 0.25f, 0.0f, 0.6f, 1.0f, 0.22f, 0.19f, 0.5f, 0.0f, 0.17f, 0.5f); fillpatch(i++, "Soft Pick Bass", 0.37f, 0.51f, 0.77f, 0.71f, 0.22f, 0.5f, 0.33f, 0.47f, 0.71f, 0.16f, 0.59f, 0.0f, 0.0f, 0.0f, 0.25f, 0.04f, 0.58f, 0.0f, 0.22f, 0.15f, 0.44f, 0.33f, 0.15f, 0.5f); fillpatch(i++, "Fretless Bass", 0.5f, 0.51f, 0.17f, 0.8f, 0.34f, 0.5f, 0.51f, 0.0f, 0.58f, 0.0f, 0.67f, 0.0f, 0.09f, 0.0f, 0.25f, 0.2f, 0.85f, 0.0f, 0.3f, 0.81f, 0.7f, 0.0f, 0.0f, 0.5f); fillpatch(i++, "Whistler", 0.23f, 0.51f, 0.38f, 0.0f, 0.35f, 0.5f, 0.33f, 1.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.29f, 0.0f, 0.25f, 0.68f, 0.39f, 0.58f, 0.36f, 0.81f, 0.64f, 0.38f, 0.92f, 0.5f); fillpatch(i++, "Very Soft Pad", 0.39f, 0.51f, 0.27f, 0.38f, 0.12f, 0.5f, 0.35f, 0.78f, 0.5f, 0.0f, 0.5f, 0.0f, 0.3f, 0.0f, 0.25f, 0.35f, 0.5f, 0.8f, 0.7f, 0.81f, 0.5f, 0.0f, 0.5f, 0.5f); fillpatch(i++, "Pizzicato", 0.0f, 0.25f, 0.5f, 0.0f, 0.35f, 0.5f, 0.23f, 0.2f, 0.75f, 0.0f, 0.5f, 0.0f, 0.22f, 0.0f, 0.25f, 0.0f, 0.47f, 0.0f, 0.3f, 0.81f, 0.5f, 0.8f, 0.5f, 0.5f); fillpatch(i++, "Synth Strings", 1.0f, 0.51f, 0.24f, 0.0f, 0.0f, 0.35f, 0.42f, 0.26f, 0.75f, 0.14f, 0.69f, 0.0f, 0.67f, 0.55f, 0.97f, 0.82f, 0.7f, 1.0f, 0.42f, 0.84f, 0.67f, 0.3f, 0.47f, 0.5f); fillpatch(i++, "Synth Strings 2", 0.75f, 0.51f, 0.29f, 0.0f, 0.49f, 0.5f, 0.55f, 0.16f, 0.69f, 0.08f, 0.2f, 0.76f, 0.29f, 0.76f, 1.0f, 0.46f, 0.8f, 1.0f, 0.39f, 0.79f, 0.27f, 0.0f, 0.68f, 0.5f); fillpatch(i++, "Leslie Organ", 0.0f, 0.5f, 0.53f, 0.0f, 0.13f, 0.39f, 0.38f, 0.74f, 0.54f, 0.2f, 0.0f, 0.0f, 0.55f, 0.52f, 0.31f, 0.0f, 0.17f, 0.73f, 0.28f, 0.87f, 0.24f, 0.0f, 0.29f, 0.5f); fillpatch(i++, "Click Organ", 0.5f, 0.77f, 0.52f, 0.0f, 0.35f, 0.5f, 0.44f, 0.5f, 0.65f, 0.16f, 0.0f, 0.0f, 0.0f, 0.18f, 0.0f, 0.0f, 0.75f, 0.8f, 0.0f, 0.81f, 0.49f, 0.0f, 0.44f, 0.5f); fillpatch(i++, "Hard Organ", 0.89f, 0.91f, 0.37f, 0.0f, 0.35f, 0.5f, 0.51f, 0.62f, 0.54f, 0.0f, 0.0f, 0.0f, 0.37f, 0.0f, 1.0f, 0.04f, 0.08f, 0.72f, 0.04f, 0.77f, 0.49f, 0.0f, 0.58f, 0.5f); fillpatch(i++, "Bass Clarinet", 1.0f, 0.51f, 0.51f, 0.37f, 0.0f, 0.5f, 0.51f, 0.1f, 0.5f, 0.11f, 0.5f, 0.0f, 0.0f, 0.0f, 0.25f, 0.35f, 0.65f, 0.65f, 0.32f, 0.79f, 0.49f, 0.2f, 0.35f, 0.5f); fillpatch(i++, "Trumpet", 0.0f, 0.51f, 0.51f, 0.82f, 0.06f, 0.5f, 0.57f, 0.0f, 0.32f, 0.15f, 0.5f, 0.21f, 0.15f, 0.0f, 0.25f, 0.24f, 0.6f, 0.8f, 0.1f, 0.75f, 0.55f, 0.25f, 0.69f, 0.5f); fillpatch(i++, "Soft Horn", 0.12f, 0.9f, 0.67f, 0.0f, 0.35f, 0.5f, 0.5f, 0.21f, 0.29f, 0.12f, 0.6f, 0.0f, 0.35f, 0.36f, 0.25f, 0.08f, 0.5f, 1.0f, 0.27f, 0.83f, 0.51f, 0.1f, 0.25f, 0.5f); fillpatch(i++, "Brass Section", 0.43f, 0.76f, 0.23f, 0.0f, 0.28f, 0.36f, 0.5f, 0.0f, 0.59f, 0.0f, 0.5f, 0.24f, 0.16f, 0.91f, 0.08f, 0.17f, 0.5f, 0.8f, 0.45f, 0.81f, 0.5f, 0.0f, 0.58f, 0.5f); fillpatch(i++, "Synth Brass", 0.4f, 0.51f, 0.25f, 0.0f, 0.3f, 0.28f, 0.39f, 0.15f, 0.75f, 0.0f, 0.5f, 0.39f, 0.3f, 0.82f, 0.25f, 0.33f, 0.74f, 0.76f, 0.41f, 0.81f, 0.47f, 0.23f, 0.5f, 0.5f); fillpatch(i++, "Detuned Syn Brass [ZF]", 0.68f, 0.5f, 0.93f, 0.0f, 0.31f, 0.62f, 0.26f, 0.07f, 0.85f, 0.0f, 0.66f, 0.0f, 0.83f, 0.0f, 0.05f, 0.0f, 0.75f, 0.54f, 0.32f, 0.76f, 0.37f, 0.29f, 0.56f, 0.5f); fillpatch(i++, "Power PWM", 1.0f, 0.27f, 0.22f, 0.0f, 0.35f, 0.5f, 0.82f, 0.13f, 0.75f, 0.0f, 0.0f, 0.24f, 0.3f, 0.88f, 0.34f, 0.0f, 0.5f, 1.0f, 0.48f, 0.71f, 0.37f, 0.0f, 0.35f, 0.5f); fillpatch(i++, "Water Velocity [SA]", 0.76f, 0.51f, 0.35f, 0.0f, 0.49f, 0.5f, 0.87f, 0.67f, 1.0f, 0.32f, 0.09f, 0.95f, 0.56f, 0.72f, 1.0f, 0.04f, 0.76f, 0.11f, 0.46f, 0.88f, 0.72f, 0.0f, 0.38f, 0.5f); fillpatch(i++, "Ghost [SA]", 0.75f, 0.51f, 0.24f, 0.45f, 0.16f, 0.48f, 0.38f, 0.58f, 0.75f, 0.16f, 0.81f, 0.0f, 0.3f, 0.4f, 0.31f, 0.37f, 0.5f, 1.0f, 0.54f, 0.85f, 0.83f, 0.43f, 0.46f, 0.5f); fillpatch(i++, "Soft E.Piano", 0.31f, 0.51f, 0.43f, 0.0f, 0.35f, 0.5f, 0.34f, 0.26f, 0.53f, 0.0f, 0.63f, 0.0f, 0.22f, 0.0f, 0.39f, 0.0f, 0.8f, 0.0f, 0.44f, 0.81f, 0.51f, 0.0f, 0.5f, 0.5f); fillpatch(i++, "Thumb Piano", 0.72f, 0.82f, 1.0f, 0.0f, 0.35f, 0.5f, 0.37f, 0.47f, 0.54f, 0.0f, 0.5f, 0.0f, 0.45f, 0.0f, 0.39f, 0.0f, 0.39f, 0.0f, 0.48f, 0.81f, 0.6f, 0.0f, 0.71f, 0.5f); fillpatch(i++, "Steel Drums [ZF]", 0.81f, 0.76f, 0.19f, 0.0f, 0.18f, 0.7f, 0.4f, 0.3f, 0.54f, 0.17f, 0.4f, 0.0f, 0.42f, 0.23f, 0.47f, 0.12f, 0.48f, 0.0f, 0.49f, 0.53f, 0.36f, 0.34f, 0.56f, 0.5f); fillpatch(58, "Car Horn", 0.57f, 0.49f, 0.31f, 0.0f, 0.35f, 0.5f, 0.46f, 0.0f, 0.68f, 0.0f, 0.5f, 0.46f, 0.3f, 1.0f, 0.23f, 0.3f, 0.5f, 1.0f, 0.31f, 1.0f, 0.38f, 0.0f, 0.5f, 0.5f); fillpatch(59, "Helicopter", 0.0f, 0.25f, 0.5f, 0.0f, 0.35f, 0.5f, 0.08f, 0.36f, 0.69f, 1.0f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.96f, 0.5f, 1.0f, 0.92f, 0.97f, 0.5f, 1.0f, 0.0f, 0.5f); fillpatch(60, "Arctic Wind", 0.0f, 0.25f, 0.5f, 0.0f, 0.35f, 0.5f, 0.16f, 0.85f, 0.5f, 0.28f, 0.5f, 0.37f, 0.3f, 0.0f, 0.25f, 0.89f, 0.5f, 1.0f, 0.89f, 0.24f, 0.5f, 1.0f, 1.0f, 0.5f); fillpatch(61, "Thip", 1.0f, 0.37f, 0.51f, 0.0f, 0.35f, 0.5f, 0.0f, 1.0f, 0.97f, 0.0f, 0.5f, 0.02f, 0.2f, 0.0f, 0.2f, 0.0f, 0.46f, 0.0f, 0.3f, 0.81f, 0.5f, 0.78f, 0.48f, 0.5f); fillpatch(62, "Synth Tom", 0.0f, 0.25f, 0.5f, 0.0f, 0.76f, 0.94f, 0.3f, 0.33f, 0.76f, 0.0f, 0.68f, 0.0f, 0.59f, 0.0f, 0.59f, 0.1f, 0.5f, 0.0f, 0.5f, 0.81f, 0.5f, 0.7f, 0.0f, 0.5f); fillpatch(63, "Squelchy Frog", 0.5f, 0.41f, 0.23f, 0.45f, 0.77f, 0.0f, 0.4f, 0.65f, 0.95f, 0.0f, 0.5f, 0.33f, 0.5f, 0.0f, 0.25f, 0.0f, 0.7f, 0.65f, 0.18f, 0.32f, 1.0f, 0.0f, 0.06f, 0.5f); //for testing... //fillpatch(0, "Monosynth", 0.62f, 0.26f, 0.51f, 0.79f, 0.35f, 0.54f, 0.64f, 0.39f, 0.51f, 0.65f, 0.0f, 0.07f, 0.52f, 0.24f, 0.84f, 0.13f, 0.3f, 0.76f, 0.21f, 0.58f, 0.3f, 0.0f, 0.36f, 0.5f); setProgram(0); } setUniqueID("mdaJX10"); if(audioMaster) { setNumInputs(0); setNumOutputs(NOUTS); canProcessReplacing(); isSynth(); } //initialise... for(LvzInt32 v=0; v<NVOICES; v++) { voice[v].dp = voice[v].dp2 = 1.0f; voice[v].saw = voice[v].p = voice[v].p2 = 0.0f; voice[v].env = voice[v].envd = voice[v].envl = 0.0f; voice[v].fenv = voice[v].fenvd = voice[v].fenvl = 0.0f; voice[v].f0 = voice[v].f1 = voice[v].f2 = 0.0f; voice[v].note = 0; } notes[0] = EVENTS_DONE; lfo = modwhl = filtwhl = press = fzip = 0.0f; rezwhl = pbend = ipbend = 1.0f; volume = 0.0005f; K = mode = lastnote = sustain = activevoices = 0; noise = 22222; update(); suspend(); } void mdaJX10::update() //parameter change { double ifs = 1.0 / Fs; float * param = programs[curProgram].param; mode = (LvzInt32)(7.9f * param[3]); noisemix = param[21] * param[21]; voltrim = (3.2f - param[0] - 1.5f * noisemix) * (1.5f - 0.5f * param[7]); noisemix *= 0.06f; oscmix = param[0]; semi = (float)floor(48.0f * param[1]) - 24.0f; cent = 15.876f * param[2] - 7.938f; cent = 0.1f * (float)floor(cent * cent * cent); detune = (float)pow(1.059463094359f, - semi - 0.01f * cent); tune = -23.376f - 2.0f * param[23] - 12.0f * (float)floor(param[22] * 4.9); tune = Fs * (float)pow(1.059463094359f, tune); vibrato = pwmdep = 0.2f * (param[20] - 0.5f) * (param[20] - 0.5f); if(param[20]<0.5f) vibrato = 0.0f; lfoHz = (float)exp(7.0f * param[19] - 4.0f); dlfo = lfoHz * (float)(ifs * TWOPI * KMAX); filtf = 8.0f * param[6] - 1.5f; filtq = (1.0f - param[7]) * (1.0f - param[7]); ////// + 0.02f; filtlfo = 2.5f * param[9] * param[9]; filtenv = 12.0f * param[8] - 6.0f; filtvel = 0.1f * param[10] - 0.05f; if(param[10]<0.05f) { veloff = 1; filtvel = 0; } else veloff = 0; att = 1.0f - (float)exp(-ifs * exp(5.5 - 7.5 * param[15])); dec = 1.0f - (float)exp(-ifs * exp(5.5 - 7.5 * param[16])); sus = param[17]; rel = 1.0f - (float)exp(-ifs * exp(5.5 - 7.5 * param[18])); if(param[18]<0.01f) rel = 0.1f; //extra fast release ifs *= KMAX; //lower update rate... fatt = 1.0f - (float)exp(-ifs * exp(5.5 - 7.5 * param[11])); fdec = 1.0f - (float)exp(-ifs * exp(5.5 - 7.5 * param[12])); fsus = param[13] * param[13]; frel = 1.0f - (float)exp(-ifs * exp(5.5 - 7.5 * param[14])); if(param[4]<0.02f) glide = 1.0f; else glide = 1.0f - (float)exp(-ifs * exp(6.0 - 7.0 * param[4])); glidedisp = (6.604f * param[5] - 3.302f); glidedisp *= glidedisp * glidedisp; } void mdaJX10::setSampleRate(float rate) { AudioEffectX::setSampleRate(rate); Fs = rate; dlfo = lfoHz * (float)(TWOPI * KMAX) / Fs; } void mdaJX10::resume() { DECLARE_LVZ_DEPRECATED (wantEvents) (); } void mdaJX10::suspend() //Used by Logic (have note off code in 3 places now...) { for(LvzInt32 v=0; v<NVOICES; v++) { voice[v].envl = voice[v].env = 0.0f; voice[v].envd = 0.99f; voice[v].note = 0; voice[v].f0 = voice[v].f1 = voice[v].f2 = 0.0f; } } mdaJX10::~mdaJX10() //destroy any buffers... { if(programs) delete[] programs; } void mdaJX10::setProgram(LvzInt32 program) { curProgram = program; update(); } //may want all notes off here - but this stops use of patches as snapshots! void mdaJX10::setParameter(LvzInt32 index, float value) { programs[curProgram].param[index] = value; update(); ///if(editor) editor->postUpdate(); } void mdaJX10::fillpatch(LvzInt32 p, const char *name, float p0, float p1, float p2, float p3, float p4, float p5, float p6, float p7, float p8, float p9, float p10, float p11, float p12, float p13, float p14, float p15, float p16, float p17, float p18, float p19, float p20, float p21, float p22, float p23) { strcpy(programs[p].name, name); programs[p].param[0] = p0; programs[p].param[1] = p1; programs[p].param[2] = p2; programs[p].param[3] = p3; programs[p].param[4] = p4; programs[p].param[5] = p5; programs[p].param[6] = p6; programs[p].param[7] = p7; programs[p].param[8] = p8; programs[p].param[9] = p9; programs[p].param[10] = p10; programs[p].param[11] = p11; programs[p].param[12] = p12; programs[p].param[13] = p13; programs[p].param[14] = p14; programs[p].param[15] = p15; programs[p].param[16] = p16; programs[p].param[17] = p17; programs[p].param[18] = p18; programs[p].param[19] = p19; programs[p].param[20] = p20; programs[p].param[21] = p21; programs[p].param[22] = p22; programs[p].param[23] = p23; } float mdaJX10::getParameter(LvzInt32 index) { return programs[curProgram].param[index]; } void mdaJX10::setProgramName(char *name) { strcpy(programs[curProgram].name, name); } void mdaJX10::getProgramName(char *name) { strcpy(name, programs[curProgram].name); } void mdaJX10::setBlockSize(LvzInt32 blockSize) { AudioEffectX::setBlockSize(blockSize); } bool mdaJX10::getEffectName(char* name) { strcpy(name, "MDA JX10 Synth"); return true; } bool mdaJX10::getVendorString(char* text) { strcpy(text, "MDA"); return true; } bool mdaJX10::getProductString(char* text) { strcpy(text, "MDA JX10 Synth"); return true; } bool mdaJX10::getOutputProperties(LvzInt32 index, LvzPinProperties* properties) { if(index<NOUTS) { sprintf(properties->label, "JX10%d", index + 1); properties->flags = kLvzPinIsActive; if(index<2) properties->flags |= kLvzPinIsStereo; //make channel 1+2 stereo return true; } return false; } bool mdaJX10::getProgramNameIndexed(LvzInt32 category, LvzInt32 index, char* text) { if ((unsigned int)index < NPROGS) { strcpy(text, programs[index].name); return true; } return false; } bool mdaJX10::copyProgram(LvzInt32 destination) { if(destination<NPROGS) { programs[destination] = programs[curProgram]; return true; } return false; } LvzInt32 mdaJX10::canDo(char* text) { if(!strcmp (text, "receiveLvzEvents")) return 1; if(!strcmp (text, "receiveLvzMidiEvent")) return 1; return -1; } void mdaJX10::getParameterName(LvzInt32 index, char *label) { switch (index) { case 0: strcpy(label, "OSC Mix"); break; case 1: strcpy(label, "OSC Tune"); break; case 2: strcpy(label, "OSC Fine"); break; case 3: strcpy(label, "Glide"); break; case 4: strcpy(label, "Gld Rate"); break; case 5: strcpy(label, "Gld Bend"); break; case 6: strcpy(label, "VCF Freq"); break; case 7: strcpy(label, "VCF Reso"); break; case 8: strcpy(label, "VCF Env"); break; case 9: strcpy(label, "VCF LFO"); break; case 10: strcpy(label, "VCF Vel"); break; case 11: strcpy(label, "VCF Att"); break; case 12: strcpy(label, "VCF Dec"); break; case 13: strcpy(label, "VCF Sus"); break; case 14: strcpy(label, "VCF Rel"); break; case 15: strcpy(label, "ENV Att"); break; case 16: strcpy(label, "ENV Dec"); break; case 17: strcpy(label, "ENV Sus"); break; case 18: strcpy(label, "ENV Rel"); break; case 19: strcpy(label, "LFO Rate"); break; case 20: strcpy(label, "Vibrato"); break; case 21: strcpy(label, "Noise"); break; case 22: strcpy(label, "Octave"); break; default: strcpy(label, "Tuning"); } } void mdaJX10::getParameterDisplay(LvzInt32 index, char *text) { char string[16]; float * param = programs[curProgram].param; switch(index) { case 0: sprintf(string, "%4.0f:%2.0f", 100.0-50.0f*param[index], 50.0f*param[index]); break; case 1: sprintf(string, "%.0f", semi); break; case 2: sprintf(string, "%.1f", cent); break; case 3: switch(mode) { case 0: case 1: strcpy(string, "POLY "); break; case 2: strcpy(string, "P-LEGATO"); break; case 3: strcpy(string, "P-GLIDE "); break; case 4: case 5: strcpy(string, "MONO "); break; case 6: strcpy(string, "M-LEGATO"); break; default: strcpy(string, "M-GLIDE "); break; } break; case 5: sprintf(string, "%.2f", glidedisp); break; case 6: sprintf(string, "%.1f", 100.0f * param[index]); break; case 8: case 23: sprintf(string, "%.1f", 200.0f * param[index] - 100.0f); break; case 10: if(param[index]<0.05f) strcpy(string, " OFF "); else sprintf(string, "%.0f", 200.0f * param[index] - 100.0f); break; case 19: sprintf(string, "%.3f", lfoHz); break; case 20: if(param[index]<0.5f) sprintf(string, "PWM %3.0f", 100.0f - 200.0f * param[index]); else sprintf(string, "%7.0f", 200.0f * param[index] - 100.0f); break; case 22: sprintf(string, "%d", (LvzInt32)(param[index] * 4.9f) - 2); break; default: sprintf(string, "%.0f", 100.0f * param[index]); } string[8] = 0; strcpy(text, (char *)string); } void mdaJX10::getParameterLabel(LvzInt32 index, char *label) { switch(index) { case 1: case 5: strcpy(label, " semi "); break; case 2: case 23: strcpy(label, " cent "); break; case 3: case 22: strcpy(label, " "); break; case 19: strcpy(label, " Hz "); break; default: strcpy(label, " % "); } } void mdaJX10::process(float **inputs, float **outputs, LvzInt32 sampleFrames) { float* out1 = outputs[0]; float* out2 = outputs[1]; LvzInt32 event=0, frame=0, frames, v; float o, e, vib, pwm, pb=pbend, ipb=ipbend, gl=glide; float x, y, hpf=0.997f, min=1.0f, w=0.0f, ww=noisemix; float ff, fe=filtenv, fq=filtq * rezwhl, fx=1.97f-0.85f*fq, fz=fzip; LvzInt32 k=K; unsigned int r; vib = (float)sin(lfo); ff = filtf + filtwhl + (filtlfo + press) * vib; //have to do again here as way that pwm = 1.0f + vib * (modwhl + pwmdep); //below triggers on k was too cheap! vib = 1.0f + vib * (modwhl + vibrato); if(activevoices>0 || notes[event]<sampleFrames) { while(frame<sampleFrames) { frames = notes[event++]; if(frames>sampleFrames) frames = sampleFrames; frames -= frame; frame += frames; while(--frames>=0) { VOICE *V = voice; o = 0.0f; noise = (noise * 196314165) + 907633515; r = (noise & 0x7FFFFF) + 0x40000000; //generate noise + fast convert to float w = *(float *)&r; w = ww * (w - 3.0f); if(--k<0) { lfo += dlfo; if(lfo>PI) lfo -= TWOPI; vib = (float)sin(lfo); ff = filtf + filtwhl + (filtlfo + press) * vib; pwm = 1.0f + vib * (modwhl + pwmdep); vib = 1.0f + vib * (modwhl + vibrato); k = KMAX; } for(v=0; v<NVOICES; v++) //for each voice { e = V->env; if(e > SILENCE) { //Sinc-Loop Oscillator x = V->p + V->dp; if(x > min) { if(x > V->pmax) { x = V->pmax + V->pmax - x; V->dp = -V->dp; } V->p = x; x = V->sin0 * V->sinx - V->sin1; //sine osc V->sin1 = V->sin0; V->sin0 = x; x = x / V->p; } else { V->p = x = - x; V->dp = V->period * vib * pb; //set period for next cycle V->pmax = (float)floor(0.5f + V->dp) - 0.5f; V->dc = -0.5f * V->lev / V->pmax; V->pmax *= PI; V->dp = V->pmax / V->dp; V->sin0 = V->lev * (float)sin(x); V->sin1 = V->lev * (float)sin(x - V->dp); V->sinx = 2.0f * (float)cos(V->dp); if(x*x > .1f) x = V->sin0 / x; else x = V->lev; //was 0.01f; } y = V->p2 + V->dp2; //osc2 if(y > min) { if(y > V->pmax2) { y = V->pmax2 + V->pmax2 - y; V->dp2 = -V->dp2; } V->p2 = y; y = V->sin02 * V->sinx2 - V->sin12; V->sin12 = V->sin02; V->sin02 = y; y = y / V->p2; } else { V->p2 = y = - y; V->dp2 = V->period * V->detune * pwm * pb; V->pmax2 = (float)floor(0.5f + V->dp2) - 0.5f; V->dc2 = -0.5f * V->lev2 / V->pmax2; V->pmax2 *= PI; V->dp2 = V->pmax2 / V->dp2; V->sin02 = V->lev2 * (float)sin(y); V->sin12 = V->lev2 * (float)sin(y - V->dp2); V->sinx2 = 2.0f * (float)cos(V->dp2); if(y*y > .1f) y = V->sin02 / y; else y = V->lev2; } V->saw = V->saw * hpf + V->dc + x - V->dc2 - y; //integrated sinc = saw x = V->saw + w; V->env += V->envd * (V->envl - V->env); if(k==KMAX) //filter freq update at LFO rate { if((V->env+V->envl)>3.0f) { V->envd=dec; V->envl=sus; } //envelopes V->fenv += V->fenvd * (V->fenvl - V->fenv); if((V->fenv+V->fenvl)>3.0f) { V->fenvd=fdec; V->fenvl=fsus; } fz += 0.005f * (ff - fz); //filter zipper noise filter y = V->fc * (float)exp(fz + fe * V->fenv) * ipb; //filter cutoff if(y<0.005f) y=0.005f; V->ff = y; V->period += gl * (V->target - V->period); //glide if(V->target < V->period) V->period += gl * (V->target - V->period); } if(V->ff > fx) V->ff = fx; //stability limit V->f0 += V->ff * V->f1; //state-variable filter V->f1 -= V->ff * (V->f0 + fq * V->f1 - x - V->f2); V->f1 -= 0.2f * V->f1 * V->f1 * V->f1; //soft limit //was 0.08f V->f2 = x; o += V->env * V->f0; } V++; } *out1++ += o; *out2++ += o; } if(frame<sampleFrames) { LvzInt32 note = notes[event++]; LvzInt32 vel = notes[event++]; noteOn(note, vel); } } activevoices = NVOICES; for(v=0; v<NVOICES; v++) { if(voice[v].env<SILENCE) //choke voices { voice[v].env = voice[v].envl = 0.0f; voice[v].f0 = voice[v].f1 = voice[v].f2 = 0.0f; activevoices--; } } } notes[0] = EVENTS_DONE; //mark events buffer as done fzip = fz; K = k; } void mdaJX10::processReplacing(float **inputs, float **outputs, LvzInt32 sampleFrames) { float* out1 = outputs[0]; float* out2 = outputs[1]; LvzInt32 event=0, frame=0, frames, v; float o, e, vib, pwm, pb=pbend, ipb=ipbend, gl=glide; float x, y, hpf=0.997f, min=1.0f, w=0.0f, ww=noisemix; float ff, fe=filtenv, fq=filtq * rezwhl, fx=1.97f-0.85f*fq, fz=fzip; LvzInt32 k=K; unsigned int r; vib = (float)sin(lfo); ff = filtf + filtwhl + (filtlfo + press) * vib; //have to do again here as way that pwm = 1.0f + vib * (modwhl + pwmdep); //below triggers on k was too cheap! vib = 1.0f + vib * (modwhl + vibrato); if(activevoices>0 || notes[event]<sampleFrames) { while(frame<sampleFrames) { frames = notes[event++]; if(frames>sampleFrames) frames = sampleFrames; frames -= frame; frame += frames; while(--frames>=0) { VOICE *V = voice; o = 0.0f; noise = (noise * 196314165) + 907633515; r = (noise & 0x7FFFFF) + 0x40000000; //generate noise + fast convert to float w = *(float *)&r; w = ww * (w - 3.0f); if(--k<0) { lfo += dlfo; if(lfo>PI) lfo -= TWOPI; vib = (float)sin(lfo); ff = filtf + filtwhl + (filtlfo + press) * vib; pwm = 1.0f + vib * (modwhl + pwmdep); vib = 1.0f + vib * (modwhl + vibrato); k = KMAX; } for(v=0; v<NVOICES; v++) //for each voice { e = V->env; if(e > SILENCE) { //Sinc-Loop Oscillator x = V->p + V->dp; if(x > min) { if(x > V->pmax) { x = V->pmax + V->pmax - x; V->dp = -V->dp; } V->p = x; x = V->sin0 * V->sinx - V->sin1; //sine osc V->sin1 = V->sin0; V->sin0 = x; x = x / V->p; } else { V->p = x = - x; V->dp = V->period * vib * pb; //set period for next cycle V->pmax = (float)floor(0.5f + V->dp) - 0.5f; V->dc = -0.5f * V->lev / V->pmax; V->pmax *= PI; V->dp = V->pmax / V->dp; V->sin0 = V->lev * (float)sin(x); V->sin1 = V->lev * (float)sin(x - V->dp); V->sinx = 2.0f * (float)cos(V->dp); if(x*x > .1f) x = V->sin0 / x; else x = V->lev; //was 0.01f; } y = V->p2 + V->dp2; //osc2 if(y > min) { if(y > V->pmax2) { y = V->pmax2 + V->pmax2 - y; V->dp2 = -V->dp2; } V->p2 = y; y = V->sin02 * V->sinx2 - V->sin12; V->sin12 = V->sin02; V->sin02 = y; y = y / V->p2; } else { V->p2 = y = - y; V->dp2 = V->period * V->detune * pwm * pb; V->pmax2 = (float)floor(0.5f + V->dp2) - 0.5f; V->dc2 = -0.5f * V->lev2 / V->pmax2; V->pmax2 *= PI; V->dp2 = V->pmax2 / V->dp2; V->sin02 = V->lev2 * (float)sin(y); V->sin12 = V->lev2 * (float)sin(y - V->dp2); V->sinx2 = 2.0f * (float)cos(V->dp2); if(y*y > .1f) y = V->sin02 / y; else y = V->lev2; } V->saw = V->saw * hpf + V->dc + x - V->dc2 - y; //integrated sinc = saw x = V->saw + w; V->env += V->envd * (V->envl - V->env); if(k==KMAX) //filter freq update at LFO rate { if((V->env+V->envl)>3.0f) { V->envd=dec; V->envl=sus; } //envelopes V->fenv += V->fenvd * (V->fenvl - V->fenv); if((V->fenv+V->fenvl)>3.0f) { V->fenvd=fdec; V->fenvl=fsus; } fz += 0.005f * (ff - fz); //filter zipper noise filter y = V->fc * (float)exp(fz + fe * V->fenv) * ipb; //filter cutoff if(y<0.005f) y=0.005f; V->ff = y; V->period += gl * (V->target - V->period); //glide if(V->target < V->period) V->period += gl * (V->target - V->period); } if(V->ff > fx) V->ff = fx; //stability limit V->f0 += V->ff * V->f1; //state-variable filter V->f1 -= V->ff * (V->f0 + fq * V->f1 - x - V->f2); V->f1 -= 0.2f * V->f1 * V->f1 * V->f1; //soft limit V->f2 = x; o += V->env * V->f0; } V++; } *out1++ = o; *out2++ = o; } if(frame<sampleFrames) { LvzInt32 note = notes[event++]; LvzInt32 vel = notes[event++]; noteOn(note, vel); } } activevoices = NVOICES; for(v=0; v<NVOICES; v++) { if(voice[v].env<SILENCE) //choke voices { voice[v].env = voice[v].envl = 0.0f; voice[v].f0 = voice[v].f1 = voice[v].f2 = 0.0f; activevoices--; } } } else //empty block { while(--sampleFrames >= 0) { *out1++ = 0.0f; *out2++ = 0.0f; } } notes[0] = EVENTS_DONE; //mark events buffer as done fzip = fz; K = k; } void mdaJX10::noteOn(LvzInt32 note, LvzInt32 velocity) { float p, l=100.0f; //louder than any envelope! LvzInt32 v=0, tmp, held=0; if(velocity>0) //note on { if(veloff) velocity = 80; if(mode & 4) //monophonic { if(voice[0].note > 0) //legato pitch change { for(tmp=(NVOICES-1); tmp>0; tmp--) //queue any held notes { voice[tmp].note = voice[tmp - 1].note; } p = tune * (float)exp(-0.05776226505 * ((double)note + ANALOG * (double)v)); while(p<3.0f || (p * detune)<3.0f) p += p; voice[v].target = p; if((mode & 2)==0) voice[v].period = p; voice[v].fc = (float)exp(filtvel * (float)(velocity - 64)) / p; voice[v].env += SILENCE + SILENCE; ///was missed out below if returned? voice[v].note = note; return; } } else //polyphonic { for(tmp=0; tmp<NVOICES; tmp++) //replace quietest voice not in attack { if(voice[tmp].note > 0) held++; if(voice[tmp].env<l && voice[tmp].envl<2.0f) { l=voice[tmp].env; v=tmp; } } } p = tune * (float)exp(-0.05776226505 * ((double)note + ANALOG * (double)v)); while(p<3.0f || (p * detune)<3.0f) p += p; voice[v].target = p; voice[v].detune = detune; tmp = 0; if(mode & 2) { if((mode & 1) || held) tmp = note - lastnote; //glide } voice[v].period = p * (float)pow(1.059463094359, (double)tmp - glidedisp); if(voice[v].period<3.0f) voice[v].period = 3.0f; //limit min period voice[v].note = lastnote = note; voice[v].fc = (float)exp(filtvel * (float)(velocity - 64)) / p; //filter tracking voice[v].lev = voltrim * volume * (0.004f * (float)((velocity + 64) * (velocity + 64)) - 8.0f); voice[v].lev2 = voice[v].lev * oscmix; if(programs[curProgram].param[20]<0.5f) //force 180 deg phase difference for PWM { if(voice[v].dp>0.0f) { p = voice[v].pmax + voice[v].pmax - voice[v].p; voice[v].dp2 = -voice[v].dp; } else { p = voice[v].p; voice[v].dp2 = voice[v].dp; } voice[v].p2 = voice[v].pmax2 = p + PI * voice[v].period; voice[v].dc2 = 0.0f; voice[v].sin02 = voice[v].sin12 = voice[v].sinx2 = 0.0f; } if(mode & 4) //monophonic retriggering { voice[v].env += SILENCE + SILENCE; } else { //if(programs[curProgram].param[15] < 0.28f) //{ // voice[v].f0 = voice[v].f1 = voice[v].f2 = 0.0f; //reset filter // voice[v].env = SILENCE + SILENCE; // voice[v].fenv = 0.0f; //} //else voice[v].env += SILENCE + SILENCE; //anti-glitching trick } voice[v].envl = 2.0f; voice[v].envd = att; voice[v].fenvl = 2.0f; voice[v].fenvd = fatt; } else //note off { if((mode & 4) && (voice[0].note==note)) //monophonic (and current note) { for(v=(NVOICES-1); v>0; v--) { if(voice[v].note>0) held = v; //any other notes queued? } if(held>0) { voice[v].note = voice[held].note; voice[held].note = 0; p = tune * (float)exp(-0.05776226505 * ((double)voice[v].note + ANALOG * (double)v)); while(p<3.0f || (p * detune)<3.0f) p += p; voice[v].target = p; if((mode & 2)==0) voice[v].period = p; voice[v].fc = 1.0f / p; } else { voice[v].envl = 0.0f; voice[v].envd = rel; voice[v].fenvl = 0.0f; voice[v].fenvd = frel; voice[v].note = 0; } } else //polyphonic { for(v=0; v<NVOICES; v++) if(voice[v].note==note) //any voices playing that note? { if(sustain==0) { voice[v].envl = 0.0f; voice[v].envd = rel; voice[v].fenvl = 0.0f; voice[v].fenvd = frel; voice[v].note = 0; } else voice[v].note = SUSTAIN; } } } } LvzInt32 mdaJX10::processEvents(LvzEvents* ev) { LvzInt32 npos=0; for (LvzInt32 i=0; i<ev->numEvents; i++) { if((ev->events[i])->type != kLvzMidiType) continue; LvzMidiEvent* event = (LvzMidiEvent*)ev->events[i]; char* midiData = event->midiData; switch(midiData[0] & 0xf0) //status byte (all channels) { case 0x80: //note off notes[npos++] = event->deltaFrames; //delta notes[npos++] = midiData[1] & 0x7F; //note notes[npos++] = 0; //vel break; case 0x90: //note on notes[npos++] = event->deltaFrames; //delta notes[npos++] = midiData[1] & 0x7F; //note notes[npos++] = midiData[2] & 0x7F; //vel break; case 0xB0: //controller switch(midiData[1]) { case 0x01: //mod wheel modwhl = 0.000005f * (float)(midiData[2] * midiData[2]); break; case 0x02: //filter + case 0x4A: filtwhl = 0.02f * (float)(midiData[2]); break; case 0x03: //filter - filtwhl = -0.03f * (float)(midiData[2]); break; case 0x07: //volume volume = 0.00000005f * (float)(midiData[2] * midiData[2]); break; case 0x10: //resonance case 0x47: rezwhl = 0.0065f * (float)(154 - midiData[2]); break; case 0x40: //sustain sustain = midiData[2] & 0x40; if(sustain==0) { notes[npos++] = event->deltaFrames; notes[npos++] = SUSTAIN; //end all sustained notes notes[npos++] = 0; } break; default: //all notes off if(midiData[1]>0x7A) { for(LvzInt32 v=0; v<NVOICES; v++) { voice[v].envl = voice[v].env = 0.0f; voice[v].envd = 0.99f; voice[v].note = 0; //could probably reset some more stuff here for safety! } sustain = 0; } break; } break; case 0xC0: //program change if(midiData[1]<NPROGS) setProgram(midiData[1]); break; case 0xD0: //channel aftertouch press = 0.00001f * (float)(midiData[1] * midiData[1]); break; case 0xE0: //pitch bend ipbend = (float)exp(0.000014102 * (double)(midiData[1] + 128 * midiData[2] - 8192)); pbend = 1.0f / ipbend; break; default: break; } if(npos>EVENTBUFFER) npos -= 3; //discard events if buffer full!! event++; } notes[npos] = EVENTS_DONE; return 1; }