summaryrefslogtreecommitdiff
path: root/src/model/pulsedevice.cpp
diff options
context:
space:
mode:
authorCalvin Morrison <calvin@pobox.com>2026-05-12 21:32:53 -0400
committerCalvin Morrison <calvin@pobox.com>2026-05-12 21:32:53 -0400
commitf6f7c36909fa161efe53c40e9b4c34856e751536 (patch)
treeeff44527b0be61eb2e19c9f483ed38b72879af11 /src/model/pulsedevice.cpp
Initial tmix skeleton — model layer + basic UI
PulseModel: stable PulseDevice objects keyed by PA index, updated in-place via postEvent reconciliation. No bulk rebuilds. Three signals: deviceAdded, deviceRemoved (device changed handled per-device via volumeChanged/muteChanged/nameChanged). MixerWindow: four-tab layout (Output/Input/Playback/Recording), adds and removes individual DeviceWidgets in response to model signals. Builds and links cleanly against TQt3/TDE + libpulse. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/model/pulsedevice.cpp')
-rw-r--r--src/model/pulsedevice.cpp101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/model/pulsedevice.cpp b/src/model/pulsedevice.cpp
new file mode 100644
index 0000000..e0f84ab
--- /dev/null
+++ b/src/model/pulsedevice.cpp
@@ -0,0 +1,101 @@
+#include "pulsedevice.h"
+#include "../ui/devicewidget.h"
+#include <tqwidget.h>
+
+PulseDevice::PulseDevice( AudioDevice::Category cat, uint32_t paIndex, TQObject *parent )
+ : AudioDevice(parent),
+ m_category(cat), m_paIndex(paIndex),
+ m_volume(0), m_muted(false),
+ m_context(0), m_mainloop(0)
+{
+}
+
+void PulseDevice::setPAContext( pa_context *ctx, pa_threaded_mainloop *mainloop )
+{
+ m_context = ctx;
+ m_mainloop = mainloop;
+}
+
+void PulseDevice::update( const TQString &name, int volume, bool muted )
+{
+ bool nameChange = ( name != m_name );
+ bool volumeChange = ( volume != m_volume );
+ bool muteChange = ( muted != m_muted );
+
+ m_name = name;
+ m_volume = volume;
+ m_muted = muted;
+
+ if ( nameChange ) emit nameChanged( m_name );
+ if ( volumeChange ) emit volumeChanged( m_volume );
+ if ( muteChange ) emit muteChanged( m_muted );
+}
+
+// ---- write back to PA -------------------------------------------------------
+
+static pa_volume_t percentToPA( int pct )
+{
+ if ( pct <= 0 ) return 0;
+ if ( pct >= 100 ) return PA_VOLUME_NORM;
+ return (pa_volume_t)( (double)pct / 100.0 * PA_VOLUME_NORM + 0.5 );
+}
+
+void PulseDevice::setVolume( int v )
+{
+ if ( !m_context ) return;
+ v = v < 0 ? 0 : v > 100 ? 100 : v;
+
+ pa_cvolume cv;
+ pa_cvolume_set( &cv, 2, percentToPA(v) );
+
+ pa_threaded_mainloop_lock( m_mainloop );
+ pa_operation *op = 0;
+ switch ( m_category ) {
+ case Output:
+ op = pa_context_set_sink_volume_by_index( m_context, m_paIndex, &cv, 0, 0 );
+ break;
+ case Input:
+ op = pa_context_set_source_volume_by_index( m_context, m_paIndex, &cv, 0, 0 );
+ break;
+ case Playback:
+ op = pa_context_set_sink_input_volume( m_context, m_paIndex, &cv, 0, 0 );
+ break;
+ case Recording:
+ op = pa_context_set_source_output_volume( m_context, m_paIndex, &cv, 0, 0 );
+ break;
+ }
+ if ( op ) pa_operation_unref( op );
+ pa_threaded_mainloop_unlock( m_mainloop );
+}
+
+void PulseDevice::setMuted( bool m )
+{
+ if ( !m_context ) return;
+
+ pa_threaded_mainloop_lock( m_mainloop );
+ pa_operation *op = 0;
+ int mute = m ? 1 : 0;
+ switch ( m_category ) {
+ case Output:
+ op = pa_context_set_sink_mute_by_index( m_context, m_paIndex, mute, 0, 0 );
+ break;
+ case Input:
+ op = pa_context_set_source_mute_by_index( m_context, m_paIndex, mute, 0, 0 );
+ break;
+ case Playback:
+ op = pa_context_set_sink_input_mute( m_context, m_paIndex, mute, 0, 0 );
+ break;
+ case Recording:
+ op = pa_context_set_source_output_mute( m_context, m_paIndex, mute, 0, 0 );
+ break;
+ }
+ if ( op ) pa_operation_unref( op );
+ pa_threaded_mainloop_unlock( m_mainloop );
+}
+
+TQWidget *PulseDevice::createWidget( TQWidget *parent )
+{
+ return new DeviceWidget( this, parent );
+}
+
+#include "pulsedevice.moc"