Give the theme access to basic audio information.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 16 Feb 2020 23:59:14 +0000 (00:59 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 16 Feb 2020 23:59:14 +0000 (00:59 +0100)
Currently, it can get (not set) number of buses and channel names,
get/set fader volume, and get/set mute. This should already be fairly
useful for most applications.

nageru/mainwindow.cpp
nageru/mainwindow.h
nageru/theme.cpp

index 66a1144..c369f28 100644 (file)
@@ -1207,6 +1207,15 @@ void MainWindow::set_fader(unsigned bus_idx, float value)
        set_relative_value_if_exists(bus_idx, &Ui::AudioExpandedView::fader, value);
 }
 
+void MainWindow::set_fader_absolute(unsigned bus_idx, float value_db)
+{
+       if (global_audio_mixer != nullptr &&
+           global_audio_mixer->get_mapping_mode() == AudioMixer::MappingMode::MULTICHANNEL &&
+           bus_idx < audio_expanded_views.size()) {
+               audio_expanded_views[bus_idx]->fader->setDbValue(value_db);
+       }
+}
+
 void MainWindow::toggle_mute(unsigned bus_idx)
 {
        click_button_if_exists(bus_idx, &Ui::AudioExpandedView::mute_button);
index b6a053b..7d6b42a 100644 (file)
@@ -87,6 +87,7 @@ public slots:
        void set_gain(unsigned bus_idx, float value) override;
        void set_compressor_threshold(unsigned bus_idx, float value) override;
        void set_fader(unsigned bus_idx, float value) override;
+       void set_fader_absolute(unsigned bus_idx, float value_db);  // Used by the theme only.
 
        void toggle_mute(unsigned bus_idx) override;
        void toggle_locut(unsigned bus_idx) override;
index d2a7bba..ade4e8f 100644 (file)
@@ -29,6 +29,7 @@
 #include <new>
 #include <utility>
 
+#include "audio_mixer.h"
 #include "defs.h"
 #ifdef HAVE_CEF
 #include "cef_capture.h"
@@ -38,6 +39,7 @@
 #include "image_input.h"
 #include "input_state.h"
 #include "lua_utils.h"
+#include "mainwindow.h"
 #include "pbo_frame_allocator.h"
 #include "scene.h"
 
@@ -1298,6 +1300,118 @@ int Nageru_set_supports_wb(lua_State *L)
        return 0;
 }
 
+// NOTE: There's a race condition in all of the audio functions; if the mapping
+// is changed by the user underway, you might not be manipulating the bus you
+// expect. (You should not get crashes, though.) There's not all that much we
+// can do about it, short of locking the entire mixer while anything from the
+// theme runs.
+
+int Nageru_get_num_audio_buses(lua_State *L)
+{
+       if (global_audio_mixer == nullptr) {
+               // The audio mixer isn't set up until we know how many FFmpeg inputs we have.
+               luaL_error(L, "Audio functions can not be called before the theme is done initializing.");
+       }
+       lua_pushinteger(L, global_audio_mixer->num_buses());
+       return 1;
+}
+
+int Nageru_get_audio_bus_name(lua_State *L)
+{
+       if (global_audio_mixer == nullptr) {
+               // The audio mixer isn't set up until we know how many FFmpeg inputs we have.
+               luaL_error(L, "Audio functions can not be called before the theme is done initializing.");
+       }
+       int bus_index = luaL_checknumber(L, 1);
+       InputMapping input_mapping = global_audio_mixer->get_input_mapping();
+       if (bus_index < 0 || size_t(bus_index) >= input_mapping.buses.size()) {
+               // Doesn't fix the race, but fixes other out-of-bounds.
+               print_warning(L, "Theme called get_audio_bus_name() on nonexistent bus %d; returning nil.\n", bus_index);
+               lua_pushnil(L);
+       } else {
+               lua_pushstring(L, input_mapping.buses[bus_index].name.c_str());
+       }
+       return 1;
+}
+
+int Nageru_get_audio_bus_fader_level_db(lua_State *L)
+{
+       if (global_audio_mixer == nullptr) {
+               // The audio mixer isn't set up until we know how many FFmpeg inputs we have.
+               luaL_error(L, "Audio functions can not be called before the theme is done initializing.");
+       }
+
+       int bus_index = luaL_checknumber(L, 1);
+       if (bus_index < 0 || size_t(bus_index) >= global_audio_mixer->num_buses()) {
+               // Doesn't fix the race, but fixes other out-of-bounds.
+               print_warning(L, "Theme called get_audio_bus_fader_level_db() on nonexistent bus %d; returning 0.0.\n", bus_index);
+               lua_pushnumber(L, 0.0);
+       } else {
+               lua_pushnumber(L, global_audio_mixer->get_fader_volume(bus_index));
+       }
+       return 1;
+}
+
+int Nageru_set_audio_bus_fader_level_db(lua_State *L)
+{
+       if (global_audio_mixer == nullptr || global_mainwindow == nullptr) {
+               // The audio mixer isn't set up until we know how many FFmpeg inputs we have.
+               luaL_error(L, "Audio functions can not be called before the theme is done initializing.");
+       }
+
+       int bus_index = luaL_checknumber(L, 1);
+       if (bus_index < 0 || size_t(bus_index) >= global_audio_mixer->num_buses()) {
+               // Doesn't fix the race, but fixes other out-of-bounds.
+               print_warning(L, "Theme called set_audio_bus_fader_level_db() on nonexistent bus %d; ignoring.\n", bus_index);
+               return 0;
+       }
+       double level_db = luaL_checknumber(L, 2);
+
+       // Go through the UI, so that it gets updated.
+       global_mainwindow->set_fader_absolute(bus_index, level_db);
+       return 0;
+}
+
+int Nageru_get_audio_bus_mute(lua_State *L)
+{
+       if (global_audio_mixer == nullptr) {
+               // The audio mixer isn't set up until we know how many FFmpeg inputs we have.
+               luaL_error(L, "Audio functions can not be called before the theme is done initializing.");
+       }
+
+       int bus_index = luaL_checknumber(L, 1);
+       if (bus_index < 0 || size_t(bus_index) >= global_audio_mixer->num_buses()) {
+               // Doesn't fix the race, but fixes other out-of-bounds.
+               print_warning(L, "Theme called get_audio_bus_mute() on nonexistent bus %d; returning false.\n", bus_index);
+               lua_pushboolean(L, false);
+       } else {
+               lua_pushboolean(L, global_audio_mixer->get_mute(bus_index));
+       }
+       return 1;
+}
+
+int Nageru_set_audio_bus_mute(lua_State *L)
+{
+       if (global_audio_mixer == nullptr || global_mainwindow == nullptr) {
+               // The audio mixer isn't set up until we know how many FFmpeg inputs we have.
+               luaL_error(L, "Audio functions can not be called before the theme is done initializing.");
+       }
+
+       int bus_index = luaL_checknumber(L, 1);
+       if (bus_index < 0 || size_t(bus_index) >= global_audio_mixer->num_buses()) {
+               // Doesn't fix the race, but fixes other out-of-bounds.
+               print_warning(L, "Theme called set_audio_bus_mute() on nonexistent bus %d; ignoring.\n", bus_index);
+               return 0;
+       }
+       bool mute = checkbool(L, 2);
+
+       // Go through the UI, so that it gets updated.
+       if (mute != global_audio_mixer->get_mute(bus_index)) {
+               global_mainwindow->toggle_mute(bus_index);
+       }
+       return 0;
+}
+
 Theme::Theme(const string &filename, const vector<string> &search_dirs, ResourcePool *resource_pool, unsigned num_cards)
        : resource_pool(resource_pool), num_cards(num_cards), signal_to_card_mapping(global_flags.default_stream_mapping)
 {
@@ -1443,11 +1557,21 @@ void Theme::register_globals()
        }
 
        const luaL_Reg Nageru_funcs[] = {
+               // Channel information.
                { "set_channel_name", Nageru_set_channel_name },
                { "set_num_channels", Nageru_set_num_channels },
                { "set_channel_signal", Nageru_set_channel_signal },
                { "set_supports_wb", Nageru_set_supports_wb },
-               { NULL, NULL }
+
+               // Audio.
+               { "get_num_audio_buses", Nageru_get_num_audio_buses },
+               { "get_audio_bus_name", Nageru_get_audio_bus_name },
+               { "get_audio_bus_fader_level_db", Nageru_get_audio_bus_fader_level_db },
+               { "set_audio_bus_fader_level_db", Nageru_set_audio_bus_fader_level_db },
+               { "get_audio_bus_mute", Nageru_get_audio_bus_mute },
+               { "set_audio_bus_mute", Nageru_set_audio_bus_mute },
+
+               { nullptr, nullptr }
        };
        lua_pushlightuserdata(L, this);
        luaL_setfuncs(L, Nageru_funcs, 1);        // for (name,f in funcs) { mt[name] = f, with upvalue {theme} }