mirror of
https://github.com/jwetzell/QControlKit.git
synced 2026-07-26 10:38:54 +00:00
Basic workspace connection and Cue Lists fetching working
This commit is contained in:
+41
-4
@@ -1,23 +1,60 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QSharp", "QSharp\QSharp.csproj", "{51CD2579-79C9-49A9-B68D-93CBE878BAA1}"
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30128.74
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QSharp", "QSharp\QSharp.csproj", "{51CD2579-79C9-49A9-B68D-93CBE878BAA1}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QSharpDemo", "QSharpDemo\QSharpDemo.csproj", "{8518D042-D511-4DBB-8406-5B11B2777ED2}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QSharpDemo", "QSharpDemo\QSharpDemo.csproj", "{8518D042-D511-4DBB-8406-5B11B2777ED2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM = Debug|ARM
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM = Release|ARM
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{51CD2579-79C9-49A9-B68D-93CBE878BAA1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|x64.Build.0 = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{8518D042-D511-4DBB-8406-5B11B2777ED2}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {E5BF7535-FB56-4373-89F2-B0ABBD010092}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public class QServerFoundArgs : EventArgs
|
||||
{
|
||||
public QServer server { get; set; }
|
||||
}
|
||||
public class QWorkspacesUpdatedArgs : EventArgs
|
||||
{
|
||||
public List<QWorkspaceInfo> Workspaces { get; set; }
|
||||
}
|
||||
|
||||
public class QWorkspaceUpdatedArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class QWorkspaceSettingsUpdatedArgs : EventArgs
|
||||
{
|
||||
public string settingsType { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class QWorkspaceLightDashboardUpdatedArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class QWorkspaceConnectedArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class QWorkspaceDisconnectedArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class QWorkspaceConnectionErrorArgs : EventArgs
|
||||
{
|
||||
public string status { get; set; }
|
||||
}
|
||||
public class QQLabPreferencesUpdatedArgs : EventArgs
|
||||
{
|
||||
public string key { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class QCueUpdatedArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class QCueListsUpdatedArgs : EventArgs
|
||||
{
|
||||
public JToken data { get; set; }
|
||||
}
|
||||
|
||||
public class QCueNeedsUpdatedArgs : EventArgs
|
||||
{
|
||||
public string cueID { get; set; }
|
||||
}
|
||||
|
||||
public class QCueListChangedPlaybackPositionArgs : EventArgs
|
||||
{
|
||||
public string cueID { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public delegate void QServerFoundHandler(object source, QServerFoundArgs args);
|
||||
|
||||
public delegate void QWorkspacesUpdatedHandler(object source, QWorkspacesUpdatedArgs args);
|
||||
|
||||
public delegate void QWorkspaceUpdatedHandler(object source, QWorkspaceUpdatedArgs args);
|
||||
public delegate void QWorkspaceSettingsUpdatedHandler(object source, QWorkspaceSettingsUpdatedArgs args);
|
||||
public delegate void QWorkspaceLightDashboardUpdatedHandler(object source, QWorkspaceLightDashboardUpdatedArgs args);
|
||||
public delegate void QWorkspaceConnectedHandler(object source, QWorkspaceConnectedArgs args);
|
||||
public delegate void QWorkspaceDisconnectedHandler(object source, QWorkspaceDisconnectedArgs args);
|
||||
public delegate void QWorkspaceConnectionErrorHandler(object source, QWorkspaceConnectionErrorArgs args);
|
||||
public delegate void QQLabPreferencesUpdatedHandler(object source, QQLabPreferencesUpdatedArgs args);
|
||||
|
||||
|
||||
public delegate void QCueUpdatedHandler(object source, QCueUpdatedArgs args);
|
||||
public delegate void QCueListsUpdatesHandler(object source, QCueListsUpdatedArgs args);
|
||||
public delegate void QCueNeedsUpdatedHandler(object source, QCueNeedsUpdatedArgs args);
|
||||
public delegate void QCueListChangedPlaybackPositionHandler(object source, QCueListChangedPlaybackPositionArgs args);
|
||||
}
|
||||
+37
-17
@@ -6,49 +6,50 @@ namespace QSharp
|
||||
{
|
||||
public class QBrowser
|
||||
{
|
||||
const string UDPServiceType = "_qlab._udp.local.";
|
||||
const string TCPServiceType = "_qlab._tcp.local.";
|
||||
|
||||
const int udpPort = 53000;
|
||||
ZeroconfResolver.ResolverListener zeroconfTCPBrowser;
|
||||
|
||||
IObservable<IZeroconfHost> netServices;
|
||||
ZeroconfResolver.ResolverListener netServiceTCPBrowser;
|
||||
public ObservableCollection<QServer> servers = new ObservableCollection<QServer>();
|
||||
|
||||
public event QServerFoundHandler ServerFound;
|
||||
|
||||
ObservableCollection<QServer> servers = new ObservableCollection<QServer>();
|
||||
|
||||
public QBrowser()
|
||||
{
|
||||
|
||||
Console.WriteLine("QBrowser Init");
|
||||
netServiceTCPBrowser = ZeroconfResolver.CreateListener(TCPServiceType);
|
||||
netServiceTCPBrowser.ServiceFound += ServerFound;
|
||||
netServiceTCPBrowser.ServiceLost += ServerLost;
|
||||
zeroconfTCPBrowser = ZeroconfResolver.CreateListener(QBonjour.TCPService);
|
||||
zeroconfTCPBrowser.ServiceFound += ZeroconfHostFound;
|
||||
zeroconfTCPBrowser.ServiceLost += ZeroconfHostLost;
|
||||
}
|
||||
|
||||
private void ServerLost(object sender, IZeroconfHost e)
|
||||
private void ZeroconfHostLost(object sender, IZeroconfHost e)
|
||||
{
|
||||
Console.WriteLine($"Lost {e.DisplayName} : {e.IPAddress}");
|
||||
|
||||
}
|
||||
|
||||
private void ServerFound(object sender, IZeroconfHost e)
|
||||
private void ZeroconfHostFound(object sender, IZeroconfHost e)
|
||||
{
|
||||
|
||||
|
||||
foreach(var service in e.Services)
|
||||
{
|
||||
if (service.Key.Equals(TCPServiceType))
|
||||
if (service.Key.Equals(QBonjour.TCPService))
|
||||
{
|
||||
Console.WriteLine($"Found {e.DisplayName} : {e.IPAddress} : {service.Value.Port}");
|
||||
|
||||
QServer server = getServerFromAddress(e.IPAddress);
|
||||
QServer server = serverForAddress(e.IPAddress);
|
||||
|
||||
if(server == null)
|
||||
{
|
||||
Console.WriteLine("New Server Found so adding");
|
||||
QServer serverToAdd = new QServer(e.IPAddress, service.Value.Port, e.DisplayName);
|
||||
QServer serverToAdd = new QServer(e.IPAddress, service.Value.Port);
|
||||
serverToAdd.name = e.DisplayName;
|
||||
serverToAdd.zeroconfHost = e;
|
||||
servers.Add(serverToAdd);
|
||||
serverToAdd.refreshWorkspaces();
|
||||
OnServerFound(serverToAdd);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -60,9 +61,8 @@ namespace QSharp
|
||||
|
||||
}
|
||||
|
||||
public QServer getServerFromAddress(string address)
|
||||
public QServer serverForAddress(string address)
|
||||
{
|
||||
QServer foundServer = null;
|
||||
foreach(var server in servers)
|
||||
{
|
||||
if (server.host.Equals(address))
|
||||
@@ -71,7 +71,27 @@ namespace QSharp
|
||||
}
|
||||
}
|
||||
|
||||
return foundServer;
|
||||
return null;
|
||||
}
|
||||
|
||||
public QServer serverForIZeroconfHost(IZeroconfHost zeroconfHost)
|
||||
{
|
||||
foreach (var server in servers)
|
||||
{
|
||||
if (server.zeroconfHost == zeroconfHost)
|
||||
{
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual void OnServerFound(QServer server)
|
||||
{
|
||||
if (ServerFound != null)
|
||||
ServerFound(this, new QServerFoundArgs { server = server });
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
-31
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SharpOSC;
|
||||
|
||||
namespace QSharp
|
||||
@@ -9,62 +11,208 @@ namespace QSharp
|
||||
{
|
||||
TCPClient tcpClient;
|
||||
|
||||
public class WorkspacesUpdatedArgs : EventArgs
|
||||
{
|
||||
public List<QWorkspaceInfo> Workspaces { get; set; }
|
||||
}
|
||||
public event QWorkspacesUpdatedHandler WorkspacesUpdated;
|
||||
|
||||
public event QCueUpdatedHandler CueUpdated;
|
||||
public event QCueListsUpdatesHandler CueListsUpdated;
|
||||
public event QCueNeedsUpdatedHandler CueNeedsUpdated;
|
||||
|
||||
public event QCueListChangedPlaybackPositionHandler CueListChangedPlaybackPosition;
|
||||
|
||||
public delegate void WorkspacesUpdatedHandler(object source, WorkspacesUpdatedArgs args);
|
||||
public event WorkspacesUpdatedHandler WorkspacesUpdated;
|
||||
public event QWorkspaceUpdatedHandler WorkspaceUpdated;
|
||||
public event QWorkspaceSettingsUpdatedHandler WorkspaceSettingsUpdated;
|
||||
|
||||
public event QWorkspaceLightDashboardUpdatedHandler WorkspaceLightDashboardUpdated;
|
||||
public event QQLabPreferencesUpdatedHandler QLabPreferencesUpdated;
|
||||
|
||||
public event QWorkspaceDisconnectedHandler WorkspaceDisconnected;
|
||||
public event QWorkspaceConnectedHandler WorkspaceConnected;
|
||||
public event QWorkspaceConnectionErrorHandler WorkspaceConnectionError;
|
||||
|
||||
public QClient(string host, int port)
|
||||
{
|
||||
tcpClient = new TCPClient(host, port);
|
||||
tcpClient.Connect();
|
||||
Console.WriteLine($"QClient setup {host}:{port}");
|
||||
tcpClient.MessageReceived += ResponseReceived;
|
||||
Console.WriteLine($"[QClient] setup connection to: <{host}:{port}>");
|
||||
tcpClient.MessageReceived += ProcessMessage;
|
||||
}
|
||||
|
||||
private void ResponseReceived(object source, MessageEventArgs args)
|
||||
|
||||
public bool IsConnnected { get { return tcpClient.IsConnected; } }
|
||||
|
||||
public bool connect()
|
||||
{
|
||||
OscMessage msg = args.Message;
|
||||
foreach (var obj in msg.Arguments)
|
||||
{
|
||||
QResponse response = JsonConvert.DeserializeObject<QResponse>(obj.ToString());
|
||||
|
||||
switch (response.getReplyType())
|
||||
{
|
||||
case "WORKSPACES":
|
||||
Console.WriteLine("WORKSPACES RECEIVED");
|
||||
OnWorkspacesUpdated(response);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return tcpClient.Connect();
|
||||
}
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
tcpClient.Close();
|
||||
}
|
||||
|
||||
|
||||
public void sendMessage(string address, params object[] args)
|
||||
{
|
||||
tcpClient.Send(new OscMessage(address, args));
|
||||
Console.WriteLine($"QClient send message {address}");
|
||||
// Console.WriteLine($"QClient send message {address}");
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspacesUpdated(QResponse response)
|
||||
private void ProcessMessage(object source, MessageEventArgs args)
|
||||
{
|
||||
|
||||
QMessage message = new QMessage(args.Message);
|
||||
|
||||
if (message.IsReply)
|
||||
{
|
||||
JToken data = message.response;
|
||||
//special case, want to update cue properties
|
||||
if (message.IsReplyFromCue)
|
||||
{
|
||||
//todo check data type?
|
||||
}
|
||||
else if (message.IsReplyFromCueLists)
|
||||
{
|
||||
OnCueListsUpdated(message.response);
|
||||
}
|
||||
else if (message.IsWorkspacesInfo)
|
||||
{
|
||||
OnWorkspacesUpdated(message);
|
||||
}
|
||||
else if (message.IsConnect)
|
||||
{
|
||||
if (message.response.ToString() == "ok")
|
||||
OnWorkspaceConnected();
|
||||
else
|
||||
OnWorkspaceConnectionError(message.response.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[client] unhandled reply message: {message.address}");
|
||||
}
|
||||
}
|
||||
else if(message.IsUpdate) {
|
||||
if (message.IsCueUpdate)
|
||||
{
|
||||
OnCueNeedsUpdated(message.cueID);
|
||||
}
|
||||
else if (message.IsPlaybackPositionUpdate)
|
||||
{
|
||||
OnCueListChangedPlaybackPosition(message.cueID);
|
||||
}
|
||||
else if (message.IsWorkspaceUpdate)
|
||||
{
|
||||
OnWorkspaceUpdated();
|
||||
}
|
||||
else if (message.IsWorkspaceSettingsUpdate)
|
||||
{
|
||||
string settingsType = message.AddressParts.Last();
|
||||
if (settingsType == null)
|
||||
return;
|
||||
OnWorkspaceSettingsUpdated(settingsType);
|
||||
}
|
||||
else if (message.IsLightDashboardUpdate)
|
||||
{
|
||||
//need to do checks for 4.2 or newer
|
||||
OnWorkspaceLightDashboardUpdated();
|
||||
}
|
||||
else if ( message.IsPreferencesUpdate)
|
||||
{
|
||||
//need to do checks for 4.2 or newer
|
||||
|
||||
string key = message.AddressParts.Last();
|
||||
if (key == null)
|
||||
return;
|
||||
OnQLabPreferencesUpdated(key);
|
||||
}
|
||||
else if (message.IsDisconnect)
|
||||
{
|
||||
Console.WriteLine($"[client] disconnect message received: {message.address}");
|
||||
OnWorkspaceDisconnected();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[client] unhandled update message: {message.address}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[client] unhandled message: {message.address}");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnCueNeedsUpdated(string cueID)
|
||||
{
|
||||
if (CueNeedsUpdated != null)
|
||||
CueNeedsUpdated(this, new QCueNeedsUpdatedArgs { cueID = cueID });
|
||||
}
|
||||
|
||||
protected virtual void OnCueListsUpdated(JToken response)
|
||||
{
|
||||
if (CueListsUpdated != null)
|
||||
CueListsUpdated(this, new QCueListsUpdatedArgs { data = response });
|
||||
}
|
||||
|
||||
protected virtual void OnCueListChangedPlaybackPosition(string cueID)
|
||||
{
|
||||
if (CueListChangedPlaybackPosition != null)
|
||||
CueListChangedPlaybackPosition(this, new QCueListChangedPlaybackPositionArgs { cueID = cueID });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceUpdated()
|
||||
{
|
||||
if (WorkspaceUpdated != null)
|
||||
WorkspaceUpdated(this, new QWorkspaceUpdatedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceSettingsUpdated(string settingsType)
|
||||
{
|
||||
if (WorkspaceSettingsUpdated != null)
|
||||
WorkspaceSettingsUpdated(this, new QWorkspaceSettingsUpdatedArgs { settingsType = settingsType});
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceLightDashboardUpdated()
|
||||
{
|
||||
if (WorkspaceLightDashboardUpdated != null)
|
||||
WorkspaceLightDashboardUpdated(this, new QWorkspaceLightDashboardUpdatedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnQLabPreferencesUpdated(string key)
|
||||
{
|
||||
if (QLabPreferencesUpdated != null)
|
||||
QLabPreferencesUpdated(this, new QQLabPreferencesUpdatedArgs { key = key });
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceDisconnected()
|
||||
{
|
||||
if (WorkspaceDisconnected != null)
|
||||
WorkspaceDisconnected(this, new QWorkspaceDisconnectedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceConnected()
|
||||
{
|
||||
if (WorkspaceConnected != null)
|
||||
WorkspaceConnected(this, new QWorkspaceConnectedArgs());
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspaceConnectionError(string status)
|
||||
{
|
||||
if (WorkspaceConnectionError != null)
|
||||
WorkspaceConnectionError(this, new QWorkspaceConnectionErrorArgs { status = status});
|
||||
}
|
||||
|
||||
protected virtual void OnWorkspacesUpdated(QMessage message)
|
||||
{
|
||||
if(WorkspacesUpdated != null)
|
||||
{
|
||||
List<QWorkspaceInfo> workspaces = new List<QWorkspaceInfo>();
|
||||
foreach (var item in response.data)
|
||||
foreach (var item in message.response)
|
||||
{
|
||||
QWorkspaceInfo workspacefound = JsonConvert.DeserializeObject<QWorkspaceInfo>(item.ToString());
|
||||
workspaces.Add(workspacefound);
|
||||
Console.WriteLine(workspacefound.displayName);
|
||||
}
|
||||
WorkspacesUpdated(this, new WorkspacesUpdatedArgs { Workspaces = workspaces });
|
||||
WorkspacesUpdated(this, new QWorkspacesUpdatedArgs { Workspaces = workspaces });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+668
-5
@@ -1,19 +1,682 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public class QCue
|
||||
{
|
||||
Dictionary<string,object> cueData = new Dictionary<string,object>();
|
||||
|
||||
public QWorkspace workspace;
|
||||
public Dictionary<string, object> cueData;
|
||||
public List<QCue> childCues;
|
||||
public Dictionary<string, QCue> childCuesUIDMap;
|
||||
|
||||
public int sortIndex;
|
||||
|
||||
private bool needsSortChildCues;//?
|
||||
private bool needsNotifyCueUpdated;//?
|
||||
|
||||
public bool ignoreUpdates;
|
||||
|
||||
|
||||
public QCue()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
public object propertyForKey(string key)
|
||||
public QCue(QWorkspace workspace)
|
||||
{
|
||||
if (cueData.ContainsKey(key))
|
||||
return cueData[key];
|
||||
init();
|
||||
this.workspace = workspace;
|
||||
}
|
||||
|
||||
public QCue(JToken dict, QWorkspace workspace)
|
||||
{
|
||||
init();
|
||||
this.workspace = workspace;
|
||||
|
||||
JToken children = dict[QOSCKey.Cues];
|
||||
if(children != null && children.Type == JTokenType.Array)
|
||||
{
|
||||
//Console.WriteLine($"[cue] new cue being created with {children.Count()} childCues");
|
||||
foreach (var aChildDict in children)
|
||||
{
|
||||
string uid = (string)aChildDict[QOSCKey.UID];
|
||||
//Console.WriteLine($"[cue] childDict with uid: {uid} being processed");
|
||||
if (uid == null)
|
||||
continue;
|
||||
|
||||
QCue child = new QCue(aChildDict, workspace);
|
||||
|
||||
childCues.Add(child);
|
||||
childCuesUIDMap.Add(uid, child);
|
||||
}
|
||||
}
|
||||
|
||||
updatePropertiesWithDictionary(dict);
|
||||
}
|
||||
|
||||
public void init()
|
||||
{
|
||||
cueData = new Dictionary<string, object> {
|
||||
{ QOSCKey.Flagged, false },
|
||||
{ QOSCKey.Armed, false },
|
||||
{ QOSCKey.PreWait, false },
|
||||
{ QOSCKey.PercentPreWaitElapsed, false },
|
||||
{ QOSCKey.PercentActionElapsed, false },
|
||||
{ QOSCKey.PostWait, false },
|
||||
{ QOSCKey.PercentPostWaitElapsed, false },
|
||||
{ QOSCKey.IsPanicking, false },
|
||||
{ QOSCKey.IsTailingOut, false },
|
||||
{ QOSCKey.IsRunning, false },
|
||||
{ QOSCKey.IsLoaded, false },
|
||||
{ QOSCKey.IsPaused, false },
|
||||
{ QOSCKey.IsBroken, false },
|
||||
{ QOSCKey.IsOverridden, false },
|
||||
{ QOSCKey.ContinueMode, false }
|
||||
};
|
||||
//TODO init cueData with some keys
|
||||
|
||||
childCues = new List<QCue>();
|
||||
childCuesUIDMap = new Dictionary<string, QCue>();
|
||||
}
|
||||
|
||||
public string description
|
||||
{
|
||||
get
|
||||
{
|
||||
return $"(Cue: {this}) name: {name} [id:{uid} number:{number} type: {type}";
|
||||
}
|
||||
}
|
||||
|
||||
//isEqual?
|
||||
//hash?
|
||||
//compare?
|
||||
public bool isEqualToCue(QCue cue) { throw new NotImplementedException(); }
|
||||
public void setWorkspace(QWorkspace workspace)
|
||||
{
|
||||
if(this.workspace != workspace)
|
||||
{
|
||||
this.workspace = workspace;
|
||||
}
|
||||
}
|
||||
public void addChildCue(QCue cue)
|
||||
{
|
||||
string uid = propertyForKey(QOSCKey.UID).ToString();
|
||||
addChildCue(cue, uid);
|
||||
}
|
||||
public void addChildCue(QCue cue, string uid)
|
||||
{
|
||||
if (uid.Length == 0)
|
||||
return;
|
||||
childCues.Add(cue);
|
||||
childCuesUIDMap.Add(uid, cue);
|
||||
//some sorting of the childCues needs to be done?
|
||||
//reset sorting index
|
||||
}
|
||||
public void removeChildCue(QCue cue) { throw new NotImplementedException(); }
|
||||
public void removeAllChildCues() { throw new NotImplementedException(); }
|
||||
public void removeChildCuesWithIDs(List<string> uids) { throw new NotImplementedException(); }
|
||||
|
||||
//copied: yes
|
||||
//implemented: no
|
||||
#region Class Methods
|
||||
public string iconForType(string type) { throw new NotImplementedException(); }
|
||||
public bool cueTypeIsAudio(string type) { throw new NotImplementedException(); }
|
||||
public bool cueTypeIsVideo(string type) { throw new NotImplementedException(); }
|
||||
public bool cueTypeIsGroup(string type) { throw new NotImplementedException(); }
|
||||
public bool cueTypeIsCueList(string type) { throw new NotImplementedException(); }
|
||||
public List<string> fadeModeTitles() { throw new NotImplementedException(); }
|
||||
#endregion
|
||||
|
||||
//KVC Compliance... do I need this?
|
||||
|
||||
//copied: yes
|
||||
//implemented: not all
|
||||
#region Convenience Accessors
|
||||
public List<QCue> cues
|
||||
{
|
||||
get
|
||||
{
|
||||
List<QCue> cues = (List<QCue>)propertyForKey(QOSCKey.Cues);
|
||||
if (cues == null)
|
||||
return new List<QCue>();
|
||||
return cues;
|
||||
}
|
||||
}
|
||||
public string parentID
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Parent).ToString();
|
||||
}
|
||||
}
|
||||
public string playbackPositionID() { throw new NotImplementedException(); }
|
||||
public string name
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Name).ToString();
|
||||
}
|
||||
}
|
||||
public string number
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Number).ToString();
|
||||
}
|
||||
}
|
||||
public string uid
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.UID).ToString();
|
||||
}
|
||||
}
|
||||
public string listName
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.ListName).ToString();
|
||||
}
|
||||
}
|
||||
public string type
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Type).ToString();
|
||||
}
|
||||
}
|
||||
public string notes
|
||||
{
|
||||
get
|
||||
{
|
||||
return propertyForKey(QOSCKey.Notes).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsFlagged
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey(QOSCKey.Flagged);
|
||||
}
|
||||
}
|
||||
public bool IsOverridden
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey("OSCNameKey");
|
||||
}
|
||||
}
|
||||
public bool IsBroken
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey("OSCNameKey");
|
||||
}
|
||||
}
|
||||
public bool IsRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey("OSCNameKey");
|
||||
}
|
||||
}
|
||||
public bool IsTailingOut
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey("OSCNameKey");
|
||||
}
|
||||
}
|
||||
public bool IsPanicking
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)propertyForKey("OSCNameKey");
|
||||
}
|
||||
}
|
||||
public bool IsGroup
|
||||
{
|
||||
get
|
||||
{
|
||||
if (type.Equals(QCueType.Group))
|
||||
return true;
|
||||
if (type.Equals(QCueType.CueList))
|
||||
return true;
|
||||
if (type.Equals(QCueType.Cart))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool IsCueList
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( type.Equals(QCueType.CueList))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public string displayName
|
||||
{
|
||||
get
|
||||
{
|
||||
string number = this.number;
|
||||
if (number.Length > 0)
|
||||
return $"{number} \u00b7 {nonEmptyName}";
|
||||
else
|
||||
return nonEmptyName;
|
||||
}
|
||||
}
|
||||
public string nonEmptyName
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO
|
||||
string nonEmptyName;
|
||||
if (name != null && !name.Equals(""))
|
||||
nonEmptyName = name;
|
||||
else if (listName != null && !listName.Equals(""))
|
||||
nonEmptyName = listName;
|
||||
else
|
||||
nonEmptyName = $"Untitled {type} Cue";
|
||||
|
||||
return nonEmptyName;
|
||||
}
|
||||
}
|
||||
public string workspaceName{ get { return workspace.name; } }
|
||||
public double currentDuration
|
||||
{
|
||||
|
||||
get
|
||||
{
|
||||
//try v4 current duration key first
|
||||
if (propertyForKey(QOSCKey.CurrentDuration) != null)
|
||||
return (double)propertyForKey(QOSCKey.CurrentDuration);
|
||||
else
|
||||
return (double)propertyForKey(QOSCKey.Duration);
|
||||
}
|
||||
}
|
||||
public string audioFadeModeName
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO
|
||||
if (type.Equals(QCueType.Fade))
|
||||
return "";
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public string geoFadeModeName
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO
|
||||
if (type.Equals(QCueType.Fade))
|
||||
return "";
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public string surfaceName{ get { return propertyForKey("surfaceName").ToString(); } }
|
||||
public string patchName
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO
|
||||
return (string)propertyForKey("patchDecription");
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: THIS IS WHERE THINGS START TO GET TRICKY!
|
||||
|
||||
//TODO add object color method
|
||||
public string color { get { return propertyForKey(QOSCKey.ColorName).ToString(); } }
|
||||
|
||||
//TODO add quaternion property and setter
|
||||
|
||||
public Size surfaceSize() { throw new NotImplementedException(); }
|
||||
public Size cueSize() { throw new NotImplementedException(); }
|
||||
public List<string> availableSurfaceName() { throw new NotImplementedException(); }
|
||||
public List<string> propertyKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO add null check?
|
||||
return cueData.Keys.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public bool hasChildren
|
||||
{
|
||||
get
|
||||
{
|
||||
return cues.Count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public QCue firstCue
|
||||
{
|
||||
get
|
||||
{
|
||||
return cues.First();
|
||||
}
|
||||
}
|
||||
|
||||
public QCue lastCue
|
||||
{
|
||||
get
|
||||
{
|
||||
return cues.Last();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setIgnoreUpdates(bool ignoreUpdates)
|
||||
{
|
||||
if(this.ignoreUpdates != ignoreUpdates)
|
||||
{
|
||||
this.ignoreUpdates = ignoreUpdates;
|
||||
|
||||
if (!this.ignoreUpdates)
|
||||
{
|
||||
//TODO: update local with QLab
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//Copied: Yes
|
||||
//Implemented: Not all
|
||||
#region Mutators
|
||||
public void setCues(List<QCue> cues)
|
||||
{
|
||||
|
||||
}
|
||||
public void setName() { }
|
||||
public void setNumber() { }
|
||||
public void setUid() { }
|
||||
public void setListName() { }
|
||||
public void setType() { }
|
||||
public void setFlagged() { }
|
||||
#endregion
|
||||
|
||||
//Copied: Yes
|
||||
//Implemented: Not all
|
||||
#region Update Methods
|
||||
public bool updatePropertiesWithDictionary(JToken dict)
|
||||
{
|
||||
return updatePropertiesWithDictionary(dict, true);
|
||||
}
|
||||
public bool updatePropertiesWithDictionary(JToken dict, bool notify)
|
||||
{
|
||||
bool cueUpdated = false;
|
||||
|
||||
//TODO
|
||||
JObject dictObj = (JObject)dict;
|
||||
foreach (var obj in dictObj)
|
||||
{
|
||||
//Console.WriteLine($"[cue] found property {obj.Key} ");
|
||||
JToken value = obj.Value;
|
||||
if (obj.Key.Equals(QOSCKey.Cues))
|
||||
{
|
||||
if (value.Type != JTokenType.Array)
|
||||
continue;
|
||||
updateChildCuesWithPropertiesArray(value, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool didSetProptery = setProperty(value, obj.Key, false);
|
||||
if (didSetProptery)
|
||||
cueUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cueUpdated)
|
||||
return false;
|
||||
if (notify)
|
||||
Console.WriteLine("should notify cue updated.");
|
||||
//something about notifying cueUpdated ? OnCueUpdated event handler maybe?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//enqueue updated notification?
|
||||
public void updateChildCuesWithPropertiesArray(JToken value, bool removeUnused)
|
||||
{
|
||||
if (!workspace.connected)
|
||||
return;
|
||||
|
||||
List<string> previousUids = null;
|
||||
if (removeUnused)
|
||||
previousUids = allChildCueUids();
|
||||
|
||||
int index = 0;
|
||||
|
||||
foreach (var dict in value)
|
||||
{
|
||||
string uid = (string)dict[QOSCKey.UID];
|
||||
if (uid == null)
|
||||
continue;
|
||||
|
||||
if (removeUnused)
|
||||
previousUids.Remove(uid);
|
||||
|
||||
QCue child = cueWithID(uid, false);
|
||||
|
||||
if (child != null)
|
||||
{
|
||||
bool didUpdateProperties = updatePropertiesWithDictionary(dict);
|
||||
if (didUpdateProperties)
|
||||
needsNotifyCueUpdated = true;
|
||||
|
||||
if (child.sortIndex != index)
|
||||
{
|
||||
child.sortIndex = index;
|
||||
|
||||
needsSortChildCues = true;
|
||||
needsNotifyCueUpdated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
child = new QCue(dict, workspace);
|
||||
child.sortIndex = index;
|
||||
addChildCue(child, uid);
|
||||
needsNotifyCueUpdated = true;
|
||||
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
|
||||
//TODO: TEST?!
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
//Methods Copied: Yes
|
||||
//Methods Implemented: Not all
|
||||
#region Children Cues
|
||||
public List<string> allChildCueUids()
|
||||
{
|
||||
//TODO
|
||||
return new List<string>();
|
||||
}
|
||||
public QCue cueAtIndex(int index)
|
||||
{
|
||||
//TODO
|
||||
return new QCue();
|
||||
}
|
||||
public QCue cueWithID(string uid)
|
||||
{
|
||||
return cueWithID(uid, true);
|
||||
}
|
||||
public QCue cueWithID(string uid, bool includeChildren)
|
||||
{
|
||||
//Console.WriteLine($"[cue] searching for cue with id: {uid} - includeChildren: {includeChildren}");
|
||||
if(childCuesUIDMap.ContainsKey(uid))
|
||||
return childCuesUIDMap[uid];
|
||||
|
||||
if (!includeChildren)
|
||||
return null;
|
||||
|
||||
foreach(var cue in cues)
|
||||
{
|
||||
if (!cue.IsGroup)
|
||||
continue;
|
||||
QCue childCue = cue.cueWithID(uid, includeChildren);
|
||||
if (childCue != null)
|
||||
return childCue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public QCue cueWithNumber(string number)
|
||||
{
|
||||
//TODO
|
||||
return new QCue();
|
||||
}
|
||||
public object propertyForKey(string key)
|
||||
{
|
||||
//TODO: implerment special key checks color, surfaceName, patchDescription,
|
||||
if (key.Equals(QOSCKey.Cues))
|
||||
{
|
||||
return childCues;
|
||||
}
|
||||
if (cueData.ContainsKey(key))
|
||||
{
|
||||
return cueData[key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool setProperty(object value, string key)
|
||||
{
|
||||
return setProperty( value, key, workspace.defaultSendUpdatesOSC);
|
||||
}
|
||||
|
||||
public bool setProperty(object value, string key, bool osc)
|
||||
{
|
||||
//TODO:
|
||||
object existingValue = null;
|
||||
if(cueData.ContainsKey(key))
|
||||
existingValue = cueData[key];
|
||||
|
||||
if(existingValue != null)
|
||||
{
|
||||
if (existingValue == value || existingValue.Equals(value))
|
||||
{
|
||||
//Console.WriteLine($"[cue] skipping set property: {key} with type: {value.GetType()} and value: {value}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Console.WriteLine($"[cue] attempting set property: {key} with type: {value.GetType()} and value: {value}");
|
||||
|
||||
|
||||
|
||||
if (workspace.connectedToQLab3 && key.Equals(QOSCKey.Type) && existingValue.Equals(QCueType.CueList) && value.Equals(QCueType.Group))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (key.Equals(QOSCKey.Cues))
|
||||
{
|
||||
if (value.GetType() != typeof(List<QCue>))
|
||||
return false;
|
||||
|
||||
|
||||
Dictionary<string,QCue> newChildCuesUIDMap = new Dictionary<string, QCue>();
|
||||
int index = 0;
|
||||
string uid = null;
|
||||
|
||||
foreach(var aCue in (List<QCue>)value)
|
||||
{
|
||||
uid = aCue.uid;
|
||||
if (uid == null)
|
||||
continue;
|
||||
aCue.sortIndex = index;
|
||||
newChildCuesUIDMap.Add(uid, aCue);
|
||||
index++;
|
||||
}
|
||||
childCues = (List<QCue>)value;
|
||||
childCuesUIDMap = newChildCuesUIDMap;
|
||||
|
||||
}
|
||||
else if(key.Equals(QOSCKey.PlaybackPositionId))
|
||||
{
|
||||
if (!IsCueList)
|
||||
return false;
|
||||
if (value != null && value.GetType() != typeof(string))
|
||||
return false;
|
||||
|
||||
if (value.Equals("none"))
|
||||
value = null;
|
||||
if (value != null)
|
||||
cueData[key] = value;
|
||||
else
|
||||
cueData.Remove(key);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (value != null)
|
||||
cueData[key] = value;
|
||||
else
|
||||
cueData.Remove(key);
|
||||
}
|
||||
|
||||
//Console.WriteLine($"[cue] set property: {key} with type: {value.GetType()} and value: {value}");
|
||||
//check for type key and update icon? do I want to do this here?
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
//Methods Copied: Yes
|
||||
//Methods Implemented: Yes
|
||||
#region Actions
|
||||
public void start() { workspace.startCue(this); }
|
||||
public void stop() { workspace.stopCue(this); }
|
||||
public void pause() { workspace.pauseCue(this); }
|
||||
public void reset() { workspace.resetCue(this); }
|
||||
public void load() { workspace.loadCue(this); }
|
||||
public void resume() { workspace.resumeCue(this); }
|
||||
public void hardStop() { workspace.hardStopCue(this); }
|
||||
public void hardPause() { workspace.hardPauseCue(this); }
|
||||
public void togglePause() { workspace.togglePauseCue(this); }
|
||||
public void preview() { workspace.previewCue(this); }
|
||||
public void panic() { workspace.panicCue(this); }
|
||||
#endregion
|
||||
|
||||
#region Printing
|
||||
public void Print()
|
||||
{
|
||||
if (IsCueList)
|
||||
{
|
||||
if(cues != null && cues.Count() > 0)
|
||||
{
|
||||
Console.WriteLine(displayName);
|
||||
foreach(var cue in cues)
|
||||
{
|
||||
cue.Print();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"{displayName} : {color}");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
static class QBonjour
|
||||
{
|
||||
public const string TCPService = "_qlab._tcp.local.";
|
||||
public const string UDPService = "_qlab._udp.local.";
|
||||
}
|
||||
static class QCueType
|
||||
{
|
||||
public const string Cue = "Cue";
|
||||
public const string CueList = "Cue List";
|
||||
public const string Cart = "Cart";
|
||||
public const string Group = "Group";
|
||||
public const string Audio = "";
|
||||
public const string Mic = "Mic";
|
||||
public const string Video = "Video";
|
||||
public const string Camera = "Camera";
|
||||
public const string Text = "Text";
|
||||
public const string Light = "Light";
|
||||
public const string Fade = "Fade";
|
||||
public const string Network = "Network";
|
||||
public const string MIDI = "MIDI";
|
||||
public const string MIDIFile = "MIDI File";
|
||||
public const string Timecode = "Timecode";
|
||||
public const string Start = "Start";
|
||||
public const string Stop = "Stop";
|
||||
public const string Pause = "Paus";
|
||||
public const string Load = "Load";
|
||||
public const string Reset = "Reset";
|
||||
public const string Devamp = "Devamp";
|
||||
public const string Goto = "GoTo";
|
||||
public const string Target = "Target";
|
||||
public const string Arm = "Arm";
|
||||
public const string Disarm = "Disarm";
|
||||
public const string Wait = "Wait";
|
||||
public const string Memo = "Memo";
|
||||
public const string Script = "Script";
|
||||
public const string Stagetracker = "Stagetracker";
|
||||
|
||||
//v3
|
||||
public const string OSC = "OSC";
|
||||
public const string Titles = "Titles";
|
||||
|
||||
}
|
||||
|
||||
static class QOSCKey
|
||||
{
|
||||
public const string UID = "uniqueID";
|
||||
public const string Type = "type";
|
||||
public const string Parent = "parent";
|
||||
public const string Name = "name";
|
||||
public const string Number = "number";
|
||||
public const string Notes = "notes";
|
||||
public const string FileTarget = "fileTarget";
|
||||
public const string CueTargetNumber = "cueTargetNumber";
|
||||
public const string CurrentCueTarget = "currentCueTarget";
|
||||
public const string ColorName = "colorName";
|
||||
public const string Flagged = "flagged";
|
||||
public const string Armed = "armed";
|
||||
public const string ContinueMode = "continueMode";
|
||||
public const string PreWait = "preWait";
|
||||
public const string PostWait = "postWait";
|
||||
public const string CurrentDuration = "currentDuration";
|
||||
public const string PercentPreWaitElapsed = "percentPreWaitElapsed";
|
||||
public const string PercentPostWaitElapsed = "percentPostWaitElapsed";
|
||||
public const string PercentActionElapsed = "percentActionElapsed";
|
||||
public const string PreWaitElapsed = "preWaitElapsed";
|
||||
public const string PostWaitElapsed = "postWaitElapsed";
|
||||
public const string ActionElapsed = "actionElapsed";
|
||||
public const string GroupMode = "mode";
|
||||
public const string CartPosition = "cartPosition";
|
||||
public const string CartRows = "cartRows";
|
||||
public const string CartColumns = "cartColumns";
|
||||
public const string HasFileTargets = "hasFileTargets";
|
||||
public const string HasCueTargets = "hasCueTargets";
|
||||
public const string AllowsEditingDuration = "allowsEditingDuration";
|
||||
public const string IsPanicking = "isPanicking";
|
||||
public const string IsTailingOut = "isTailingOut";
|
||||
public const string IsRunning = "isRunning";
|
||||
public const string IsLoaded = "isLoaded";
|
||||
public const string IsPaused = "isPaused";
|
||||
public const string IsBroken = "isBroken";
|
||||
public const string IsOverridden = "isOverridden";
|
||||
public const string TranslationX = "translationX";
|
||||
public const string TranslationY = "translationY";
|
||||
public const string ScaleX = "scaleX";
|
||||
public const string ScaleY = "scaleY";
|
||||
public const string OriginX = "originX";
|
||||
public const string OriginY = "originY";
|
||||
public const string Quaternion = "quaternion";
|
||||
public const string SurfaceSize = "surfaceSize";
|
||||
public const string CueSize = "cueSize";
|
||||
public const string PreserveAspectRatio = "preserveAspectRatio";
|
||||
public const string Layer = "layer";
|
||||
public const string Patch = "patch";
|
||||
public const string PatchList = "patchList";
|
||||
public const string SurfaceList = "surfaceList";
|
||||
public const string Cues = "cues";
|
||||
public const string ListName = "listName";
|
||||
public const string SurfaceID = "surfaceID";
|
||||
public const string FullSurface = "fullSurface";
|
||||
public const string Opacity = "opacity";
|
||||
public const string RotationZ = "rotationZ";
|
||||
public const string RotationY = "rotationY";
|
||||
public const string RotationX = "rotationX";
|
||||
public const string PlaybackPositionId = "playbackPositionId";
|
||||
public const string StartNextCueWhenSliceEnds = "startNextCueWhenSliceEnds";
|
||||
public const string StopTargetWhenSliceEnds = "stopTargetWhenSliceEnds";
|
||||
public const string SliderLevel = "sliderLevel";
|
||||
|
||||
// v3
|
||||
public const string Duration = "duration";
|
||||
public const string FullScreen = "fullScreen";
|
||||
}
|
||||
|
||||
static class QIdentifiers
|
||||
{
|
||||
// Identifiers for "fake" cues
|
||||
public const string RootCue = "__root__";
|
||||
public const string ActiveCues = "__active__";
|
||||
}
|
||||
|
||||
|
||||
//these should really be enums
|
||||
static class QFadeMode
|
||||
{
|
||||
public const int Absolute = 0;
|
||||
public const int Relative = 1;
|
||||
}
|
||||
|
||||
static class QContinueMode
|
||||
{
|
||||
public const int NoContinue = 0;
|
||||
public const int AutoContinue = 1;
|
||||
public const int AutoFollow = 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SharpOSC;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public class QMessage
|
||||
{
|
||||
|
||||
private OscMessage OSCMessage;
|
||||
|
||||
public QMessage(OscMessage oscMessage)
|
||||
{
|
||||
OSCMessage = oscMessage;
|
||||
}
|
||||
|
||||
public string description
|
||||
{
|
||||
get
|
||||
{
|
||||
//string join probably won't work might need to cast argument objects to strings first
|
||||
return $"address: {address}, arguments: {string.Join(" - ", arguments)}";
|
||||
}
|
||||
}
|
||||
|
||||
#region Message Type Checks
|
||||
public bool IsReply { get { return OSCMessage.Address.StartsWith("/reply"); } }
|
||||
|
||||
// /reply/cue_id/1/action
|
||||
public bool IsReplyFromCue { get{ return OSCMessage.Address.StartsWith("/reply/cue_id"); } }
|
||||
public bool IsReplyFromCueLists { get { return IsReply && OSCMessage.Address.EndsWith("cueLists"); } }
|
||||
|
||||
public bool IsUpdate { get{ return OSCMessage.Address.StartsWith("/update"); } }
|
||||
|
||||
|
||||
public bool IsWorkspaceUpdate {
|
||||
get {
|
||||
// /update/workspace/{workspace_id}
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 3 && parts[1].Equals("workspace"));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWorkspacesInfo {
|
||||
get {
|
||||
// /workspaces
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 2 && parts[1] == "workspaces");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsWorkspaceSettingsUpdate {
|
||||
get {
|
||||
// /update/workspace/{workspace_id}/settings/{settings_controller}
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 5 && parts[1].Equals("workspace") && parts[3].Equals("settings"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsLightDashboardUpdate {
|
||||
get {
|
||||
// /update/workspace/{workspace_id}/dashboard
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 4 && parts[1].Equals("workspace") && parts[3].Equals("dashboard"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsCueUpdate {
|
||||
get {
|
||||
// /update/workspace/{workspace_id}/cue_id/{cue_id}
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 5 && parts[1].Equals("workspace") && parts[3].Equals("cue_id"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsPlaybackPositionUpdate {
|
||||
get {
|
||||
// /update/workspace/{workspace_id}/cueList/{cue_list_id}/playbackPosition {cue_id}
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 6 && address.EndsWith("/playbakPosition"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool IsPreferencesUpdate {
|
||||
get {
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 4 && parts[3].Equals("preferences"));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDisconnect {
|
||||
get {
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 4 && parts[3].Equals("disconnect"));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsConnect
|
||||
{
|
||||
get
|
||||
{
|
||||
string[] parts = AddressParts;
|
||||
return (parts.Length == 4 && parts[3].Equals("connect"));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public string address { get { return OSCMessage.Address; } }
|
||||
|
||||
public string replyAddress { get{ return IsReply ? address.Substring("/reply".Length) : address; } }
|
||||
|
||||
public string addressWithoutWorkspace
|
||||
{
|
||||
get
|
||||
{
|
||||
//TODO
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public string[] AddressParts { get { return address.Split("/",StringSplitOptions.RemoveEmptyEntries); } }
|
||||
|
||||
public JToken response
|
||||
{
|
||||
get
|
||||
{
|
||||
JObject responseObj = JObject.Parse((string)arguments[0]);
|
||||
|
||||
//TODO
|
||||
return responseObj["data"];
|
||||
}
|
||||
}
|
||||
|
||||
public List<Object> arguments { get { return OSCMessage.Arguments; } }
|
||||
|
||||
public string cueID
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsCueUpdate)
|
||||
{
|
||||
return AddressParts[4];
|
||||
}else if (IsPlaybackPositionUpdate)
|
||||
{
|
||||
//TODO: check string cast
|
||||
return arguments.Count > 0 ? (string)arguments[0] : null;
|
||||
}else if (IsReplyFromCue)
|
||||
{
|
||||
return AddressParts[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public class QResponse
|
||||
{
|
||||
private const string WORKSPACES_REGEX = @"/workspaces";
|
||||
public string status { get; set; }
|
||||
public string address { get; set; }
|
||||
public object[] data { get; set; }
|
||||
|
||||
public string getReplyType()
|
||||
{
|
||||
Console.WriteLine($"QRESPONSE - Address to match: '{address}'");
|
||||
Match m = Regex.Match(address, WORKSPACES_REGEX);
|
||||
if (m.Success)
|
||||
return "WORKSPACES";
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
-19
@@ -1,53 +1,67 @@
|
||||
//General information about a QLab Workspace
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using Zeroconf;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public class QServer
|
||||
{
|
||||
private QClient qClient;
|
||||
private QClient client;
|
||||
|
||||
public string host;
|
||||
public int port;
|
||||
public string name;
|
||||
public IZeroconfHost zeroconfHost;
|
||||
List<QWorkspace> workspaces = new List<QWorkspace>();
|
||||
|
||||
public QServer(string host, int port, string name)
|
||||
public QServer(string host, int port)
|
||||
{
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.name = name;
|
||||
|
||||
qClient = new QClient(host, port);
|
||||
qClient.WorkspacesUpdated += OnWorkspacesUpdated;
|
||||
client = new QClient(host, port);
|
||||
client.WorkspacesUpdated += OnWorkspacesUpdated;
|
||||
}
|
||||
|
||||
private void OnWorkspacesUpdated(object source, QClient.WorkspacesUpdatedArgs args)
|
||||
{
|
||||
foreach(var workspace in args.Workspaces)
|
||||
{
|
||||
QWorkspace existingWorkspace = workspaceWithID(workspace.uniqueID);
|
||||
if(existingWorkspace == null)
|
||||
{
|
||||
QWorkspace workspaceToAdd = new QWorkspace(workspace, this);
|
||||
workspaces.Add(workspaceToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
public string description { get { return $"{name} - {host} - {port}"; } }
|
||||
|
||||
|
||||
public void refreshWorkspaces()
|
||||
{
|
||||
qClient.sendMessage("/workspaces");
|
||||
if (!client.connect())
|
||||
{
|
||||
System.Console.WriteLine($"Error: QServer unable to connect to QLab Server: {host}:{port}");
|
||||
return;
|
||||
}
|
||||
client.sendMessage("/workspaces");
|
||||
}
|
||||
|
||||
public QWorkspace workspaceWithID(string uniqueID)
|
||||
{
|
||||
foreach(var workspace in workspaces)
|
||||
{
|
||||
if (workspace.getUniqueID().Equals(uniqueID))
|
||||
if (workspace.uniqueID.Equals(uniqueID))
|
||||
return workspace;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
#region EventHandlers
|
||||
private void OnWorkspacesUpdated(object source, QWorkspacesUpdatedArgs args)
|
||||
{
|
||||
foreach (var workspace in args.Workspaces)
|
||||
{
|
||||
QWorkspace existingWorkspace = workspaceWithID(workspace.uniqueID);
|
||||
if (existingWorkspace == null)
|
||||
{
|
||||
QWorkspace workspaceToAdd = new QWorkspace(workspace, this);
|
||||
workspaces.Add(workspaceToAdd);
|
||||
workspaceToAdd.connectWithPasscode("1234");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+324
-40
@@ -1,4 +1,9 @@
|
||||
//TODO: connect methods, cue property fetch methods, everything else
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
|
||||
namespace QSharp
|
||||
{
|
||||
public class QWorkspace
|
||||
@@ -7,11 +12,20 @@ namespace QSharp
|
||||
private QServer server;
|
||||
private QClient client;
|
||||
|
||||
private string name;
|
||||
private string uniqueID;
|
||||
private bool connected;
|
||||
public string name;
|
||||
public string uniqueID;
|
||||
public bool connected;
|
||||
private bool hasPasscode;
|
||||
private string oscPrefix;
|
||||
private string passcode;
|
||||
|
||||
private QCue root;
|
||||
|
||||
private Timer heartbeatTimer;
|
||||
private int heartbeatAttempts;
|
||||
|
||||
public bool defaultSendUpdatesOSC;
|
||||
|
||||
public string version;
|
||||
|
||||
private void Init()
|
||||
{
|
||||
@@ -20,26 +34,42 @@ namespace QSharp
|
||||
connected = false;
|
||||
|
||||
hasPasscode = false;
|
||||
defaultSendUpdatesOSC = false;
|
||||
|
||||
root = new QCue(this);
|
||||
root.setProperty(QIdentifiers.RootCue, QOSCKey.UID, false);
|
||||
root.setProperty("Cue Lists", QOSCKey.Name, false);
|
||||
root.setProperty(QCueType.CueList, QOSCKey.Type, false);
|
||||
|
||||
//TODO: add version
|
||||
version = "3.0.0";
|
||||
|
||||
}
|
||||
|
||||
public QWorkspace(QWorkspaceInfo workspaceInfo, QServer server)
|
||||
{
|
||||
if(workspaceInfo.uniqueID.Length > 0)
|
||||
{
|
||||
uniqueID = workspaceInfo.uniqueID;
|
||||
oscPrefix = workspacePrefix();
|
||||
}
|
||||
Init();
|
||||
|
||||
if(workspaceInfo.uniqueID.Length > 0)
|
||||
uniqueID = workspaceInfo.uniqueID;
|
||||
|
||||
if (workspaceInfo.version.Length > 0)
|
||||
version = workspaceInfo.version;
|
||||
|
||||
//TODO add version if it has one if no version then it is QLab 3?
|
||||
updateWithWorkspaceInfo(workspaceInfo);
|
||||
|
||||
client = new QClient(server.host, server.port);
|
||||
this.server = server;
|
||||
|
||||
client.WorkspaceConnected += OnWorkspaceConnection;
|
||||
client.WorkspaceConnectionError += OnWorkspaceConnectionError;
|
||||
client.WorkspaceDisconnected += OnWorkspaceDisconnected;
|
||||
client.CueListsUpdated += OnCueListsUpdated;
|
||||
|
||||
this.server = server;
|
||||
Console.WriteLine($"[workspace] <{name}> initizalied for server: {server.name} ");
|
||||
}
|
||||
|
||||
//updateWithDictionary
|
||||
public bool updateWithWorkspaceInfo(QWorkspaceInfo workspaceInfo) {
|
||||
bool didUpdate = false;
|
||||
if(workspaceInfo.displayName.Length > 0 && !workspaceInfo.displayName.Equals(this.name))
|
||||
@@ -55,61 +85,315 @@ namespace QSharp
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
|
||||
public string description { get { return $"{name} : {uniqueID}"; } }
|
||||
|
||||
|
||||
public string nameWithoutPathExtension { get { return name; } } //TODO
|
||||
|
||||
public string getUniqueID()
|
||||
public string serverName { get { return server.name; } }
|
||||
|
||||
public string fullName { get { return $"{name} ({server.name})"; } }
|
||||
|
||||
public QCue firstCue { get { return firstCueList.firstCue; } }
|
||||
public QCue firstCueList { get { return root.firstCue; } }
|
||||
public string fullNameWithCueList(QCue cueList) { return ""; }
|
||||
//TODO other convenience methods
|
||||
|
||||
public bool connectedToQLab3 { get { return false; } } //TODO implement the version system
|
||||
|
||||
#region Connection/reconnection
|
||||
|
||||
public void connectWithPasscode(string passcode)
|
||||
{
|
||||
return uniqueID;
|
||||
//TODO
|
||||
|
||||
if (!client.connect())
|
||||
{
|
||||
System.Console.WriteLine($"[workspace] *** Error: couldn't connect to server");
|
||||
return;
|
||||
}
|
||||
|
||||
System.Console.WriteLine("[workspace] connecting...");
|
||||
client.sendMessage($"{workspacePrefix}/connect",passcode);
|
||||
|
||||
}
|
||||
|
||||
#region OSC address helpers
|
||||
private string addressForCue(QCue cue, string action)
|
||||
private void finishConnection()
|
||||
{
|
||||
return $"{oscPrefix}/cue_id/{cue.propertyForKey("uniqueId")}/{action}";
|
||||
//TODO
|
||||
System.Console.WriteLine($"[workspace] connected to <{name}> running on QLab version <{version}>");
|
||||
connected = true;
|
||||
startReceivingUpdates();
|
||||
//fetchQLabVersion();
|
||||
fetchCueLists();
|
||||
|
||||
}
|
||||
|
||||
private string addressForWildcardNumber(string number, string action) {
|
||||
return $"{oscPrefix}/cue/{number}/{action}";
|
||||
public void reconnect()
|
||||
{
|
||||
if (connected)
|
||||
return;
|
||||
connectWithPasscode(passcode);
|
||||
|
||||
//todo
|
||||
}
|
||||
|
||||
private string workspacePrefix()
|
||||
public void disconnect()
|
||||
{
|
||||
return $"/workspace/{uniqueID}";
|
||||
//TODO
|
||||
Console.WriteLine($"[workspace] disconnect: {name}");
|
||||
stopHeartbeat();
|
||||
stopReceivingUpdates();
|
||||
disconnectFromWorkspace();
|
||||
|
||||
connected = false;
|
||||
|
||||
client.disconnect();
|
||||
//root.removeAllChildCues();
|
||||
|
||||
}
|
||||
|
||||
public void temporarilyDisconnect()
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cues
|
||||
public QCue cueWithId(string uid)
|
||||
{
|
||||
return root.cueWithID(uid);
|
||||
}
|
||||
|
||||
public QCue cueWithNumber(string number)
|
||||
{
|
||||
return root.cueWithNumber(number);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Workspace Methods
|
||||
public void disconnectFromWorkspace() { client.sendMessage($"{oscPrefix}/disconnect"); }
|
||||
public void startReceivingUpdates() { client.sendMessage($"{oscPrefix}/updates", 1); }
|
||||
public void stopReceivingUpdates() { client.sendMessage($"{oscPrefix}/updates", 0); }
|
||||
public void enableAlwaysReply() { client.sendMessage($"{oscPrefix}/alwaysReply", 1); }
|
||||
public void disableAlwaysReply() { client.sendMessage($"{oscPrefix}/alwaysReply", 0); }
|
||||
public void disconnectFromWorkspace() { client.sendMessage($"{workspacePrefix}/disconnect"); }
|
||||
public void startReceivingUpdates() { client.sendMessage($"{workspacePrefix}/updates", 1); }
|
||||
public void stopReceivingUpdates() { client.sendMessage($"{workspacePrefix}/updates", 0); }
|
||||
public void enableAlwaysReply() { client.sendMessage($"{workspacePrefix}/alwaysReply", 1); }
|
||||
public void disableAlwaysReply() { client.sendMessage($"{workspacePrefix}/alwaysReply", 0); }
|
||||
public void fetchQLabVersion() { client.sendMessage($"{workspacePrefix}/version"); } //TODO: EventHandler for this
|
||||
public void fetchCueLists() { client.sendMessage($"{workspacePrefix}/cueLists"); } //TODO: EventHandler for CueListUpdated
|
||||
public void fetchPlaybackPositionForCue(QCue cue) { client.sendMessage(addressForCue(cue, QOSCKey.PlaybackPositionId)); } //EventHandler for this? can I use the CueListPlaybackPosition one?
|
||||
public void go() { client.sendMessage($"{workspacePrefix}/go"); }
|
||||
public void save() { client.sendMessage($"{workspacePrefix}/save"); }
|
||||
public void undo() { client.sendMessage($"{workspacePrefix}/undo"); }
|
||||
public void redo() { client.sendMessage($"{workspacePrefix}/redo"); }
|
||||
public void resetAll() { client.sendMessage($"{workspacePrefix}/reset"); }
|
||||
public void pauseAll() { client.sendMessage($"{workspacePrefix}/pause"); }
|
||||
public void resumeAll() { client.sendMessage($"{workspacePrefix}/resume"); }
|
||||
public void stopAll() { client.sendMessage($"{workspacePrefix}/stop"); }
|
||||
public void panicAll() { client.sendMessage($"{workspacePrefix}/panic"); }
|
||||
#endregion
|
||||
|
||||
public void fetchQLabVersion() {
|
||||
#region Heartbeat
|
||||
//TODO
|
||||
public void startHeartbeat()
|
||||
{
|
||||
clearHeartbeatTimeout();
|
||||
sendHeartbeat();
|
||||
}
|
||||
|
||||
public void stopHeartbeat()
|
||||
{
|
||||
clearHeartbeatTimeout();
|
||||
heartbeatAttempts = -1;
|
||||
}
|
||||
|
||||
public void clearHeartbeatTimeout()
|
||||
{
|
||||
heartbeatTimer.Stop();
|
||||
heartbeatTimer = null;
|
||||
heartbeatAttempts = 0;
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void fetchCueLists()
|
||||
public void sendHeartbeat()
|
||||
{
|
||||
client.sendMessage("/thump");
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void heartbeatTimeout(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
public void fetchPlaybackPositionForCue()
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Cue Actions
|
||||
public void startCue(QCue cue) { client.sendMessage(addressForCue(cue, "start")); }
|
||||
public void stopCue(QCue cue) { client.sendMessage(addressForCue(cue, "stop")); }
|
||||
public void pauseCue(QCue cue) { client.sendMessage(addressForCue(cue, "pause")); } //TODO: immediately update local for snappier whatever
|
||||
public void loadCue(QCue cue) { client.sendMessage(addressForCue(cue, "load")); }
|
||||
public void resetCue(QCue cue) { client.sendMessage(addressForCue(cue, "reset")); }
|
||||
public void deleteCue(QCue cue) { client.sendMessage(addressForCue(cue, "")); }
|
||||
public void resumeCue(QCue cue) { client.sendMessage(addressForCue(cue, "resume")); }
|
||||
public void hardStopCue(QCue cue) { client.sendMessage(addressForCue(cue, "hardStop")); }
|
||||
public void hardPauseCue(QCue cue) { client.sendMessage(addressForCue(cue, "hardPause")); } //TODO: immediately update local for snappier whatever
|
||||
public void togglePauseCue(QCue cue) { client.sendMessage(addressForCue(cue, "togglePause")); }
|
||||
public void previewCue(QCue cue) { client.sendMessage(addressForCue(cue, "preview")); }
|
||||
public void panicCue(QCue cue) { client.sendMessage(addressForCue(cue, "panic")); } //TODO: immediately update local for snappier whatever
|
||||
#endregion
|
||||
|
||||
#region Cue Getters/Setters
|
||||
//TODO
|
||||
#endregion
|
||||
|
||||
#region Property Fetching
|
||||
//TODO
|
||||
#endregion
|
||||
|
||||
#region OSC address helpers
|
||||
public void sendMessage(string address, params object[] args)
|
||||
{
|
||||
//TODO
|
||||
//check for workspace prefix?
|
||||
client.sendMessage(address, args);
|
||||
}
|
||||
|
||||
public void go() { client.sendMessage($"{oscPrefix}/go"); }
|
||||
public void save() { client.sendMessage($"{oscPrefix}/save"); }
|
||||
public void undo() { client.sendMessage($"{oscPrefix}/undo"); }
|
||||
public void redo() { client.sendMessage($"{oscPrefix}/redo"); }
|
||||
public void resetAll() { client.sendMessage($"{oscPrefix}/reset"); }
|
||||
public void pauseAll() { client.sendMessage($"{oscPrefix}/pause"); }
|
||||
public void resumeAll() { client.sendMessage($"{oscPrefix}/resume"); }
|
||||
public void stopAll() { client.sendMessage($"{oscPrefix}/stop"); }
|
||||
public void panicAll() { client.sendMessage($"{oscPrefix}/panic"); }
|
||||
private string addressForCue(QCue cue, string action)
|
||||
{
|
||||
return $"{workspacePrefix}/cue_id/{cue.propertyForKey("uniqueId")}/{action}";
|
||||
}
|
||||
|
||||
private string addressForWildcardNumber(string number, string action) {
|
||||
return $"{workspacePrefix}/cue/{number}/{action}";
|
||||
}
|
||||
|
||||
private string workspacePrefix
|
||||
{
|
||||
get { return $"/workspace/{uniqueID}"; }
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
public string workspaceID
|
||||
{
|
||||
get
|
||||
{
|
||||
return uniqueID;
|
||||
}
|
||||
}
|
||||
|
||||
#region Event Handling
|
||||
private void OnWorkspaceConnectionError(object source, QWorkspaceConnectionErrorArgs args)
|
||||
{
|
||||
if (args.status.Equals("badpass"))
|
||||
Console.WriteLine($"[workspace] *** Error: Password for workspace {name} was incorrect!");
|
||||
else
|
||||
Console.WriteLine($"[workspace] *** Error: Unable to connect to workspace: {name} on server: {server.name}");
|
||||
|
||||
}
|
||||
|
||||
private void OnWorkspaceConnection(object source, QWorkspaceConnectedArgs args)
|
||||
{
|
||||
finishConnection();
|
||||
Console.WriteLine($"[workspace] Connection finished this is the first cue in this workspace {root.firstCue.displayName}");
|
||||
}
|
||||
|
||||
private void OnWorkspaceDisconnected(object source, QWorkspaceDisconnectedArgs args)
|
||||
{
|
||||
//this might not be called with TCP?
|
||||
Console.WriteLine($"[workspace] *** Workspace has indicated it is disconnecting");
|
||||
}
|
||||
|
||||
private void OnCueListsUpdated(object source, QCueListsUpdatedArgs args)
|
||||
{
|
||||
bool rootCueUpdated = false;
|
||||
List<QCue> currentCueLists = new List<QCue>(args.data.Count());
|
||||
int index = 0;
|
||||
|
||||
foreach (var aCueList in args.data)
|
||||
{
|
||||
string uid = aCueList[QOSCKey.UID].ToString();
|
||||
if (uid == null)
|
||||
continue;
|
||||
QCue cueList = root.cueWithID(uid, false);
|
||||
|
||||
if(cueList != null)
|
||||
{
|
||||
if(cueList.sortIndex != index)
|
||||
{
|
||||
cueList.sortIndex = index;
|
||||
rootCueUpdated = true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
cueList = new QCue(aCueList, this);
|
||||
cueList.sortIndex = index;
|
||||
if (connectedToQLab3)
|
||||
cueList.setProperty(QCueType.CueList, QOSCKey.Type);
|
||||
rootCueUpdated = true;
|
||||
}
|
||||
currentCueLists.Add(cueList);
|
||||
index++;
|
||||
}
|
||||
|
||||
QCue activeCuesList = root.cueWithID(QIdentifiers.ActiveCues, false);
|
||||
if(activeCuesList != null)
|
||||
{
|
||||
if (activeCuesList.sortIndex != index)
|
||||
{
|
||||
activeCuesList.setProperty(QIdentifiers.ActiveCues, QOSCKey.UID, false);
|
||||
activeCuesList.setProperty("Active Cues", QOSCKey.Name, false);
|
||||
activeCuesList.setProperty(QCueType.CueList, QOSCKey.Type, false);
|
||||
|
||||
rootCueUpdated = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
activeCuesList = new QCue(this);
|
||||
activeCuesList.setProperty(QIdentifiers.ActiveCues, QOSCKey.UID, false);
|
||||
activeCuesList.setProperty("Active Cues", QOSCKey.Name, false);
|
||||
activeCuesList.setProperty(QCueType.CueList, QOSCKey.Type, false);
|
||||
rootCueUpdated = true;
|
||||
}
|
||||
currentCueLists.Add(activeCuesList);
|
||||
|
||||
if (root.cues.Count() != currentCueLists.Count())
|
||||
rootCueUpdated = true;
|
||||
|
||||
root.setProperty(currentCueLists, QOSCKey.Cues);
|
||||
|
||||
if (rootCueUpdated)
|
||||
{
|
||||
//add Event handled? use CueUpdated one?
|
||||
}
|
||||
|
||||
Console.WriteLine($"[workspace] cueLists finished processing. root updated? {rootCueUpdated}");
|
||||
|
||||
Print();
|
||||
}
|
||||
|
||||
|
||||
//OnWorkspaceUpdated
|
||||
//OnWorkspaceSettingsUpdated
|
||||
//LightDashboardUpdated
|
||||
//PreferencesUpdated
|
||||
//CueNeedsUpdated
|
||||
//CueUpdated
|
||||
//ClientShouldDisconnect
|
||||
#endregion
|
||||
|
||||
|
||||
#region Printing
|
||||
public void Print()
|
||||
{
|
||||
foreach(var cueList in root.cues)
|
||||
{
|
||||
cueList.Print();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +46,22 @@ namespace SharpOSC
|
||||
_address = address;
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
public bool Connect()
|
||||
{
|
||||
client = new TcpClient(Address, Port);
|
||||
Console.WriteLine($"TCPClient - connect called for <{Address}:{Port}>");
|
||||
Thread receivingThread = new Thread(ReceiveLoop);
|
||||
receivingThread.Start();
|
||||
try
|
||||
{
|
||||
client = new TcpClient(Address, Port);
|
||||
Thread receivingThread = new Thread(ReceiveLoop);
|
||||
receivingThread.Start();
|
||||
//Console.WriteLine($"TCPClient - connected to <{Address}:{Port}>");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//Console.WriteLine(e.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Send(byte[] message)
|
||||
@@ -67,6 +77,14 @@ namespace SharpOSC
|
||||
Send(data);
|
||||
}
|
||||
|
||||
public bool IsConnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return client.Connected;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveLoop()
|
||||
{
|
||||
while (client.Connected)
|
||||
@@ -109,7 +127,7 @@ namespace SharpOSC
|
||||
}
|
||||
} catch(Exception e)
|
||||
{
|
||||
//Log.Debug("TCPSENDER - Receive Exception: " + e.ToString());
|
||||
//Console.WriteLine("TCPSENDER - Receive Exception: " + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,9 @@ namespace qControlDemo
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
||||
Console.WriteLine("qControlDemo Started");
|
||||
QBrowser browser = new QBrowser();
|
||||
|
||||
|
||||
|
||||
Thread.Sleep(100000000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Terminal.Gui" Version="0.81.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\QSharp\QSharp.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user