summaryrefslogtreecommitdiff
path: root/NT/src
diff options
context:
space:
mode:
Diffstat (limited to 'NT/src')
-rw-r--r--NT/src/cvimage.cpp252
-rw-r--r--NT/src/cvimage.h302
-rw-r--r--NT/src/nodes.h41
-rw-r--r--NT/src/nodes_audio_analysis.h10
-rw-r--r--NT/src/nodes_source.h77
-rw-r--r--NT/src/rotor.h5
6 files changed, 664 insertions, 23 deletions
diff --git a/NT/src/cvimage.cpp b/NT/src/cvimage.cpp
new file mode 100644
index 0000000..b255848
--- /dev/null
+++ b/NT/src/cvimage.cpp
@@ -0,0 +1,252 @@
+#include "cvimage.h"
+
+using namespace std;
+
+namespace Rotor {
+ //space out to 32 bit RGB padding for cairo
+ void Image::convert24(){
+ cv::cvtColor(rgb,rgb, CV_RGBA2RGB);
+ }
+ void Image::convert32(){
+ cv::cvtColor(rgb,rgb, CV_RGB2RGBA);
+ }
+ Image & Image::operator+=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ rgb+=other.rgb;
+ }
+ return *this;
+ }
+ Image & Image::operator*=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot multiply images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ //rgb/=other.rgb; //does funny glitchy stuff
+ //could use cv::Mat.mul() here
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ rgb.data[i]=pixels.multiply[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::operator^=(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ rgb^=other.rgb;
+ }
+ return *this;
+ }
+ Image & Image::add_wrap(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //creates rainbow overload, openCV doesn't do this
+ rgb.data[i]=(unsigned char)(((int)other.rgb.data[i]+(int)rgb.data[i]));
+ }
+ }
+ return *this;
+ }
+ Image & Image::divide_wrap(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot add images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //creates rainbow overload, openCV doesn't do this
+ rgb/=other.rgb; //does funny glitchy stuff
+ }
+ }
+ return *this;
+ }
+ //THIS OPENCV VERSION IS SLOWER THAN THE OLDSKOOL VERSION BELOW
+ Image & Image::alpha_blend_cv(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //why not??
+ }
+ else if (!other.alpha.data){
+ //default to full on alpha
+ rgb=other.rgb.clone();
+ }
+ else {
+ //overlay the other image based on its alpha values
+ //https://gist.github.com/Brick85/5009046 - this is a dumb way to do it?
+ //how to invert a matrix?
+ //'invert' is matrix invert - different
+ //subtract from a scalar (1) ?
+ vector<cv::Mat> ichans,ochans;
+ vector<cv::Mat> compchans;
+ cv::split(rgb,ichans);
+ cv::split(other.rgb,ochans);
+ uint8_t b=0xFF;
+ cv::Mat iA=b-other.alpha;
+ for (int i=0;i<3;i++) {
+ compchans.push_back(ichans[i].mul(iA,1.0/255.0)+ochans[i].mul(other.alpha,1.0/255.0));
+ }
+ merge(compchans,rgb);
+ //rgb+=other.rgb;
+ //for (int i=0;i<w*h*3;i++) {
+ // rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8));
+ //}
+ }
+
+ return *this;
+ }
+ Image & Image::alpha_blend(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot blend images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //why not??
+ }
+ else if (!other.alpha.data){
+ //default to full on alpha
+ rgb=other.rgb.clone();
+ }
+ else {
+ for (int i=0;i<w*h*3;i++) {
+ rgb.data[i]=(uint8_t)(((((int)rgb.data[i])*(0xFF-other.alpha.data[i/3]))>>8)+((((int)other.rgb.data[i])*((int)other.alpha.data[i/3]))>>8));
+ }
+ }
+ return *this;
+ }
+ Image & Image::alpha_merge(const Image &other) {
+ //converts the incoming image to monochrome and inserts it into the alpha channel of this image
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot merge alpha with different size! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ cv::cvtColor(other.rgb,alpha,CV_RGB2GRAY);
+ }
+ return *this;
+ }
+ Image & Image::alpha_from_cv(cv::Mat &other){
+ //if (other.w!=w||other.h!=h) {
+ // cerr<<"Rotor: cannot merge alpha with different size! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //}
+ //else {
+ if (other.channels()==1) {
+ alpha=other;
+ }
+ else cv::cvtColor(other,alpha,CV_RGB2GRAY);
+ //}
+ return *this;
+ }
+ Image & Image::overlay(const Image &other){
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot overlay images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ //why not??
+ }
+ else {
+ for (int i=0;i<h*w*3;i++) {
+ rgb.data[i]=pixels.overlay[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::min(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot min images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ rgb.data[i]=pixels.min[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::max(const Image &other) {
+ if (other.w!=w||other.h!=h) {
+ cerr<<"Rotor: cannot min images with different sizes! (wanted "<<w<<"x"<<h<<", got "<<other.w<<"x"<<other.h<<")"<<endl;
+ }
+ else {
+ for (int i=0;i<w*h*3;i++){
+ //calculate with tables
+ rgb.data[i]=pixels.max[rgb.data[i]][other.rgb.data[i]];
+ }
+ }
+ return *this;
+ }
+ Image & Image::operator=(const Image &other) {
+ //can be optimised? was trying to use other.data.clone()
+ if (setup(other.w,other.h)){
+ //for (int i=0;i<h*w*3;i++) {
+ // rgb.data[i]=other.rgb.data[i];
+ //}
+ memcpy(rgb.data,other.rgb.data,h*w*3); //saves ~2.4 ms copying a 640x360 image
+
+ }
+ return *this;
+ }
+ //channel rearrangement
+ //RGBAZ - these are channels 0-4
+ //HSB - can also have these virtual channels 5-7
+ //convert channels- int outChannel[5] - {0,1,2,-5,4} - this mapping sends inverted brightness to alpha
+
+ //scalar operations allocate a new image.
+ //maybe this could not be the case if the data is owned by this image?
+ //need to look into auto_ptr
+ Image & Image::operator*=(const double &amount) {
+ //cerr<<"amount: "<<amount<<endl;
+ //rgb*=amount;
+ uint8_t amt=(uint8_t)(amount*255.0);
+ for (int i=0;i<h*w*3;i++) {
+ rgb.data[i]=pixels.multiply[rgb.data[i]][amt];
+ }
+ //again this is faster
+ return *this;
+ }
+ Image & Image::operator+=(const double &amount) {
+ rgb+=(amount*255.0);
+ return *this;
+ }
+ Image & Image::operator-=(const double &amount) {
+ rgb-=(amount*255.0);
+ return *this;
+ }
+ Image & Image::operator/=(const double &amount) {
+ rgb/=amount;
+ return *this;
+ }
+ Image * Image::operator*(const double &amount) {
+ //LEAK!! even if the image is deleted!! opencv??
+ Image *other=new Image(w,h);
+ other->rgb=rgb*amount;
+ return other;
+ }
+ Image * Image::operator+(const double &amount) {
+ uint8_t amt=(uint8_t)(amount*255.0);
+ Image *other=new Image(w,h);
+ other->rgb=rgb+amt;
+ return other;
+ }
+ Image * Image::operator-(const double &amount) {
+ uint8_t amt=(uint8_t)(amount*255.0);
+ Image *other=new Image(w,h);
+ other->rgb=rgb-amt;
+ return other;
+ }
+ Image * Image::operator/(const double &amount) {
+ Image *other=new Image(w,h);
+ other->rgb=rgb/amount;
+ return other;
+ }
+ cv::Mat& Image::get_mipmap(int level){
+ if (mipmaps.find(level)!=mipmaps.end()) return mipmaps[level];
+ //levels start at 1
+ int nw=std::max(1.0,w/pow(2,level));
+ int nh=std::max(1.0,h/pow(2,level));
+ cv::Mat mip;;
+ cv::resize(rgb,mip,cv::Size(nw,nh),0,0,cv::INTER_AREA );
+ mipmaps[level]=mip;
+ return mipmaps[level];
+
+ }
+}
diff --git a/NT/src/cvimage.h b/NT/src/cvimage.h
new file mode 100644
index 0000000..d3f824c
--- /dev/null
+++ b/NT/src/cvimage.h
@@ -0,0 +1,302 @@
+#ifndef ROTOR_CVIMAGE
+#define ROTOR_CVIMAGE
+
+#include <math.h>
+#include <cv.h>
+#include <highgui.h>
+#include <unordered_map>
+
+//converting to use a cv image...
+//cv::Mat supports most of what we want here
+//need to think
+//http://answers.opencv.org/question/8202/using-external-image-data-in-a-cvmat/
+
+//all access to the image is presently through a pointer to the data
+//cv::Mat supports this
+
+//how will copying work?
+//Rotor::Image will contain a cv::Mat object which may own its data or inherit it
+//cv::Mat should take care of reference counting
+
+//can cv::Mat
+
+namespace Rotor {
+ class pixeltables{
+ //handy pixel arithmetic lookup tables as nested arrays
+ //so - pixels.add[0x78][0x66]; will give the precalculated result of adding with saturation
+ // pixels.mono_weights[0][0x100]; will give the red component to convert to mono
+ public:
+ pixeltables(){
+ add=new uint8_t*[256];
+ multiply=new uint8_t*[256];
+ overlay=new uint8_t*[256];
+ min=new uint8_t*[256];
+ max=new uint8_t*[256];
+ for (int i=0;i<256;i++){
+ add[i]=new uint8_t[256];
+ multiply[i]=new uint8_t[256];
+ overlay[i]=new uint8_t[256];
+ min[i]=new uint8_t[256];
+ max[i]=new uint8_t[256];
+ for (int j=0;j<256;j++){
+ add[i][j]=(uint8_t)std::min(i+j,0xFF);
+ multiply[i][j]=(uint8_t)(((double)i)*(((double)j)/255.0));
+ overlay[i][j]=j<128?(uint8_t)((i*j)>>7):255-(((0xFF-i)*(0xFF-j))>>7);
+ min[i][j]=j<i?j:i;
+ max[i][j]=j>i?j:i;
+ }
+ }
+ mono_weights=new uint8_t*[3];
+ double weights[3]={0.2989, 0.5870, 0.1140};
+ for (int i=0;i<3;i++) {
+ mono_weights[i]=new uint8_t[256];
+ for (int j=0;j<256;j++){
+ mono_weights[i][j]=(uint8_t)(((double)j)*weights[i]);
+ }
+ }
+ }
+ virtual ~pixeltables(){
+ for (int i=0;i<256;i++){
+ delete[] add[i];
+ delete[] multiply[i];
+ delete[] overlay[i];
+ delete[] min[i];
+ delete[] max[i];
+ }
+ delete[] add;
+ delete[] multiply;
+ delete[] overlay;
+ delete[] min;
+ delete[] max;
+ for (int i=0;i<3;i++) {
+ delete[] mono_weights[i];
+ }
+ delete[] mono_weights;
+ }
+ uint8_t **add;
+ uint8_t **multiply;
+ uint8_t **overlay;
+ uint8_t **mono_weights;
+ uint8_t **max;
+ uint8_t **min;
+ };
+ static pixeltables pixels;
+ class Image{
+ //transform should be a method of image
+ public:
+ Image(){
+ zero();
+ };
+ Image(int _w,int _h){
+ zero();
+ setup(_w,_h);
+ };
+ Image(const Image &mom) {
+ // copy constructor
+ zero();
+ rgb=mom.rgb.clone();
+ w=mom.w;
+ h=mom.h;
+ RGBdata=rgb.data; //can move to use the bare pointer eventually
+ ownsRGBdata=false; //always just deallocate cv::Mat from stack
+ }
+ ~Image() {
+ free();
+ };
+ void free(){
+ if (RGBdata&&ownsRGBdata) delete[] RGBdata;
+ if (Adata&&ownsAdata) delete[] Adata;
+ if (Zdata&&ownsZdata) delete[] Zdata;
+ rgb.release();
+ alpha.release();
+ zero();
+ }
+ void zero(){
+ RGBdata=nullptr;
+ Adata=nullptr;
+ Zdata=nullptr;
+ w=0;
+ h=0;
+ ownsRGBdata=ownsAdata=ownsZdata=false;
+ }
+ //space out to 32 bit RGB padding for cairo
+ void convert24();
+ void convert32();
+ int getStride(){
+ return w*3;
+ }
+ bool clear(){
+ rgb.setTo(0);
+ return true;
+ };
+ bool setup(int _w,int _h){ //set up with internal data
+ if (_w==0||_h==0||(_w*_h*3)>10000000) {
+ //some kind of elusive thing that shows up only in non debug builds
+ std::cerr<<"Error! cvimage: request to set up image at "<<_w<<"x"<<_h<<std::endl;
+ return false;
+ }
+ if ((w!=_w)|(h!=_h)){
+ free();
+ rgb.create(_h,_w,CV_8UC3);
+ RGBdata=rgb.data; //can move to use the bare pointer eventually
+ ownsRGBdata=false; //will not be necessary
+ w=_w;
+ h=_h;
+ }
+ return true;
+ /*
+ if (w!=_w||h!=_h||!ownsRGBdata||!ownsAdata||!ownsZdata){
+ free();
+ w=_w;
+ h=_h;
+ RGBdata=new uint8_t[w*h*3];
+ Adata=new uint8_t[w*h];
+ Zdata=new uint16_t[w*h];
+ ownsRGBdata=ownsAdata=ownsZdata=true;
+ return true;
+ }
+ else return false;
+ */
+ }
+ bool read_file(std::string &filename){
+ rgb=cv::imread(filename,CV_LOAD_IMAGE_COLOR);
+ if (rgb.empty()) return false;
+ RGBdata=rgb.data;
+ ownsRGBdata=false;
+ w=rgb.rows;
+ h=rgb.cols;
+ return true;
+ }
+ bool setup_fromRGB(int _w,int _h,uint8_t *pRGBdata,int linepadding=0){
+ //here the data belongs to libavcodec or other
+ //could move to using cv::Mat there also and just passing cv:Mat over
+
+ //linepadding causes crash, but it doesn't seem to be necessary
+ // Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
+ rgb=cv::Mat(_h,_w,CV_8UC3,pRGBdata,(_w*3)+linepadding);
+ //std::cerr<<"created cv::Mat with step= "<<rgb.step<<",should be "<<((_w*3)+linepadding)<<std::endl;
+
+ RGBdata=rgb.data; //can move to use the bare pointer eventually
+ ownsRGBdata=false; //will not be necessary
+ w=_w;
+ h=_h;
+ return true;
+ /*
+ if (w!=_w||h!=_h||ownsRGBdata||!ownsAdata||!ownsZdata){
+ free();
+ w=_w;
+ h=_h;
+ RGBdata=pRGBdata;
+ Adata=new uint8_t[w*h];
+ Zdata=new uint16_t[w*h];
+ ownsRGBdata=false;
+ ownsAdata=ownsZdata=true;
+ return true;
+ }
+ return false;
+ */
+ }
+ bool setup_fromMat(cv::Mat& othermat){
+ //here the mat belongs to another object
+ if (othermat.channels()==1) {
+ cv::cvtColor(othermat, rgb, CV_GRAY2RGB);
+ }
+ else rgb=othermat;
+ RGBdata=rgb.data; //can move to use the bare pointer eventually
+ ownsRGBdata=false; //will not be necessary
+ w=rgb.rows;
+ h=rgb.cols;
+ return true;
+ }
+ //leaks
+ Image* clone(){
+ Image *t=new Image();
+ t->rgb=rgb.clone();
+ t->w=w;
+ t->h=h;
+ t->RGBdata=t->rgb.data; //can move to use the bare pointer eventually
+ t->ownsRGBdata=false; //always just deallocate cv::Mat from stack
+ /*
+ for (int i=0;i<w*h*3;i++) {
+ t->RGBdata[i]=RGBdata[i];
+ }
+ */
+ return t;
+ }
+ void crop(int _w,int _h){ //change borders, crop/ extend, centred
+ cv::Mat source;
+ int X,Y,W,H;
+ //do crop part
+ if ( _w<w||_h<h){
+ //create crop rectangle xywh
+ X=Y=0;
+ W=w;
+ H=h;
+ if (_w<w){
+ W=_w;
+ X=(w-_w)/2;
+ w=_w;
+ }
+ if (_h<h){
+ H=_h;
+ Y=(h-_h)/2;
+ h=_h;
+ }
+ cv::Mat cropped;
+ CvRect r=cvRect(X,Y,W,H) ;
+ rgb(r).copyTo(source);
+ }
+ else source=rgb;
+ copyMakeBorder(source,rgb,(_h-h)/2,(_h-h)/2,(_w-w)/2,(_w-w)/2,cv::BORDER_REPLICATE);
+ w=rgb.rows;
+ h=rgb.cols;
+ }
+ void resize(int _w,int _h){
+ cv::resize(rgb,rgb,cv::Size(_w,_h),0,0,cv::INTER_LINEAR );
+ w=rgb.rows;
+ h=rgb.cols;
+ }
+ Image & operator=(const Image &other);
+ //believe these still work, don't know if these optimisations are better than opencvs..
+ Image & operator+=(const Image &other);
+ Image & operator*=(const Image &other);
+ Image & operator^=(const Image &other);
+ Image & alpha_blend(const Image &other);
+ Image & alpha_blend_cv(const Image &other);
+ Image & alpha_merge(const Image &other);
+ Image & alpha_from_cv(cv::Mat &other);
+ Image & add_wrap(const Image &other);
+ Image & divide_wrap(const Image &other);
+ Image & overlay(const Image &other);
+ Image & min(const Image &other);
+ Image & max(const Image &other);
+ Image & operator*=(const double &amount);
+ Image & operator+=(const double &amount);
+ Image & operator-=(const double &amount);
+ Image & operator/=(const double &amount);
+ Image * operator*(const double &amount);
+ Image * operator+(const double &amount);
+ Image * operator-(const double &amount);
+ Image * operator/(const double &amount);
+ uint8_t *RGBdata;
+ uint8_t *Adata;
+ uint16_t *Zdata;
+ int h,w;
+ bool ownsRGBdata,ownsAdata,ownsZdata; //better done through auto_ptr?
+
+ //making the interface for mip mapping
+ //should reduce in powers of 2
+ //
+
+ cv::Mat rgb;
+ cv::Mat alpha;
+
+ //store a library of mipmaps
+ std::unordered_map<int,cv::Mat> mipmaps;
+
+ cv::Mat& get_mipmap(int level);
+
+ };
+}
+
+#endif
diff --git a/NT/src/nodes.h b/NT/src/nodes.h
index 6bfb6f5..f6a8a0d 100644
--- a/NT/src/nodes.h
+++ b/NT/src/nodes.h
@@ -7,11 +7,27 @@
using namespace std;
namespace Rotor{
- class Double_node: public Node_type<double> {
- public:
- Double_node(){};
- };
- class Time: public Double_node {
+ typedef Node_type<double> Number_node;
+ typedef Node_type<string> String_node;
+ typedef Node_type<Image> Image_node;
+
+ typedef Variable_type<double> Number_inlet;
+ typedef Variable_type<string> String_inlet;
+ typedef Variable_type<Image> Image_inlet;
+
+ typedef Variable_array_type<double> Number_array;
+ typedef Variable_array_type<string> String_array;
+ typedef Variable_array_type<Image> Image_array;
+
+
+ //colour node could be an alias of vec3f node and they could be interchangeable?
+ //image node
+ //vector_image node: supporting scalable images
+ //image cache types?
+ //timeline type could get around the big problem with needing to find keyframes
+
+ //basic test nodes
+ class Time: public Number_node {
public:
Time(){
type="time";
@@ -24,12 +40,11 @@ namespace Rotor{
init(settings);
};
const double &get_output(const Frame_parameters &frame){
- value=frame.time;
- return value;
+ result=frame.time;
+ return result;
}
Time* clone(Json::Value &_settings) { return new Time(_settings);};
private:
- double value;
};
class Multiply: public Double_node {
public:
@@ -58,12 +73,7 @@ namespace Rotor{
}
Multiply* clone(Json::Value &_settings) { return new Multiply(_settings);};
private:
- Variable_array_type<double> *factors;
- double result;
- };
- class String_node: public Node_type<string> {
- public:
- String_node(){};
+ Double_array *factors;
};
class Print: public String_node {
public:
@@ -86,8 +96,7 @@ namespace Rotor{
}
Print* clone(Json::Value &_settings) { return new Print(_settings);};
private:
- Variable_type<double> *inlet;
- std::string result;
+ Double_inlet *inlet;
};
}
diff --git a/NT/src/nodes_audio_analysis.h b/NT/src/nodes_audio_analysis.h
index 00f4303..6523c71 100644
--- a/NT/src/nodes_audio_analysis.h
+++ b/NT/src/nodes_audio_analysis.h
@@ -76,18 +76,18 @@ namespace Rotor {
if (i->second.values.size()) v1=i->second.values[0];
switch (mode->get()){
case VAMPHOST_Timeline:
- value= (((frame.time-lk-lk)/(uk-lk))+ln);
+ result= (((frame.time-lk-lk)/(uk-lk))+ln);
case VAMPHOST_Timesteps:
- value= (double)ln;
+ result= (double)ln;
case VAMPHOST_Valueline:
- value= ((frame.time-lk)/(uk-lk))+v1; //((((time.time-lk)/(uk-lk))*(v2-v1))+v1);
+ result= ((frame.time-lk)/(uk-lk))+v1; //((((time.time-lk)/(uk-lk))*(v2-v1))+v1);
case VAMPHOST_Values:
- value= v1;
+ result= v1;
}
//}
//return (--features.end())->second.values[0];
}
- return value;
+ return result;
}
string get_features();
void print_summary(){
diff --git a/NT/src/nodes_source.h b/NT/src/nodes_source.h
new file mode 100644
index 0000000..08da163
--- /dev/null
+++ b/NT/src/nodes_source.h
@@ -0,0 +1,77 @@
+#ifndef ROTOR_NODES_SOURCE
+#define ROTOR_NODES_SOURCE
+
+#include "rotor.h"
+
+namespace Rotor {
+ class Signal_colour: public Image_node {
+ public:
+ Signal_colour(){
+ selector=create_inlet<double>("selector");
+ create_attribute("palette","palette list of web colours","Colour palette","000000");
+ title="Signal colour";
+ description="Cycles through a palette of background colours according to selector signal";
+ NODEID="a2183fe0-2d09-11e3-9a64-538ee2cf40bc";
+ };
+ Signal_colour(map<string,string> &settings):Signal_colour() {
+ base_settings(settings);
+ for (uint32_t i=0;i<attributes["palette"]->value.size()/6;i++){
+ palette.push_back(Colour(attributes["palette"]->value.substr(i*6,6)));
+ }
+ prevcol=-1;
+ };
+ ~Signal_colour(){};
+ Image *output(const Frame_spec &frame){
+ if (palette.size()) {
+ int col=((int)inputs[0]->get((Time_spec)frame))%palette.size();
+ //if (col!=prevcol) cerr<<"colour now "<<palette[col].r<<","<<palette[col].g<<","<<palette[col].b<<endl;
+ //if (col!=prevcol){ //how about when starting a new render?
+ for (int i=0;i<image.w*image.h;i++){
+ image.RGBdata[i*3]=palette[col].r;
+ image.RGBdata[i*3+1]=palette[col].g;
+ image.RGBdata[i*3+2]=palette[col].b;
+ }
+ prevcol=col;
+ //}
+ return &image;
+ }
+ return nullptr;
+ }
+ Signal_colour* clone(map<string,string> &_settings) { return new Signal_colour(_settings);};
+ private:
+ vector<Colour> palette;
+ int prevcol;
+ Number_inlet *selector;
+ };
+ class Signal_greyscale: public Image_node {
+ //Draws signal bars in greyscale
+ public:
+ Signal_greyscale(){
+ create_signal_input("Signal","Signal input");
+ title="Signal greyscale";
+ description="Renders signal level as greyscale background";
+ NODEID="ae91b8a0-2d09-11e3-aa7d-8b7f1ef1a439";
+ };
+ Signal_greyscale(map<string,string> &settings):Signal_greyscale() {
+ base_settings(settings);
+ prevcol=-1;
+ };
+ ~Signal_greyscale(){};
+ Image *output(const Frame_spec &frame){
+ uint8_t col=((uint8_t)(inputs[0]->get((Time_spec)frame)*255.0));
+ if (col!=prevcol){ //how about when starting a new render?
+ //for (int i=0;i<image.w*image.h*3;i++){
+ // image.RGBdata[i]=col;
+ //}
+ prevcol=col;
+ memset(image.RGBdata,col,image.w*image.h*3);
+ }
+ return &image;
+
+ }
+ Signal_greyscale* clone(map<string,string> &_settings) { return new Signal_greyscale(_settings);};
+ private:
+ uint8_t prevcol;
+ };
+}
+#endif
diff --git a/NT/src/rotor.h b/NT/src/rotor.h
index 485ec8c..2ddf3ee 100644
--- a/NT/src/rotor.h
+++ b/NT/src/rotor.h
@@ -28,6 +28,7 @@ seperate framework? ie in Python- load server- send http commands
#include "xmlIO.h"
#include "libavwrapper.h"
+#include "cvimage.h"
#include "Poco/Logger.h"
#include "Poco/Channel.h"
@@ -330,7 +331,7 @@ namespace Rotor {
template <class NT> class Node_type : public Node {
public:
- virtual const NT& get_output(const Frame_parameters &frame){return value;};
+ virtual const NT& get_output(const Frame_parameters &frame){return result;};
void init(Json::Value settings){
if (!settings["vars"].empty()){
for ( uint32_t i = 0; i < settings["vars"].size(); ++i ) {
@@ -357,7 +358,7 @@ namespace Rotor {
return (dynamic_cast<Variable_array_type<IT>*>(vars[name]));
}
protected:
- NT value; //every node has an internal value so it can return a reference
+ NT result; //internal value is returned as a reference
};
}