blob: 8d4b712e9c66294f3c031606366ffdda5357a4e7 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
|
/*
requirement driven design
do we store graphs as files or in a db with UUID as key?
do we traverse the graph as direct recursive function calls or programmatically from outside?
or keep a reference to the container graph in each node?
graph parent;
vector<signal_input> signal_inputs;
vector<image_input> image_inputs;
//in input
int input_id;
&image get_ouput()
{
for (int i=0;i<inputs.size;i++){
if (inputs[i].input_id) parent.nodes[input_id].get_output(); ///how to find the output in the node? uids for everything?
}
render();
return &image_data;
}
OR
for (int i=0;i<inputs.size;i++){
if (inputs[i].connection) inputs[i].connection->get_output(); ///methinks this is neater? you can check pointer for NULL, can't be ref
}
NO NODE HAS MORE THAN ONE OUTPUT
WE DON'T LINK TO AN OUTPUT OBJECT WE LINK TO THE NODE - GET_OUTPUT IS THE RENDER FUNCTION
settings - how do we deal with settings being controllable
signal inputs can have a gui representation as well
other gui items don't have an input
scaling to come
time is always in floating points seconds - time has to be requested when rendering - either a preview
what about testing a float for equality?
maybe we should look at time in int (frames) - - what does this imply
is it easier to have a function like:
bool Same_frame(float time1, float time2);
2 main questions
authentication - how
authentication to renderer or just session?
files - where
generated images & movies where?
nb where a signal enters a channel comp input - it is duplicated
next - Poco create thread
1st - create thread and return id - create method to kill it
sql stuff
messaging - http factory includes a poco notication center
when it creates the rotor session it registers it
session messages are posted thus and consumed
best way to control the rendering process? work queue isn't bad as it means we keep concurrency
also need to:
find out what the renderer is doing
get progress
*/
#include <unordered_map>
#include <deque>
#include "Poco/UUID.h"
#include "Poco/UUIDGenerator.h"
#include "Poco/Notification.h"
#include "Poco/NotificationCenter.h"
#include "Poco/Observer.h"
#include "Poco/ThreadPool.h"
#include "Poco/Thread.h"
#include "Poco/Runnable.h"
#include "Poco/Mutex.h"
#include "Poco/Random.h"
#include "Poco/AutoPtr.h"
#include "Poco/File.h"
#include <iostream>
using Poco::UUID;
using Poco::UUIDGenerator;
namespace Rotor {
#define IDLE 0
#define ANALYSING_AUDIO 1
#define AUDIO_READY 2
#define CREATING_PREVIEW 3
#define PREVIEW_READY 4
#define RENDERING 5
#define RENDER_READY 6
#define ANALYSE_AUDIO 0
#define PREVIEW 1
#define RENDER 2
//forward declaration
class Node;
class Render_status{
public:
int id;
float progress;
};
class Render_requirements{
public:
int num_performances;
int num_clips;
};
class Command_response{
public:
Command_response() { status=HTTPResponse::HTTP_OK; }
string description;
HTTPResponse::HTTPStatus status;
};
class Render_context: public Poco::Task { //Poco task object
//manages a 'patchbay'
//high level interfaces for the wizard
//and low level interface onto the graph
public:
Render_context(const std::string& name): Task(name) {
state=IDLE;
};
void runTask() {
while (!isCancelled()) {
mutex.lock();
if (work_queue.size()){
int cmd=work_queue[0];
work_queue.pop_front();
if (cmd==ANALYSE_AUDIO) {
}
}
mutex.unlock();
sleep(100);
}
printf("Rotor: stopping thread\n");
}
void add_queue(int item) {
mutex.lock();
work_queue.push_back(item);
mutex.unlock();
}
Command_response session_command(const std::vector<std::string>& command){
//method,id,command1,{command2,}{body}
//here we allow the controlling server to communicate with running tasks
Command_response response;
mutex.lock();
if (command[2]=="audio") {
if (command[0]=="PUT") { //get audio file location and initiate analysis
if (command.size()>2) {
if (state==IDLE) {
//check file exists
Poco::File f=Poco::File(command[3]);
if (f.exists()) {
//pass to worker thread ??if engine is ready?? ??what if engine has finished but results aren't read??
audio_filename=command[3]; //for now, store session variables in memory
work_queue.push_back(ANALYSE_AUDIO);
response.description="<status>Starting audio analysis: "+command[3]+"</status>\n";
}
else {
response.status=HTTPResponse::HTTP_NOT_FOUND;
response.description="<status>File "+command[3]+" not found</status>\n";
}
}
else {
response.status=HTTPResponse::HTTP_BAD_REQUEST;
response.description="<status>Rotor: session busy</status>\n";
}
}
}
}
mutex.unlock();
return response;
}
Render_status get_status();
void cancel(); //interrupt locking process
int make_preview(int nodeID, float time); //starts a frame preview - returns status code - how to retrieve?
int load_graph(Poco::UUID uid);
UUID save_graph(); //returns UUID of saved graph
int load_audio(string filename);
Render_requirements get_requirements();
int load_video(int num,string filename); //can be performance or clip
private:
int state;
float progress; //for a locking process: audio analysis or rendering
std::deque<int> work_queue;
Poco::Mutex mutex; //lock for access from parent thread
std::string audio_filename;
};
class Input{
public:
Node* connection;
};
class Image_input: public Input{
public:
};
class Signal_input: public Input{
public:
};
class Node{
public:
UUID uid; //every usable node has a UUID
int id;
vector<Signal_input> inputs; //simple node has signal inputs and outputs
void get_output(float time);
void gather_inputs(float time) {
for (uint i=0;i<inputs.size();i++){
if (inputs[i].connection) inputs[i].connection->get_output(time);
}
}
};
class Image{
char* data;
};
class Image_node: public Node{
public:
vector<Image_input> image_inputs; //image node also has image inputs and outputs
void gather_inputs(float time) {
Node::gather_inputs(time);
for (uint i=0;i<image_inputs.size();i++){
if (image_inputs[i].connection) image_inputs[i].connection->get_output(time);
}
}
Image* get_output(float time){ //sample implementation
gather_inputs(time);
//do something with the inputs
//and then
return ((Image_node*)image_inputs[0].connection)->image;
}
void get_preview(float time);
Image* image; //this can be privately allocated or just passed on as the node see fit
private:
float image_time;
};
class Graph{
public:
UUID uid; //every version of a graph has a UUID
private:
std::unordered_map<int,Node> nodes;
};
}
/*
coding style
Types begin with a capital, use underscore as a seperator
*/
|