]> git.sesse.net Git - nageru/blobdiff - mixer.cpp
Release Nageru 1.3.1.
[nageru] / mixer.cpp
index 597585c1c5ec0c7c7231c6f95695565342491160..1934ee9429bcae271b3c6d22a9df64e2820a49fc 100644 (file)
--- a/mixer.cpp
+++ b/mixer.cpp
@@ -142,6 +142,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
        theme.reset(new Theme(global_flags.theme_filename.c_str(), resource_pool.get(), num_cards));
        for (unsigned i = 0; i < NUM_OUTPUTS; ++i) {
                output_channel[i].parent = this;
+               output_channel[i].channel = i;
        }
 
        ImageFormat inout_format;
@@ -248,6 +249,7 @@ Mixer::Mixer(const QSurfaceFormat &format, unsigned num_cards)
        // except the final makeup gain.
        if (global_flags.flat_audio) {
                set_locut_enabled(false);
+               set_gain_staging_auto(false);
                set_limiter_enabled(false);
                set_compressor_enabled(false);
        }
@@ -289,7 +291,7 @@ void Mixer::configure_card(unsigned card_index, const QSurfaceFormat &format, Ca
        card->frame_allocator.reset(new PBOFrameAllocator(8 << 20, WIDTH, HEIGHT));  // 8 MB.
        card->capture->set_video_frame_allocator(card->frame_allocator.get());
        card->surface = create_surface(format);
-       card->resampling_queue.reset(new ResamplingQueue(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY, 2));
+       card->resampling_queue.reset(new ResamplingQueue(card_index, OUTPUT_FREQUENCY, OUTPUT_FREQUENCY, 2));
        card->capture->configure_card();
 }
 
@@ -358,7 +360,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                }
        }
 
-       int64_t frame_length = int64_t(TIMEBASE * video_format.frame_rate_den) / video_format.frame_rate_nom;
+       int64_t frame_length = int64_t(TIMEBASE) * video_format.frame_rate_den / video_format.frame_rate_nom;
 
        size_t num_samples = (audio_frame.len > audio_offset) ? (audio_frame.len - audio_offset) / audio_format.num_channels / (audio_format.bits_per_sample / 8) : 0;
        if (num_samples > OUTPUT_FREQUENCY / 10) {
@@ -409,7 +411,7 @@ void Mixer::bm_frame(unsigned card_index, uint16_t timecode,
                if (dropped_frames > MAX_FPS * 2) {
                        fprintf(stderr, "Card %d lost more than two seconds (or time code jumping around; from 0x%04x to 0x%04x), resetting resampler\n",
                                card_index, card->last_timecode, timecode);
-                       card->resampling_queue.reset(new ResamplingQueue(OUTPUT_FREQUENCY, OUTPUT_FREQUENCY, 2));
+                       card->resampling_queue.reset(new ResamplingQueue(card_index, OUTPUT_FREQUENCY, OUTPUT_FREQUENCY, 2));
                        dropped_frames = 0;
                } else if (dropped_frames > 0) {
                        // Insert silence as needed.
@@ -827,7 +829,10 @@ void Mixer::audio_thread_func()
 
                {
                        unique_lock<mutex> lock(audio_mutex);
-                       audio_task_queue_changed.wait(lock, [this]{ return !audio_task_queue.empty(); });
+                       audio_task_queue_changed.wait(lock, [this]{ return should_quit || !audio_task_queue.empty(); });
+                       if (should_quit) {
+                               return;
+                       }
                        task = audio_task_queue.front();
                        audio_task_queue.pop();
                }
@@ -849,9 +854,7 @@ void Mixer::process_audio_one_frame(int64_t frame_pts_int, int num_samples)
                samples_card.resize(num_samples * 2);
                {
                        unique_lock<mutex> lock(cards[card_index].audio_mutex);
-                       if (!cards[card_index].resampling_queue->get_output_samples(double(frame_pts_int) / TIMEBASE, &samples_card[0], num_samples)) {
-                               printf("Card %d reported previous underrun.\n", card_index);
-                       }
+                       cards[card_index].resampling_queue->get_output_samples(double(frame_pts_int) / TIMEBASE, &samples_card[0], num_samples);
                }
                if (card_index == selected_audio_card) {
                        samples_out = move(samples_card);
@@ -1077,6 +1080,7 @@ void Mixer::start()
 void Mixer::quit()
 {
        should_quit = true;
+       audio_task_queue_changed.notify_one();
        mixer_thread.join();
        audio_thread.join();
 }
@@ -1140,9 +1144,47 @@ void Mixer::OutputChannel::output_frame(DisplayFrame frame)
                has_ready_frame = true;
        }
 
-       if (has_new_frame_ready_callback) {
+       if (new_frame_ready_callback) {
                new_frame_ready_callback();
        }
+
+       // Reduce the number of callbacks by filtering duplicates. The reason
+       // why we bother doing this is that Qt seemingly can get into a state
+       // where its builds up an essentially unbounded queue of signals,
+       // consuming more and more memory, and there's no good way of collapsing
+       // user-defined signals or limiting the length of the queue.
+       if (transition_names_updated_callback) {
+               vector<string> transition_names = global_mixer->get_transition_names();
+               bool changed = false;
+               if (transition_names.size() != last_transition_names.size()) {
+                       changed = true;
+               } else {
+                       for (unsigned i = 0; i < transition_names.size(); ++i) {
+                               if (transition_names[i] != last_transition_names[i]) {
+                                       changed = true;
+                                       break;
+                               }
+                       }
+               }
+               if (changed) {
+                       transition_names_updated_callback(transition_names);
+                       last_transition_names = transition_names;
+               }
+       }
+       if (name_updated_callback) {
+               string name = global_mixer->get_channel_name(channel);
+               if (name != last_name) {
+                       name_updated_callback(name);
+                       last_name = name;
+               }
+       }
+       if (color_updated_callback) {
+               string color = global_mixer->get_channel_color(channel);
+               if (color != last_color) {
+                       color_updated_callback(color);
+                       last_color = color;
+               }
+       }
 }
 
 bool Mixer::OutputChannel::get_display_frame(DisplayFrame *frame)
@@ -1173,7 +1215,21 @@ bool Mixer::OutputChannel::get_display_frame(DisplayFrame *frame)
 void Mixer::OutputChannel::set_frame_ready_callback(Mixer::new_frame_ready_callback_t callback)
 {
        new_frame_ready_callback = callback;
-       has_new_frame_ready_callback = true;
+}
+
+void Mixer::OutputChannel::set_transition_names_updated_callback(Mixer::transition_names_updated_callback_t callback)
+{
+       transition_names_updated_callback = callback;
+}
+
+void Mixer::OutputChannel::set_name_updated_callback(Mixer::name_updated_callback_t callback)
+{
+       name_updated_callback = callback;
+}
+
+void Mixer::OutputChannel::set_color_updated_callback(Mixer::color_updated_callback_t callback)
+{
+       color_updated_callback = callback;
 }
 
 mutex RefCountedGLsync::fence_lock;