~ubuntu-branches/ubuntu/precise/lmms/precise-proposed

« back to all changes in this revision

Viewing changes to src/core/audio/AudioJack.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessio Treglia
  • Date: 2010-11-12 13:32:32 UTC
  • mfrom: (1.1.9 upstream) (3.1.8 sid)
  • Revision ID: james.westby@ubuntu.com-20101112133232-vdld83iyji8srqti
Tags: 0.4.7-2ubuntu1
* Re-sync with Debian (LP: #606533):
  - Replace build-dep on libwine-dev with libwine-dev-unstable to build
    against the newer Wine.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * AudioJack.cpp - support for JACK-transport
 
3
 *
 
4
 * Copyright (c) 2005-2009 Tobias Doerffel <tobydox/at/users.sourceforge.net>
 
5
 *
 
6
 * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public
 
19
 * License along with this program (see COPYING); if not, write to the
 
20
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
21
 * Boston, MA 02110-1301 USA.
 
22
 *
 
23
 */
 
24
 
 
25
#include "AudioJack.h"
 
26
 
 
27
#ifdef LMMS_HAVE_JACK
 
28
 
 
29
#include <QtGui/QLineEdit>
 
30
#include <QtGui/QLabel>
 
31
#include <QtGui/QMessageBox>
 
32
 
 
33
#include <stdlib.h>
 
34
 
 
35
#include "debug.h"
 
36
#include "engine.h"
 
37
#include "templates.h"
 
38
#include "gui_templates.h"
 
39
#include "config_mgr.h"
 
40
#include "lcd_spinbox.h"
 
41
#include "AudioPort.h"
 
42
#include "MainWindow.h"
 
43
 
 
44
 
 
45
 
 
46
 
 
47
AudioJack::AudioJack( bool & _success_ful, mixer * _mixer ) :
 
48
        AudioDevice( tLimit<int>( configManager::inst()->value(
 
49
                                        "audiojack", "channels" ).toInt(),
 
50
                                        DEFAULT_CHANNELS, SURROUND_CHANNELS ),
 
51
                                                                _mixer ),
 
52
        m_client( NULL ),
 
53
        m_active( false ),
 
54
        m_stopSemaphore( 1 ),
 
55
        m_tempOutBufs( new jack_default_audio_sample_t *[channels()] ),
 
56
        m_outBuf( new surroundSampleFrame[getMixer()->framesPerPeriod()] ),
 
57
        m_framesDoneInCurBuf( 0 ),
 
58
        m_framesToDoInCurBuf( 0 )
 
59
{
 
60
        _success_ful = initJackClient();
 
61
        if( _success_ful )
 
62
        {
 
63
                m_stopSemaphore.acquire();
 
64
 
 
65
                connect( this, SIGNAL( zombified() ),
 
66
                                this, SLOT( restartAfterZombified() ),
 
67
                                Qt::QueuedConnection );
 
68
        }
 
69
 
 
70
}
 
71
 
 
72
 
 
73
 
 
74
 
 
75
AudioJack::~AudioJack()
 
76
{
 
77
        m_stopSemaphore.release();
 
78
 
 
79
#ifdef AUDIO_PORT_SUPPORT
 
80
        while( m_portMap.size() )
 
81
        {
 
82
                unregisterPort( m_portMap.begin().key() );
 
83
        }
 
84
#endif
 
85
 
 
86
        if( m_client != NULL )
 
87
        {
 
88
                if( m_active )
 
89
                {
 
90
                        jack_deactivate( m_client );
 
91
                }
 
92
                jack_client_close( m_client );
 
93
        }
 
94
 
 
95
        delete[] m_tempOutBufs;
 
96
 
 
97
        delete[] m_outBuf;
 
98
}
 
99
 
 
100
 
 
101
 
 
102
 
 
103
void AudioJack::restartAfterZombified()
 
104
{
 
105
        if( initJackClient() )
 
106
        {
 
107
                m_active = false;
 
108
                startProcessing();
 
109
                QMessageBox::information( engine::mainWindow(),
 
110
                        tr( "JACK client restarted" ),
 
111
                        tr( "LMMS was kicked by JACK for some reason. "
 
112
                                "Therefore the JACK backend of LMMS has been "
 
113
                                "restarted. You will have to make manual "
 
114
                                "connections again." ) );
 
115
        }
 
116
        else
 
117
        {
 
118
                QMessageBox::information( engine::mainWindow(),
 
119
                        tr( "JACK server down" ),
 
120
                        tr( "The JACK server seems to have been shutdown "
 
121
                                "and starting a new instance failed. "
 
122
                                "Therefore LMMS is unable to proceed. "
 
123
                                "You should save your project and restart "
 
124
                                                "JACK and LMMS." ) );
 
125
        }
 
126
}
 
127
 
 
128
 
 
129
 
 
130
 
 
131
 
 
132
bool AudioJack::initJackClient()
 
133
{
 
134
        QString clientName = configManager::inst()->value( "audiojack",
 
135
                                                                "clientname" );
 
136
        if( clientName.isEmpty() )
 
137
        {
 
138
                clientName = "lmms";
 
139
        }
 
140
 
 
141
        const char * serverName = NULL;
 
142
        jack_status_t status;
 
143
        m_client = jack_client_open( clientName.toAscii().constData(),
 
144
                                                JackNullOption, &status,
 
145
                                                                serverName );
 
146
        if( m_client == NULL )
 
147
        {
 
148
                printf( "jack_client_open() failed, status 0x%2.0x\n", status );
 
149
                if( status & JackServerFailed )
 
150
                {
 
151
                        printf( "Could not connect to JACK server.\n" );
 
152
                }
 
153
                return false;
 
154
        }
 
155
        if( status & JackNameNotUnique )
 
156
        {
 
157
                printf( "there's already a client with name '%s', so unique "
 
158
                        "name '%s' was assigned\n", clientName.
 
159
                                                        toAscii().constData(),
 
160
                                        jack_get_client_name( m_client ) );
 
161
        }
 
162
 
 
163
        // set process-callback
 
164
        jack_set_process_callback( m_client, staticProcessCallback, this );
 
165
 
 
166
        // set shutdown-callback
 
167
        jack_on_shutdown( m_client, shutdownCallback, this );
 
168
 
 
169
 
 
170
 
 
171
        if( jack_get_sample_rate( m_client ) != sampleRate() )
 
172
        {
 
173
                setSampleRate( jack_get_sample_rate( m_client ) );
 
174
        }
 
175
 
 
176
        for( ch_cnt_t ch = 0; ch < channels(); ++ch )
 
177
        {
 
178
                QString name = QString( "master out " ) +
 
179
                                ( ( ch % 2 ) ? "R" : "L" ) +
 
180
                                QString::number( ch / 2 + 1 );
 
181
                m_outputPorts.push_back( jack_port_register( m_client,
 
182
                                                name.toAscii().constData(),
 
183
                                                JACK_DEFAULT_AUDIO_TYPE,
 
184
                                                JackPortIsOutput, 0 ) );
 
185
                if( m_outputPorts.back() == NULL )
 
186
                {
 
187
                        printf( "no more JACK-ports available!\n" );
 
188
                        return false;
 
189
                }
 
190
        }
 
191
 
 
192
        return true;
 
193
}
 
194
 
 
195
 
 
196
 
 
197
 
 
198
void AudioJack::startProcessing()
 
199
{
 
200
        m_stopped = false;
 
201
 
 
202
        if( m_active || m_client == NULL )
 
203
        {
 
204
                return;
 
205
        }
 
206
 
 
207
        if( jack_activate( m_client ) )
 
208
        {
 
209
                printf( "cannot activate client\n" );
 
210
                return;
 
211
        }
 
212
 
 
213
        m_active = true;
 
214
 
 
215
 
 
216
        // try to sync JACK's and LMMS's buffer-size
 
217
//      jack_set_buffer_size( m_client, getMixer()->framesPerPeriod() );
 
218
 
 
219
 
 
220
 
 
221
        const char * * ports = jack_get_ports( m_client, NULL, NULL,
 
222
                                                JackPortIsPhysical |
 
223
                                                JackPortIsInput );
 
224
        if( ports == NULL )
 
225
        {
 
226
                printf( "no physical playback ports. you'll have to do "
 
227
                        "connections at your own!\n" );
 
228
        }
 
229
        else
 
230
        {
 
231
                for( ch_cnt_t ch = 0; ch < channels(); ++ch )
 
232
                {
 
233
                        if( jack_connect( m_client, jack_port_name(
 
234
                                                        m_outputPorts[ch] ),
 
235
                                                                ports[ch] ) )
 
236
                        {
 
237
                                printf( "cannot connect output ports. you'll "
 
238
                                        "have to do connections at your own!\n"
 
239
                                                                        );
 
240
                        }
 
241
                }
 
242
        }
 
243
 
 
244
        free( ports );
 
245
}
 
246
 
 
247
 
 
248
 
 
249
 
 
250
void AudioJack::stopProcessing()
 
251
{
 
252
        m_stopSemaphore.acquire();
 
253
}
 
254
 
 
255
 
 
256
 
 
257
 
 
258
void AudioJack::applyQualitySettings()
 
259
{
 
260
        if( hqAudio() )
 
261
        {
 
262
                setSampleRate( engine::getMixer()->processingSampleRate() );
 
263
 
 
264
                if( jack_get_sample_rate( m_client ) != sampleRate() )
 
265
                {
 
266
                        setSampleRate( jack_get_sample_rate( m_client ) );
 
267
                }
 
268
        }
 
269
 
 
270
        AudioDevice::applyQualitySettings();
 
271
}
 
272
 
 
273
 
 
274
 
 
275
 
 
276
void AudioJack::registerPort( AudioPort * _port )
 
277
{
 
278
#ifdef AUDIO_PORT_SUPPORT
 
279
        // make sure, port is not already registered
 
280
        unregisterPort( _port );
 
281
        const QString name[2] = { _port->name() + " L",
 
282
                                        _port->name() + " R" } ;
 
283
 
 
284
        for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
 
285
        {
 
286
                m_portMap[_port].ports[ch] = jack_port_register( m_client,
 
287
                                                name[ch].toAscii().constData(),
 
288
                                                JACK_DEFAULT_AUDIO_TYPE,
 
289
                                                        JackPortIsOutput, 0 );
 
290
        }
 
291
#endif
 
292
}
 
293
 
 
294
 
 
295
 
 
296
 
 
297
void AudioJack::unregisterPort( AudioPort * _port )
 
298
{
 
299
#ifdef AUDIO_PORT_SUPPORT
 
300
        if( m_portMap.contains( _port ) )
 
301
        {
 
302
                for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
 
303
                {
 
304
                        if( m_portMap[_port].ports[ch] != NULL )
 
305
                        {
 
306
                                jack_port_unregister( m_client,
 
307
                                                m_portMap[_port].ports[ch] );
 
308
                        }
 
309
                }
 
310
                m_portMap.erase( m_portMap.find( _port ) );
 
311
        }
 
312
#endif
 
313
}
 
314
 
 
315
 
 
316
 
 
317
 
 
318
void AudioJack::renamePort( AudioPort * _port )
 
319
{
 
320
#ifdef AUDIO_PORT_SUPPORT
 
321
        if( m_portMap.contains( _port ) )
 
322
        {
 
323
                const QString name[2] = { _port->name() + " L",
 
324
                                        _port->name() + " R" };
 
325
                for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
 
326
                {
 
327
                        jack_port_set_name( m_portMap[_port].ports[ch],
 
328
                                        name[ch].toAscii().constData() );
 
329
                }
 
330
        }
 
331
#endif
 
332
}
 
333
 
 
334
 
 
335
 
 
336
 
 
337
int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
 
338
{
 
339
        for( int c = 0; c < channels(); ++c )
 
340
        {
 
341
                m_tempOutBufs[c] =
 
342
                        (jack_default_audio_sample_t *) jack_port_get_buffer(
 
343
                                                                                                m_outputPorts[c], _nframes );
 
344
        }
 
345
 
 
346
#ifdef AUDIO_PORT_SUPPORT
 
347
        const Uint32 frames = qMin<Uint32>( _nframes,
 
348
                                                getMixer()->framesPerPeriod() );
 
349
        for( jackPortMap::iterator it = m_portMap.begin();
 
350
                                                it != m_portMap.end(); ++it )
 
351
        {
 
352
                for( ch_cnt_t ch = 0; ch < channels(); ++ch )
 
353
                {
 
354
                        if( it.data().ports[ch] == NULL )
 
355
                        {
 
356
                                continue;
 
357
                        }
 
358
                        jack_default_audio_sample_t * buf =
 
359
                        (jack_default_audio_sample_t *) jack_port_get_buffer(
 
360
                                                        it.data().ports[ch],
 
361
                                                                _nframes );
 
362
                        for( Uint32 frame = 0; frame < frames; ++frame )
 
363
                        {
 
364
                                buf[frame] = it.key()->firstBuffer()[frame][ch];
 
365
                        }
 
366
                }
 
367
        }
 
368
#endif
 
369
 
 
370
        jack_nframes_t done = 0;
 
371
        while( done < _nframes && m_stopped == false )
 
372
        {
 
373
                jack_nframes_t todo = qMin<jack_nframes_t>(
 
374
                                                _nframes,
 
375
                                                m_framesToDoInCurBuf -
 
376
                                                        m_framesDoneInCurBuf );
 
377
                const float gain = getMixer()->masterGain();
 
378
                for( int c = 0; c < channels(); ++c )
 
379
                {
 
380
                        jack_default_audio_sample_t * o = m_tempOutBufs[c];
 
381
                        for( jack_nframes_t frame = 0; frame < todo; ++frame )
 
382
                        {
 
383
                                o[done+frame] = m_outBuf[m_framesDoneInCurBuf+frame][c] * gain;
 
384
                        }
 
385
                }
 
386
                done += todo;
 
387
                m_framesDoneInCurBuf += todo;
 
388
                if( m_framesDoneInCurBuf == m_framesToDoInCurBuf )
 
389
                {
 
390
                        m_framesToDoInCurBuf = getNextBuffer( m_outBuf );
 
391
                        if( !m_framesToDoInCurBuf )
 
392
                        {
 
393
                                m_stopped = true;
 
394
                                m_stopSemaphore.release();
 
395
                        }
 
396
                        m_framesDoneInCurBuf = 0;
 
397
                }
 
398
        }
 
399
 
 
400
        if( m_stopped == true )
 
401
        {
 
402
                for( int c = 0; c < channels(); ++c )
 
403
                {
 
404
                        jack_default_audio_sample_t * b = m_tempOutBufs[c] + done;
 
405
                        memset( b, 0, sizeof( *b ) * ( _nframes - done ) );
 
406
                }
 
407
        }
 
408
 
 
409
        return 0;
 
410
}
 
411
 
 
412
 
 
413
 
 
414
 
 
415
int AudioJack::staticProcessCallback( jack_nframes_t _nframes, void * _udata )
 
416
{
 
417
        return static_cast<AudioJack *>( _udata )->
 
418
                                        processCallback( _nframes, _udata );
 
419
}
 
420
 
 
421
 
 
422
 
 
423
 
 
424
void AudioJack::shutdownCallback( void * _udata )
 
425
{
 
426
        AudioJack * _this = static_cast<AudioJack *>( _udata );
 
427
        _this->m_client = NULL;
 
428
        _this->zombified();
 
429
}
 
430
 
 
431
 
 
432
 
 
433
 
 
434
 
 
435
AudioJack::setupWidget::setupWidget( QWidget * _parent ) :
 
436
        AudioDevice::setupWidget( AudioJack::name(), _parent )
 
437
{
 
438
        QString cn = configManager::inst()->value( "audiojack", "clientname" );
 
439
        if( cn.isEmpty() )
 
440
        {
 
441
                cn = "lmms";
 
442
        }
 
443
        m_clientName = new QLineEdit( cn, this );
 
444
        m_clientName->setGeometry( 10, 20, 160, 20 );
 
445
 
 
446
        QLabel * cn_lbl = new QLabel( tr( "CLIENT-NAME" ), this );
 
447
        cn_lbl->setFont( pointSize<6>( cn_lbl->font() ) );
 
448
        cn_lbl->setGeometry( 10, 40, 160, 10 );
 
449
 
 
450
        lcdSpinBoxModel * m = new lcdSpinBoxModel( /* this */ );        
 
451
        m->setRange( DEFAULT_CHANNELS, SURROUND_CHANNELS );
 
452
        m->setStep( 2 );
 
453
        m->setValue( configManager::inst()->value( "audiojack",
 
454
                                                        "channels" ).toInt() );
 
455
 
 
456
        m_channels = new lcdSpinBox( 1, this );
 
457
        m_channels->setModel( m );
 
458
        m_channels->setLabel( tr( "CHANNELS" ) );
 
459
        m_channels->move( 180, 20 );
 
460
 
 
461
}
 
462
 
 
463
 
 
464
 
 
465
 
 
466
AudioJack::setupWidget::~setupWidget()
 
467
{
 
468
}
 
469
 
 
470
 
 
471
 
 
472
 
 
473
void AudioJack::setupWidget::saveSettings()
 
474
{
 
475
        configManager::inst()->setValue( "audiojack", "clientname",
 
476
                                                        m_clientName->text() );
 
477
        configManager::inst()->setValue( "audiojack", "channels",
 
478
                                QString::number( m_channels->value<int>() ) );
 
479
}
 
480
 
 
481
 
 
482
 
 
483
#include "moc_AudioJack.cxx"
 
484
 
 
485
#endif
 
486