2008-09-17 12:58:33 +00:00
/*
Copyright ( C ) 2008 Paul Davis
Author : Sakari Bergen
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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include <ardour/export_channel_configuration.h>
# include <ardour/export_handler.h>
# include <ardour/export_filename.h>
# include <ardour/export_processor.h>
# include <ardour/export_timespan.h>
# include <ardour/audio_port.h>
# include <ardour/export_failed.h>
# include <ardour/midi_port.h>
2008-09-20 22:06:02 +00:00
# include <ardour/session.h>
# include <ardour/audioengine.h>
# include <pbd/convert.h>
2008-09-17 12:58:33 +00:00
# include <pbd/pthread_utils.h>
namespace ARDOUR
{
/* ExportChannel */
void
ExportChannel : : read_ports ( float * data , nframes_t frames ) const
{
memset ( data , 0 , frames * sizeof ( float ) ) ;
for ( iterator it = begin ( ) ; it ! = end ( ) ; + + it ) {
if ( * it ! = 0 ) {
Sample * port_buffer = ( * it ) - > get_audio_buffer ( ) . data ( ) ;
for ( uint32_t i = 0 ; i < frames ; + + i ) {
data [ i ] + = ( float ) port_buffer [ i ] ;
}
}
}
}
/* ExportChannelConfiguration */
2008-09-20 22:06:02 +00:00
ExportChannelConfiguration : : ExportChannelConfiguration ( ExportStatus & status , Session & session ) :
session ( session ) ,
2008-09-17 12:58:33 +00:00
writer_thread ( * this ) ,
status ( status ) ,
files_written ( false ) ,
split ( false )
{
}
2008-09-20 22:06:02 +00:00
XMLNode &
ExportChannelConfiguration : : get_state ( )
2008-09-17 12:58:33 +00:00
{
2008-09-20 22:06:02 +00:00
XMLNode * root = new XMLNode ( " ExportChannelConfiguration " ) ;
XMLNode * channel ;
XMLNode * port_node ;
root - > add_property ( " split " , get_split ( ) ? " true " : " false " ) ;
root - > add_property ( " channels " , to_string ( get_n_chans ( ) , std : : dec ) ) ;
uint32_t i = 1 ;
for ( ExportChannelConfiguration : : ChannelList : : const_iterator c_it = channels . begin ( ) ; c_it ! = channels . end ( ) ; + + c_it ) {
channel = root - > add_child ( " Channel " ) ;
if ( ! channel ) { continue ; }
channel - > add_property ( " number " , to_string ( i , std : : dec ) ) ;
for ( ExportChannel : : const_iterator p_it = ( * c_it ) - > begin ( ) ; p_it ! = ( * c_it ) - > end ( ) ; + + p_it ) {
if ( ( port_node = channel - > add_child ( " Port " ) ) ) {
port_node - > add_property ( " name " , ( * p_it ) - > name ( ) ) ;
}
}
+ + i ;
}
return * root ;
}
int
ExportChannelConfiguration : : set_state ( const XMLNode & root )
{
XMLProperty const * prop ;
if ( ( prop = root . property ( " split " ) ) ) {
set_split ( ! prop - > value ( ) . compare ( " true " ) ) ;
}
XMLNodeList channels = root . children ( " Channel " ) ;
for ( XMLNodeList : : iterator it = channels . begin ( ) ; it ! = channels . end ( ) ; + + it ) {
boost : : shared_ptr < ExportChannel > channel ( new ExportChannel ( ) ) ;
XMLNodeList ports = ( * it ) - > children ( " Port " ) ;
for ( XMLNodeList : : iterator p_it = ports . begin ( ) ; p_it ! = ports . end ( ) ; + + p_it ) {
if ( ( prop = ( * p_it ) - > property ( " name " ) ) ) {
channel - > add_port ( dynamic_cast < AudioPort * > ( session . engine ( ) . get_port_by_name ( prop - > value ( ) ) ) ) ;
}
}
register_channel ( channel ) ;
}
2008-09-17 12:58:33 +00:00
2008-09-20 22:06:02 +00:00
return 0 ;
2008-09-17 12:58:33 +00:00
}
bool
ExportChannelConfiguration : : all_channels_have_ports ( )
{
for ( ChannelList : : iterator it = channels . begin ( ) ; it ! = channels . end ( ) ; + + it ) {
if ( ( * it ) - > empty ( ) ) { return false ; }
}
return true ;
}
bool
ExportChannelConfiguration : : write_files ( boost : : shared_ptr < ExportProcessor > new_processor )
{
if ( files_written | | writer_thread . running ) {
return false ;
}
files_written = true ;
if ( ! timespan ) {
throw ExportFailed ( _ ( " Export failed due to a programming error " ) , _ ( " No timespan registered to channel configuration when requesting files to be written " ) ) ;
}
/* Take a local copy of the processor to be used in the thread that is created below */
processor . reset ( new_processor - > copy ( ) ) ;
/* Create new thread for post processing */
pthread_create ( & writer_thread . thread , 0 , _write_files , & writer_thread ) ;
writer_thread . running = true ;
pthread_detach ( writer_thread . thread ) ;
return true ;
}
void
ExportChannelConfiguration : : write_file ( )
{
timespan - > rewind ( ) ;
nframes_t progress = 0 ;
nframes_t timespan_length = timespan - > get_length ( ) ;
nframes_t frames = 2048 ; // TODO good block size ?
nframes_t frames_read = 0 ;
float * channel_buffer = new float [ frames ] ;
float * file_buffer = new float [ channels . size ( ) * frames ] ;
uint32_t channel_count = channels . size ( ) ;
uint32_t channel ;
do {
if ( status . aborted ( ) ) { break ; }
channel = 0 ;
for ( ChannelList : : iterator it = channels . begin ( ) ; it ! = channels . end ( ) ; + + it ) {
/* Get channel data */
frames_read = timespan - > get_data ( channel_buffer , frames , * * it ) ;
/* Interleave into file buffer */
for ( uint32_t i = 0 ; i < frames_read ; + + i ) {
file_buffer [ channel + ( channel_count * i ) ] = channel_buffer [ i ] ;
}
+ + channel ;
}
progress + = frames_read ;
status . progress = ( float ) progress / timespan_length ;
} while ( processor - > process ( file_buffer , frames_read ) > 0 ) ;
delete [ ] channel_buffer ;
delete [ ] file_buffer ;
}
void *
ExportChannelConfiguration : : _write_files ( void * arg )
{
PBD : : ThreadCreated ( pthread_self ( ) , " Export post-processing " ) ;
// cc can be trated like 'this'
WriterThread & cc ( * ( ( WriterThread * ) arg ) ) ;
for ( FileConfigList : : iterator it = cc - > file_configs . begin ( ) ; it ! = cc - > file_configs . end ( ) ; + + it ) {
if ( cc - > status . aborted ( ) ) {
break ;
}
cc - > processor - > prepare ( it - > first , it - > second , cc - > channels . size ( ) , cc - > split , cc - > timespan - > get_start ( ) ) ;
cc - > write_file ( ) ; // Writes tempfile
cc - > processor - > prepare_post_processors ( ) ;
cc - > processor - > write_files ( ) ;
}
cc . running = false ;
cc - > files_written = true ;
cc - > FilesWritten ( ) ;
return 0 ; // avoid compiler warnings
}
void
ExportChannelConfiguration : : register_with_timespan ( TimespanPtr new_timespan )
{
timespan = new_timespan ;
for ( ChannelList : : iterator it = channels . begin ( ) ; it ! = channels . end ( ) ; + + it ) {
timespan - > register_channel ( * * it ) ;
}
}
void
ExportChannelConfiguration : : unregister_all ( )
{
timespan . reset ( ) ;
processor . reset ( ) ;
file_configs . clear ( ) ;
files_written = false ;
}
} // namespace ARDOUR