Very basic audio processing framework.
authorCarl Hetherington <cth@carlh.net>
Sun, 13 Jul 2014 19:44:45 +0000 (20:44 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 13 Jul 2014 19:44:45 +0000 (20:44 +0100)
14 files changed:
src/lib/audio_content.cc
src/lib/audio_content.h
src/lib/audio_decoder.cc
src/lib/audio_decoder.h
src/lib/audio_mapping.cc
src/lib/audio_processor.cc [new file with mode: 0644]
src/lib/audio_processor.h [new file with mode: 0644]
src/lib/channel_count.h [new file with mode: 0644]
src/lib/mid_side_decoder.cc [new file with mode: 0644]
src/lib/mid_side_decoder.h [new file with mode: 0644]
src/lib/util.cc
src/lib/wscript
src/wx/audio_panel.cc
src/wx/audio_panel.h

index 6317aa4cb7d7390c9a47fc1523353e7c5b50a39f..d02728b00018f5ed6d8bc023698b6fe4a94c7536 100644 (file)
@@ -26,6 +26,7 @@
 #include "exceptions.h"
 #include "config.h"
 #include "frame_rate_change.h"
+#include "audio_processor.h"
 
 #include "i18n.h"
 
@@ -42,11 +43,13 @@ int const AudioContentProperty::AUDIO_FRAME_RATE = 202;
 int const AudioContentProperty::AUDIO_GAIN = 203;
 int const AudioContentProperty::AUDIO_DELAY = 204;
 int const AudioContentProperty::AUDIO_MAPPING = 205;
+int const AudioContentProperty::AUDIO_PROCESSOR = 206;
 
 AudioContent::AudioContent (shared_ptr<const Film> f)
        : Content (f)
        , _audio_gain (0)
        , _audio_delay (Config::instance()->default_audio_delay ())
+       , _audio_processor (0)
 {
 
 }
@@ -55,6 +58,7 @@ AudioContent::AudioContent (shared_ptr<const Film> f, DCPTime s)
        : Content (f, s)
        , _audio_gain (0)
        , _audio_delay (Config::instance()->default_audio_delay ())
+       , _audio_processor (0)
 {
 
 }
@@ -63,15 +67,20 @@ AudioContent::AudioContent (shared_ptr<const Film> f, boost::filesystem::path p)
        : Content (f, p)
        , _audio_gain (0)
        , _audio_delay (Config::instance()->default_audio_delay ())
+       , _audio_processor (0)
 {
 
 }
 
 AudioContent::AudioContent (shared_ptr<const Film> f, cxml::ConstNodePtr node)
        : Content (f, node)
+       , _audio_processor (0)
 {
        _audio_gain = node->number_child<float> ("AudioGain");
        _audio_delay = node->number_child<int> ("AudioDelay");
+       if (node->optional_string_child ("AudioProcessor")) {
+               _audio_processor = AudioProcessor::from_id (node->string_child ("AudioProcessor"));
+       }
 }
 
 AudioContent::AudioContent (shared_ptr<const Film> f, vector<shared_ptr<Content> > c)
@@ -94,6 +103,7 @@ AudioContent::AudioContent (shared_ptr<const Film> f, vector<shared_ptr<Content>
 
        _audio_gain = ref->audio_gain ();
        _audio_delay = ref->audio_delay ();
+       _audio_processor = ref->audio_processor ();
 }
 
 void
@@ -102,6 +112,9 @@ AudioContent::as_xml (xmlpp::Node* node) const
        boost::mutex::scoped_lock lm (_mutex);
        node->add_child("AudioGain")->add_child_text (raw_convert<string> (_audio_gain));
        node->add_child("AudioDelay")->add_child_text (raw_convert<string> (_audio_delay));
+       if (_audio_processor) {
+               node->add_child("AudioProcessor")->add_child_text (_audio_processor->id ());
+       }
 }
 
 
@@ -127,6 +140,22 @@ AudioContent::set_audio_delay (int d)
        signal_changed (AudioContentProperty::AUDIO_DELAY);
 }
 
+void
+AudioContent::set_audio_processor (AudioProcessor const * p)
+{
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _audio_processor = p;
+       }
+
+       /* The channel count might have changed, so reset the mapping */
+       AudioMapping m (processed_audio_channels ());
+       m.make_default ();
+       set_audio_mapping (m);
+
+       signal_changed (AudioContentProperty::AUDIO_PROCESSOR);
+}
+
 boost::signals2::connection
 AudioContent::analyse_audio (boost::function<void()> finished)
 {
@@ -196,3 +225,14 @@ AudioContent::resampled_audio_frame_rate () const
 
        return rint (t);
 }
+
+int
+AudioContent::processed_audio_channels () const
+{
+       if (!audio_processor ()) {
+               return audio_channels ();
+       }
+
+       return audio_processor()->out_channels (audio_channels ());
+}
+
index 131ced61aead11dab059a600aa4f3f3b1aed024c..540839d695241be94e769bb6e42218b4128e3d50 100644 (file)
@@ -31,6 +31,8 @@ namespace cxml {
        class Node;
 }
 
+class AudioProcessor;
+
 class AudioContentProperty
 {
 public:
@@ -40,6 +42,7 @@ public:
        static int const AUDIO_GAIN;
        static int const AUDIO_DELAY;
        static int const AUDIO_MAPPING;
+       static int const AUDIO_PROCESSOR;
 };
 
 /** @class AudioContent
@@ -70,11 +73,13 @@ public:
        virtual boost::filesystem::path audio_analysis_path () const;
 
        int resampled_audio_frame_rate () const;
+       int processed_audio_channels () const;
 
        boost::signals2::connection analyse_audio (boost::function<void()>);
 
        void set_audio_gain (double);
        void set_audio_delay (int);
+       void set_audio_processor (AudioProcessor const *);
        
        double audio_gain () const {
                boost::mutex::scoped_lock lm (_mutex);
@@ -86,11 +91,17 @@ public:
                return _audio_delay;
        }
 
+       AudioProcessor const * audio_processor () const {
+               boost::mutex::scoped_lock lm (_mutex);
+               return _audio_processor;
+       }
+       
 private:
        /** Gain to apply to audio in dB */
        double _audio_gain;
        /** Delay to apply to audio (positive moves audio later) in milliseconds */
        int _audio_delay;
+       AudioProcessor const * _audio_processor;
 };
 
 #endif
index 97a088791ad9bbe2c4b5e84cec227d016ce23175..19f31d30ac3f50fc08ac1ce68757da6b0b011255 100644 (file)
@@ -24,6 +24,7 @@
 #include "resampler.h"
 #include "util.h"
 #include "film.h"
+#include "audio_processor.h"
 
 #include "i18n.h"
 
@@ -43,13 +44,17 @@ AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content)
                _resampler.reset (new Resampler (content->audio_frame_rate(), content->resampled_audio_frame_rate(), content->audio_channels ()));
        }
 
+       if (content->audio_processor ()) {
+               _processor = content->audio_processor()->clone ();
+       }
+
        reset_decoded_audio ();
 }
 
 void
 AudioDecoder::reset_decoded_audio ()
 {
-       _decoded_audio = ContentAudio (shared_ptr<AudioBuffers> (new AudioBuffers (_audio_content->audio_channels(), 0)), 0);
+       _decoded_audio = ContentAudio (shared_ptr<AudioBuffers> (new AudioBuffers (_audio_content->processed_audio_channels(), 0)), 0);
 }
 
 shared_ptr<ContentAudio>
@@ -125,6 +130,10 @@ AudioDecoder::audio (shared_ptr<const AudioBuffers> data, ContentTime time)
                data = _resampler->run (data);
        }
 
+       if (_processor) {
+               data = _processor->run (data);
+       }
+
        AudioFrame const frame_rate = _audio_content->resampled_audio_frame_rate ();
 
        if (_seek_reference) {
index 0553d7c819732df323f5ef67f2331ec3dc290e58..045efc00207758d01cb56fce7996d685f1a1b458 100644 (file)
@@ -61,6 +61,7 @@ protected:
 
        boost::shared_ptr<const AudioContent> _audio_content;
        boost::shared_ptr<Resampler> _resampler;
+       boost::shared_ptr<AudioProcessor> _processor;
        boost::optional<AudioFrame> _audio_position;
        /** Currently-available decoded audio data */
        ContentAudio _decoded_audio;
index b3757c5f1be9bd2fefc2a38199215201cde2cf11..e86e2e2ac6820499cd551ddaed17ffe8e7f30019 100644 (file)
@@ -40,7 +40,7 @@ AudioMapping::AudioMapping ()
 
 }
 
-/** Create a default AudioMapping for a given channel count.
+/** Create an empty AudioMapping for a given channel count.
  *  @param channels Number of channels.
  */
 AudioMapping::AudioMapping (int channels)
diff --git a/src/lib/audio_processor.cc b/src/lib/audio_processor.cc
new file mode 100644 (file)
index 0000000..2714680
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "audio_processor.h"
+#include "mid_side_decoder.h"
+
+using std::string;
+using std::list;
+
+list<AudioProcessor const *> AudioProcessor::_all;
+
+void
+AudioProcessor::setup_audio_processors ()
+{
+       _all.push_back (new MidSideDecoder ());
+}
+
+AudioProcessor const *
+AudioProcessor::from_id (string id)
+{
+       for (list<AudioProcessor const *>::const_iterator i = _all.begin(); i != _all.end(); ++i) {
+               if ((*i)->id() == id) {
+                       return *i;
+               }
+       }
+
+       return 0;
+}
+
+list<AudioProcessor const *>
+AudioProcessor::all ()
+{
+       return _all;
+}
diff --git a/src/lib/audio_processor.h b/src/lib/audio_processor.h
new file mode 100644 (file)
index 0000000..7ff9f0e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef DCPOMATIC_AUDIO_PROCESSOR_H
+#define DCPOMATIC_AUDIO_PROCESSOR_H
+
+#include <list>
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include "channel_count.h"
+
+class AudioBuffers;
+
+class AudioProcessor
+{
+public:
+       virtual ~AudioProcessor () {}
+
+       virtual std::string name () const = 0;
+       virtual std::string id () const = 0;
+       virtual ChannelCount in_channels () const = 0;
+       virtual int out_channels (int) const = 0;
+       virtual boost::shared_ptr<AudioProcessor> clone () const = 0;
+       virtual boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>) = 0;
+
+       static std::list<AudioProcessor const *> all ();
+       static void setup_audio_processors ();
+       static AudioProcessor const * from_id (std::string);
+
+private:
+       static std::list<AudioProcessor const *> _all;
+};
+
+#endif
diff --git a/src/lib/channel_count.h b/src/lib/channel_count.h
new file mode 100644 (file)
index 0000000..4247fc0
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef DCPOMATIC_CHANNEL_COUNT_H
+#define DCPOMATIC_CHANNEL_COUNT_H
+
+class ChannelCount
+{
+public:
+       ChannelCount ()
+               : min (0)
+               , max (0)
+       {}
+
+       ChannelCount (int n)
+               : min (n)
+               , max (n)
+       {}
+       
+       ChannelCount (int min_, int max_)
+               : min (min_)
+               , max (max_)
+       {}
+
+       bool includes (int c) {
+               return min <= c && c <= max;
+       }
+
+       int min;
+       int max;
+};
+
+#endif
diff --git a/src/lib/mid_side_decoder.cc b/src/lib/mid_side_decoder.cc
new file mode 100644 (file)
index 0000000..a518a43
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "mid_side_decoder.h"
+#include "audio_buffers.h"
+
+#include "i18n.h"
+
+using std::string;
+using boost::shared_ptr;
+
+string
+MidSideDecoder::name () const
+{
+       return _("Mid-side decoder");
+}
+
+string
+MidSideDecoder::id () const
+{
+       return N_("mid-side-decoder");
+}
+
+ChannelCount
+MidSideDecoder::in_channels () const
+{
+       return ChannelCount (2);
+}
+
+int
+MidSideDecoder::out_channels (int) const
+{
+       return 3;
+}
+
+shared_ptr<AudioProcessor>
+MidSideDecoder::clone () const
+{
+       return shared_ptr<AudioProcessor> (new MidSideDecoder ());
+}
+
+shared_ptr<AudioBuffers>
+MidSideDecoder::run (shared_ptr<const AudioBuffers> in)
+{
+       shared_ptr<AudioBuffers> out (new AudioBuffers (3, in->frames ()));
+       for (int i = 0; i < in->frames(); ++i) {
+               float const left = in->data()[0][i];
+               float const right = in->data()[1][i];
+               float const mid = (left + right) / 2;
+               out->data()[0][i] = left - mid;
+               out->data()[1][i] = right - mid;
+               out->data()[2][i] = mid;
+       }
+
+       return out;
+}
diff --git a/src/lib/mid_side_decoder.h b/src/lib/mid_side_decoder.h
new file mode 100644 (file)
index 0000000..a6d2721
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    Copyright (C) 2014 Carl Hetherington <cth@carlh.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "audio_processor.h"
+
+class MidSideDecoder : public AudioProcessor
+{
+public:
+       std::string name () const;
+       std::string id () const;
+       ChannelCount in_channels () const;
+       int out_channels (int) const;
+       boost::shared_ptr<AudioProcessor> clone () const;
+       boost::shared_ptr<AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+};
+
+       
index 55df5cc83798ba126eeebc82a0e9ca0d7f71aa34..dd39e286e110608dadbe2de842703e6297d49f46 100644 (file)
@@ -72,6 +72,7 @@ extern "C" {
 #include "video_content.h"
 #include "rect.h"
 #include "md5_digester.h"
+#include "audio_processor.h"
 #ifdef DCPOMATIC_WINDOWS
 #include "stack.hpp"
 #endif
@@ -336,6 +337,7 @@ dcpomatic_setup ()
        Scaler::setup_scalers ();
        Filter::setup_filters ();
        SoundProcessor::setup_sound_processors ();
+       AudioProcessor::setup_audio_processors ();
 
        ui_thread = boost::this_thread::get_id ();
 }
index d96bb7f96c8eac8981f8ac74552a14c68686d20d..60150f4da5216f55a8f458aef8f12679d767d23f 100644 (file)
@@ -8,6 +8,7 @@ sources = """
           audio_content.cc
           audio_decoder.cc
           audio_mapping.cc
+          audio_processor.cc
           cinema.cc
           colour_conversion.cc
           config.cc
@@ -55,6 +56,7 @@ sources = """
           log.cc
           magick_image_proxy.cc
           md5_digester.cc
+          mid_side_decoder.cc
           player.cc
           player_video.cc
           playlist.cc
index 10b5a5f76a0d1dfdf01b15a02b3f59c3dfd0057a..651ea93e10d317e1706c210283a4b5f36b09ef85 100644 (file)
@@ -23,6 +23,7 @@
 #include "lib/sound_processor.h"
 #include "lib/ffmpeg_content.h"
 #include "lib/ffmpeg_audio_stream.h"
+#include "lib/audio_processor.h"
 #include "audio_dialog.h"
 #include "audio_panel.h"
 #include "audio_mapping_view.h"
@@ -33,6 +34,7 @@
 using std::vector;
 using std::cout;
 using std::string;
+using std::list;
 using boost::dynamic_pointer_cast;
 using boost::lexical_cast;
 using boost::shared_ptr;
@@ -84,6 +86,12 @@ AudioPanel::AudioPanel (ContentPanel* p)
        grid->Add (_stream, wxGBPosition (r, 1));
        _description = add_label_to_grid_bag_sizer (grid, this, "", false, wxGBPosition (r, 3));
        ++r;
+
+       add_label_to_grid_bag_sizer (grid, this, _("Process with"), true, wxGBPosition (r, 0));
+       _processor = new wxChoice (this, wxID_ANY);
+       setup_processors ();
+       grid->Add (_processor, wxGBPosition (r, 1));
+       ++r;
        
        _mapping = new AudioMappingView (this);
        _sizer->Add (_mapping, 1, wxEXPAND | wxALL, 6);
@@ -93,9 +101,10 @@ AudioPanel::AudioPanel (ContentPanel* p)
        _gain->wrapped()->SetIncrement (0.5);
        _delay->wrapped()->SetRange (-1000, 1000);
 
-       _stream->Bind                (wxEVT_COMMAND_CHOICE_SELECTED,  boost::bind (&AudioPanel::stream_changed, this));
-       _show->Bind                  (wxEVT_COMMAND_BUTTON_CLICKED,   boost::bind (&AudioPanel::show_clicked, this));
-       _gain_calculate_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED,   boost::bind (&AudioPanel::gain_calculate_button_clicked, this));
+       _stream->Bind                (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&AudioPanel::stream_changed, this));
+       _show->Bind                  (wxEVT_COMMAND_BUTTON_CLICKED,  boost::bind (&AudioPanel::show_clicked, this));
+       _gain_calculate_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED,  boost::bind (&AudioPanel::gain_calculate_button_clicked, this));
+       _processor->Bind             (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&AudioPanel::processor_changed, this));
 
        _mapping->Changed.connect (boost::bind (&AudioPanel::mapping_changed, this, _1));
 }
@@ -145,6 +154,12 @@ AudioPanel::film_content_changed (int property)
                                setup_stream_description ();
                        }
                }
+       } else if (property == AudioContentProperty::AUDIO_PROCESSOR) {
+               if (acs) {
+                       checked_set (_processor, acs->audio_processor() ? acs->audio_processor()->id() : N_("none"));
+               } else {
+                       checked_set (_processor, N_("none"));
+               }
        }
 }
 
@@ -245,6 +260,21 @@ AudioPanel::setup_stream_description ()
        }
 }
 
+void
+AudioPanel::processor_changed ()
+{
+       string const s = string_client_data (_processor->GetClientObject (_processor->GetSelection ()));
+       AudioProcessor const * p = 0;
+       if (s != wx_to_std (N_("none"))) {
+               p = AudioProcessor::from_id (s);
+       }
+               
+       AudioContentList c = _parent->selected_audio ();
+       for (AudioContentList::const_iterator i = c.begin(); i != c.end(); ++i) {
+               (*i)->set_audio_processor (p);
+       }
+}
+
 void
 AudioPanel::mapping_changed (AudioMapping m)
 {
@@ -266,11 +296,37 @@ AudioPanel::content_selection_changed ()
        _gain->set_content (sel);
        _delay->set_content (sel);
 
+       _gain_calculate_button->Enable (sel.size() == 1);
        _show->Enable (sel.size() == 1);
        _stream->Enable (sel.size() == 1);
+       _processor->Enable (!sel.empty());
        _mapping->Enable (sel.size() == 1);
 
+       setup_processors ();
+
        film_content_changed (AudioContentProperty::AUDIO_MAPPING);
+       film_content_changed (AudioContentProperty::AUDIO_PROCESSOR);
        film_content_changed (FFmpegContentProperty::AUDIO_STREAM);
        film_content_changed (FFmpegContentProperty::AUDIO_STREAMS);
 }
+
+void
+AudioPanel::setup_processors ()
+{
+       AudioContentList sel = _parent->selected_audio ();
+
+       _processor->Clear ();
+       list<AudioProcessor const *> ap = AudioProcessor::all ();
+       _processor->Append (_("None"), new wxStringClientData (N_("none")));
+       for (list<AudioProcessor const *>::const_iterator i = ap.begin(); i != ap.end(); ++i) {
+
+               AudioContentList::const_iterator j = sel.begin();
+               while (j != sel.end() && (*i)->in_channels().includes ((*j)->audio_channels ())) {
+                       ++j;
+               }
+
+               if (j == sel.end ()) {
+                       _processor->Append (std_to_wx ((*i)->name ()), new wxStringClientData (std_to_wx ((*i)->id ())));
+               }
+       }
+}
index 02faf6cd47c6f0ba7b7232738f739c9a12ce2604..9a9d326985975bc60f98216f85f92f02d0d31a76 100644 (file)
@@ -43,6 +43,8 @@ private:
        void stream_changed ();
        void mapping_changed (AudioMapping);
        void setup_stream_description ();
+       void processor_changed ();
+       void setup_processors ();
 
        ContentSpinCtrlDouble<AudioContent>* _gain;
        wxButton* _gain_calculate_button;
@@ -50,6 +52,7 @@ private:
        ContentSpinCtrl<AudioContent>* _delay;
        wxChoice* _stream;
        wxStaticText* _description;
+       wxChoice* _processor;
        AudioMappingView* _mapping;
        AudioDialog* _audio_dialog;
 };