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

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

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

revision 292 by schoenebeck, Mon Oct 25 14:59:18 2004 UTC revision 3293 by schoenebeck, Tue Jun 27 22:19:19 2017 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6     *   Copyright (C) 2005 - 2017 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 33  namespace LinuxSampler { Line 34  namespace LinuxSampler {
34      EventGenerator::EventGenerator(uint SampleRate) {      EventGenerator::EventGenerator(uint SampleRate) {
35          uiSampleRate       = SampleRate;          uiSampleRate       = SampleRate;
36          uiSamplesProcessed = 0;          uiSamplesProcessed = 0;
37          FragmentTime.end   = CreateTimeStamp();          FragmentTime.end   = RTMath::CreateTimeStamp();
38            uiTotalSamplesProcessed = 0;
39        }
40    
41        void EventGenerator::SetSampleRate(uint SampleRate) {
42            uiSampleRate = SampleRate;
43      }      }
44    
45      /**      /**
# Line 45  namespace LinuxSampler { Line 51  namespace LinuxSampler {
51       *                           audio fragment cycle       *                           audio fragment cycle
52       */       */
53      void EventGenerator::UpdateFragmentTime(uint SamplesToProcess) {      void EventGenerator::UpdateFragmentTime(uint SamplesToProcess) {
54            // update total amount of sample points being processed since this object was created
55            uiTotalSamplesProcessed += uiSamplesProcessed;
56          // update time stamp for this audio fragment cycle          // update time stamp for this audio fragment cycle
57          FragmentTime.begin = FragmentTime.end;          FragmentTime.begin = FragmentTime.end;
58          FragmentTime.end   = CreateTimeStamp();          FragmentTime.end   = RTMath::CreateTimeStamp();
59          // recalculate sample ratio for this audio fragment          // recalculate sample ratio for this audio fragment
60          time_stamp_t fragmentDuration = FragmentTime.end - FragmentTime.begin;          time_stamp_t fragmentDuration = FragmentTime.end - FragmentTime.begin;
61          FragmentTime.sample_ratio = (float) uiSamplesProcessed / (float) fragmentDuration;          FragmentTime.sample_ratio = (float) uiSamplesProcessed / (float) fragmentDuration;
62          // store amount of samples to process for the next cycle          // store amount of samples to process for the next cycle
63          uiSamplesProcessed = SamplesToProcess;          uiSamplesProcessed = SamplesToProcess;
64      }      }
65        
66        /**
67         * Get the next scheduled MIDI event (the one with the lowest time value)
68         * for the current audio fragment cycle and remove it from the queue. This
69         * method will not return any event scheduled past the current audio
70         * fragment boundary.
71         *
72         * @param queue - where the MIDI events are scheduled on
73         * @param pool - used to allocate and deallocate ScheduledEvent objects
74         * @param end - you @b MUST always pass EventGenerator::schedTimeAtCurrentFragmentEnd()
75         *              here reflecting the current audio fragment's scheduler end time
76         */
77        RTList<ScheduledEvent>::Iterator EventGenerator::popNextScheduledEvent(RTAVLTree<ScheduledEvent>& queue, Pool<ScheduledEvent>& pool, sched_time_t end) {
78            if (queue.isEmpty())
79                return RTList<ScheduledEvent>::Iterator(); // return invalid iterator
80            ScheduledEvent& e = queue.lowest();
81            if (e.scheduleTime >= end)
82                return RTList<ScheduledEvent>::Iterator(); // no event scheduled before 'end'
83            RTList<ScheduledEvent>::Iterator itEvent = pool.fromPtr(&e);
84            queue.erase(e);
85            if (!itEvent || !itEvent->itEvent) {
86                dmsg(1,("EventGenerator::popNextScheduledEvent(): !itEvent\n"));
87                return itEvent; // should never happen at this point, but just to be sure
88            }
89            if (!itEvent->itEvent) {
90                dmsg(1,("EventGenerator::popNextScheduledEvent(): !itEvent->itEvent\n"));
91                return itEvent; // should never happen at this point, but just to be sure
92            }
93    
94            // update position of this event in the current audio fragment
95            // (since calling scheduleAheadMicroSec() will relate to this)
96            itEvent->itEvent->iFragmentPos = int32_t( uiSamplesProcessed - (end - itEvent->scheduleTime) );
97            // safety first: fragment boundary sanity checks
98            if (itEvent->itEvent->iFragmentPos < 0)
99                itEvent->itEvent->iFragmentPos = 0;
100            if (itEvent->itEvent->iFragmentPos >= uiSamplesProcessed)
101                itEvent->itEvent->iFragmentPos = uiSamplesProcessed - 1;
102    
103            return itEvent;
104        }
105    
106        /**
107         * Get the next instrument script event (the one with the lowest time value)
108         * for the current audio fragment cycle and remove it from the queue. This
109         * method will not return any event scheduled past the current audio
110         * fragment boundary.
111         *
112         * @param queue - where the instrument script events are scheduled on
113         * @param pool - used to allocate and deallocate ScriptEvent objects
114         * @param end - you @b MUST always pass EventGenerator::schedTimeAtCurrentFragmentEnd()
115         *              here reflecting the current audio fragment's scheduler end time
116         */
117        RTList<ScriptEvent>::Iterator EventGenerator::popNextScheduledScriptEvent(RTAVLTree<ScriptEvent>& queue, Pool<ScriptEvent>& pool, sched_time_t end) {
118            if (queue.isEmpty())
119                return RTList<ScriptEvent>::Iterator(); // return invalid iterator
120            ScriptEvent& e = queue.lowest();
121            if (e.scheduleTime >= end)
122                return RTList<ScriptEvent>::Iterator(); // no event scheduled before 'end'
123            RTList<ScriptEvent>::Iterator itEvent = pool.fromPtr(&e);
124            queue.erase(e);
125            if (!itEvent) { // should never happen at this point, but just to be sure
126                dmsg(1,("EventGenerator::popNextScheduledScriptEvent(): !itEvent\n"));
127                return itEvent;
128            }
129    
130            // update position of this event in the current audio fragment
131            // (since calling scheduleAheadMicroSec() will relate to this)
132            itEvent->cause.iFragmentPos = int32_t( uiSamplesProcessed - (end - itEvent->scheduleTime) );
133            // safety first: fragment boundary sanity checks
134            if (itEvent->cause.iFragmentPos < 0)
135                itEvent->cause.iFragmentPos = 0;
136            if (itEvent->cause.iFragmentPos >= uiSamplesProcessed)
137                itEvent->cause.iFragmentPos = uiSamplesProcessed - 1;
138    
139            return itEvent;
140        }
141    
142      /**      /**
143       * Create a new event with the current time as time stamp.       * Create a new event with the current time as time stamp.
144       */       */
145      Event EventGenerator::CreateEvent() {      Event EventGenerator::CreateEvent() {
146          return Event(this, CreateTimeStamp());          return Event(this, RTMath::CreateTimeStamp());
147      }      }
148    
149      /**      /**
150       * Creates a real time stamp for the current moment. Out of efficiency this       * Create a new event for the given sample point position in the current
151       * is implemented in inline assembly for each CPU independently; we currently       * audio fragment.
152       * don't use a generic solution for CPUs that are not yet covered by the       *
153       * assembly code, instead an error message is prompted on compile time, forcing       * @param FragmentPos - actual sample point position in the current
154       * the user to contact us.       *                      audio fragment to which the new event belongs to
155       */       */
156      EventGenerator::time_stamp_t EventGenerator::CreateTimeStamp() {      Event EventGenerator::CreateEvent(int32_t FragmentPos) {
157          #if defined(__i386__) || defined(__x86_64__)          return Event(this, FragmentPos);
             uint64_t t;  
             __asm__ __volatile__ ("rdtsc" : "=A" (t));  
             return t >> 8;  
         #elif defined(__ia64__)  
             time_stamp_t t;  
             __asm__ __volatile__ ("mov %0=ar.itc" : "=r"(t));  
             return t;  
         #elif defined(__powerpc__)  
             time_stamp_t t;  
             __asm__ __volatile__ (  
                 "98:    mftb %0\n"  
                 "99:\n"  
                 ".section __ftr_fixup,\"a\"\n"  
                 "       .long %1\n"  
                 "       .long 0\n"  
                 "       .long 98b\n"  
                 "       .long 99b\n"  
                 ".previous"  
                 : "=r" (t) : "i" (0x00000100)  
             );  
             return t;  
         #elif defined(__alpha__)  
             time_stamp_t t;  
             __asm__ __volatile__ ("rpcc %0" : "=r"(t));  
             return t;  
         #else // we don't want to use a slow generic solution  
         #  error "Sorry, LinuxSampler lacks time stamp code for your system."  
         #  error "Please report this error and the CPU you are using to the LinuxSampler developers mailing list!"  
         #endif  
158      }      }
159    
160      /**      /**
161       * Will be called by an EventGenerator to create a new Event.       * Will be called by an EventGenerator to create a new Event.
162         * This Constructor expects a time stamp. The actual sample point
163         * position to which this event belongs to will be calculated later
164         * when FragmentPos() was called the first time.
165         *
166         * @param pGenerator - creator of this event
167         * @param Time       - time stamp on which this event occured
168       */       */
169      Event::Event(EventGenerator* pGenerator, time_stamp_t Time) {      Event::Event(EventGenerator* pGenerator, time_stamp_t Time) {
170            Init();
171          pEventGenerator = pGenerator;          pEventGenerator = pGenerator;
172          TimeStamp       = Time;          TimeStamp       = Time;
173          iFragmentPos    = -1;          iFragmentPos    = -1;
174      }      }
175    
176        /**
177         * Will be called by an EventGenerator to create a new Event.
178         * This constructor expects the final sample point position to which
179         * this event belongs to.
180         *
181         * @param pGenerator  - creator of this event
182         * @param FragmentPos - actual sample point position in the current
183         *                      audio fragment to which this event belongs to
184         */
185        Event::Event(EventGenerator* pGenerator, int32_t FragmentPos) {
186            Init();
187            pEventGenerator = pGenerator;
188            iFragmentPos    = FragmentPos;
189        }
190    
191        /**
192         * Implements fork() behavior, that is it copies the current state of this
193         * script event handler to the new event handler @a e with entire execution
194         * state and polyphonic data.
195         *
196         * After calling this method, addChildHandler() should be called as well.
197         */
198        void ScriptEvent::forkTo(ScriptEvent* e, bool bAutoAbort) const {
199            e->scheduleTime = scheduleTime;
200            e->cause = cause;
201            e->id = id;
202            // forked script shall only run the current event handler of parent,
203            // no other potentially chained handlers
204            e->handlers[0] = handlers[currentHandler];
205            e->handlers[1] = NULL; // NULL termination of list
206            e->currentHandler = 0;
207            e->executionSlices = 0;
208            e->ignoreAllWaitCalls = ignoreAllWaitCalls;
209            e->handlerType = handlerType;
210            e->parentHandlerID = 0; // just an arbitrary init value, must still be set later!
211            e->childHandlerID[0] = 0;
212            e->autoAbortByParent = bAutoAbort;
213            e->forkIndex = 1; // just an arbitrary init value, must still be set later!
214    
215            execCtx->forkTo(e->execCtx);
216        }
217    
218        /**
219         * Returns amount of child event handlers that have been created so far
220         * during the entire life time of this event handler instance by calls of
221         * this event handler instace to the built-in script function fork().
222         *
223         * To make this clear: this number does never decrease during the entire
224         * life time of an event handler instance! It may only increase, i.e. by
225         * additional calls to fork(). Consequently even if child event handler
226         * instances already terminated, this will not decrease this count.
227         */
228        int ScriptEvent::countChildHandlers() const {
229            int n = 0;
230            for (int i = 0; i < MAX_FORK_PER_SCRIPT_HANDLER && childHandlerID[i]; ++i)
231                ++n;
232            return n;
233        }
234    
235        /**
236         * This must be called after calling forkTo() to stick the script callback
237         * ID of the newly forked child execution instance to the parent execution
238         * instance.
239         *
240         * @param childID - script callback ID of the newly forked child handler
241         */
242        void ScriptEvent::addChildHandlerID(script_callback_id_t childID) {
243            const int n = countChildHandlers();
244            if (n >= MAX_FORK_PER_SCRIPT_HANDLER) {
245                dmsg(1,("ScriptEvent::addChildHandlerID(): MAX_FORK_PER_SCRIPT_HANDLER exceeded, this is a bug!\n"));
246                return;
247            }
248            childHandlerID[n]   = childID;
249            childHandlerID[n+1] = 0; // zero termination of list
250        }
251    
252  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.292  
changed lines
  Added in v.3293

  ViewVC Help
Powered by ViewVC