/[svn]/linuxsampler/trunk/src/engines/gig/Engine.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/Engine.cpp

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

revision 242 by schoenebeck, Wed Sep 15 13:59:08 2004 UTC revision 246 by schoenebeck, Sun Sep 19 14:12:55 2004 UTC
# Line 37  namespace LinuxSampler { namespace gig { Line 37  namespace LinuxSampler { namespace gig {
37          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
38          pDiskThread        = NULL;          pDiskThread        = NULL;
39          pEventGenerator    = NULL;          pEventGenerator    = NULL;
40          pEventQueue        = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT);          pSysexBuffer       = new RingBuffer<uint8_t>(SYSEX_BUFFER_SIZE, 0);
41            pEventQueue        = new RingBuffer<Event>(MAX_EVENTS_PER_FRAGMENT, 0);
42          pEventPool         = new RTELMemoryPool<Event>(MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new RTELMemoryPool<Event>(MAX_EVENTS_PER_FRAGMENT);
43          pVoicePool         = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES);          pVoicePool         = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES);
44          pActiveKeys        = new RTELMemoryPool<uint>(128);          pActiveKeys        = new RTELMemoryPool<uint>(128);
# Line 93  namespace LinuxSampler { namespace gig { Line 94  namespace LinuxSampler { namespace gig {
94          if (pEventPool)  delete pEventPool;          if (pEventPool)  delete pEventPool;
95          if (pVoicePool)  delete pVoicePool;          if (pVoicePool)  delete pVoicePool;
96          if (pActiveKeys) delete pActiveKeys;          if (pActiveKeys) delete pActiveKeys;
97            if (pSysexBuffer) delete pSysexBuffer;
98          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
99          if (pMainFilterParameters) delete[] pMainFilterParameters;          if (pMainFilterParameters) delete[] pMainFilterParameters;
100          if (pBasicFilterParameters) delete[] pBasicFilterParameters;          if (pBasicFilterParameters) delete[] pBasicFilterParameters;
# Line 155  namespace LinuxSampler { namespace gig { Line 157  namespace LinuxSampler { namespace gig {
157          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
158          GlobalVolume        = 1.0;          GlobalVolume        = 1.0;
159    
160            // reset to normal chromatic scale (means equal temper)
161            memset(&ScaleTuning[0], 0x00, 12);
162    
163          // set all MIDI controller values to zero          // set all MIDI controller values to zero
164          memset(ControllerTable, 0x00, 128);          memset(ControllerTable, 0x00, 128);
165    
# Line 408  namespace LinuxSampler { namespace gig { Line 413  namespace LinuxSampler { namespace gig {
413              pNextEvent = pEvents->next();              pNextEvent = pEvents->next();
414              switch (pEvent->Type) {              switch (pEvent->Type) {
415                  case Event::type_note_on:                  case Event::type_note_on:
416                      dmsg(5,("Audio Thread: Note on received\n"));                      dmsg(5,("Engine: Note on received\n"));
417                      ProcessNoteOn(pEvent);                      ProcessNoteOn(pEvent);
418                      break;                      break;
419                  case Event::type_note_off:                  case Event::type_note_off:
420                      dmsg(5,("Audio Thread: Note off received\n"));                      dmsg(5,("Engine: Note off received\n"));
421                      ProcessNoteOff(pEvent);                      ProcessNoteOff(pEvent);
422                      break;                      break;
423                  case Event::type_control_change:                  case Event::type_control_change:
424                      dmsg(5,("Audio Thread: MIDI CC received\n"));                      dmsg(5,("Engine: MIDI CC received\n"));
425                      ProcessControlChange(pEvent);                      ProcessControlChange(pEvent);
426                      break;                      break;
427                  case Event::type_pitchbend:                  case Event::type_pitchbend:
428                      dmsg(5,("Audio Thread: Pitchbend received\n"));                      dmsg(5,("Engine: Pitchbend received\n"));
429                      ProcessPitchbend(pEvent);                      ProcessPitchbend(pEvent);
430                      break;                      break;
431                    case Event::type_sysex:
432                        dmsg(5,("Engine: Sysex received\n"));
433                        ProcessSysex(pEvent);
434                        break;
435              }              }
436          }          }
437    
# Line 470  namespace LinuxSampler { namespace gig { Line 479  namespace LinuxSampler { namespace gig {
479       *  @param Velocity - MIDI velocity value of the triggered key       *  @param Velocity - MIDI velocity value of the triggered key
480       */       */
481      void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) {      void Engine::SendNoteOn(uint8_t Key, uint8_t Velocity) {
482          Event event    = pEventGenerator->CreateEvent();          Event event               = pEventGenerator->CreateEvent();
483          event.Type     = Event::type_note_on;          event.Type                = Event::type_note_on;
484          event.Key      = Key;          event.Param.Note.Key      = Key;
485          event.Velocity = Velocity;          event.Param.Note.Velocity = Velocity;
486          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
487          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
488      }      }
# Line 486  namespace LinuxSampler { namespace gig { Line 495  namespace LinuxSampler { namespace gig {
495       *  @param Velocity - MIDI release velocity value of the released key       *  @param Velocity - MIDI release velocity value of the released key
496       */       */
497      void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) {      void Engine::SendNoteOff(uint8_t Key, uint8_t Velocity) {
498          Event event    = pEventGenerator->CreateEvent();          Event event               = pEventGenerator->CreateEvent();
499          event.Type     = Event::type_note_off;          event.Type                = Event::type_note_off;
500          event.Key      = Key;          event.Param.Note.Key      = Key;
501          event.Velocity = Velocity;          event.Param.Note.Velocity = Velocity;
502          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
503          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
504      }      }
# Line 501  namespace LinuxSampler { namespace gig { Line 510  namespace LinuxSampler { namespace gig {
510       *  @param Pitch - MIDI pitch value (-8192 ... +8191)       *  @param Pitch - MIDI pitch value (-8192 ... +8191)
511       */       */
512      void Engine::SendPitchbend(int Pitch) {      void Engine::SendPitchbend(int Pitch) {
513          Event event = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
514          event.Type  = Event::type_pitchbend;          event.Type              = Event::type_pitchbend;
515          event.Pitch = Pitch;          event.Param.Pitch.Pitch = Pitch;
516          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
517          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
518      }      }
# Line 516  namespace LinuxSampler { namespace gig { Line 525  namespace LinuxSampler { namespace gig {
525       *  @param Value      - value of the control change       *  @param Value      - value of the control change
526       */       */
527      void Engine::SendControlChange(uint8_t Controller, uint8_t Value) {      void Engine::SendControlChange(uint8_t Controller, uint8_t Value) {
528          Event event      = pEventGenerator->CreateEvent();          Event event               = pEventGenerator->CreateEvent();
529          event.Type       = Event::type_control_change;          event.Type                = Event::type_control_change;
530          event.Controller = Controller;          event.Param.CC.Controller = Controller;
531          event.Value      = Value;          event.Param.CC.Value      = Value;
532          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);          if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
533          else dmsg(1,("Engine: Input event queue full!"));          else dmsg(1,("Engine: Input event queue full!"));
534      }      }
535    
536      /**      /**
537         *  Will be called by the MIDI input device whenever a MIDI system
538         *  exclusive message has arrived.
539         *
540         *  @param pData - pointer to sysex data
541         *  @param Size  - lenght of sysex data (in bytes)
542         */
543        void Engine::SendSysex(void* pData, uint Size) {
544            Event event             = pEventGenerator->CreateEvent();
545            event.Type              = Event::type_sysex;
546            event.Param.Sysex.Size  = Size;
547            if (pEventQueue->write_space() > 0) {
548                if (pSysexBuffer->write_space() >= Size) {
549                    // copy sysex data to input buffer
550                    uint toWrite = Size;
551                    uint8_t* pPos = (uint8_t*) pData;
552                    while (toWrite) {
553                        const uint writeNow = RTMath::Min(toWrite, pSysexBuffer->write_space_to_end());
554                        pSysexBuffer->write(pPos, writeNow);
555                        toWrite -= writeNow;
556                        pPos    += writeNow;
557    
558                    }
559                    // finally place sysex event into input event queue
560                    pEventQueue->push(&event);
561                }
562                else dmsg(1,("Engine: Sysex message too large (%d byte) for input buffer (%d byte)!",Size,SYSEX_BUFFER_SIZE));
563            }
564            else dmsg(1,("Engine: Input event queue full!"));
565        }
566    
567        /**
568       *  Assigns and triggers a new voice for the respective MIDI key.       *  Assigns and triggers a new voice for the respective MIDI key.
569       *       *
570       *  @param pNoteOnEvent - key, velocity and time stamp of the event       *  @param pNoteOnEvent - key, velocity and time stamp of the event
571       */       */
572      void Engine::ProcessNoteOn(Event* pNoteOnEvent) {      void Engine::ProcessNoteOn(Event* pNoteOnEvent) {
573          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Param.Note.Key];
574    
575          pKey->KeyPressed = true; // the MIDI key was now pressed down          pKey->KeyPressed = true; // the MIDI key was now pressed down
576    
# Line 560  namespace LinuxSampler { namespace gig { Line 600  namespace LinuxSampler { namespace gig {
600       *  @param pNoteOffEvent - key, velocity and time stamp of the event       *  @param pNoteOffEvent - key, velocity and time stamp of the event
601       */       */
602      void Engine::ProcessNoteOff(Event* pNoteOffEvent) {      void Engine::ProcessNoteOff(Event* pNoteOffEvent) {
603          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Key];          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Param.Note.Key];
604    
605          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
606    
# Line 586  namespace LinuxSampler { namespace gig { Line 626  namespace LinuxSampler { namespace gig {
626       *  @param pPitchbendEvent - absolute pitch value and time stamp of the event       *  @param pPitchbendEvent - absolute pitch value and time stamp of the event
627       */       */
628      void Engine::ProcessPitchbend(Event* pPitchbendEvent) {      void Engine::ProcessPitchbend(Event* pPitchbendEvent) {
629          this->Pitch = pPitchbendEvent->Pitch; // store current pitch value          this->Pitch = pPitchbendEvent->Param.Pitch.Pitch; // store current pitch value
630          pEvents->move(pPitchbendEvent, pSynthesisEvents[Event::destination_vco]);          pEvents->move(pPitchbendEvent, pSynthesisEvents[Event::destination_vco]);
631      }      }
632    
# Line 602  namespace LinuxSampler { namespace gig { Line 642  namespace LinuxSampler { namespace gig {
642       *                               (optional, default = false)       *                               (optional, default = false)
643       */       */
644      void Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) {      void Engine::LaunchVoice(Event* pNoteOnEvent, int iLayer, bool ReleaseTriggerVoice) {
645          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];          midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Param.Note.Key];
646    
647          // allocate a new voice for the key          // allocate a new voice for the key
648          Voice* pNewVoice = pKey->pActiveVoices->alloc();          Voice* pNewVoice = pKey->pActiveVoices->alloc();
# Line 631  namespace LinuxSampler { namespace gig { Line 671  namespace LinuxSampler { namespace gig {
671                  if (!pKey->Active) { // mark as active key                  if (!pKey->Active) { // mark as active key
672                      pKey->Active = true;                      pKey->Active = true;
673                      pKey->pSelf  = pActiveKeys->alloc();                      pKey->pSelf  = pActiveKeys->alloc();
674                      *pKey->pSelf = pNoteOnEvent->Key;                      *pKey->pSelf = pNoteOnEvent->Param.Note.Key;
675                  }                  }
676                  if (pNewVoice->KeyGroup) {                  if (pNewVoice->KeyGroup) {
677                      *ppKeyGroup = pKey->pSelf; // put key as the (new) active key to its key group                      *ppKeyGroup = pKey->pSelf; // put key as the (new) active key to its key group
# Line 681  namespace LinuxSampler { namespace gig { Line 721  namespace LinuxSampler { namespace gig {
721       *  @param pControlChangeEvent - controller, value and time stamp of the event       *  @param pControlChangeEvent - controller, value and time stamp of the event
722       */       */
723      void Engine::ProcessControlChange(Event* pControlChangeEvent) {      void Engine::ProcessControlChange(Event* pControlChangeEvent) {
724          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Controller, pControlChangeEvent->Value));          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Param.CC.Controller, pControlChangeEvent->Param.CC.Value));
725    
726          switch (pControlChangeEvent->Controller) {          switch (pControlChangeEvent->Param.CC.Controller) {
727              case 64: {              case 64: {
728                  if (pControlChangeEvent->Value >= 64 && !SustainPedal) {                  if (pControlChangeEvent->Param.CC.Value >= 64 && !SustainPedal) {
729                      dmsg(4,("PEDAL DOWN\n"));                      dmsg(4,("PEDAL DOWN\n"));
730                      SustainPedal = true;                      SustainPedal = true;
731    
# Line 705  namespace LinuxSampler { namespace gig { Line 745  namespace LinuxSampler { namespace gig {
745                          }                          }
746                      }                      }
747                  }                  }
748                  if (pControlChangeEvent->Value < 64 && SustainPedal) {                  if (pControlChangeEvent->Param.CC.Value < 64 && SustainPedal) {
749                      dmsg(4,("PEDAL UP\n"));                      dmsg(4,("PEDAL UP\n"));
750                      SustainPedal = false;                      SustainPedal = false;
751    
# Line 730  namespace LinuxSampler { namespace gig { Line 770  namespace LinuxSampler { namespace gig {
770          }          }
771    
772          // update controller value in the engine's controller table          // update controller value in the engine's controller table
773          ControllerTable[pControlChangeEvent->Controller] = pControlChangeEvent->Value;          ControllerTable[pControlChangeEvent->Param.CC.Controller] = pControlChangeEvent->Param.CC.Value;
774    
775          // move event from the unsorted event list to the control change event list          // move event from the unsorted event list to the control change event list
776          pEvents->move(pControlChangeEvent, pCCEvents);          pEvents->move(pControlChangeEvent, pCCEvents);
777      }      }
778    
779      /**      /**
780         *  Reacts on MIDI system exclusive messages.
781         *
782         *  @param pSysexEvent - sysex data size and time stamp of the sysex event
783         */
784        void Engine::ProcessSysex(Event* pSysexEvent) {
785            RingBuffer<uint8_t>::NonVolatileReader reader = pSysexBuffer->get_non_volatile_reader();
786    
787            uint8_t exclusive_status, id;
788            if (!reader.pop(&exclusive_status)) goto free_sysex_data;
789            if (!reader.pop(&id))               goto free_sysex_data;
790            if (exclusive_status != 0xF0)       goto free_sysex_data;
791    
792            switch (id) {
793                case 0x41: { // Roland
794                    uint8_t device_id, model_id, cmd_id;
795                    if (!reader.pop(&device_id)) goto free_sysex_data;
796                    if (!reader.pop(&model_id))  goto free_sysex_data;
797                    if (!reader.pop(&cmd_id))    goto free_sysex_data;
798                    if (model_id != 0x42 /*GS*/) goto free_sysex_data;
799                    if (cmd_id != 0x12 /*DT1*/)  goto free_sysex_data;
800    
801                    // command address
802                    uint8_t addr[3]; // 2 byte addr MSB, followed by 1 byte addr LSB)
803                    const RingBuffer<uint8_t>::NonVolatileReader checksum_reader = reader; // so we can calculate the check sum later
804                    if (reader.read(&addr[0], 3) != 3) goto free_sysex_data;
805                    if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters
806                    }
807                    else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters
808                    }
809                    else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x10) { // Part Parameters (1)
810                        switch (addr[3]) {
811                            case 0x40: { // scale tuning
812                                uint8_t scale_tunes[12]; // detuning of all 12 semitones of an octave
813                                if (reader.read(&scale_tunes[0], 12) != 12) goto free_sysex_data;
814                                uint8_t checksum;
815                                if (!reader.pop(&checksum))                      goto free_sysex_data;
816                                if (GSCheckSum(checksum_reader, 12) != checksum) goto free_sysex_data;
817                                for (int i = 0; i < 12; i++) scale_tunes[i] -= 64;
818                                AdjustScale((int8_t*) scale_tunes);
819                                break;
820                            }
821                        }
822                    }
823                    else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
824                    }
825                    else if (addr[0] == 0x41) { // Drum Setup Parameters
826                    }
827                    break;
828                }
829            }
830    
831            free_sysex_data: // finally free sysex data
832            pSysexBuffer->increment_read_ptr(pSysexEvent->Param.Sysex.Size);
833        }
834    
835        /**
836         * Calculates the Roland GS sysex check sum.
837         *
838         * @param AddrReader - reader which currently points to the first GS
839         *                     command address byte of the GS sysex message in
840         *                     question
841         * @param DataSize   - size of the GS message data (in bytes)
842         */
843        uint8_t Engine::GSCheckSum(const RingBuffer<uint8_t>::NonVolatileReader AddrReader, uint DataSize) {
844            RingBuffer<uint8_t>::NonVolatileReader reader = AddrReader;
845            uint bytes = 3 /*addr*/ + DataSize;
846            uint8_t addr_and_data[bytes];
847            reader.read(&addr_and_data[0], bytes);
848            uint8_t sum = 0;
849            for (uint i = 0; i < bytes; i++) sum += addr_and_data[i];
850            return 128 - sum % 128;
851        }
852    
853        /**
854         * Allows to tune each of the twelve semitones of an octave.
855         *
856         * @param ScaleTunes - detuning of all twelve semitones (in cents)
857         */
858        void Engine::AdjustScale(int8_t ScaleTunes[12]) {
859            memcpy(&this->ScaleTuning[0], &ScaleTunes[0], 12); //TODO: currently not sample accurate
860        }
861    
862        /**
863       * Initialize the parameter sequence for the modulation destination given by       * Initialize the parameter sequence for the modulation destination given by
864       * by 'dst' with the constant value given by val.       * by 'dst' with the constant value given by val.
865       */       */
# Line 840  namespace LinuxSampler { namespace gig { Line 963  namespace LinuxSampler { namespace gig {
963      }      }
964    
965      String Engine::Version() {      String Engine::Version() {
966          String s = "$Revision: 1.11 $";          String s = "$Revision: 1.13 $";
967          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
968      }      }
969    

Legend:
Removed from v.242  
changed lines
  Added in v.246

  ViewVC Help
Powered by ViewVC