--- /dev/null
+
+/*
+ * CINELERRA
+ * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "asset.h"
+#include "audiodevice.h"
+#include "bcdisplayinfo.h"
+#include "bcsignals.h"
+#include "clip.h"
+#include "bchash.h"
+#include "edlsession.h"
+#include "filexml.h"
+#include "guicast.h"
+#include "language.h"
+#include "mwindow.h"
+#include "pluginaclient.h"
+#include "pluginserver.h"
+#include "recordconfig.h"
+#include "samples.h"
+#include "transportque.inc"
+#include "vframe.h"
+
+#include <string.h>
+#include <stdint.h>
+
+class LiveAudio;
+class LiveAudioWindow;
+
+
+class LiveAudioConfig
+{
+public:
+ LiveAudioConfig();
+};
+
+
+
+
+
+
+class LiveAudioWindow : public PluginClientWindow
+{
+public:
+ LiveAudioWindow(LiveAudio *plugin);
+ ~LiveAudioWindow();
+
+ void create_objects();
+
+ LiveAudio *plugin;
+};
+
+
+
+
+
+
+class LiveAudio : public PluginAClient
+{
+public:
+ LiveAudio(PluginServer *server);
+ ~LiveAudio();
+
+
+ PLUGIN_CLASS_MEMBERS(LiveAudioConfig);
+
+ int process_buffer(int64_t size,
+ Samples **buffer,
+ int64_t start_position,
+ int sample_rate);
+ int is_realtime();
+ int is_multichannel();
+ int is_synthesis();
+ void save_data(KeyFrame *keyframe);
+ void read_data(KeyFrame *keyframe);
+ void update_gui();
+ void render_stop();
+
+ AudioDevice *adevice;
+
+ Samples **history;
+ int history_ptr;
+ int history_channels;
+ int64_t history_position;
+ int history_size;
+// Fragment size from the EDL session
+ int fragment_size;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+LiveAudioConfig::LiveAudioConfig()
+{
+}
+
+
+
+
+
+
+
+
+LiveAudioWindow::LiveAudioWindow(LiveAudio *plugin)
+ : PluginClientWindow(plugin,
+ 300,
+ 160,
+ 300,
+ 160,
+ 0)
+{
+ this->plugin = plugin;
+}
+
+LiveAudioWindow::~LiveAudioWindow()
+{
+}
+
+void LiveAudioWindow::create_objects()
+{
+ int x = 10, y = 10;
+
+ BC_Title *title;
+ add_subwindow(title = new BC_Title(x, y, _("Live audio")));
+ show_window();
+ flush();
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+REGISTER_PLUGIN(LiveAudio)
+
+
+
+
+
+
+LiveAudio::LiveAudio(PluginServer *server)
+ : PluginAClient(server)
+{
+ adevice = 0;
+ history = 0;
+ history_channels = 0;
+ history_ptr = 0;
+ history_position = 0;
+ history_size = 0;
+
+ fragment_size = 0;
+}
+
+
+LiveAudio::~LiveAudio()
+{
+ if(adevice)
+ {
+ adevice->interrupt_crash();
+ adevice->close_all();
+ }
+ delete adevice;
+ if(history)
+ {
+ for(int i = 0; i < history_channels; i++)
+ delete history[i];
+ delete [] history;
+ }
+}
+
+
+
+int LiveAudio::process_buffer(int64_t size,
+ Samples **buffer,
+ int64_t start_position,
+ int sample_rate)
+{
+ load_configuration();
+
+// printf("LiveAudio::process_buffer 10 size=%lld buffer_size=%d channels=%d size=%d\n",
+// size, get_buffer_size(), get_total_buffers(), size);
+
+ int first_buffer = 0;
+
+ if(!adevice)
+ {
+ EDLSession *session = PluginClient::get_edlsession();
+ if(session)
+ {
+ fragment_size = session->record_fragment_size;
+ history_channels = session->aconfig_in->channels;
+
+ adevice = new AudioDevice(server ? server->mwindow : 0);
+// Take fragment size & channels from the recording config
+ adevice->open_input(session->aconfig_in,
+ session->vconfig_in,
+ get_project_samplerate(),
+ fragment_size,
+ session->aconfig_in->channels,
+ session->real_time_record);
+ adevice->start_recording();
+ first_buffer = 1;
+ history_position = start_position;
+ }
+ }
+
+ if(!history || history[0]->get_allocated() < size)
+ {
+// compute new history which is a multiple of our fragment size
+ int new_history_size = fragment_size;
+ while(new_history_size < size)
+ new_history_size += fragment_size;
+
+
+ if(!history)
+ {
+ history = new Samples*[history_channels];
+ for(int i = 0; i < history_channels; i++)
+ history[i] = 0;
+ }
+
+ for(int i = 0; i < history_channels; i++)
+ {
+ delete history[i];
+ history[i] = new Samples(new_history_size);
+ bzero(history[i]->get_data(), sizeof(double) * new_history_size);
+ }
+ }
+
+
+
+// if(get_direction() == PLAY_FORWARD)
+ {
+// Reset history buffer to current position if before maximum history
+ if(start_position < history_position - history[0]->get_allocated())
+ history_position = start_position;
+
+
+
+// Extend history buffer
+ int64_t end_position = start_position + size;
+// printf("LiveAudio::process_buffer %lld %lld %lld\n",
+// end_position,
+// history_position,
+// end_position - history_position);
+ if(end_position > history_position)
+ {
+// Reset history buffer to current position if after maximum history
+ if(start_position >= history_position + history[0]->get_allocated())
+ history_position = start_position;
+// A delay seems required because ALSA playback may get ahead of
+// ALSA recording and never recover.
+ if(first_buffer) end_position += sample_rate;
+ int done = 0;
+ while(!done && history_position < end_position)
+ {
+ if(history_ptr + fragment_size >= history[0]->get_allocated())
+ {
+ done = 1;
+ }
+
+// Read rest of buffer from sound driver
+ if(adevice)
+ {
+ int over[history_channels];
+ double max[history_channels];
+ int result = adevice->read_buffer(history,
+ history_channels,
+ fragment_size,
+ over,
+ max,
+ history_ptr);
+ if( result && adevice->config_updated() )
+ adevice->config_update();
+ }
+
+ history_ptr += fragment_size;
+// wrap around buffer
+ if(history_ptr >= history[0]->get_allocated())
+ history_ptr = 0;
+ history_position += fragment_size;
+ }
+ }
+
+// Copy data from history buffer
+ int buffer_position = 0;
+ int history_buffer_ptr = history_ptr - history_position + start_position;
+ while(history_buffer_ptr < 0)
+ history_buffer_ptr += history[0]->get_allocated();
+ while(buffer_position < size)
+ {
+ int fragment = size;
+ if(history_buffer_ptr + fragment > history[0]->get_allocated())
+ fragment = history[0]->get_allocated() - history_buffer_ptr;
+ if(buffer_position + fragment > size)
+ fragment = size - buffer_position;
+
+ for(int i = 0; i < get_total_buffers(); i++)
+ {
+ int input_channel = i;
+// Clamp channel to total history channels
+ if(input_channel >= history_channels)
+ input_channel = history_channels - 1;
+ memcpy(buffer[i]->get_data() + buffer_position,
+ history[input_channel]->get_data() + history_buffer_ptr,
+ sizeof(double) * fragment);
+ }
+
+ history_buffer_ptr += fragment;
+ if(history_buffer_ptr >= history[0]->get_allocated())
+ history_buffer_ptr = 0;
+ buffer_position += fragment;
+ }
+
+
+ }
+
+
+ return 0;
+}
+
+void LiveAudio::render_stop()
+{
+ if(adevice)
+ {
+ adevice->interrupt_crash();
+ adevice->close_all();
+ }
+ delete adevice;
+ adevice = 0;
+ history_ptr = 0;
+ history_position = 0;
+ history_size = 0;
+}
+
+
+const char* LiveAudio::plugin_title() { return _("Live Audio"); }
+int LiveAudio::is_realtime() { return 1; }
+int LiveAudio::is_multichannel() { return 1; }
+int LiveAudio::is_synthesis() { return 1; }
+
+
+
+NEW_WINDOW_MACRO(LiveAudio, LiveAudioWindow)
+
+
+
+int LiveAudio::load_configuration()
+{
+ return 0;
+}
+
+
+void LiveAudio::save_data(KeyFrame *keyframe)
+{
+}
+
+void LiveAudio::read_data(KeyFrame *keyframe)
+{
+}
+
+void LiveAudio::update_gui()
+{
+}
+
+
+
+
+