/[svn]/linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/common/InstrumentScriptVMFunctions.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2953 by schoenebeck, Sat Jul 16 11:24:39 2016 UTC revision 3118 by schoenebeck, Fri Apr 21 13:33:03 2017 UTC
# Line 1  Line 1 
1  /*  /*
2   * Copyright (c) 2014-2016 Christian Schoenebeck   * Copyright (c) 2014-2017 Christian Schoenebeck
3   *   *
4   * http://www.linuxsampler.org   * http://www.linuxsampler.org
5   *   *
# Line 365  namespace LinuxSampler { Line 365  namespace LinuxSampler {
365      VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_vol::exec(VMFnArgs* args) {
366          int volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB          int volume = args->arg(1)->asInt()->evalInt(); // volume change in milli dB
367          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
368            const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);
369    
370          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
371              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 383  namespace LinuxSampler { Line 384  namespace LinuxSampler {
384              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
385              if (!pNote) return successResult();              if (!pNote) return successResult();
386    
387              const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);              // if change_vol() was called immediately after note was triggered
388              // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior              // then immediately apply the volume to note object
389              /*if (relative)              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
390                  pNote->Override.Volume *= fVolumeLin;                  if (relative)
             else  
                 pNote->Override.Volume = fVolumeLin;*/  
   
             Event e = m_vm->m_event->cause; // copy to get fragment time for "now"  
             e.Init(); // clear IDs  
             e.Type = Event::type_note_synth_param;  
             e.Param.NoteSynthParam.NoteID   = id.noteID();  
             e.Param.NoteSynthParam.Type     = Event::synth_param_volume;  
             e.Param.NoteSynthParam.Delta    = fVolumeLin;  
             e.Param.NoteSynthParam.Relative = relative;  
   
             pEngineChannel->ScheduleEventMicroSec(&e, 0);  
         } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {  
             VMIntArrayExpr* ids = args->arg(0)->asIntArray();  
             for (int i = 0; i < ids->arraySize(); ++i) {  
                 const ScriptID id = ids->evalIntElement(i);  
                 if (!id || !id.isNoteID()) continue;  
   
                 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );  
                 if (!pNote) continue;  
   
                 const float fVolumeLin = RTMath::DecibelToLinRatio(float(volume) / 1000.f);  
                 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior  
                 /*if (relative)  
391                      pNote->Override.Volume *= fVolumeLin;                      pNote->Override.Volume *= fVolumeLin;
392                  else                  else
393                      pNote->Override.Volume = fVolumeLin;*/                      pNote->Override.Volume = fVolumeLin;
394                } else { // otherwise schedule the volume change ...
395                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
396                  e.Init(); // clear IDs                  e.Init(); // clear IDs
397                  e.Type = Event::type_note_synth_param;                  e.Type = Event::type_note_synth_param;
# Line 425  namespace LinuxSampler { Line 402  namespace LinuxSampler {
402    
403                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
404              }              }
405            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
406                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
407                for (int i = 0; i < ids->arraySize(); ++i) {
408                    const ScriptID id = ids->evalIntElement(i);
409                    if (!id || !id.isNoteID()) continue;
410    
411                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
412                    if (!pNote) continue;
413    
414                    // if change_vol() was called immediately after note was triggered
415                    // then immediately apply the volume to Note object
416                    if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
417                        if (relative)
418                            pNote->Override.Volume *= fVolumeLin;
419                        else
420                            pNote->Override.Volume = fVolumeLin;
421                    } else { // otherwise schedule the volume change ...
422                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
423                        e.Init(); // clear IDs
424                        e.Type = Event::type_note_synth_param;
425                        e.Param.NoteSynthParam.NoteID   = id.noteID();
426                        e.Param.NoteSynthParam.Type     = Event::synth_param_volume;
427                        e.Param.NoteSynthParam.Delta    = fVolumeLin;
428                        e.Param.NoteSynthParam.Relative = relative;
429    
430                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
431                    }
432                }
433          }          }
434    
435          return successResult();          return successResult();
# Line 447  namespace LinuxSampler { Line 452  namespace LinuxSampler {
452      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {      VMFnResult* InstrumentScriptVMFunction_change_tune::exec(VMFnArgs* args) {
453          int tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents          int tune = args->arg(1)->asInt()->evalInt(); // tuning change in milli cents
454          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;          bool relative = (args->argsCount() >= 3) ? (args->arg(2)->asInt()->evalInt() & 1) : false;
455            const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);
456    
457          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
458              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 465  namespace LinuxSampler { Line 471  namespace LinuxSampler {
471              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
472              if (!pNote) return successResult();              if (!pNote) return successResult();
473    
474              const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);              // if change_tune() was called immediately after note was triggered
475              // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior              // then immediately apply the tuning to Note object
476              /*if (relative)              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
477                  pNote->Override.Pitch *= fFreqRatio;                  if (relative)
             else  
                 pNote->Override.Pitch = fFreqRatio;*/  
   
             Event e = m_vm->m_event->cause; // copy to get fragment time for "now"  
             e.Init(); // clear IDs  
             e.Type = Event::type_note_synth_param;  
             e.Param.NoteSynthParam.NoteID   = id.noteID();  
             e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;  
             e.Param.NoteSynthParam.Delta    = fFreqRatio;  
             e.Param.NoteSynthParam.Relative = relative;  
   
             pEngineChannel->ScheduleEventMicroSec(&e, 0);  
         } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {  
             VMIntArrayExpr* ids = args->arg(0)->asIntArray();  
             for (int i = 0; i < ids->arraySize(); ++i) {  
                 const ScriptID id = ids->evalIntElement(i);  
                 if (!id || !id.isNoteID()) continue;  
   
                 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );  
                 if (!pNote) continue;  
   
                 const float fFreqRatio = RTMath::CentsToFreqRatioUnlimited(float(tune) / 1000.f);  
                 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior  
                 /*if (relative)  
478                      pNote->Override.Pitch *= fFreqRatio;                      pNote->Override.Pitch *= fFreqRatio;
479                  else                  else
480                      pNote->Override.Pitch = fFreqRatio;*/                      pNote->Override.Pitch = fFreqRatio;
481                } else { // otherwise schedule tuning change ...
482                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
483                  e.Init(); // clear IDs                  e.Init(); // clear IDs
484                  e.Type = Event::type_note_synth_param;                  e.Type = Event::type_note_synth_param;
# Line 507  namespace LinuxSampler { Line 489  namespace LinuxSampler {
489    
490                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
491              }              }
492            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
493                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
494                for (int i = 0; i < ids->arraySize(); ++i) {
495                    const ScriptID id = ids->evalIntElement(i);
496                    if (!id || !id.isNoteID()) continue;
497    
498                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
499                    if (!pNote) continue;
500    
501                    // if change_tune() was called immediately after note was triggered
502                    // then immediately apply the tuning to Note object
503                    if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
504                        if (relative)
505                            pNote->Override.Pitch *= fFreqRatio;
506                        else
507                            pNote->Override.Pitch = fFreqRatio;
508                    } else { // otherwise schedule tuning change ...
509                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
510                        e.Init(); // clear IDs
511                        e.Type = Event::type_note_synth_param;
512                        e.Param.NoteSynthParam.NoteID   = id.noteID();
513                        e.Param.NoteSynthParam.Type     = Event::synth_param_pitch;
514                        e.Param.NoteSynthParam.Delta    = fFreqRatio;
515                        e.Param.NoteSynthParam.Relative = relative;
516    
517                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
518                    }
519                }
520          }          }
521    
522          return successResult();          return successResult();
# Line 537  namespace LinuxSampler { Line 547  namespace LinuxSampler {
547              wrnMsg("change_pan(): argument 2 may not be smaller than -1000");              wrnMsg("change_pan(): argument 2 may not be smaller than -1000");
548              pan = -1000;              pan = -1000;
549          }          }
550            const float fPan = float(pan) / 1000.f;
551    
552          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
553              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 555  namespace LinuxSampler { Line 566  namespace LinuxSampler {
566              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
567              if (!pNote) return successResult();              if (!pNote) return successResult();
568    
569              const float fPan = float(pan) / 1000.f;              // if change_pan() was called immediately after note was triggered
570              // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior              // then immediately apply the panning to Note object
571              /*if (relative) {              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
572                  pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                  if (relative) {
             } else {  
                 pNote->Override.Pan = fPan;  
                 pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set  
             }*/  
   
             Event e = m_vm->m_event->cause; // copy to get fragment time for "now"  
             e.Init(); // clear IDs  
             e.Type = Event::type_note_synth_param;  
             e.Param.NoteSynthParam.NoteID   = id.noteID();  
             e.Param.NoteSynthParam.Type     = Event::synth_param_pan;  
             e.Param.NoteSynthParam.Delta    = fPan;  
             e.Param.NoteSynthParam.Relative = relative;  
   
             pEngineChannel->ScheduleEventMicroSec(&e, 0);  
         } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {  
             VMIntArrayExpr* ids = args->arg(0)->asIntArray();  
             for (int i = 0; i < ids->arraySize(); ++i) {  
                 const ScriptID id = ids->evalIntElement(i);  
                 if (!id || !id.isNoteID()) continue;  
   
                 NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );  
                 if (!pNote) continue;  
   
                 const float fPan = float(pan) / 1000.f;  
                 // commented out, performed by EngineBase::ProcessNoteSynthParam() for time accuracy behavior  
                 /*if (relative) {  
573                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);                      pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
574                  } else {                  } else {
575                      pNote->Override.Pan = fPan;                      pNote->Override.Pan = fPan;
576                      pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set                      pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
577                  }*/                  }
578                } else { // otherwise schedule panning change ...
579                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
580                  e.Init(); // clear IDs                  e.Init(); // clear IDs
581                  e.Type = Event::type_note_synth_param;                  e.Type = Event::type_note_synth_param;
# Line 601  namespace LinuxSampler { Line 586  namespace LinuxSampler {
586    
587                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
588              }              }
589            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
590                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
591                for (int i = 0; i < ids->arraySize(); ++i) {
592                    const ScriptID id = ids->evalIntElement(i);
593                    if (!id || !id.isNoteID()) continue;
594    
595                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
596                    if (!pNote) continue;
597    
598                    // if change_pan() was called immediately after note was triggered
599                    // then immediately apply the panning to Note object
600                    if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
601                        if (relative) {
602                            pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, fPan, ++pNote->Override.PanSources);
603                        } else {
604                            pNote->Override.Pan = fPan;
605                            pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() calls on same note with 'relative' being set
606                        }
607                    } else { // otherwise schedule panning change ...
608                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
609                        e.Init(); // clear IDs
610                        e.Type = Event::type_note_synth_param;
611                        e.Param.NoteSynthParam.NoteID   = id.noteID();
612                        e.Param.NoteSynthParam.Type     = Event::synth_param_pan;
613                        e.Param.NoteSynthParam.Delta    = fPan;
614                        e.Param.NoteSynthParam.Relative = relative;
615    
616                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
617                    }
618                }
619          }          }
620    
621          return successResult();          return successResult();
# Line 632  namespace LinuxSampler { Line 647  namespace LinuxSampler {
647              wrnMsg("change_cutoff(): argument 2 may not be negative");              wrnMsg("change_cutoff(): argument 2 may not be negative");
648              cutoff = 0;              cutoff = 0;
649          }          }
650            const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);
651    
652          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
653              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 650  namespace LinuxSampler { Line 666  namespace LinuxSampler {
666              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
667              if (!pNote) return successResult();              if (!pNote) return successResult();
668    
669              const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);              // if change_cutoff() was called immediately after note was triggered
670                // then immediately apply cutoff to Note object
671              Event e = m_vm->m_event->cause; // copy to get fragment time for "now"              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
672              e.Init(); // clear IDs                  pNote->Override.Cutoff = fCutoff;
673              e.Type = Event::type_note_synth_param;              } else { // otherwise schedule cutoff change ...
674              e.Param.NoteSynthParam.NoteID   = id.noteID();                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
675              e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;                  e.Init(); // clear IDs
676              e.Param.NoteSynthParam.Delta    = fCutoff;                  e.Type = Event::type_note_synth_param;
677              e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.NoteID   = id.noteID();
678                    e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;
679                    e.Param.NoteSynthParam.Delta    = fCutoff;
680                    e.Param.NoteSynthParam.Relative = false;
681    
682              pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
683                }
684          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
685              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
686              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
# Line 670  namespace LinuxSampler { Line 690  namespace LinuxSampler {
690                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
691                  if (!pNote) continue;                  if (!pNote) continue;
692    
693                  const float fCutoff = float(cutoff) / float(VM_FILTER_PAR_MAX_VALUE);                  // if change_cutoff() was called immediately after note was triggered
694                    // then immediately apply cutoff to Note object
695                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
696                  e.Init(); // clear IDs                      pNote->Override.Cutoff = fCutoff;
697                  e.Type = Event::type_note_synth_param;                  } else { // otherwise schedule cutoff change ...
698                  e.Param.NoteSynthParam.NoteID   = id.noteID();                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
699                  e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;                      e.Init(); // clear IDs
700                  e.Param.NoteSynthParam.Delta    = fCutoff;                      e.Type = Event::type_note_synth_param;
701                  e.Param.NoteSynthParam.Relative = false;                      e.Param.NoteSynthParam.NoteID   = id.noteID();
702                        e.Param.NoteSynthParam.Type     = Event::synth_param_cutoff;
703                        e.Param.NoteSynthParam.Delta    = fCutoff;
704                        e.Param.NoteSynthParam.Relative = false;
705    
706                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
707                    }
708              }              }
709          }          }
710    
# Line 710  namespace LinuxSampler { Line 734  namespace LinuxSampler {
734              wrnMsg("change_reso(): argument 2 may not be negative");              wrnMsg("change_reso(): argument 2 may not be negative");
735              resonance = 0;              resonance = 0;
736          }          }
737            const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);
738    
739          AbstractEngineChannel* pEngineChannel =          AbstractEngineChannel* pEngineChannel =
740              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);              static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
# Line 728  namespace LinuxSampler { Line 753  namespace LinuxSampler {
753              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
754              if (!pNote) return successResult();              if (!pNote) return successResult();
755    
756              const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);              // if change_reso() was called immediately after note was triggered
757                // then immediately apply resonance to Note object
758              Event e = m_vm->m_event->cause; // copy to get fragment time for "now"              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
759              e.Init(); // clear IDs                  pNote->Override.Resonance = fResonance;
760              e.Type = Event::type_note_synth_param;              } else { // otherwise schedule resonance change ...
761              e.Param.NoteSynthParam.NoteID   = id.noteID();                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
762              e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;                  e.Init(); // clear IDs
763              e.Param.NoteSynthParam.Delta    = fResonance;                  e.Type = Event::type_note_synth_param;
764              e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.NoteID   = id.noteID();
765                    e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;
766                    e.Param.NoteSynthParam.Delta    = fResonance;
767                    e.Param.NoteSynthParam.Relative = false;
768    
769              pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
770                }
771          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
772              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
773              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
# Line 748  namespace LinuxSampler { Line 777  namespace LinuxSampler {
777                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
778                  if (!pNote) continue;                  if (!pNote) continue;
779    
780                  const float fResonance = float(resonance) / float(VM_FILTER_PAR_MAX_VALUE);                  // if change_reso() was called immediately after note was triggered
781                    // then immediately apply resonance to Note object
782                    if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
783                        pNote->Override.Resonance = fResonance;
784                    } else { // otherwise schedule resonance change ...
785                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
786                        e.Init(); // clear IDs
787                        e.Type = Event::type_note_synth_param;
788                        e.Param.NoteSynthParam.NoteID   = id.noteID();
789                        e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;
790                        e.Param.NoteSynthParam.Delta    = fResonance;
791                        e.Param.NoteSynthParam.Relative = false;
792    
793                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
794                  e.Init(); // clear IDs                  }
                 e.Type = Event::type_note_synth_param;  
                 e.Param.NoteSynthParam.NoteID   = id.noteID();  
                 e.Param.NoteSynthParam.Type     = Event::synth_param_resonance;  
                 e.Param.NoteSynthParam.Delta    = fResonance;  
                 e.Param.NoteSynthParam.Relative = false;  
   
                 pEngineChannel->ScheduleEventMicroSec(&e, 0);  
795              }              }
796          }          }
797    
# Line 805  namespace LinuxSampler { Line 838  namespace LinuxSampler {
838              }              }
839    
840              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
841              if (!pNote) return successResult();                          if (!pNote) return successResult();
842    
843              Event e = m_vm->m_event->cause; // copy to get fragment time for "now"              // if change_attack() was called immediately after note was triggered
844              e.Init(); // clear IDs              // then immediately apply attack to Note object
845              e.Type = Event::type_note_synth_param;              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
846              e.Param.NoteSynthParam.NoteID   = id.noteID();                  pNote->Override.Attack = fAttack;
847              e.Param.NoteSynthParam.Type     = Event::synth_param_attack;              } else { // otherwise schedule attack change ...
848              e.Param.NoteSynthParam.Delta    = fAttack;                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
849              e.Param.NoteSynthParam.Relative = false;                  e.Init(); // clear IDs
850                    e.Type = Event::type_note_synth_param;
851                    e.Param.NoteSynthParam.NoteID   = id.noteID();
852                    e.Param.NoteSynthParam.Type     = Event::synth_param_attack;
853                    e.Param.NoteSynthParam.Delta    = fAttack;
854                    e.Param.NoteSynthParam.Relative = false;
855    
856              pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
857                }
858          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
859              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
860              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
# Line 825  namespace LinuxSampler { Line 864  namespace LinuxSampler {
864                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
865                  if (!pNote) continue;                  if (!pNote) continue;
866    
867                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  // if change_attack() was called immediately after note was triggered
868                  e.Init(); // clear IDs                  // then immediately apply attack to Note object
869                  e.Type = Event::type_note_synth_param;                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
870                  e.Param.NoteSynthParam.NoteID   = id.noteID();                      pNote->Override.Attack = fAttack;
871                  e.Param.NoteSynthParam.Type     = Event::synth_param_attack;                  } else { // otherwise schedule attack change ...
872                  e.Param.NoteSynthParam.Delta    = fAttack;                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
873                  e.Param.NoteSynthParam.Relative = false;                      e.Init(); // clear IDs
874                        e.Type = Event::type_note_synth_param;
875                        e.Param.NoteSynthParam.NoteID   = id.noteID();
876                        e.Param.NoteSynthParam.Type     = Event::synth_param_attack;
877                        e.Param.NoteSynthParam.Delta    = fAttack;
878                        e.Param.NoteSynthParam.Relative = false;
879    
880                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
881                    }
882              }              }
883          }          }
884    
# Line 880  namespace LinuxSampler { Line 925  namespace LinuxSampler {
925              }              }
926    
927              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
928              if (!pNote) return successResult();                          if (!pNote) return successResult();
929    
930              Event e = m_vm->m_event->cause; // copy to get fragment time for "now"              // if change_decay() was called immediately after note was triggered
931              e.Init(); // clear IDs              // then immediately apply decay to Note object
932              e.Type = Event::type_note_synth_param;              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
933              e.Param.NoteSynthParam.NoteID   = id.noteID();                  pNote->Override.Decay = fDecay;
934              e.Param.NoteSynthParam.Type     = Event::synth_param_decay;              } else { // otherwise schedule decay change ...
935              e.Param.NoteSynthParam.Delta    = fDecay;                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
936              e.Param.NoteSynthParam.Relative = false;                  e.Init(); // clear IDs
937                    e.Type = Event::type_note_synth_param;
938                    e.Param.NoteSynthParam.NoteID   = id.noteID();
939                    e.Param.NoteSynthParam.Type     = Event::synth_param_decay;
940                    e.Param.NoteSynthParam.Delta    = fDecay;
941                    e.Param.NoteSynthParam.Relative = false;
942    
943              pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
944                }
945          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
946              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
947              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
# Line 900  namespace LinuxSampler { Line 951  namespace LinuxSampler {
951                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
952                  if (!pNote) continue;                  if (!pNote) continue;
953    
954                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  // if change_decay() was called immediately after note was triggered
955                  e.Init(); // clear IDs                  // then immediately apply decay to Note object
956                  e.Type = Event::type_note_synth_param;                  if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
957                  e.Param.NoteSynthParam.NoteID   = id.noteID();                      pNote->Override.Decay = fDecay;
958                  e.Param.NoteSynthParam.Type     = Event::synth_param_decay;                  } else { // otherwise schedule decay change ...
959                  e.Param.NoteSynthParam.Delta    = fDecay;                      Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
960                  e.Param.NoteSynthParam.Relative = false;                      e.Init(); // clear IDs
961                        e.Type = Event::type_note_synth_param;
962                        e.Param.NoteSynthParam.NoteID   = id.noteID();
963                        e.Param.NoteSynthParam.Type     = Event::synth_param_decay;
964                        e.Param.NoteSynthParam.Delta    = fDecay;
965                        e.Param.NoteSynthParam.Relative = false;
966    
967                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                      pEngineChannel->ScheduleEventMicroSec(&e, 0);
968                    }
969              }              }
970          }          }
971    
# Line 955  namespace LinuxSampler { Line 1012  namespace LinuxSampler {
1012              }              }
1013    
1014              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );              NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1015              if (!pNote) return successResult();                          if (!pNote) return successResult();
1016    
1017              Event e = m_vm->m_event->cause; // copy to get fragment time for "now"              // if change_release() was called immediately after note was triggered
1018              e.Init(); // clear IDs              // then immediately apply relase to Note object
1019              e.Type = Event::type_note_synth_param;              if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
1020              e.Param.NoteSynthParam.NoteID   = id.noteID();                  pNote->Override.Release = fRelease;
1021              e.Param.NoteSynthParam.Type     = Event::synth_param_release;              } else { // otherwise schedule release change ...
1022              e.Param.NoteSynthParam.Delta    = fRelease;                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1023              e.Param.NoteSynthParam.Relative = false;                  e.Init(); // clear IDs
1024                    e.Type = Event::type_note_synth_param;
1025                    e.Param.NoteSynthParam.NoteID   = id.noteID();
1026                    e.Param.NoteSynthParam.Type     = Event::synth_param_release;
1027                    e.Param.NoteSynthParam.Delta    = fRelease;
1028                    e.Param.NoteSynthParam.Relative = false;
1029    
1030              pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1031                }
1032          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {          } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1033              VMIntArrayExpr* ids = args->arg(0)->asIntArray();              VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1034              for (int i = 0; i < ids->arraySize(); ++i) {              for (int i = 0; i < ids->arraySize(); ++i) {
# Line 975  namespace LinuxSampler { Line 1038  namespace LinuxSampler {
1038                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );                  NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1039                  if (!pNote) continue;                  if (!pNote) continue;
1040    
1041                    // if change_release() was called immediately after note was triggered
1042                    // then immediately apply relase to Note object
1043                    if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
1044                        pNote->Override.Release = fRelease;
1045                    } else { // otherwise schedule release change ...
1046                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1047                        e.Init(); // clear IDs
1048                        e.Type = Event::type_note_synth_param;
1049                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1050                        e.Param.NoteSynthParam.Type     = Event::synth_param_release;
1051                        e.Param.NoteSynthParam.Delta    = fRelease;
1052                        e.Param.NoteSynthParam.Relative = false;
1053    
1054                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1055                    }
1056                }
1057            }
1058    
1059            return successResult();
1060        }
1061    
1062        #define VM_GENERAL_CHANGE_SYNTH_PAR_MAX_VALUE 1000000
1063    
1064        bool VMChangeSynthParamFunction::acceptsArgType(int iArg, ExprType_t type) const {
1065            if (iArg == 0)
1066                return type == INT_EXPR || type == INT_ARR_EXPR;
1067            else
1068                return INT_EXPR;
1069        }
1070    
1071        template<float NoteBase::_Override::*T_noteParam, int T_synthParam>
1072        VMFnResult* VMChangeSynthParamFunction::execTemplate(VMFnArgs* args, const char* functionName) {
1073            int value = args->arg(1)->asInt()->evalInt();
1074            if (value > VM_GENERAL_CHANGE_SYNTH_PAR_MAX_VALUE) {
1075                wrnMsg(String(functionName) + "(): argument 2 may not be larger than 1000000");
1076                value = VM_GENERAL_CHANGE_SYNTH_PAR_MAX_VALUE;
1077            } else if (value < 0) {
1078                wrnMsg(String(functionName) + "(): argument 2 may not be negative");
1079                value = 0;
1080            }
1081            const float fValue = float(value) / float(VM_GENERAL_CHANGE_SYNTH_PAR_MAX_VALUE);
1082    
1083            AbstractEngineChannel* pEngineChannel =
1084                static_cast<AbstractEngineChannel*>(m_vm->m_event->cause.pEngineChannel);
1085    
1086            if (args->arg(0)->exprType() == INT_EXPR) {
1087                const ScriptID id = args->arg(0)->asInt()->evalInt();
1088                if (!id) {
1089                    wrnMsg(String(functionName) + "(): note ID for argument 1 may not be zero");
1090                    return successResult();
1091                }
1092                if (!id.isNoteID()) {
1093                    wrnMsg(String(functionName) + "(): argument 1 is not a note ID");
1094                    return successResult();
1095                }
1096    
1097                NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1098                if (!pNote) return successResult();
1099    
1100                // if this change_*() script function was called immediately after
1101                // note was triggered then immediately apply the synth parameter
1102                // change to Note object
1103                if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
1104                    pNote->Override.*T_noteParam = fValue;
1105                } else { // otherwise schedule this synth parameter change ...
1106                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"                  Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1107                  e.Init(); // clear IDs                  e.Init(); // clear IDs
1108                  e.Type = Event::type_note_synth_param;                  e.Type = Event::type_note_synth_param;
1109                  e.Param.NoteSynthParam.NoteID   = id.noteID();                  e.Param.NoteSynthParam.NoteID   = id.noteID();
1110                  e.Param.NoteSynthParam.Type     = Event::synth_param_release;                  e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1111                  e.Param.NoteSynthParam.Delta    = fRelease;                  e.Param.NoteSynthParam.Delta    = fValue;
1112                  e.Param.NoteSynthParam.Relative = false;                  e.Param.NoteSynthParam.Relative = false;
1113    
1114                  pEngineChannel->ScheduleEventMicroSec(&e, 0);                  pEngineChannel->ScheduleEventMicroSec(&e, 0);
1115              }              }
1116            } else if (args->arg(0)->exprType() == INT_ARR_EXPR) {
1117                VMIntArrayExpr* ids = args->arg(0)->asIntArray();
1118                for (int i = 0; i < ids->arraySize(); ++i) {
1119                    const ScriptID id = ids->evalIntElement(i);
1120                    if (!id || !id.isNoteID()) continue;
1121    
1122                    NoteBase* pNote = pEngineChannel->pEngine->NoteByID( id.noteID() );
1123                    if (!pNote) continue;
1124    
1125                    // if this change_*() script function was called immediately after
1126                    // note was triggered then immediately apply the synth parameter
1127                    // change to Note object
1128                    if (m_vm->m_event->cause.SchedTime() == pNote->triggerSchedTime) {
1129                        pNote->Override.*T_noteParam = fValue;
1130                    } else { // otherwise schedule this synth parameter change ...
1131                        Event e = m_vm->m_event->cause; // copy to get fragment time for "now"
1132                        e.Init(); // clear IDs
1133                        e.Type = Event::type_note_synth_param;
1134                        e.Param.NoteSynthParam.NoteID   = id.noteID();
1135                        e.Param.NoteSynthParam.Type     = (Event::synth_param_t) T_synthParam;
1136                        e.Param.NoteSynthParam.Delta    = fValue;
1137                        e.Param.NoteSynthParam.Relative = false;
1138    
1139                        pEngineChannel->ScheduleEventMicroSec(&e, 0);
1140                    }
1141                }
1142          }          }
1143    
1144          return successResult();          return successResult();
1145      }      }
1146    
1147        // change_amp_lfo_depth() function
1148    
1149        VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_depth::exec(VMFnArgs* args) {
1150            return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::AmpLFODepth, Event::synth_param_amp_lfo_depth >(args, "change_amp_lfo_depth");
1151        }
1152    
1153        // change_amp_lfo_freq() function
1154    
1155        VMFnResult* InstrumentScriptVMFunction_change_amp_lfo_freq::exec(VMFnArgs* args) {
1156            return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::AmpLFOFreq, Event::synth_param_amp_lfo_freq >(args, "change_amp_lfo_freq");
1157        }
1158    
1159        // change_pitch_lfo_depth() function
1160    
1161        VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_depth::exec(VMFnArgs* args) {
1162            return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::PitchLFODepth, Event::synth_param_pitch_lfo_depth >(args, "change_pitch_lfo_depth");
1163        }
1164    
1165        // change_pitch_lfo_freq() function
1166    
1167        VMFnResult* InstrumentScriptVMFunction_change_pitch_lfo_freq::exec(VMFnArgs* args) {
1168            return VMChangeSynthParamFunction::execTemplate< &NoteBase::_Override::PitchLFOFreq, Event::synth_param_pitch_lfo_freq >(args, "change_pitch_lfo_freq");
1169        }
1170    
1171      // event_status() function      // event_status() function
1172    
1173      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)      InstrumentScriptVMFunction_event_status::InstrumentScriptVMFunction_event_status(InstrumentScriptVM* parent)

Legend:
Removed from v.2953  
changed lines
  Added in v.3118

  ViewVC Help
Powered by ViewVC