Exemplo n.º 1
0
/** begin recording */
void
Record_DS::start ( nframes_t frame )
{
    THREAD_ASSERT( UI );

    if ( _recording )
    {
        WARNING( "programming error: attempt to start recording while recording is still in progress" );
        return;
    }

/*     /\* FIXME: safe to do this here? *\/ */
/*     flush(); */

    DMESSAGE( "recording started at frame %lu", (unsigned long)frame);

    _frame = frame;

    _capture = new Track::Capture;

    run();

    _recording = true;

}
Exemplo n.º 2
0
/** read /nframes/ from the attached track into /buf/ */
void
Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
{
    THREAD_ASSERT( Playback );

    memset( buf, 0, nframes * sizeof( sample_t ) * channels() );

//    printf( "IO: attempting to read block @ %lu\n", _frame );

    if ( !timeline )
        return;

    while ( timeline->sequence_lock.tryrdlock() )
    {
        if ( _terminate )
            return;
        
        usleep( 1000 * 10 );
    }
    
    if ( sequence() )
    {
        if ( ! sequence()->play( buf, _frame + _undelay, nframes, channels() ) )
            WARNING( "Programming error?" );
        
        _frame += nframes;
    }
    
    timeline->sequence_lock.unlock();
}
Exemplo n.º 3
0
void
Meter_Indicator_Module::handle_control_changed ( Port *p )
{
    THREAD_ASSERT( UI );

    /* The engine is already locked by the UI thread at this point in
     the call-graph, so we can be sure that process() won't be
     executed concurrently. */
    if ( p->connected() )
    {
        p = p->connected_port();

        if ( dpm_pack->children() != p->hints.dimensions )
        {
            dpm_pack->clear();

            control_value = new float[p->hints.dimensions];

            for ( int i = p->hints.dimensions; i--; )
            {
                DPM *dpm = new DPM( x(), y(), w(), h() );
                dpm->type( FL_VERTICAL );
                align( (Fl_Align)(FL_ALIGN_CENTER | FL_ALIGN_INSIDE ) );

                dpm_pack->add( dpm );
                dpm_pack->redraw();

                control_value[i] = -70.0f;
                dpm->value( -70.0f );
            }

            redraw();
        }
    }
}
Exemplo n.º 4
0
/** flush buffers and reset. Must only be called from the RT thread. */
void
Disk_Stream::base_flush ( bool is_output )
{
    THREAD_ASSERT( RT );

    /* flush buffers */
    for ( int i = _rb.size(); i--; )
        jack_ringbuffer_read_advance( _rb[ i ], jack_ringbuffer_read_space( _rb[ i ] ) );

/*  sem_destroy( &_blocks ); */

/*     if ( is_output ) */
/*         sem_init( &_blocks, 0, _total_blocks ); */
/*     else */
/*         sem_init( &_blocks, 0, 0 ); */

    if ( is_output )
    {
        int n;
        sem_getvalue( &_blocks, &n );

        n = _total_blocks - n;

        while ( n-- )
            sem_post( &_blocks );
    }
    else
    {
        sem_destroy( &_blocks );

        sem_init( &_blocks, 0, 0 );
    }


}
Exemplo n.º 5
0
/** read /nframes/ from the attached track into /buf/ */
void
Playback_DS::read_block ( sample_t *buf, nframes_t nframes )
{
    THREAD_ASSERT( Playback );

    memset( buf, 0, nframes * sizeof( sample_t ) * channels() );

    /* stupid chicken/egg */
    if ( ! timeline )
        return;

//    printf( "IO: attempting to read block @ %lu\n", _frame );

    if ( ! sequence() )
    {
        /* FIXME: what to do here? */
//        _frame += _nframes;
        return;
    }

    timeline->rdlock();

    /* FIXME: how does this work if _delay is not a multiple of bufsize? */

    if ( _frame >= _delay )
    {
        if ( ! sequence()->play( buf, _frame - _delay, nframes, channels() ) )
            WARNING( "Programming error?" );
    }

    _frame += nframes;

    timeline->unlock();
}
Exemplo n.º 6
0
/** take a single block from the ringbuffers and send it out the
 *  attached track's ports */
nframes_t
Playback_DS::process ( nframes_t nframes )
{
    THREAD_ASSERT( RT );


    const size_t block_size = nframes * sizeof( sample_t );

//    printf( "process: %lu %lu %lu\n", _frame, _frame + nframes, nframes );

    for ( int i = channels(); i--;  )
    {

        void *buf = track()->output[ i ].buffer( nframes );

        if ( jack_ringbuffer_read( _rb[ i ], (char*)buf, block_size ) < block_size )
        {
            ++_xruns;
            memset( buf, 0, block_size );
            /* FIXME: we need to resync somehow */
        }

        /* TODO: figure out a way to stop IO while muted without losing sync */
        if ( track()->mute() || ( Track::soloing() && ! track()->solo() ) )
            buffer_fill_with_silence( (sample_t*)buf, nframes );
    }

    block_processed();

    /* FIXME: bogus */
    return nframes;
}
Exemplo n.º 7
0
/** prepare for capturing */
void
Audio_Region::prepare ( void )
{
    THREAD_ASSERT( Capture );

    DMESSAGE( "Preparing capture region" );

    log_start();
}
Exemplo n.º 8
0
/** read from the attached track's ports and stuff the ringbuffers */
nframes_t
Record_DS::process ( nframes_t nframes )
{
    THREAD_ASSERT( RT );

    if ( ! _recording )
        return 0;

     if ( transport->frame < _frame  )
         return 0;

/*    DMESSAGE( "recording actually happening at %lu (start frame %lu)", (unsigned long)transport->frame, (unsigned long)_frame); */

    nframes_t offset = 0;

    if ( _frame > transport->frame &&
         _frame < transport->frame + nframes )
    {
        /* The record start frame falls somewhere within the current
           buffer.  We must discard the unneeded portion and only
           stuff the part requested into the ringbuffer. */

        offset = _frame - transport->frame;

/*         DMESSAGE( "offset = %lu", (unsigned long)offset ); */
    }

    const size_t offset_size = offset * sizeof( sample_t );
    const size_t block_size = ( nframes * sizeof( sample_t ) ) - offset_size;

    for ( int i = channels(); i--;  )
    {
        /* read the entire input buffer */
        void *buf = track()->input[ i ].buffer( nframes );

/*         if ( buffer_is_digital_black( (sample_t*)buf, nframes ) ) */
/*              DWARNING( "recording an entirely blank buffer" ); */

        /* FIXME: this results in a ringbuffer size that is no longer
         necessarily a multiple of nframes...  how will the other side
         handle that? */
        if ( jack_ringbuffer_write( _rb[ i ], (char*)buf + offset, block_size ) < block_size )
        {
            ++_xruns;
            memset( buf, 0, block_size );
            /* FIXME: we need to resync somehow */
        }
    }

    block_processed();

    /* FIXME: bogus */
    return nframes;
}
Exemplo n.º 9
0
/** write /nframes/ from buf to the capture file of the attached track */
void
Record_DS::write_block ( sample_t *buf, nframes_t nframes )
{
    THREAD_ASSERT( Capture );

    /* stupid chicken/egg */
    if ( ! ( timeline && sequence() ) )
        return;

    track()->write( _capture, buf, nframes );

    _frames_written += nframes;
}
Exemplo n.º 10
0
/** request that the IO thread perform a seek and rebuffer.  This is
 called for each Disk_Stream whenever the RT thread determines that
 the transport has jumped to a new position. This is called *before*
 process. */
void
Playback_DS::seek ( nframes_t frame )
{
    THREAD_ASSERT( RT );

    /* FIXME: non-RT-safe IO */
    DMESSAGE( "requesting seek to frame %lu", (unsigned long)frame );

    if ( seek_pending() )
        printf( "seek error, attempt to seek while seek is pending\n" );

    _pending_seek = frame;

    flush();
}
Exemplo n.º 11
0
/** finalize region capture. Assumes that this *is* a captured region
    and that no other regions refer to the same source */
bool
Audio_Region::finalize ( nframes_t frame )
{
    THREAD_ASSERT( Capture );

    DMESSAGE( "finalizing capture region" );

    _range.length = frame - _range.start;

    _clip->close();
    _clip->open();

    log_end();

    return true;
}
Exemplo n.º 12
0
/** request that the IO thread perform a seek and rebuffer.  This is
 called for each Disk_Stream whenever the RT thread determines that
 the transport has jumped to a new position. This is called *before*
 process. */
void
Playback_DS::seek ( nframes_t frame )
{
    THREAD_ASSERT( RT );

    /* FIXME: non-RT-safe IO */
    DMESSAGE( "requesting seek to frame %lu", (unsigned long)frame );

    if ( seek_pending() )
        printf( "seek error, attempt to seek while seek is pending\n" );

    _seek_frame = frame;
    _pending_seek = true;

    /* wake the IO thread */
    block_processed();
}
Exemplo n.º 13
0
/** write /nframes/ from buf to the capture file of the attached track */
void
Record_DS::write_block ( sample_t *buf, nframes_t nframes )
{
    THREAD_ASSERT( Capture );

    /* stupid chicken/egg */
    if ( ! ( timeline && sequence() ) )
        return;


    if ( ! _capture->audio_file )
        /* create the file */
        track()->record( _capture, _frame );

    track()->write( _capture, buf, nframes );

    _frames_written += nframes;
}
Exemplo n.º 14
0
/** finalize the recording process. */
void
Record_DS::stop ( nframes_t frame )
{
    THREAD_ASSERT( UI );

    if ( ! _recording )
    {
        WARNING( "programming error: attempt to stop recording when no recording is being made" );
        return;
    }

    _recording = false;

    _stop_frame = frame;

//    detach();

    DMESSAGE( "recording finished" );
}
Exemplo n.º 15
0
/** write /nframes/ from /buf/ to source. /buf/ is interleaved and
    must match the channel layout of the write source!  */
nframes_t
Audio_Region::write ( nframes_t nframes )
{
    THREAD_ASSERT( Capture );

    if ( 0 == ( timeline->ts_to_x( _range.length ) % 20 ) )
    {
        int W = 20;

        if ( W )
        {
            Fl::lock();
            sequence()->damage(FL_DAMAGE_USER1, x(), y(), w(), h());
            Fl::unlock();
        }
    }

    _range.length += nframes;

    return nframes;
}
Exemplo n.º 16
0
void
Controller_Module::process ( nframes_t nframes )
{
    THREAD_ASSERT( RT );

    if ( type() == SPATIALIZATION )
    {
        return;
    }

    if (  control_output[0].connected() )
    {
        float f = control_value;

        if ( mode() == CV )
        {
            f = *((float*)jack_input[0].buffer( nframes ));

            const Port *p = control_output[0].connected_port();

            if (p->hints.ranged )
            {
                // scale value to range.
                // we assume that CV values are between 0 and 1

                float scale = p->hints.maximum - p->hints.minimum;
                float offset = p->hints.minimum;

                f = ( f * scale ) + offset;
            }
        }
//        else
//            f =  *((float*)control_output[0].buffer());

        *((float*)control_output[0].buffer()) = f;

        control_value = f;
    }
}
Exemplo n.º 17
0
void thread_queue(thread_t *thread)
{
	THREAD_ASSERT(thread);
	HASH_ADD_INT(thread_list, pid, thread);
}
Exemplo n.º 18
0
void thread_set_ready(thread_t *thread)
{
	THREAD_ASSERT(thread);
	thread->status = THREAD_READY;
}
Exemplo n.º 19
0
/* FIXME: it is far more efficient to read all the channels from a
   multichannel source at once... But how should we handle the case of a
   mismatch between the number of channels in this region's source and
   the number of channels on the track/buffer this data is being read
   for? Would it not be better to simply buffer and deinterlace the
   frames in the Audio_File class instead, so that sequential requests
   for different channels at the same position avoid hitting the disk
   again? */
nframes_t
Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const
{
    THREAD_ASSERT( Playback );

    const Range r = _range;

    /* do nothing if we aren't covered by this frame range */
    if ( pos > r.start + r.length || pos + nframes < r.start )
        return 0;

    /* calculate offsets into file and sample buffer */

    nframes_t sofs,                                              /* offset into source */
        ofs,                                                    /* offset into buffer */
        cnt;                                                    /* number of frames to read  */

    cnt = nframes;

    if ( pos < r.start )
    {
        /* region starts somewhere after the beginning of this buffer */
        sofs = 0;
        ofs = r.start - pos;
        cnt -= ofs;
    }
    else
    {
        /* region started before this buffer */
        ofs = 0;
        sofs = pos - r.start;
    }

    if ( ofs >= nframes )
        return 0;

//    const nframes_t start = ofs + r.start + sofs;
    const nframes_t start = r.offset + sofs;
    const nframes_t len = cnt;

    if ( len == 0 )
        return 0;

    /* now that we know how much and where to read, get on with it */

    //    printf( "reading region ofs = %lu, sofs = %lu, %lu-%lu\n", ofs, sofs, start, end  );

    /* FIXME: keep the declick defults someplace else */
    Fade declick;

    declick.length = 256;
    declick.type   = Fade::Sigmoid;

    if ( _loop )
    {
        nframes_t lofs = sofs % _loop;
        nframes_t lstart = r.offset + lofs;


        if ( lofs + len > _loop )
        {
            /* this buffer covers a loop binary */

            /* read the first part */
            cnt = _clip->read( buf + ofs, channel, lstart, len - ( ( lofs + len ) - _loop ) );
            /* read the second part */
            cnt += _clip->read( buf + ofs + cnt, channel, lstart + cnt, len - cnt );

            /* TODO: declick/crossfade transition? */

            assert( cnt == len );
        }
        else
            cnt = _clip->read( buf + ofs, channel, lstart, len );

        /* this buffer is inside declicking proximity to the loop boundary */

        if ( lofs + cnt + declick.length > _loop /* buffer ends within declick length of the end of loop */
             &&
             sofs + declick.length < r.length /* not the last loop */
            )
        {
            /* */
            /* fixme: what if loop is shorter than declick? */
            const nframes_t declick_start = _loop - declick.length;

            /* when the buffer covers the beginning of the
             * declick, how many frames between the beginning of
             * the buffer and the beginning of the declick */
            const nframes_t declick_onset_offset = declick_start > lofs ? declick_start - lofs : 0;

            /* how far into the declick we are */
            const nframes_t declick_offset = lofs > declick_start ? lofs - declick_start : 0;

            /* this is the end side of the loop boundary */

            const nframes_t fl = cnt - declick_onset_offset;

            declick.apply( buf + ofs + declick_onset_offset,
                           Fade::Out,
                           declick_offset, fl );
        }
            
        if ( lofs < declick.length /* buffer begins within declick length of beginning of loop */
             &&
             sofs > _loop )               /* not the first loop */
        {
                
            const nframes_t declick_end = declick.length;
                
            const nframes_t click_len = lofs + cnt > declick_end ? declick_end - lofs : cnt;

            /* this is the beginning of the loop next boundary */
            declick.apply( buf + ofs, Fade::In, lofs, click_len );
        }
    }
    else
        cnt = _clip->read( buf + ofs, channel, start, len );

    if ( ! cnt )
        return 0;

    /* apply gain */

    buffer_apply_gain( buf + ofs, cnt, _scale );

    /* perform declicking if necessary */


    {
        assert( cnt <= nframes );
            
        Fade fade;

        fade = declick < _fade_in ? _fade_in : declick;

        /* do fade in if necessary */
        if ( sofs < fade.length )
            fade.apply( buf + ofs, Fade::In, sofs, cnt );

        fade = declick < _fade_out ? _fade_out : declick;

        /* do fade out if necessary */
        if ( start + fade.length > r.offset + r.length )
            fade.apply( buf, Fade::Out, ( start + fade.length ) - ( r.offset + r.length ), cnt );                
    }

    return cnt;
}