Revision 4:ab6db404403a

View differences:

CollidoscopeApp/include/ParticleController.h
10 10

  
11 11
    struct Particle {
12 12

  
13
        ci::vec2	mCloudCenter;
14
        ci::vec2	mVel;
15
        float       mCloudSize;
13
        ci::vec2	mCloudCenter; // initial positin of the particle 
14
        ci::vec2	mVel;         // velocity 
15
        float       mCloudSize;   // how big is the area where particle float around. When a particle hits the 
16
                                  //   border of the area it gets deflected 
16 17

  
17
        int			mAge;
18
        int			mLifespan;
19
        bool        mFlyOver;
18
        int			mAge;      // when mAge == mLifeSpan the particle is disposed 
19
        int			mLifespan; // how long a particle lives
20
        bool        mFlyOver;  // some particles last longer and fly over the screen and reach the other user
20 21

  
21 22
    };
22 23

  
......
28 29
    // current number of active particles
29 30
    size_t mNumParticles;
30 31

  
31
    ci::gl::VboRef			mParticleVbo;
32
    ci::gl::VboRef			mParticleVbo;    // virtual buffer object 
32 33
    ci::gl::BatchRef		mParticleBatch;
33 34

  
34 35
 public:
CollidoscopeApp/src/ParticleController.cpp
10 10
mNumParticles( 0 )
11 11

  
12 12
{
13
    // uses Cinder (and OpenGL) virtual buffer object based drawing
14
    // see ParticleSphereCPU example in Cinder library 
15
     
13 16
    mParticles.assign( kMaxParticles, Particle() );
14 17
    mParticlePositions.assign( kMaxParticles, vec2( -1, -1 ) );
15 18

  
......
20 23

  
21 24
    auto mesh = gl::VboMesh::create( mParticlePositions.size(), GL_POINTS, { { particleLayout, mParticleVbo } } );
22 25

  
26
    // creates glsl program to run the batch with 
23 27
#if ! defined( CINDER_GL_ES )
24 28
    auto glsl = gl::GlslProg::create( gl::GlslProg::Format()
25 29
        .vertex( CI_GLSL( 150,
......
70 74

  
71 75
void ParticleController::updateParticles()
72 76
{
77
    // update the positions of the particles and dispose them if they're reached their timespan
73 78
    for ( size_t i = 0; i < mNumParticles; i++ ){
74 79

  
75 80
        Particle &particle = mParticles[i];
......
95 100
        }
96 101
    }
97 102

  
103
    // Copy particle data onto the GPU.
104
	// Map the GPU memory and write over it.
98 105
    void *gpuMem = mParticleVbo->mapReplace();
99 106
    memcpy( gpuMem, mParticlePositions.data(), mParticlePositions.size() * sizeof( vec2 ) );
100 107
    mParticleVbo->unmap();
......
102 109

  
103 110
void ParticleController::addParticles(int amount, const vec2 &initialLocation, const float cloudSize)
104 111
{
112
    // reduce the particles liearly to the total number of particles already present 
113
    // the more particles aleary present the less particle are added
105 114
    int reduction = ci::lmap<int>(mNumParticles, 0, kMaxParticles, 0, kMaxParticleAdd);
106 115
    amount -= reduction;
107 116

  
108 117
    if ( mNumParticles + amount > kMaxParticles ){
109
		//return;
118
		//a.k.a. return if reached kMaxParticles 
110 119
        amount = kMaxParticles - mNumParticles;
111 120
	}
112 121

  
CollidoscopeApp/src/Wave.cpp
16 16
		mChunks.emplace_back( i );
17 17
	}
18 18

  
19
    // init cinder batch drawing
19 20
    auto lambert = gl::ShaderDef().color();
20 21
    gl::GlslProgRef shader = gl::getStockShader( lambert );
21 22
    mChunkBatch = gl::Batch::create( geom::Rect( ci::Rectf( 0, 0, Chunk::kWidth, 1 ) ), shader );
......
63 64

  
64 65
        double elapsed = now - itr->second.lastUpdate;
65 66

  
67
        // A chunk of audio corresponds to a certain time according to sample rate.
68
        // Use elapsed time to advance through chunks so that the cursor is animated 
69
        // and goes from start to end of the seleciton in the time span of the grain 
66 70
        itr->second.pos = mSelection.getStart() + int( elapsed / secondsPerChunk );
67 71

  
68
        /* check we don't go too far off */
72
        // check we don't go too far off 
69 73
        if (itr->second.pos > mSelection.getEnd()){
70 74
            itr->second.pos = Cursor::kNoPosition;
71 75
        }
JackDevice/ContextJack.cpp
26 26

  
27 27
namespace cinder { namespace audio { namespace linux {
28 28

  
29

  
30

  
31
//--------------------------------------static utilities------------------------------------------
32

  
29 33
inline void zeroJackPort( jack_port_t *port, jack_nframes_t nframes )
30 34
{   
35
  // FIXME seg fault at shutdown 
31 36
  // memset(port, 0, sizeof(jack_default_audio_sample_t) * nframes); 
32 37
}
33 38

  
39
// copy audio from node buffer to jack port 
34 40
inline void copyToJackPort(jack_port_t *port, float *source, jack_nframes_t nframes )
35 41
{
36
    // dest, source, n 
37 42
    jack_default_audio_sample_t *out;
38 43
    out = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes );
39 44

  
40 45
    memcpy( out, source, sizeof(jack_default_audio_sample_t) * nframes ) ;
41 46
}
42 47

  
48
// copy audio from jack port to  node buffer
43 49
inline void copyFromJackPort(jack_port_t *port, float *dest, jack_nframes_t nframes )
44 50
{
45
    // dest, source, n 
46 51
    jack_default_audio_sample_t *in;
47 52
    in = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes );
48 53

  
......
50 55
}
51 56

  
52 57

  
58
// -------------------------------OutputDeviceNodeJack-------------------------------------------
59

  
53 60
int OutputDeviceNodeJack::jackCallback(jack_nframes_t nframes, void* userData)
54 61
{
62
    // retrieve user data 
55 63
	RenderData *renderData = static_cast<RenderData *>( userData );
56 64

  
57 65
	OutputDeviceNodeJack *outputDeviceNode = static_cast<OutputDeviceNodeJack *>( renderData->outputNode );
58 66

  
59 67
	auto ctx = renderData->outputNode->getContext();
60 68
	if( ! ctx ) {
69
        // this is from some cinder library code but it should not happen in Collidoscope as the context is set
61 70
        for( size_t chan = 0; chan < 2; chan++)
62
            // FIXME segfault at shutdown 
63 71
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
64 72

  
65 73
		return 0;
......
82 90
	internalBuffer->zero();
83 91

  
84 92
	ctx->preProcess();
93
    // process the whole audio graph using by recursively pulling the input all the way to the top of the graph 
85 94
	outputDeviceNode->pullInputs( internalBuffer );
86 95
    
87 96
	// if clip detection is enabled and buffer clipped, silence it
88
	if( false && outputDeviceNode->checkNotClipping() ){
89
        for( size_t chan = 0; chan < 2; chan++)
90
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
91
	} 
92
    else {
97
	//if( outputDeviceNode->checkNotClipping() ){
98
        //for( size_t chan = 0; chan < 2; chan++)
99
		//    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
100
	//} 
101
    //else {
93 102
        for( size_t chan = 0; chan < 2; chan++)
94 103
            copyToJackPort( outputDeviceNode->mOutputPorts[chan], internalBuffer->getChannel( chan ), nframes  );
95
    }
104
    //}
96 105

  
97 106
	ctx->postProcess();
98 107

  
......
104 113
    mInputDeviceNode = std::static_pointer_cast<InputDeviceNodeJack>(inputDeviceNode);
105 114
}
106 115

  
107
ContextJack::ContextJack()
108
{
109

  
110
}
111

  
112
ContextJack::~ContextJack()
113
{
114

  
115
}
116

  
117

  
118
OutputDeviceNodeRef	ContextJack::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format )
119
{
120
	
121
    if( mOutputDeviceNode  == nullptr ) {
122
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
123

  
124
        mOutputDeviceNode = makeNode( new OutputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
125

  
126
        if( mInputDeviceNode != nullptr){
127
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
128
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
129
        }
130
    }
131

  
132
	return mOutputDeviceNode;
133
}
134

  
135
InputDeviceNodeRef ContextJack::createInputDeviceNode( const DeviceRef &device, const Node::Format &format  )
136
{
137
    if( mInputDeviceNode  == nullptr ) {
138
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
139

  
140
        mInputDeviceNode = makeNode( new InputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
141

  
142
        if( mOutputDeviceNode != nullptr){
143
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
144
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
145
        }
146
    }
147

  
148
	return mInputDeviceNode;
149
}
150

  
151

  
152
// OutputDeviceNodeJack 
153

  
154 116
OutputDeviceNodeJack::OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ):
155 117
    OutputDeviceNode( device, format),
156 118
    mCinderContext( context )
......
165 127
    jack_options_t options = JackNullOption;
166 128
    jack_status_t status;
167 129

  
168
    // connect to JAck server 
130
    // connect to Jack server 
169 131
    mClient = jack_client_open (client_name, options, &status, server_name);
170 132
    if( mClient == NULL){
171 133

  
......
177 139
    }
178 140

  
179 141
    
142
    // prepare user data for callback 
180 143
    mRenderData.outputNode = this;
181 144
    mRenderData.inputNode = mInputDeviceNode.get();
182 145
    CI_ASSERT(mInputDeviceNode != nullptr);
......
201 164
        throw cinder::audio::AudioContextExc("no more JACK ports available");
202 165
     }
203 166

  
204
    // setup input ports 
167
    // setup input ports. Note that the reference to the input node is used. 
205 168
    mInputDeviceNode->mInputPorts[0] = jack_port_register (mClient, "input1",
206 169
                       JACK_DEFAULT_AUDIO_TYPE,
207 170
                       JackPortIsInput, 0);
......
211 174
                       JackPortIsInput, 0);
212 175

  
213 176

  
214
    /* Tell the JACK server that we are ready to roll.  Our callback will start running now. */
177
    /* Tell the Jack server that we are ready to roll.  Our callback will start running now. */
215 178
    if (jack_activate (mClient)) {
216 179
        throw cinder::audio::AudioContextExc("cannot activate client");
217 180
    }
......
267 230
}
268 231

  
269 232

  
270
//-------------------------- InputDeviceNodeJack -------------------------------
233
//----------------------------------------- InputDeviceNodeJack ---------------------------------------------------
271 234

  
272 235

  
273 236
InputDeviceNodeJack::InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ):
......
291 254
{
292 255
}
293 256

  
257
// This is called when the output node pull all the inputs in the jack callback. 
258
// Takes audio interface input from the jack port and copies it in the node buffer
294 259
void InputDeviceNodeJack::process( Buffer *buffer )
295 260
{
296 261
    for( size_t chan = 0; chan < 2; chan++){
......
298 263
    }
299 264
}
300 265

  
266

  
267
//-------------------------------------------ContextJack-----------------------------------------------------------
268

  
269
OutputDeviceNodeRef	ContextJack::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format )
270
{
271
	
272
    if( mOutputDeviceNode  == nullptr ) {
273
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
274

  
275
        mOutputDeviceNode = makeNode( new OutputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
276

  
277
        // the output device node must have a reference to input device node. In OutputDeviceNodeJack::initialize() 
278
        // the input node is passed the jack input ports that it will use to fetch incoming audio from the audio interface
279
        // Whichever node (input or ouput) gets initialized after the other, executes the following block:
280
        if( mInputDeviceNode != nullptr){
281
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
282
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
283
        }
284
    }
285

  
286
	return mOutputDeviceNode;
287
}
288

  
289
InputDeviceNodeRef ContextJack::createInputDeviceNode( const DeviceRef &device, const Node::Format &format  )
290
{
291
    if( mInputDeviceNode  == nullptr ) {
292
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
293

  
294
        mInputDeviceNode = makeNode( new InputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
295

  
296
        // the output device node must have a reference to input device node. In OutputDeviceNodeJack::initialize() 
297
        // the input node is passed the jack input ports that it will use to fetch incoming audio from the audio interface
298
        // Whichever node (input or ouput) gets initialized after the other, executes the following block:
299
        if( mOutputDeviceNode != nullptr){
300
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
301
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
302
        }
303
    }
304

  
305
	return mInputDeviceNode;
306
}
307

  
308

  
309

  
310

  
311

  
301 312
} } } // namespace cinder::audio::linux
JackDevice/ContextJack.h
31 31
class ContextJack;
32 32
class InputDeviceNodeJack;
33 33

  
34
/**
35
 * OutputNode (as in the cinder::audio::OutputNode) that sends audio to the sound card using the jack audio callback method. 
36
 */ 
34 37
class OutputDeviceNodeJack : public OutputDeviceNode {
35 38
  public:
36 39
	OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context );
37 40

  
41
    /** Gives this output node a reference to the JackInputNode. 
42
     *  In initialize() the reference is used to give the input node access to jack input ports 
43
     */
38 44
    void setInput(InputDeviceNodeRef inputDeviceNode);
39 45

  
40 46
  protected:
......
45 51
	bool supportsProcessInPlace() const	override	{ return false; }
46 52

  
47 53
  private:
54
    // this is called by jack in the audio thread at every tick of the sound card 
48 55
    static int jackCallback(jack_nframes_t nframes, void* userData);
49 56

  
50 57

  
51 58
	void renderToBufferFromInputs();
52 59

  
60
    /**
61
     * RenderData is passed as user_data to jack when the jack process callback is installed
62
     */ 
53 63
    struct RenderData{
54 64
        RenderData() : inputNode(nullptr), outputNode(nullptr), context(nullptr){}
55 65
        ~RenderData() { inputNode = nullptr; outputNode = nullptr;  context = nullptr; }
......
67 77
    std::shared_ptr<InputDeviceNodeJack> mInputDeviceNode;
68 78
};
69 79

  
80
/**
81
 * InputNode (as in the cinder::audio::OutputNode) that reads audio from the sound card using the jack audio callback method. 
82
 */ 
70 83
class InputDeviceNodeJack : public InputDeviceNode {
71 84
  friend OutputDeviceNodeJack;
72 85

  
......
86 99

  
87 100
class ContextJack : public Context {
88 101
  public:
89
	ContextJack();
90
	virtual ~ContextJack();
102
	ContextJack() {}
103
	virtual ~ContextJack() {}
91 104
    
92 105

  
93 106
	OutputDeviceNodeRef	createOutputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override;
......
101 114
};	
102 115

  
103 116
} } } // namespace cinder::audio::linux
117

  
JackDevice/DeviceManagerJack.cpp
32 32
DeviceManagerJack::DeviceManagerJack() 
33 33
{
34 34

  
35
    // hardcoded devices. They are always JackIn and JackOut 
35 36
    mDevices.push_back( addDevice("JackIn") );
36 37
    mDevices.push_back( addDevice("JackOut") );
37 38

  
38 39
    jack_status_t status;
39 40
    
41
    // open a jack client, get info and close
40 42
	jack_client_t *client = jack_client_open ("device info", JackNullOption, &status, NULL);
41 43
    if( client == NULL){
42 44

  
......
73 75
    return mDevices[0];
74 76
}
75 77

  
78
//hardcoded name same as key 
76 79
std::string DeviceManagerJack::getName( const DeviceRef &device )
77 80
{
78 81
    return device->getKey();
JackDevice/DeviceManagerJack.h
27 27

  
28 28
namespace cinder { namespace audio { namespace linux {
29 29

  
30
/**
31
 * DeviceManager ( as in cinder::audio::DeviceManager ) that handle the hardware device through the jack library.
32
 * Note that this is not suitable for general purpose use. Most of the functionalities are indeed hard coded
33
 * just to suit Collidoscope needs. In particular only two input and two output ports are assumed. 
34
 *
35
 */ 
30 36
class DeviceManagerJack : public DeviceManager {
31 37
  public:
32 38

  

Also available in: Unified diff