/*----------------------------------------------------------------------------- © 2002, Jeff M Soft und Hardware GmbH, All Rights Reserved -----------------------------------------------------------------------------*/ #include "Module.h" #include "SEMod_struct.h" #include "SEPin.h" #include #include // define some constants to make referencing in/outs clearer #define PN_INPUT1 0 #define PN_INPUT2 1 #define PN_INPUT3 2 #define PN_INPUT4 3 #define PN_INPUT5 4 #define PN_OUTPUT1 5 #define PN_OUTPUT2 6 #define COEF1 0.45 // 0.15 - 0.25 #define COEF2 1.16 // 1.16 #define MAXR 2.5 #define COEF3 0.3673 // #define COEFR 0.5 // The most important part, processing the audio void Module::sub_MONO(long buffer_offset, long sampleFrames ) { // assign some pointers to your in/output buffers. usually blocks (array) of 96 samples float *in1 = buffer_offset + input1_buffer; // AUDIO-L // float *in2 = buffer_offset + input2_buffer; // AUTIO-R float *in3 = buffer_offset + input3_buffer; // Freq float *in4 = buffer_offset + input4_buffer; // Reso float *in5 = buffer_offset + input5_buffer; // float *out1 = buffer_offset + output1_buffer; float *out2 = buffer_offset + output2_buffer; float *o3 = buffer_offset + o3_buffer; float *o4 = buffer_offset + o4_buffer; float *in6 = buffer_offset + input6_buffer; // while(--sampleFrames >= 0) // sampleFrames = how many samples to process (can vary). repeat (loop) that many times { FREQ = (*in3 * 20000) * NI; // F / SR if( FREQ >= 1 ) { FREQ = 1; } else if( FREQ <= 0.000090702 ) { FREQ = 0.000090702; } // original 1.16 F = FREQ * COEF2; RES = *in4 * 2.5; if( RES >= MAXR ) { RES = MAXR; } FB = RES * (1.0 - COEF1 * F * F); // RES * (1.0 - 0.15 * F * F) // COEF1 LIM = *in5; // ------------------------------------------- // x0 = *in1 - (y4 * FB); // y4/OUT << (feedback) // CX = 1 - (cy4 * FB); CR = 0.54 - (RES * 0.0959999); COEFR = CR + (FREQ * 0.25); x0 *= COEFR * (F * F) * (F * F); // COEFR // original 0.35013, good looking 0.5 // COEFR // ; ------------------------------------------------------------------- Pole 1 y1 = x0 + COEF3 * x1 + (1 - F) * y1; x1 = x0; // ; ------------------------------------------------------------------- Pole 2 y2 = y1 + COEF3 * x2 + (1 - F) * y2; x2 = y1; // ; ------------------------------------------------------------------- Pole 3 y3 = y2 + COEF3 * x3 + (1 - F) * y3; x3 = y2; // ; ------------------------------------------------------------------- Pole 4 y4 = y3 + COEF3 * x4 + (1 - F) * y4; x4 = y3; // COEFX = 1.57 - 1.53 - (((RES - 1.47) * -0.358) + (RES - 3.975) * (((RES * -1) + 2.32) * 0.2225)); // COEFX = 0.633 + (RES * 0.8668); COEFX = 0.404 + (RES * 0.8764001); switch (MODE) { case 1: OUT = y4 * 1; // LP break; case 2: OUT = (*in1 - (y4 * COEFX)); // HP (pri res 1.4V e ok) break; case 3: OUT = ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX)); break; case 4: OUT = *in1 + ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX)); break; case 5: F = 2.f * sin(M_PI * FREQ); //[approximately] Q = *in4; QS = Q; SVFL = SVFL + F * SVFB; SVFH = QS * *in1 - SVFL - Q * SVFB; SVFB = F * SVFH + SVFB; SVFN = SVFH + SVFL; OUT = SVFL; break; default: return; }; // if (OUT > LIM) { OUT = LIM; } // else if (OUT < (LIM * -1)) { OUT = (LIM * -1); } *out1 = OUT; // OUTPUT *out2 = OUT; // MONO *o3 = RES * 0.1; *o4 = FREQ * 0.1; // increment the pointers (move to next sample in buffers) in1++; // in2++; in3++; in4++; in5++; in6++; out1++; out2++; o3++; o4++; } } void Module::sub_STEREO(long buffer_offset, long sampleFrames ) { // assign some pointers to your in/output buffers. usually blocks (array) of 96 samples float *in1 = buffer_offset + input1_buffer; // AUDIO-L float *in2 = buffer_offset + input2_buffer; // AUTIO-R float *in3 = buffer_offset + input3_buffer; // Freq float *in4 = buffer_offset + input4_buffer; // Reso float *in5 = buffer_offset + input5_buffer; // float *in6 = buffer_offset + input6_buffer; float *out1 = buffer_offset + output1_buffer; float *out2 = buffer_offset + output2_buffer; while(--sampleFrames >= 0) // sampleFrames = how many samples to process (can vary). repeat (loop) that many times { FREQ = (*in3 * 20000) * NI; if( FREQ >= 1 ) { FREQ = 1; } else if( FREQ <= 0.000090702 ) { FREQ = 0.000090702; } // original 1.16 F = FREQ * COEF2; RES = *in4 * 2.5; if( RES >= MAXR ) { RES = MAXR; } FB = RES * (1.0 - COEF1 * F * F); // RES * (1.0 - 0.15 * F * F) // COEF1 LIM = *in5; // ------------------------------------------- // x0 = *in1 - (y4 * FB); // y4/OUT << (feedback) v0 = *in2 - (z4 * FB); // y4/OUT << (feedback) x0 *= COEFR * (F * F) * (F * F); v0 *= COEFR * (F * F) * (F * F); // original 0.35013, good looking 0.5 // COEFR // ; ------------------------------------------------------------------- Pole 1 y1 = x0 + COEF3 * x1 + (1 - F) * y1; z1 = v0 + COEF3 * v1 + (1 - F) * z1; x1 = x0; v1 = v0; // ; ------------------------------------------------------------------- Pole 2 y2 = y1 + COEF3 * x2 + (1 - F) * y2; z2 = z1 + COEF3 * v2 + (1 - F) * z2; x2 = y1; v2 = z1; // ; ------------------------------------------------------------------- Pole 3 y3 = y2 + COEF3 * x3 + (1 - F) * y3; z3 = z2 + COEF3 * v3 + (1 - F) * z3; x3 = y2; v3 = z2; // ; ------------------------------------------------------------------- Pole 4 y4 = y3 + COEF3 * x4 + (1 - F) * y4; z4 = z3 + COEF3 * v4 + (1 - F) * z4; x4 = y3; v4 = z3; COEFX = 0.633 + (RES * 0.8668); switch (MODE) { case 1: OUTL = (y4 * COEFX); // LP OUTR = (z4 * COEFX); // LP break; case 2: OUTL = (*in1 - (y4 * COEFX)); // HP (pri res 1.4V e ok) OUTR = (*in2 - (z4 * COEFX)); // HP (pri res 1.4V e ok) break; case 3: OUTL = ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX)); OUTR = ((z1 * COEFX) + (z2 * COEFX) + (z3 * COEFX) + ((z4 * -1) * COEFX)); break; case 4: OUTL = *in1 + ((y1 * COEFX) + (y2 * COEFX) + (y3 * COEFX) + ((y4 * -1) * COEFX)); OUTR = *in2 + ((z1 * COEFX) + (z2 * COEFX) + (z3 * COEFX) + ((z4 * -1) * COEFX)); break; case 5: y5 = y4 + COEF3 * x5 + (1 - F) * y5; z5 = z4 + COEF3 * v5 + (1 - F) * z5; x5 = y4; v5 = z4; y6 = y5 + COEF3 * x6 + (1 - F) * y6; z6 = z5 + COEF3 * v6 + (1 - F) * z6; x6 = y5; v6 = z5; OUTL = (y6 * 0.2); OUTR = (z6 * 0.2); break; default: return; }; //OUTL = y4; //OUTR = z4; //if (OUTL > LIM) { OUTL = LIM; } //else if (OUTL < (LIM * -1)) { OUTL = (LIM * -1); } //if (OUTR > LIM) { OUTR = LIM; } //else if (OUTR < (LIM * -1)) { OUTR = (LIM * -1); } *out1 = OUTL; // OUTPUT *out2 = OUTR; // OUTPUT // increment the pointers (move to next sample in buffers) in1++; in2++; in3++; in4++; in5++; out1++; out2++; } } // every module has an output buffer of approx 100 samples. // before deactivating module, need to fill that buffer with silence. // "static_count" is counting out those 100 samples. void Module::sub_process_static(long buffer_offset, long sampleFrames ) { sub_MONO(buffer_offset, sampleFrames); static_count = static_count - sampleFrames; if( static_count <= 0 ) { // CallHost(seaudioMasterSleepMode); } } Module::Module(seaudioMasterCallback2 seaudioMaster, void *p_resvd1) : SEModule_base(seaudioMaster, p_resvd1) { } void Module::open() { // SET SAMPLE RATE SR = getSampleRate(); NI = SR / 2; NI = 1 / NI; // call the base class SEModule_base::open(); // choose which function is used to process audio SET_PROCESS_FUNC(Module::sub_MONO); // How to prevent other people using your custom module. // query the current registered user's name char host_registered_to[100]; CallHost( seaudioMasterGetRegisteredName, 0,0, host_registered_to ); bool registered_to_me = strcmp(host_registered_to, "Jeff McClintock") == 0; if( !registered_to_me ) { // do something appropriate here if you don't want other people using your module } } Module::~Module() { // This is where you free any memory/resources your module has created } // describe your module bool Module::getModuleProperties (SEModuleProperties* properties) { // describe the plugin, this is the name the end-user will see. properties->name = "AS_F24S"; // !!TODO!! // return a unique string 32 characters max // if posible include manufacturer and plugin identity // this is used internally by SE to identify the plug. // No two plugs may have the same id. properties->id = "AS_F24S_v0.98"; // !!TODO!! // Info, may include Author, Web page whatever properties->about = "by Anton Savov [antto]"; // !!TODO!! return true; } // describe the pins (plugs and parameters) bool Module::getPinProperties (long index, SEPinProperties* properties) { switch( index ) // !!TODO!! list your in / out plugs { // typical input plug (inputs are listed first) case 0: properties->name = "LEFT"; properties->variable_address = &input1_buffer; properties->direction = DR_IN; properties->datatype = DT_FSAMPLE; properties->default_value = "0"; break; case 1: properties->name = "RIGHT"; properties->variable_address = &input2_buffer; properties->direction = DR_IN; properties->datatype = DT_FSAMPLE; properties->default_value = "0"; break; case 2: properties->name = "Freq(KHz)"; properties->variable_address = &input3_buffer; properties->direction = DR_IN; properties->datatype = DT_FSAMPLE; properties->default_value = "0.440"; break; // typical output plug case 3: properties->name = "Res"; properties->variable_address = &input4_buffer; properties->direction = DR_IN; properties->datatype = DT_FSAMPLE; properties->default_value = "0"; break; case 4: properties->name = "Limit"; properties->variable_address = &input5_buffer; properties->direction = DR_IN; properties->datatype = DT_FSAMPLE; properties->default_value = "5"; break; case 5: properties->name = "LEFT"; properties->variable_address = &output1_buffer; properties->direction = DR_OUT; properties->datatype = DT_FSAMPLE; break; case 6: properties->name = "RIGHT"; properties->variable_address = &output2_buffer; properties->direction = DR_OUT; properties->datatype = DT_FSAMPLE; break; case 7: properties->name = "MONO/STEREO"; properties->variable_address = &MNST; properties->datatype_extra = "MONO=1,STEREO=2"; properties->default_value = "1"; properties->direction = DR_IN; properties->datatype = DT_ENUM; break; case 8: properties->name = "MODE"; properties->variable_address = &MODE; properties->datatype_extra = "LP24=1,HP24=2,BP24=3,BR24=4,SVF LP12=5"; properties->default_value = "1"; properties->direction = DR_IN; properties->datatype = DT_ENUM; break; case 9: properties->name = "F"; properties->variable_address = &o3_buffer; properties->direction = DR_OUT; properties->datatype = DT_FSAMPLE; break; case 10: properties->name = "FB"; properties->variable_address = &o4_buffer; properties->direction = DR_OUT; properties->datatype = DT_FSAMPLE; break; case 11: properties->name = "zzz"; properties->variable_address = &input6_buffer; properties->direction = DR_IN; properties->datatype = DT_FSAMPLE; properties->default_value = "5"; break; default: return false; // host will ask for plugs 0,1,2,3 etc. return false to signal when done }; return true; } // An input plug has changed value void Module::OnPlugStateChange(SEPin *pin) { /* if ( pin->getPinID() == 1 ) // Freq has changed! { float *in2; FREQ = (*in2 * 20000) * NI; if( FREQ >= 1 ) { FREQ = 1; } else if( FREQ <= 0.000090702 ) { FREQ = 0.000090702; } // original 1.16 F = FREQ * 1.16; FB = RES * (1.0 - 0.15 * F * F); } if ( pin->getPinID() == 2 ) // Res has changed! { float *in3; RES = *in3 * 2.5; if( RES >= 2.5 ) { RES = 2.5; } } */ // float test = getPin(PN_INPUT2)->getValue(); // int test2 = SampleClock(); if ( pin->getPinID() == 7 ) // MONO/STEREO has changed! { if (MNST == 1) { SET_PROCESS_FUNC(Module::sub_MONO); } else if (MNST == 2) { SET_PROCESS_FUNC(Module::sub_STEREO); } } if ( pin->getPinID() == 11 ) // RESET has changed! { if (RSTx <= 0 && getPin(11)->getValue() > 0) { x0 = x1 = x2 = x3 = x4 = 0; v0 = v1 = v2 = v3 = v4 = 0; y1 = y2 = y3 = y4 = 0; z1 = z2 = z3 = z4 = 0; } RSTx = getPin(11)->getValue(); } // query the 'state of the input plugs... // ST_RUN = Normal Streaming Audio (e.g. from an oscillator) // ST_STATIC = Fixed, unchanging input value (e.g. a slider at rest) state_type in_stat1 = getPin(PN_INPUT1)->getStatus(); state_type in_stat2 = getPin(PN_INPUT2)->getStatus(); // we need to pass on the state of this module's output signal // it depends on the inputs... state_type out_stat = in_stat1; if( in_stat2 > out_stat) out_stat = in_stat2; // if user has set either input to zero, we can tell downstream modules that the audio has stopped /* if( in_stat1 < ST_RUN && getPin(PN_INPUT1)->getValue() == 0.f ) { out_stat = ST_STATIC; } if( in_stat2 < ST_RUN && getPin(PN_INPUT2)->getValue() == 0.f ) { out_stat = ST_STATIC; } */ // 'transmit' this modules new output status to next module 'downstream' getPin(PN_OUTPUT1)->TransmitStatusChange( SampleClock(), ST_RUN); getPin(PN_OUTPUT2)->TransmitStatusChange( SampleClock(), ST_RUN); getPin(9)->TransmitStatusChange( SampleClock(), ST_RUN); getPin(10)->TransmitStatusChange( SampleClock(), ST_RUN); // setup up 'sleep mode' or not /* if( out_stat < ST_RUN ) { static_count = getBlockSize(); SET_PROCESS_FUNC(Module::sub_process_static); } else { SET_PROCESS_FUNC(Module::sub_MONO); } */ }