/// <summary> /// Blocks until an item is schedule to be returned at the /// current time. Returns false if the queue is empty only. /// </summary> public bool Dequeue(out T item) { Node node = null; do { // save our old node if we're switching if (node != null) { Enqueue(node); } // grab the node we'll be returning, failing if we can't get one if (Dequeue(out node) == false) { item = default(T); return(false); } } // repeat if we are interupted to switch nodes while (_sync.WaitUntil(node.executeAt) == false); #if DEBUG_LAG // print out the difference in time between the desired // run time and the actual run time (note enabling this // printing will pretty much ruin the actual accurace) LPConsole.WriteLine("RealTimeQueue", "Execution Lag={0}msec ({1} ticks)", (DateTime.UtcNow - node.executeAt).TotalMilliseconds, DateTime.UtcNow.Ticks - node.executeAt.Ticks ); #endif // we have a node and it's time to execute it item = node.item; return(true); }
/// <summary> /// Overwrites the current session settings from a parsed /// JSON object. /// </summary> private static void Deserialize(UserSession session, SessionFileFormat file) { // devices must loaded first for implant loaded to work session.Devices.ClearAll(); foreach (var item in file.devices) { try { session.Devices.MapByName(item.deviceName, item.mappedAs); var mapping = session.Devices.GetMappedDeviceByName(item.deviceName); mapping.Enabled = item.enabled; } catch (Exception ex) { LPConsole.WriteLine("SessionFile", ex.Message); } } session.Devices.AutoMap(); // load the implants session.Implants.ClearAll(); foreach (var item in file.implants) { RangeMap range; if (item.activeArea == null) { range = new RangeMap(MIDI.MappedMidiDevice.CreateNullDevice()); } else { range = item.activeArea.ToRangeMap(); } if (item.status != "not loaded") { var implant = session.Implants.Load(item.vpath, range, item.oscFormat); // important to load session values first so the init doesn't screw it up if (item.doubleValues != null) { implant.ImplantInstance.session.DoubleValues.Clear(); foreach (var key in item.doubleValues.Keys) { implant.ImplantInstance.session.DoubleValues.Add(key, item.doubleValues[key]); } } if (item.stringValues != null) { implant.ImplantInstance.session.StringValues.Clear(); foreach (var key in item.stringValues.Keys) { implant.ImplantInstance.session.StringValues.Add(key, item.stringValues[key]); } } implant.AssignedMode = item.assignedMode; if (item.status == "running") { implant.ServerInit(); } } } session.MidiMap.Mappings.Clear(); foreach (var item in file.midiMap) { var m = new OscToMidiMap(); m.ID = item.id; m.OscSource = item.oscSource; m.OscAddress = item.oscAddress; m.OscValueFrom = item.oscValueFrom; m.OscValueTo = item.oscValueTo; m.MidiDestination = item.midiDestination; m.MidiType = item.midiType.GetMidiMessageType(); //OscToMidiMap.FromString(item.midiType); m.MidiNote = item.midiNote; m.MidiValueFrom = item.midiValueFrom; m.MidiValueTo = item.midiValueTo; session.MidiMap.Mappings.Add(m); } }
/// <summary> /// Synchronizes the timer at 1/96th measures and sends an /// event. /// </summary> public override void RunTask() { _lastStep = DateTime.UtcNow; // update the click value Parent.BeatSync.Mark(); var tick = Parent.BeatSync.Tick; if (_lastValue != tick) { // send event if we have a new tick new Clock96ImplantEvent() { Value = tick, X = (int)Parent.BeatSync.Measure96AsDouble }.ScheduleTask(); _lastValue = tick; // check for MIDI sync output devices if ((_lastStep - _lastSendCheck).TotalSeconds > 5) { // TODO: would be nice to have an event to tell us when to pull this list again immediately _lastSendCheck = DateTime.UtcNow; _clocks.Clear(); foreach (var send in Parent.Parent.Devices[typeof(MidiClockOutputHardwareInterface)]) { if (send.Hardware is MidiClockOutputHardwareInterface) { _clocks.Add(send.Hardware as MidiClockOutputHardwareInterface); //_clockTasks.Add(new RealTimeTickTask() { Clock = send.Hardware as MidiClockOutputHardwareInterface }); } } //LPConsole.WriteLine("SyncManager", "Found {0} clocks", _clocks.Count); } //LPConsole.WriteLine("SyncManager", "Current: {0} Scheduled At: {1} Diff in Msec={2}", DateTime.UtcNow.Ticks, time.Ticks, (time - DateTime.UtcNow).TotalMilliseconds); } // queue up the next 96 ticks in the real time kernel at every measure. var measure = Parent.BeatSync.Measure; if (measure != _lastMeasure) { if (_lastMeasure != measure - 1) { LPConsole.WriteLine("SyncManager", "SKIPPED A MEASURE!!!! last={0} this={1}", _lastMeasure, measure); } _lastMeasure = measure; DateTime dt = Parent.BeatSync.NextMeasureTime; //LPConsole.WriteLine("SyncManager", "Scheduling next measure #{0} starting at {1} {2}msec in the future", measure, dt.ToShortTimeString(), (dt - DateTime.UtcNow).TotalMilliseconds); for (var i = 0; i < 96; i++) { foreach (var clock in _clocks) { Kernel.Current.Add( new RealTimeTickTask() { Clock = clock }, dt ); } dt = dt.AddSeconds(Parent.BeatSync.SecondsPer96); } } }