mirror of
https://github.com/vale981/openAV-Luppp
synced 2025-03-05 17:11:40 -05:00
-Refactored Worker into DiskReader and DiskWriter classes. Refactored ClipSelector into hxx / cxx pair
This commit is contained in:
parent
f37c87e48a
commit
13b5853034
13 changed files with 569 additions and 544 deletions
|
@ -6,5 +6,5 @@ CFLAGS += -g -Wall -march=native -msse -mfpmath=sse -ffast-math
|
|||
INCLUDES += `pkg-config --cflags jack sndfile cairomm-1.0 ntk ntk_images`
|
||||
|
||||
: foreach *.cxx observer/*.cxx save/*.cxx cjson/*.c dsp/*.cxx controller/*.cxx \
|
||||
|> g++ $(CFLAGS) -c %f $(INCLUDES) -o %o |> %B.o
|
||||
avtk/*.cxx |> g++ $(CFLAGS) -c %f $(INCLUDES) -o %o |> %B.o
|
||||
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
#define LUPPP_AUDIOBUFFER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/// AudioBuffer stores float samples in a big vector.
|
||||
class AudioBuffer
|
||||
{
|
||||
|
@ -36,9 +40,12 @@ class AudioBuffer
|
|||
void setName(const char* n)
|
||||
{
|
||||
if ( strlen(n) > 19 )
|
||||
{
|
||||
#ifdef DEBUG_BUFFER
|
||||
printf("AudioBuffer setName too long!\n" );
|
||||
#endif return;
|
||||
cout << "AudioBuffer setName too long!" << endl;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy( name, n, sizeof(char)* 20 );
|
||||
}
|
||||
|
@ -51,7 +58,7 @@ class AudioBuffer
|
|||
void setBeats(int b)
|
||||
{
|
||||
#ifdef DEBUG_BUFFER
|
||||
printf("AudioBuffer now has %i beats\n", b );
|
||||
cout << "AudioBuffer now has " << b << " beats\n" << endl;
|
||||
#endif
|
||||
numBeats = b;
|
||||
}
|
||||
|
|
|
@ -1,464 +0,0 @@
|
|||
/*
|
||||
* Author: Harry van Haaren 2013
|
||||
* harryhaaren@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AVTK_CLIP_SELECTOR_H
|
||||
#define AVTK_CLIP_SELECTOR_H
|
||||
|
||||
#include <FL/Fl_Button.H>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "../gridlogic.hxx"
|
||||
|
||||
#include "../worker.hxx"
|
||||
#include "../looper.hxx"
|
||||
#include "../audiobuffer.hxx"
|
||||
#include "../eventhandler.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern void luppp_tooltip(std::string s);
|
||||
|
||||
namespace Avtk
|
||||
{
|
||||
|
||||
class ClipState
|
||||
{
|
||||
public:
|
||||
ClipState() :
|
||||
state(GridLogic::STATE_EMPTY),
|
||||
name("")
|
||||
{}
|
||||
|
||||
void setName(std::string n)
|
||||
{
|
||||
name = n;
|
||||
}
|
||||
|
||||
void setState(GridLogic::State s)
|
||||
{
|
||||
state = s;
|
||||
}
|
||||
|
||||
std::string getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
GridLogic::State getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
private:
|
||||
GridLogic::State state;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class ClipSelector : public Fl_Button
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
ClipSelector(int _x, int _y, int _w, int _h, const char *_label, bool master = false):
|
||||
Fl_Button(_x, _y, _w, _h, _label)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
w = _w;
|
||||
h = _h;
|
||||
|
||||
label = _label;
|
||||
_master = master;
|
||||
|
||||
if ( _master )
|
||||
{
|
||||
for(int i = 0; i < 10; i++ )
|
||||
{
|
||||
stringstream s;
|
||||
s << i + 1;
|
||||
clips[i].setName( s.str() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
highlight = false;
|
||||
mouseOver = false;
|
||||
}
|
||||
|
||||
|
||||
int ID;
|
||||
|
||||
static const int numClips = 10;
|
||||
ClipState clips[numClips];
|
||||
|
||||
bool _master;
|
||||
bool mouseOver;
|
||||
bool highlight;
|
||||
int x, y, w, h;
|
||||
const char* label;
|
||||
|
||||
void setID( int id )
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
|
||||
/** converts the Looper::State into the UI represnted ClipSelector state.
|
||||
* It puts some of the data into clips[], and stores unique state into the class.
|
||||
**/
|
||||
void setState( int clipNum, GridLogic::State s )
|
||||
{
|
||||
#ifdef DEBUG_CLIP
|
||||
cout << "setState clipNum = " << clipNum << " state = " << s << endl;
|
||||
#endif
|
||||
switch(s)
|
||||
{
|
||||
case GridLogic::STATE_RECORDING:
|
||||
case GridLogic::STATE_STOPPED:
|
||||
case GridLogic::STATE_EMPTY:
|
||||
case GridLogic::STATE_PLAYING:
|
||||
case GridLogic::STATE_PLAY_QUEUED:
|
||||
case GridLogic::STATE_RECORD_QUEUED:
|
||||
case GridLogic::STATE_STOP_QUEUED:
|
||||
default: break;
|
||||
}
|
||||
|
||||
clips[clipNum].setState( s );
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
std::string clipName(int clip)
|
||||
{
|
||||
return clips[clip].getName();
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
if (damage() & FL_DAMAGE_ALL)
|
||||
{
|
||||
if ( value() )
|
||||
{
|
||||
highlight = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
highlight = false;
|
||||
}
|
||||
|
||||
cairo_t *cr = Fl::cairo_cc();
|
||||
|
||||
cairo_save( cr );
|
||||
|
||||
int clipWidth = w - 2;
|
||||
int clipHeight = (h / numClips);
|
||||
|
||||
int drawY = y + 1;
|
||||
for( int i = 0; i < numClips; i++) // draw each clip
|
||||
{
|
||||
cairo_rectangle( cr, x+2, drawY, clipWidth-1, clipHeight - 4 );
|
||||
cairo_set_source_rgba(cr, 66 / 255.f, 66 / 255.f , 66 / 255.f, 0.4);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_rectangle( cr, x+2, drawY, clipHeight-4, clipHeight - 4 );
|
||||
|
||||
if ( clips[i].getState() == GridLogic::STATE_RECORDING )
|
||||
{
|
||||
cairo_set_source_rgba(cr, 1.f, 0 / 255.f , 0 / 255.f, 1.f);
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_PLAYING )
|
||||
{
|
||||
cairo_set_source_rgba(cr, 0.0, 1.0, 0, 1.f );
|
||||
cairo_fill(cr);
|
||||
cairo_move_to( cr, x+10, drawY+8 );
|
||||
cairo_line_to( cr, x+19, drawY+13 );
|
||||
cairo_line_to( cr, x+10, drawY+18 );
|
||||
cairo_close_path(cr);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_PLAY_QUEUED )
|
||||
{
|
||||
cairo_set_source_rgba( cr, 0 / 255.f, 153 / 255.f , 255 / 255.f , 1 );
|
||||
cairo_fill(cr);
|
||||
cairo_move_to( cr, x+10, drawY+8 );
|
||||
cairo_line_to( cr, x+19, drawY+13 );
|
||||
cairo_line_to( cr, x+10, drawY+18 );
|
||||
cairo_close_path(cr);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_STOP_QUEUED )
|
||||
{
|
||||
cairo_set_source_rgba( cr, 0 / 255.f, 153 / 255.f , 255 / 255.f , 1 );
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_set_line_width(cr, 2.2f);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_RECORD_QUEUED )
|
||||
{
|
||||
cairo_set_source_rgba( cr, 0 / 255.f, 153 / 255.f , 255 / 255.f , 1 );
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_STOPPED )
|
||||
{
|
||||
cairo_set_source_rgba(cr, 1.0, 0.6, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_set_line_width(cr, 2.2f);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_source_rgba(cr, 66 / 255.f, 66 / 255.f , 66 / 255.f, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
|
||||
cairo_rectangle( cr, x+2, drawY, clipWidth -1, clipHeight - 3 );
|
||||
|
||||
float alpha = 1;
|
||||
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, alpha);
|
||||
cairo_set_line_width( cr, 1.3);
|
||||
cairo_move_to( cr, x+clipHeight-1, drawY );
|
||||
cairo_line_to( cr, x+clipHeight-1, drawY + clipHeight - 2);
|
||||
cairo_stroke(cr);
|
||||
|
||||
// clip name
|
||||
cairo_move_to( cr, x + clipHeight + 10, drawY + 17 );
|
||||
cairo_set_source_rgba( cr, 255 / 255.f, 255 / 255.f , 255 / 255.f , 0.9 );
|
||||
cairo_set_font_size( cr, 11 );
|
||||
cairo_show_text( cr, clips[i].getName().c_str() );
|
||||
|
||||
drawY += clipHeight;
|
||||
}
|
||||
|
||||
cairo_restore( cr );
|
||||
|
||||
//draw_label();
|
||||
}
|
||||
}
|
||||
|
||||
void resize(int X, int Y, int W, int H)
|
||||
{
|
||||
Fl_Widget::resize(X,Y,W,H);
|
||||
x = X;
|
||||
y = Y;
|
||||
w = W;
|
||||
h = H;
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int handle(int event)
|
||||
{
|
||||
switch(event) {
|
||||
case FL_ACTIVATE:
|
||||
{
|
||||
}
|
||||
case FL_DEACTIVATE:
|
||||
{
|
||||
}
|
||||
return 1;
|
||||
case FL_PUSH:
|
||||
highlight = 1;
|
||||
{
|
||||
// calculate the clicked clip number
|
||||
int clipHeight = (h / numClips);
|
||||
int clipNum = ( (Fl::event_y() ) - y ) / clipHeight;
|
||||
if (clipNum >= numClips)
|
||||
clipNum = numClips -1; // fix for clicking the lowest pixel
|
||||
|
||||
// handle right clicks: popup menu
|
||||
if ( Fl::event_state(FL_BUTTON3) )
|
||||
{
|
||||
if ( _master )
|
||||
{
|
||||
// ask new name for clip, then
|
||||
const char* name = fl_input( "Scene name: ", clips[clipNum].getName().c_str() );
|
||||
if ( name )
|
||||
clips[clipNum].setName( name );
|
||||
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Fl_Menu_Item rclick_menu[] =
|
||||
{
|
||||
{ "Load" },
|
||||
{ "Bars", 0, 0, 0, FL_SUBMENU },
|
||||
{"1 "},
|
||||
{"2"},
|
||||
{"4"},
|
||||
{"8"},
|
||||
{"16"},
|
||||
{"32"},
|
||||
{"64"},
|
||||
{0},
|
||||
//{ "Record" },
|
||||
{ "Use as tempo" },
|
||||
{ "Rename" },
|
||||
{ 0 }
|
||||
};
|
||||
Fl_Menu_Item *m = (Fl_Menu_Item*) rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
|
||||
if ( !m )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if ( strcmp(m->label(), "Load") == 0 )
|
||||
{
|
||||
// FIXME: refactor
|
||||
string path;
|
||||
Fl_Native_File_Chooser fnfc;
|
||||
fnfc.title("Pick a file");
|
||||
fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
//fnfc.filter("Wav\t*.wav");
|
||||
fnfc.directory( getenv("HOME") ); // default directory to use
|
||||
// Show native chooser
|
||||
switch ( fnfc.show() ) {
|
||||
case -1: printf("ERROR: %s\n", fnfc.errmsg()); break; // ERROR
|
||||
case 1: printf("CANCEL\n"); break; // CANCEL
|
||||
default: printf("Loading directory: %s\n", fnfc.filename());
|
||||
// update path and load it
|
||||
path = fnfc.filename();
|
||||
break;
|
||||
}
|
||||
|
||||
if ( strcmp( path.c_str(), "" ) == 0 )
|
||||
return 0;
|
||||
|
||||
AudioBuffer* ab = Worker::loadSample( path );
|
||||
EventLooperLoad e = EventLooperLoad( ID, clipNum, ab );
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
else if ( strcmp(m->label(), "1") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,1);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "2") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,2);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "4") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,4);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "8") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,8);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "16") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,16);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "32") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,32);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "64") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,64);
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
else if ( strcmp(m->label(), "Use as tempo") == 0 )
|
||||
{
|
||||
EventLooperUseAsTempo e (ID, clipNum);
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
else if ( strcmp(m->label(), "Rename") == 0 )
|
||||
{
|
||||
const char* name = fl_input( "Scene name: ", clips[clipNum].getName().c_str() );
|
||||
if ( name )
|
||||
clips[clipNum].setName( name );
|
||||
}
|
||||
else if ( strcmp(m->label(), "Record") == 0 )
|
||||
{
|
||||
/*
|
||||
//recordingClip = clipNum;
|
||||
EventLooperState e = EventLooperState( ID, clipNum, Looper::STATE_RECORD_QUEUED);
|
||||
writeToDspRingbuffer( &e );
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _master )
|
||||
{
|
||||
EventGridLaunchScene e( clipNum );
|
||||
writeToDspRingbuffer( &e );
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// write "pressed" event for this track,scene
|
||||
EventGridEvent e( ID, clipNum, true );
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
do_callback();
|
||||
return 1;
|
||||
case FL_DRAG:
|
||||
{
|
||||
int t = Fl::event_inside(this);
|
||||
if (t != highlight)
|
||||
{
|
||||
highlight = t;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
case FL_ENTER:
|
||||
mouseOver = true;
|
||||
// push help string to UI tooltip area
|
||||
luppp_tooltip( "Clip selector" );
|
||||
|
||||
redraw();
|
||||
return 1;
|
||||
case FL_LEAVE:
|
||||
mouseOver = false;
|
||||
redraw();
|
||||
return 1;
|
||||
case FL_RELEASE:
|
||||
return 1;
|
||||
case FL_SHORTCUT:
|
||||
if ( test_shortcut() )
|
||||
{
|
||||
do_callback();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return Fl_Widget::handle(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // Avtk
|
||||
|
||||
#endif // AVTK_CLIP_SELECTOR_H
|
||||
|
378
src/avtk/clipselector.cxx
Normal file
378
src/avtk/clipselector.cxx
Normal file
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* Author: Harry van Haaren 2013
|
||||
* harryhaaren@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "clipselector.hxx"
|
||||
|
||||
#include "../gui.hxx"
|
||||
|
||||
extern Gui* gui;
|
||||
|
||||
namespace Avtk
|
||||
{
|
||||
|
||||
ClipSelector::ClipSelector( int _x, int _y, int _w, int _h,
|
||||
const char *_label, bool master ) :
|
||||
Fl_Button(_x, _y, _w, _h, _label)
|
||||
{
|
||||
x = _x;
|
||||
y = _y;
|
||||
w = _w;
|
||||
h = _h;
|
||||
|
||||
label = _label;
|
||||
_master = master;
|
||||
|
||||
if ( _master )
|
||||
{
|
||||
for(int i = 0; i < 10; i++ )
|
||||
{
|
||||
stringstream s;
|
||||
s << i + 1;
|
||||
clips[i].setName( s.str() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
highlight = false;
|
||||
mouseOver = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ClipSelector::setID( int id )
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** converts the Looper::State into the UI represnted ClipSelector state.
|
||||
* It puts some of the data into clips[], and stores unique state into the class.
|
||||
**/
|
||||
void ClipSelector::setState( int clipNum, GridLogic::State s )
|
||||
{
|
||||
#ifdef DEBUG_CLIP
|
||||
cout << "setState clipNum = " << clipNum << " state = " << s << endl;
|
||||
#endif
|
||||
switch(s)
|
||||
{
|
||||
case GridLogic::STATE_RECORDING:
|
||||
case GridLogic::STATE_STOPPED:
|
||||
case GridLogic::STATE_EMPTY:
|
||||
case GridLogic::STATE_PLAYING:
|
||||
case GridLogic::STATE_PLAY_QUEUED:
|
||||
case GridLogic::STATE_RECORD_QUEUED:
|
||||
case GridLogic::STATE_STOP_QUEUED:
|
||||
default: break;
|
||||
}
|
||||
|
||||
clips[clipNum].setState( s );
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
std::string ClipSelector::clipName(int clip)
|
||||
{
|
||||
return clips[clip].getName();
|
||||
}
|
||||
|
||||
void ClipSelector::draw()
|
||||
{
|
||||
if (damage() & FL_DAMAGE_ALL)
|
||||
{
|
||||
if ( value() )
|
||||
{
|
||||
highlight = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
highlight = false;
|
||||
}
|
||||
|
||||
cairo_t *cr = Fl::cairo_cc();
|
||||
|
||||
cairo_save( cr );
|
||||
|
||||
int clipWidth = w - 2;
|
||||
int clipHeight = (h / numClips);
|
||||
|
||||
int drawY = y + 1;
|
||||
for( int i = 0; i < numClips; i++) // draw each clip
|
||||
{
|
||||
cairo_rectangle( cr, x+2, drawY, clipWidth-1, clipHeight - 4 );
|
||||
cairo_set_source_rgba(cr, 66 / 255.f, 66 / 255.f , 66 / 255.f, 0.4);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_rectangle( cr, x+2, drawY, clipHeight-4, clipHeight - 4 );
|
||||
|
||||
if ( clips[i].getState() == GridLogic::STATE_RECORDING )
|
||||
{
|
||||
cairo_set_source_rgba(cr, 1.f, 0 / 255.f , 0 / 255.f, 1.f);
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_PLAYING )
|
||||
{
|
||||
cairo_set_source_rgba(cr, 0.0, 1.0, 0, 1.f );
|
||||
cairo_fill(cr);
|
||||
cairo_move_to( cr, x+10, drawY+8 );
|
||||
cairo_line_to( cr, x+19, drawY+13 );
|
||||
cairo_line_to( cr, x+10, drawY+18 );
|
||||
cairo_close_path(cr);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_PLAY_QUEUED )
|
||||
{
|
||||
cairo_set_source_rgba( cr, 0 / 255.f, 153 / 255.f , 255 / 255.f , 1 );
|
||||
cairo_fill(cr);
|
||||
cairo_move_to( cr, x+10, drawY+8 );
|
||||
cairo_line_to( cr, x+19, drawY+13 );
|
||||
cairo_line_to( cr, x+10, drawY+18 );
|
||||
cairo_close_path(cr);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_STOP_QUEUED )
|
||||
{
|
||||
cairo_set_source_rgba( cr, 0 / 255.f, 153 / 255.f , 255 / 255.f , 1 );
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_set_line_width(cr, 2.2f);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_RECORD_QUEUED )
|
||||
{
|
||||
cairo_set_source_rgba( cr, 0 / 255.f, 153 / 255.f , 255 / 255.f , 1 );
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
else if ( clips[i].getState() == GridLogic::STATE_STOPPED )
|
||||
{
|
||||
cairo_set_source_rgba(cr, 1.0, 0.6, 0, 1.f);
|
||||
cairo_fill(cr);
|
||||
cairo_arc( cr, x+14, drawY+13, 4.3, 0, 6.29 );
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1.f);
|
||||
cairo_set_line_width(cr, 2.2f);
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
cairo_set_source_rgba(cr, 66 / 255.f, 66 / 255.f , 66 / 255.f, 1.f);
|
||||
cairo_fill(cr);
|
||||
}
|
||||
|
||||
cairo_rectangle( cr, x+2, drawY, clipWidth -1, clipHeight - 3 );
|
||||
|
||||
float alpha = 1;
|
||||
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, alpha);
|
||||
cairo_set_line_width( cr, 1.3);
|
||||
cairo_move_to( cr, x+clipHeight-1, drawY );
|
||||
cairo_line_to( cr, x+clipHeight-1, drawY + clipHeight - 2);
|
||||
cairo_stroke(cr);
|
||||
|
||||
// clip name
|
||||
cairo_move_to( cr, x + clipHeight + 10, drawY + 17 );
|
||||
cairo_set_source_rgba( cr, 255 / 255.f, 255 / 255.f , 255 / 255.f , 0.9 );
|
||||
cairo_set_font_size( cr, 11 );
|
||||
cairo_show_text( cr, clips[i].getName().c_str() );
|
||||
|
||||
drawY += clipHeight;
|
||||
}
|
||||
|
||||
cairo_restore( cr );
|
||||
|
||||
//draw_label();
|
||||
}
|
||||
}
|
||||
|
||||
void ClipSelector::resize(int X, int Y, int W, int H)
|
||||
{
|
||||
Fl_Widget::resize(X,Y,W,H);
|
||||
x = X;
|
||||
y = Y;
|
||||
w = W;
|
||||
h = H;
|
||||
redraw();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ClipSelector::handle(int event)
|
||||
{
|
||||
switch(event) {
|
||||
case FL_ACTIVATE:
|
||||
{
|
||||
}
|
||||
case FL_DEACTIVATE:
|
||||
{
|
||||
}
|
||||
return 1;
|
||||
case FL_PUSH:
|
||||
highlight = 1;
|
||||
{
|
||||
// calculate the clicked clip number
|
||||
int clipHeight = (h / numClips);
|
||||
int clipNum = ( (Fl::event_y() ) - y ) / clipHeight;
|
||||
if (clipNum >= numClips)
|
||||
clipNum = numClips -1; // fix for clicking the lowest pixel
|
||||
|
||||
// handle right clicks: popup menu
|
||||
if ( Fl::event_state(FL_BUTTON3) )
|
||||
{
|
||||
if ( _master )
|
||||
{
|
||||
// ask new name for clip, then
|
||||
const char* name = fl_input( "Scene name: ", clips[clipNum].getName().c_str() );
|
||||
if ( name )
|
||||
clips[clipNum].setName( name );
|
||||
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Fl_Menu_Item rclick_menu[] =
|
||||
{
|
||||
{ "Load" },
|
||||
{ "Bars", 0, 0, 0, FL_SUBMENU },
|
||||
{"1 "},
|
||||
{"2"},
|
||||
{"4"},
|
||||
{"8"},
|
||||
{"16"},
|
||||
{"32"},
|
||||
{"64"},
|
||||
{0},
|
||||
//{ "Record" },
|
||||
{ "Use as tempo" },
|
||||
{ "Rename" },
|
||||
{ 0 }
|
||||
};
|
||||
Fl_Menu_Item *m = (Fl_Menu_Item*) rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
|
||||
if ( !m )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if ( strcmp(m->label(), "Load") == 0 )
|
||||
{
|
||||
gui->selectLoadSample( ID, clipNum );
|
||||
}
|
||||
else if ( strcmp(m->label(), "1") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,1);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "2") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,2);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "4") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,4);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "8") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,8);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "16") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,16);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "32") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,32);
|
||||
writeToDspRingbuffer( &e );
|
||||
} else if ( strcmp(m->label(), "64") == 0 ) {
|
||||
EventLooperLoopLength e = EventLooperLoopLength(ID, clipNum ,64);
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
else if ( strcmp(m->label(), "Use as tempo") == 0 )
|
||||
{
|
||||
EventLooperUseAsTempo e (ID, clipNum);
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
else if ( strcmp(m->label(), "Rename") == 0 )
|
||||
{
|
||||
const char* name = fl_input( "Scene name: ", clips[clipNum].getName().c_str() );
|
||||
if ( name )
|
||||
clips[clipNum].setName( name );
|
||||
}
|
||||
else if ( strcmp(m->label(), "Record") == 0 )
|
||||
{
|
||||
/*
|
||||
//recordingClip = clipNum;
|
||||
EventLooperState e = EventLooperState( ID, clipNum, Looper::STATE_RECORD_QUEUED);
|
||||
writeToDspRingbuffer( &e );
|
||||
*/
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _master )
|
||||
{
|
||||
EventGridLaunchScene e( clipNum );
|
||||
writeToDspRingbuffer( &e );
|
||||
redraw();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// write "pressed" event for this track,scene
|
||||
EventGridEvent e( ID, clipNum, true );
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
}
|
||||
redraw();
|
||||
do_callback();
|
||||
return 1;
|
||||
case FL_DRAG:
|
||||
{
|
||||
int t = Fl::event_inside(this);
|
||||
if (t != highlight)
|
||||
{
|
||||
highlight = t;
|
||||
redraw();
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
case FL_ENTER:
|
||||
mouseOver = true;
|
||||
|
||||
redraw();
|
||||
return 1;
|
||||
case FL_LEAVE:
|
||||
mouseOver = false;
|
||||
redraw();
|
||||
return 1;
|
||||
case FL_RELEASE:
|
||||
return 1;
|
||||
case FL_SHORTCUT:
|
||||
if ( test_shortcut() )
|
||||
{
|
||||
do_callback();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return Fl_Widget::handle(event);
|
||||
}
|
||||
}
|
||||
|
||||
} // Avtk
|
||||
|
111
src/avtk/clipselector.hxx
Normal file
111
src/avtk/clipselector.hxx
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Author: Harry van Haaren 2013
|
||||
* harryhaaren@gmail.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AVTK_CLIP_SELECTOR_H
|
||||
#define AVTK_CLIP_SELECTOR_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <FL/Fl_Button.H>
|
||||
|
||||
#include "../config.hxx"
|
||||
|
||||
#include "../looper.hxx"
|
||||
#include "../gridlogic.hxx"
|
||||
#include "../audiobuffer.hxx"
|
||||
#include "../eventhandler.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Avtk
|
||||
{
|
||||
|
||||
class ClipState
|
||||
{
|
||||
public:
|
||||
ClipState() :
|
||||
state(GridLogic::STATE_EMPTY),
|
||||
name("")
|
||||
{}
|
||||
|
||||
void setName(std::string n)
|
||||
{
|
||||
name = n;
|
||||
}
|
||||
|
||||
void setState(GridLogic::State s)
|
||||
{
|
||||
state = s;
|
||||
}
|
||||
|
||||
std::string getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
GridLogic::State getState()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
private:
|
||||
GridLogic::State state;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class ClipSelector : public Fl_Button
|
||||
{
|
||||
public:
|
||||
ClipSelector( int _x, int _y, int _w, int _h,
|
||||
const char *_label, bool master = false);
|
||||
|
||||
int ID;
|
||||
|
||||
// FIXME: NSCENES?
|
||||
static const int numClips = 10;
|
||||
ClipState clips[numClips];
|
||||
|
||||
bool _master;
|
||||
bool mouseOver;
|
||||
bool highlight;
|
||||
int x, y, w, h;
|
||||
const char* label;
|
||||
|
||||
void setID( int id );
|
||||
|
||||
/** converts the Looper::State into the UI represnted ClipSelector state.
|
||||
* It puts some of the data into clips[], and stores unique state into the class.
|
||||
**/
|
||||
void setState( int clipNum, GridLogic::State s );
|
||||
|
||||
std::string clipName(int clip);
|
||||
|
||||
void draw();
|
||||
int handle(int event);
|
||||
|
||||
void resize(int X, int Y, int W, int H);
|
||||
};
|
||||
|
||||
} // Avtk
|
||||
|
||||
#endif // AVTK_CLIP_SELECTOR_H
|
||||
|
|
@ -10,7 +10,10 @@
|
|||
|
||||
#include "event.hxx"
|
||||
#include "eventhandler.hxx"
|
||||
#include "worker.hxx"
|
||||
|
||||
#include "audiobuffer.hxx"
|
||||
|
||||
#include <sndfile.hh>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -18,6 +21,28 @@ DiskReader::DiskReader()
|
|||
{
|
||||
};
|
||||
|
||||
AudioBuffer* DiskReader::loadSample( string path )
|
||||
{
|
||||
SndfileHandle infile( path, SFM_READ );
|
||||
|
||||
AudioBuffer* ab = new AudioBuffer();
|
||||
|
||||
std::vector<float> buf( infile.frames(), 0.f );
|
||||
|
||||
infile.read( &buf[0] , infile.frames() );
|
||||
|
||||
// read data from file
|
||||
ab->setBeats(4);
|
||||
ab->nonRtSetSample( buf );
|
||||
|
||||
cout << "Worker: loadSample() " << path << " size: " << infile.frames() << endl;
|
||||
|
||||
if ( infile.frames() > 0 )
|
||||
return ab;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DiskReader::readSession( std::string path )
|
||||
{
|
||||
cout << "DiskReader::readSession() " << path << endl;
|
||||
|
@ -140,7 +165,7 @@ void DiskReader::readGrid()
|
|||
#endif
|
||||
|
||||
// load it
|
||||
AudioBuffer* ab = Worker::loadSample( sampleFilePath.str() );
|
||||
AudioBuffer* ab = loadSample( sampleFilePath.str() );
|
||||
EventLooperLoad e = EventLooperLoad( t, s, ab );
|
||||
writeToDspRingbuffer( &e );
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ class DiskReader
|
|||
public:
|
||||
DiskReader();
|
||||
|
||||
/// loads a sample into a new AudioBuffer, returning the buffer
|
||||
AudioBuffer* loadSample( std::string path );
|
||||
|
||||
/// reads a session from disk, parsing and restoring state
|
||||
void readSession( std::string path );
|
||||
|
||||
private:
|
||||
|
|
|
@ -10,9 +10,10 @@
|
|||
#include <sys/stat.h>
|
||||
|
||||
#include "gui.hxx"
|
||||
#include "worker.hxx"
|
||||
#include "gmastertrack.hxx"
|
||||
|
||||
#include <sndfile.hh>
|
||||
|
||||
extern Gui* gui;
|
||||
|
||||
using namespace std;
|
||||
|
@ -59,7 +60,10 @@ void DiskWriter::writeAudioBuffer(int track, int scene, AudioBuffer* ab )
|
|||
// or alternatively t_<track>_s_<scene>.wav
|
||||
stringstream path;
|
||||
path << sessionPath << "/" << sessionName << "/samples/" << filename.str();
|
||||
Worker::writeSample( path.str(), ab );
|
||||
|
||||
SndfileHandle outfile( path.str(), SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 1, 44100);
|
||||
cout << "Worker::writeSample() " << path << " size: " << ab->getData().size() << endl;
|
||||
outfile.write( &ab->getData()[0], ab->getData().size() );
|
||||
|
||||
// de allocate the AudioBuffer
|
||||
delete ab;
|
||||
|
@ -139,7 +143,7 @@ void DiskWriter::writeSession( std::string path, std::string sessionName )
|
|||
cJSON_AddItemToArray( clips, clip );
|
||||
|
||||
// replace blank string if clip exists
|
||||
for(int i = 0; i < clipData.size(); i++)
|
||||
for(unsigned int i = 0; i < clipData.size(); i++)
|
||||
{
|
||||
if ( clipData.at(i).track == t &&
|
||||
clipData.at(i).scene == s )
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
#include "avtk/avtk_reverb.h"
|
||||
#include "avtk/avtk_background.h"
|
||||
#include "avtk/avtk_light_button.h"
|
||||
#include "avtk/avtk_clip_selector.h"
|
||||
#include "avtk/avtk_sidechain_gain.h"
|
||||
|
||||
#include "avtk/clipselector.hxx"
|
||||
|
||||
#include "eventhandler.hxx"
|
||||
|
||||
|
|
|
@ -15,12 +15,11 @@
|
|||
#include "avtk/avtk_button.h"
|
||||
#include "avtk/avtk_background.h"
|
||||
#include "avtk/avtk_light_button.h"
|
||||
#include "avtk/avtk_clip_selector.h"
|
||||
#include "avtk/avtk_radial_status.h"
|
||||
|
||||
#include "avtk/clipselector.hxx"
|
||||
|
||||
#include "config.hxx"
|
||||
#include "worker.hxx"
|
||||
#include "audiobuffer.hxx"
|
||||
#include "eventhandler.hxx"
|
||||
|
||||
|
|
42
src/gui.cxx
42
src/gui.cxx
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include "jack.hxx"
|
||||
#include "audiobuffer.hxx"
|
||||
#include "worker.hxx"
|
||||
|
||||
#include <FL/fl_ask.H>
|
||||
|
||||
|
@ -23,19 +22,6 @@ using namespace std;
|
|||
|
||||
extern Gui* gui;
|
||||
|
||||
|
||||
void luppp_tooltip(std::string s)
|
||||
{
|
||||
return;
|
||||
//gui->setTooltip(s);
|
||||
}
|
||||
|
||||
void Gui::setTooltip( std::string s )
|
||||
{
|
||||
tooltip = s;
|
||||
tooltipLabel->label( tooltip.c_str() );
|
||||
}
|
||||
|
||||
void close_cb(Fl_Widget*o, void*) {
|
||||
if ((Fl::event() == FL_KEYDOWN || Fl::event() == FL_SHORTCUT)
|
||||
&& Fl::event_key() == FL_Escape)
|
||||
|
@ -102,6 +88,34 @@ static void gui_header_callback(Fl_Widget *w, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
void Gui::selectLoadSample( int track, int scene )
|
||||
{
|
||||
// FIXME: refactor
|
||||
string path;
|
||||
Fl_Native_File_Chooser fnfc;
|
||||
fnfc.title("Pick a file");
|
||||
fnfc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
//fnfc.filter("Wav\t*.wav");
|
||||
fnfc.directory( getenv("HOME") ); // default directory to use
|
||||
// Show native chooser
|
||||
switch ( fnfc.show() ) {
|
||||
case -1: printf("ERROR: %s\n", fnfc.errmsg()); break; // ERROR
|
||||
case 1: printf("CANCEL\n"); break; // CANCEL
|
||||
default: printf("Loading directory: %s\n", fnfc.filename());
|
||||
// update path and load it
|
||||
path = fnfc.filename();
|
||||
break;
|
||||
}
|
||||
|
||||
if ( strcmp( path.c_str(), "" ) == 0 )
|
||||
return;
|
||||
|
||||
AudioBuffer* ab = diskReader->loadSample( path );
|
||||
EventLooperLoad e = EventLooperLoad( track, scene, ab );
|
||||
writeToDspRingbuffer( &e );
|
||||
}
|
||||
|
||||
|
||||
Gui::Gui() :
|
||||
window(1110,650),
|
||||
diskReader( new DiskReader ),
|
||||
|
|
|
@ -30,8 +30,7 @@ class Gui
|
|||
DiskWriter* getDiskWriter(){return diskWriter;}
|
||||
DiskReader* getDiskReader(){return diskReader;}
|
||||
|
||||
// for pushing strings to tooltip area
|
||||
void setTooltip( std::string s );
|
||||
void selectLoadSample( int track, int clip );
|
||||
|
||||
private:
|
||||
Fl_Double_Window window;
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
|
||||
#ifndef LUPPP_WORKER_H
|
||||
#define LUPPP_WORKER_H
|
||||
|
||||
// Library
|
||||
#include <string>
|
||||
|
||||
#include <sndfile.hh>
|
||||
|
||||
#include "audiobuffer.hxx"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Worker
|
||||
{
|
||||
/// loads a sample into a new AudioBuffer, returning the buffer
|
||||
static AudioBuffer* loadSample( string path )
|
||||
{
|
||||
SndfileHandle infile( path, SFM_READ );
|
||||
|
||||
AudioBuffer* ab = new AudioBuffer();
|
||||
|
||||
std::vector<float> buf( infile.frames(), 0.f );
|
||||
|
||||
infile.read( &buf[0] , infile.frames() );
|
||||
|
||||
// read data from file
|
||||
ab->setBeats(4);
|
||||
ab->nonRtSetSample( buf );
|
||||
|
||||
cout << "Worker: loadSample() " << path << " size: " << infile.frames() << endl;
|
||||
|
||||
if ( infile.frames() > 0 )
|
||||
return ab;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int writeSample( string path, AudioBuffer* ab )
|
||||
{
|
||||
SndfileHandle outfile( path, SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 1, 44100);
|
||||
|
||||
cout << "Worker::writeSample() " << path << " size: " << ab->getData().size() << endl;
|
||||
outfile.write( &ab->getData()[0], ab->getData().size() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // LUPPP_WORKER_H
|
Loading…
Add table
Reference in a new issue