4 * Copyright (C) 2009 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "audiodevice.h"
28 #include "bcsignals.h"
30 #include "condition.h"
33 #include "edlsession.h"
34 #include "levelwindow.h"
35 #include "mainsession.h"
36 #include "playabletracks.h"
37 #include "playbackengine.h"
38 #include "preferences.h"
39 #include "renderengine.h"
42 #include "transportque.h"
43 #include "virtualaconsole.h"
44 #include "virtualconsole.h"
45 #include "virtualnode.h"
47 ARender::ARender(RenderEngine *renderengine)
48 : CommonRender(renderengine)
50 // Clear output buffers
51 for( int i=0; i<MAXCHANNELS; ++i ) {
54 buffer_allocated[i] = 0;
57 meter_history = new MeterHistory();
58 data_type = TRACK_AUDIO;
63 for( int i=0; i<MAXCHANNELS; ++i ) delete buffer[i];
67 void ARender::arm_command()
69 // Need the meter history now so AModule can allocate its own history
70 calculate_history_size();
71 CommonRender::arm_command();
77 int ARender::get_total_tracks()
79 return renderengine->get_edl()->tracks->total_audio_tracks();
82 Module* ARender::new_module(Track *track)
84 return new AModule(renderengine, this, 0, track);
87 int ARender::calculate_history_size()
90 meter_render_fragment = renderengine->fragment_len;
91 int tracking_fragment = renderengine->get_edl()->session->sample_rate / TRACKING_RATE;
92 // This number and the timer in tracking.C determine the rate
93 while( meter_render_fragment > tracking_fragment ) meter_render_fragment /= 2;
94 total_peaks = 16 * renderengine->fragment_len / meter_render_fragment;
99 int ARender::init_meters()
101 // not providing enough peaks results in peaks that are ahead of the sound
102 meter_history->init(MAXCHANNELS, calculate_history_size());
103 for( int i=0; i<MAXCHANNELS; ++i ) {
104 if( buffer[i] ) meter_history->reset_channel(i);
109 void ARender::allocate_buffers(int samples)
111 for( int i=0; i<MAXCHANNELS; ++i ) {
112 // Reset the output buffers in case speed changed
113 if( buffer_allocated[i] < samples ||
114 i >= renderengine->get_edl()->session->audio_channels ) {
115 delete buffer[i]; buffer[i] = 0;
118 if( !buffer[i] && i < renderengine->get_edl()->session->audio_channels ) {
119 buffer[i] = new Samples(samples);
120 buffer_allocated[i] = samples;
122 audio_out[i] = buffer[i];
126 void ARender::init_output_buffers()
128 allocate_buffers(renderengine->adjusted_fragment_len);
132 VirtualConsole* ARender::new_vconsole_object()
134 return new VirtualAConsole(renderengine, this);
137 int64_t ARender::tounits(double position, int round)
140 return Units::round(position * renderengine->get_edl()->session->sample_rate);
142 return (int64_t)(position * renderengine->get_edl()->session->sample_rate);
145 double ARender::fromunits(int64_t position)
147 return (double)position / renderengine->get_edl()->session->sample_rate;
151 int ARender::process_buffer(Samples **buffer_out,
153 int64_t input_position)
157 int64_t fragment_position = 0;
158 int64_t fragment_len = input_len;
160 current_position = input_position;
162 // Process in fragments
163 int start_offset = buffer_out[0]->get_offset();
164 while(fragment_position < input_len)
166 // Set pointers for destination data
167 for(int i = 0; i < MAXCHANNELS; i++)
171 this->audio_out[i] = buffer_out[i];
172 this->audio_out[i]->set_offset(start_offset + fragment_position);
175 this->audio_out[i] = 0;
178 fragment_len = input_len;
179 if(fragment_position + fragment_len > input_len)
180 fragment_len = input_len - fragment_position;
182 reconfigure = vconsole->test_reconfigure(input_position,
185 //printf("ARender::process_buffer 1 %jd %d\n", input_position, reconfigure);
187 if(reconfigure) restart_playback();
189 result = process_buffer(fragment_len, input_position);
191 fragment_position += fragment_len;
192 input_position += fragment_len;
193 current_position = input_position;
197 for(int i = 0; i < MAXCHANNELS; i++)
199 if(buffer_out[i]) buffer_out[i]->set_offset(start_offset);
208 int ARender::process_buffer(int64_t input_len, int64_t input_position)
210 int result = ((VirtualAConsole*)vconsole)->process_buffer(input_len,
215 void ARender::send_last_buffer()
217 if( renderengine->audio )
218 renderengine->audio->set_last_buffer();
221 int ARender::stop_audio(int wait)
223 if( renderengine->audio )
224 renderengine->audio->stop_audio(wait);
228 void ARender::interrupt_playback()
230 //printf("ARender::interrupt_playback\n");
232 if( renderengine->audio )
233 renderengine->audio->interrupt_playback();
238 int64_t current_input_length;
244 start_lock->unlock();
245 if(debug) printf("ARender::run %d %d\n", __LINE__, Thread::calculate_realtime());
247 while(!done && !interrupt)
249 float speed = renderengine->command->get_speed();
250 current_input_length = (int64_t)(renderengine->fragment_len * speed +0.5) ;
252 if(debug) printf("ARender::run %d %jd %jd\n", __LINE__, current_position, current_input_length);
253 get_boundaries(current_input_length);
255 if(debug) printf("ARender::run %d %jd %jd\n", __LINE__, current_position, current_input_length);
256 if(current_input_length)
258 reconfigure = vconsole->test_reconfigure(current_position,
259 current_input_length);
260 if(reconfigure) restart_playback();
262 if(debug) printf("ARender::run %d %jd %jd\n", __LINE__, current_position, current_input_length);
265 // Update tracking if no video is playing.
266 if(renderengine->command->realtime &&
267 renderengine->playback_engine &&
268 !renderengine->do_video)
270 double position = (double)renderengine->audio->current_position() /
271 renderengine->get_edl()->session->sample_rate * speed;
273 if(renderengine->command->get_direction() == PLAY_FORWARD)
274 position += renderengine->command->playbackstart;
276 position = renderengine->command->playbackstart - position;
278 // This number is not compensated for looping. It's compensated in
279 // PlaybackEngine::get_tracking_position when interpolation also happens.
280 renderengine->playback_engine->update_tracking(position);
284 if(debug) printf("ARender::run %d %jd\n", __LINE__, current_input_length);
288 process_buffer(current_input_length, current_position);
289 if(debug) printf("ARender::run %d\n", __LINE__);
292 advance_position(current_input_length);
293 if(debug) printf("ARender::run %d\n", __LINE__);
296 if( !interrupt ) interrupt = renderengine->interrupted;
297 if( !interrupt ) interrupt = renderengine->audio->get_interrupted();
298 if( !interrupt ) interrupt = vconsole->interrupt;
301 if(debug) printf("ARender::run %d\n", __LINE__);
302 if(!interrupt) send_last_buffer();
303 if(renderengine->command->realtime)
304 stop_audio(interrupt ? 0 : 1);
305 vconsole->stop_rendering(0);