summaryrefslogtreecommitdiff
path: root/rotord
diff options
context:
space:
mode:
Diffstat (limited to 'rotord')
-rwxr-xr-xrotord/01.xml15
-rw-r--r--rotord/04.xml17
-rw-r--r--rotord/graph.cpp4
-rw-r--r--rotord/libavaudioloader.cpp52
-rw-r--r--rotord/libavaudioloader.h1
-rw-r--r--rotord/rendercontext.cpp25
-rwxr-xr-xrotord/rotor.cpp14
-rwxr-xr-xrotord/rotor.h85
-rw-r--r--rotord/utils.cpp19
-rw-r--r--rotord/utils.h6
10 files changed, 173 insertions, 65 deletions
diff --git a/rotord/01.xml b/rotord/01.xml
index 7a7315d..29d709e 100755
--- a/rotord/01.xml
+++ b/rotord/01.xml
@@ -2,15 +2,16 @@
<patchbay ID="0f7aa258-7c2f-11e2-abbd-133252267708">Sample template ©Rotor 2013
<node ID="01" type="audio_analysis" soname="qm-vamp-plugins" id="qm-tempotracker" output="signal">beats
</node>
- <node ID="03" type="divide" amount="2.0" output="signal">signal divide
- <signal_input from="01">signal 1 to divide</signal_input>
+ <node ID="02" type="on_off" output="signal">on off
+ <signal_input from="01">signal 1 to make on off</signal_input>
</node>
- <node ID="04" type="bang" output="signal">outputs a single 1 every time signal enters a new number
- <signal_input from="03">signal to analyse</signal_input>
+ <node ID="03" type="video_input" output="image">performance video
</node>
- <node ID="05" type="video_input" output="image">performance video
+ <node ID="04" type="invert" output="image">invert video
+ <signal_input from="02">invert signal</signal_input>
+ <image_input from="03">image to invert</image_input>
</node>
- <node ID="06" type="video_output">video output
- <image_input from="05">image to output</image_input>
+ <node ID="05" type="video_output">video output
+ <image_input from="04">image to output</image_input>
</node>
</patchbay>
diff --git a/rotord/04.xml b/rotord/04.xml
new file mode 100644
index 0000000..fe5c3e1
--- /dev/null
+++ b/rotord/04.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<patchbay ID="0f7aa258-7c2f-11e2-abbd-133252267708">Sample template ©Rotor 2013
+ <node ID="01" type="audio_analysis" soname="qm-vamp-plugins" id="qm-tempotracker" output="signal">beats
+ </node>
+ <node ID="02" type="video_input" output="image">performance video
+ </node>
+ <node ID="03" type="video_input" output="image">performance video
+ </node>
+ <node ID="04" type="video_cycler" output="image">video cycler
+ <signal_input from="01">switching signal</signal_input>
+ <image_input from="02">image to switch</image_input>
+ <image_input from="03">image to switch</image_input>
+ </node>
+ <node ID="05" type="video_output">video output
+ <image_input from="04">image to output</image_input>
+ </node>
+</patchbay>
diff --git a/rotord/graph.cpp b/rotord/graph.cpp
index fc9a129..2139f6c 100644
--- a/rotord/graph.cpp
+++ b/rotord/graph.cpp
@@ -29,10 +29,10 @@ bool Graph::signal_render(string &signal_xml,const float framerate) {
}
else return false;
}
-bool Graph::video_render(const string &output_filename,const string &audio_filename,const float framerate) {
+bool Graph::video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress) {
if (find_node("video_output")) {
Video_output *video_output=dynamic_cast<Video_output*>(find_node("video_output"));
- return video_output->render(duration,framerate,output_filename,audio_filename);
+ return video_output->render(duration,framerate,output_filename,audio_filename,progress);
}
else return false;
}
diff --git a/rotord/libavaudioloader.cpp b/rotord/libavaudioloader.cpp
index 03919f0..ef84560 100644
--- a/rotord/libavaudioloader.cpp
+++ b/rotord/libavaudioloader.cpp
@@ -152,42 +152,50 @@ uint16_t* libav::Audioloader::get_samples(int num){ //presumes 16bpc here
//std::cerr << "request "<<num<<" samples: "<<(ready?"ready":"not ready")<<std::endl;
if(!ready) return nullptr;
//shuffle down samples
+
if (sample_start>0){
for (int i=0;i<sample_end-sample_start;i++){
- for (int j=0;j<av_frame_get_channels(frame);j++) {
- buffer[(i*av_frame_get_channels(frame))+j]=buffer[((sample_start+i)*av_frame_get_channels(frame))+j];
+ for (int j=0;j<channels;j++) {
+ buffer[(i*channels)+j]=buffer[((sample_start+i)*channels)+j];
}
}
sample_start=sample_end-sample_start;
}
+
sample_end=sample_start;
while (sample_end<num) {
- frame=get_frame();
- if (((sample_end+std::max(num,frame->nb_samples))*av_frame_get_channels(frame))>buffer.size()){
- int m=buffer.size();
- int s=((sample_end+std::max(num,frame->nb_samples))*av_frame_get_channels(frame));
- buffer.reserve(s);
- std::cerr << "audioloader reserved buffer to " << s << std::endl;
- for (int i=m;i<s;i++) buffer.push_back(0);
+ frame=get_frame();
+ if (frame) {
+ channels=av_frame_get_channels(frame); //will always reach here 1st
+ if (((sample_end+std::max(num,frame->nb_samples))*channels)>buffer.size()){
+ int m=buffer.size();
+ int s=((sample_end+std::max(num,frame->nb_samples))*channels);
+ buffer.reserve(s);
+ std::cerr << "audioloader reserved buffer to " << s << std::endl;
+ for (int i=m;i<s;i++) buffer.push_back(0);
+ }
+ for (int i=0;i<frame->nb_samples;i++) {
+ for (int j=0;j<channels;j++) {
+ buffer[((sample_end+i)*frame->channels)+j]= ((uint16_t*) frame->buf[j]->data)[i];
+ //temporarily disabled audio as its is SIGSEV with audio from delorentos
+
+
+ //buffer[(j*frame->channels)+(sample_end+i)]= ((uint16_t*) frame->buf[j]->data)[i]; ??planar?? nope
+ }
+ }
+ sample_end+=frame->nb_samples;
}
- if (!frame) {
- for (int i=0;i<num*av_frame_get_channels(frame);i++){
- buffer[sample_end+i]=0;
+ else {
+ for (int i=sample_end;i<num;i++){
+ for (int j=0;j<channels;j++) {
+ buffer[(channels*i)+j]=0;
+ }
}
}
//std::cerr<<"filling buffer to "<<((sample_end+frame->nb_samples)*frame->channels)<<std::endl;
- for (int i=0;i<frame->nb_samples;i++) {
- for (int j=0;j<av_frame_get_channels(frame);j++) {
- buffer[((sample_end+i)*frame->channels)+j]= ((uint16_t*) frame->buf[j]->data)[i];
- //temporarily disabled audio as its is SIGSEV with audio from delorentos
-
-
- //buffer[(j*frame->channels)+(sample_end+i)]= ((uint16_t*) frame->buf[j]->data)[i]; ??planar?? nope
- }
- }
- sample_end+=frame->nb_samples;
+
//avcodec_free_frame(&frame);
}
if (sample_end>num) {
diff --git a/rotord/libavaudioloader.h b/rotord/libavaudioloader.h
index aca6bd0..1197fbb 100644
--- a/rotord/libavaudioloader.h
+++ b/rotord/libavaudioloader.h
@@ -31,6 +31,7 @@ namespace libav {
AVPacket packet;
int sample_end;
int sample_start;
+ int channels; //necessary to handle final packet
};
diff --git a/rotord/rendercontext.cpp b/rotord/rendercontext.cpp
index d6469bd..d0fa5bd 100644
--- a/rotord/rendercontext.cpp
+++ b/rotord/rendercontext.cpp
@@ -19,17 +19,19 @@ void Render_context::runTask() {
processors.push_back(dynamic_cast<Base_audio_processor*>(a));
}
if (load_audio(audio_filename,processors)) {
- state=AUDIO_READY;
+ audio_loaded=true;
+ state=IDLE;
}
else {
//an error occurred: TODO have to clean up allocated data. autoptr?
+ audio_loaded=false;
state=IDLE;
}
}
if(cmd==RENDER) {
state=RENDERING;
- if(graph.video_render(output_filename,audio_filename,output_framerate)){
- state=RENDER_READY;
+ if(graph.video_render(output_filename,audio_filename,output_framerate,progress)){
+ state=IDLE;
}
else {
//an error occurred: TODO have to clean up allocated data. autoptr?
@@ -88,7 +90,7 @@ Command_response Render_context::session_command(const std::vector<std::string>&
sprintf(c,"%02f",progress);
response.description+="<progress>"+string(c)+"</progress>\n";
}
- if (state==AUDIO_READY) {
+ else if (audio_loaded) {
//not sure about this-- should this state be retained?
//can the data only be read once?
//for now
@@ -97,7 +99,10 @@ Command_response Render_context::session_command(const std::vector<std::string>&
response.description+="<audio>\n";
response.description+=audio_thumb->print();
response.description+="</audio>";
- state=IDLE;
+ }
+ else {
+ response.status=HTTPResponse::HTTP_BAD_REQUEST;
+ response.description="<status context='"+command[1]+"'>Rotor: no audio loaded</status>\n";
}
}
if (command[0]=="DELETE") {
@@ -230,8 +235,8 @@ Command_response Render_context::session_command(const std::vector<std::string>&
if (command[0]=="GET") {
//DUMMY RESPONSE
response.status=HTTPResponse::HTTP_OK;
- response.description="<status context='"+command[1]+"'>DUMMY RESPONSE Rotor: rendering video</status>\n";
- response.description+="<progress>25.2</progress>\n";
+ response.description="<status context='"+command[1]+"'>Rotor: rendering video</status>\n";
+ response.description+="<progress>"+ofToString(progress)+"</progress>\n";
}
if (command[0]=="PUT") {
if (command.size()>2) {
@@ -383,9 +388,9 @@ bool Render_context::load_audio(const string &filename,vector<Base_audio_process
p->process_frame(frame->data[0],frame->nb_samples);
}
sample_processed+=frame->nb_samples;
- mutex.lock();
- progress=((double)sample_processed)/samples;
- mutex.unlock();
+ //mutex.lock();
+ progress=((float)sample_processed)/samples;
+ //mutex.unlock();
}
}
// You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory
diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp
index b0bf8ab..4c79fc1 100755
--- a/rotord/rotor.cpp
+++ b/rotord/rotor.cpp
@@ -13,6 +13,9 @@ Node_factory::Node_factory(){
add_type("testcard",new Testcard());
add_type("video_output",new Video_output());
add_type("video_input",new Video_input());
+ add_type("on_off",new On_off());
+ add_type("invert",new Invert());
+ add_type("video_cycler",new Video_cycler());
}
bool Signal_input::connect(Signal_node* source) {
@@ -151,7 +154,7 @@ void Audio_analysis::print_features(){
}
}
-bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename){
+bool Video_output::render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress){
//
//setup defaults
@@ -188,8 +191,15 @@ bool Video_output::render(const float duration, const float framerate,const stri
af+=exporter->get_audio_step();
}
Image* i=get_output(Frame_spec(vf,framerate,outW,outH));
- exporter->encodeFrame(i->RGBdata);
+ if (i) {
+ exporter->encodeFrame(i->RGBdata);
+ }
vf+=vstep;
+ progress=vf/duration;
+ if (progress>0.99) {
+ //stop here
+ //seems that the last frame of samples causes std::max to have <error reading variables>
+ }
/*
if (!exporter->encodeFrame(i->RGBdata)){
//if (!exporter->encodeFrame(get_output(Frame_spec(f,framerate,outW,outH))->RGBdata,audioloader.get_packet())){
diff --git a/rotord/rotor.h b/rotord/rotor.h
index 441be2f..ea4d758 100755
--- a/rotord/rotor.h
+++ b/rotord/rotor.h
@@ -62,6 +62,7 @@ extern "C" {
#include "libavaudioloader.h"
#include "libavexporter.h"
#include "gstvideoloader.h"
+#include "utils.h" //fequal
namespace Rotor {
#define IDLE 0
@@ -76,19 +77,7 @@ namespace Rotor {
#define PREVIEW 2
#define RENDER 3
-#ifndef FEQUAL
-//float equality
-bool fequal(const float u,const float v){
- if (abs(u-v)<.001) return true;
- else return false;
-};
-bool flessorequal(const float u,const float v){
- //v is less or equal to u
- if (u-v>-.001) return true;
- else return false;
-};
-#define FEQUAL
-#endif
+
//forward declaration
class Node;
@@ -344,6 +333,21 @@ bool flessorequal(const float u,const float v){
return 0.0f;
}
};
+ class On_off: public Signal_node {
+ public:
+ On_off(){};
+ On_off(map<string,string> &settings) {
+ base_settings(settings);
+ };
+ On_off* clone(map<string,string> &_settings) { return new On_off(_settings);};
+ const float get_output(const Time_spec &time) {
+ if (inputs[0]->connection) {
+ float s1=(((Signal_node*)(inputs[0]->connection))->get_output(time));
+ if ((int)s1%2) return 1.0f;
+ }
+ return 0.0f;
+ }
+ };
class Signal_output: public Signal_node {
public:
Signal_output(){};
@@ -400,12 +404,22 @@ bool flessorequal(const float u,const float v){
Invert* clone(map<string,string> &_settings) { return new Invert(_settings);};
Image *get_output(const Frame_spec &frame){
if (inputs.size()) {
- if (inputs[0]->connection) {
- Time_spec requested=Time_spec(frame.time,frame.framerate);
- if (fequal((((Signal_node*)inputs[0]->connection)->get_output(requested)),1.0f)) {
- //invert=!invert;
- }
- }
+ if (image_inputs[0]->connection){
+ if (inputs[0]->connection) {
+ Time_spec requested=Time_spec(frame.time,frame.framerate);
+ if (fmoreorequal(1.0f,(((Signal_node*)inputs[0]->connection)->get_output(requested)))) {
+ Image *in=(((Image_node*)image_inputs[0]->connection)->get_output(frame));
+ image->setup(frame.w,frame.h);
+ for (int i=0;i<in->w*in->h*3;i++) {
+ image->RGBdata[i]=255-in->RGBdata[i];
+ }
+ return image;
+
+ }
+ }
+ return (((Image_node*)image_inputs[0]->connection)->get_output(frame));
+ }
+ return nullptr;
}
if (image_inputs[0]->connection) {
@@ -431,7 +445,7 @@ bool flessorequal(const float u,const float v){
else return nullptr;
};
Video_output* clone(map<string,string> &_settings) { return new Video_output(_settings);};
- bool render(const float duration, const float framerate,const string &output_filename,const string &audio_filename);
+ bool render(const float duration, const float framerate,const string &output_filename,const string &audio_filename,float& progress);
private:
//ofxMovieExporter *exporter;
@@ -454,6 +468,31 @@ bool flessorequal(const float u,const float v){
ofGstVideoPlayer *player;
Image *image;
};
+ class Video_cycler: public Image_node {
+ //cycles through video inputs in order
+ public:
+ Video_cycler(){};
+ Video_cycler(map<string,string> &settings) {
+ base_settings(settings);
+ };
+ ~Video_cycler(){};
+ bool load(const string &filename);
+ Image *get_output(const Frame_spec &frame){
+ int which_input=0;
+ Time_spec requested=Time_spec(frame.time,frame.framerate);
+ if (inputs[0]->connection) {
+ which_input=((int)((Signal_node*)inputs[0]->connection)->get_output(requested))%image_inputs.size();
+ }
+ if (image_inputs.size()) {
+ if (image_inputs[which_input]->connection){
+ return (((Image_node*)image_inputs[which_input]->connection)->get_output(frame));
+ }
+ }
+ return nullptr;
+ }
+ Video_cycler* clone(map<string,string> &_settings) { return new Video_cycler(_settings);};
+ private:
+ };
//-------------------------------------------------------------------
class Node_factory{
public:
@@ -484,7 +523,7 @@ bool flessorequal(const float u,const float v){
vector<Node*> find_nodes(const string &type);
Node* find_node(const string &type);
bool signal_render(string &signal_xml,const float framerate);
- bool video_render(const string &output_filename,const string &audio_filename,const float framerate);
+ bool video_render(const string &output_filename,const string &audio_filename,const float framerate,float& progress);
int load(Poco::UUID uid);
bool load(string &graph_filename);
UUID save(); //save to DB, returns UUID of saved graph
@@ -526,6 +565,7 @@ bool flessorequal(const float u,const float v){
audio_thumb=new Audio_thumbnailer();
state=IDLE;
output_framerate=25.0f;
+ audio_loaded=false;
};
void runTask();
void add_queue(int item);
@@ -538,7 +578,7 @@ bool flessorequal(const float u,const float v){
bool load_video(const string &nodeID,const string &filename);//can be performance or clip
private:
int state;
- double progress; //for a locking process: audio analysis or rendering
+ float progress; //for a locking process: audio analysis or rendering
//thread only does one thing at once
std::deque<int> work_queue;
Poco::Mutex mutex; //lock for access from parent thread
@@ -550,6 +590,7 @@ bool flessorequal(const float u,const float v){
Graph graph;
Node_factory factory;
float output_framerate;
+ bool audio_loaded;
};
}
diff --git a/rotord/utils.cpp b/rotord/utils.cpp
new file mode 100644
index 0000000..d357319
--- /dev/null
+++ b/rotord/utils.cpp
@@ -0,0 +1,19 @@
+#include "utils.h"
+
+using namespace std;
+
+//float equality
+bool fequal(const float u,const float v){
+ if (abs(u-v)<.001) return true;
+ else return false;
+};
+bool flessorequal(const float u,const float v){
+ //v is less or equal to u
+ if (u-v>-.001) return true;
+ else return false;
+};
+bool fmoreorequal(const float u,const float v){
+ //v is more or equal to u
+ if (v-u>-.001) return true;
+ else return false;
+};
diff --git a/rotord/utils.h b/rotord/utils.h
new file mode 100644
index 0000000..e9084ff
--- /dev/null
+++ b/rotord/utils.h
@@ -0,0 +1,6 @@
+#include <cmath>
+
+//float equality
+bool fequal(const float u,const float v);
+bool flessorequal(const float u,const float v);
+bool fmoreorequal(const float u,const float v);