Browse Source

Add (temporary terrible) volume controls

 - Add volume control

   These volume controls are basically nothing more than sliders.  They
   look terrible and hopefully will be as temporary as they are
   terrible.

 - Allow saving of specific non-user sources via obs_load_source and
   obs_save_source functions.

 - Save data of desktop/mic audio sources (sync data, volume data, etc),
   and load the data on startup.

 - Make it so that a scene is created by default if first time using the
   application.  On certain operating systems where supported, a default
   capture will be created.  Desktop capture on mac, particularly.  Not
   sure what to do about windows because monitor capture on windows 7 is
   completely terrible and is bad to start users off with.
jp9000 11 years ago
parent
commit
52746c2523

+ 10 - 6
build/data/obs-studio/locale/en.txt

@@ -1,5 +1,15 @@
 Language="English"
 
+DesktopDevice1="Desktop Audio"
+DesktopDevice2="Desktop Audio 2"
+AuxDevice1="Mic/Aux"
+AuxDevice2="Mic/Aux 2"
+AuxDevice3="Mic/Aux 3"
+AuxDevice4="Mic/Aux 4"
+
+Studio.Basic.Scene="Scene"
+Studio.Basic.DisplayCapture="Display Capture"
+
 MainMenu.File="File"
 
 MainMenu.File.New="New"
@@ -64,9 +74,3 @@ Settings.Video.InvalidResolution="Invalid resolution value.  Must be [width]x[he
 Settings.Video.CurrentlyActive="Video output is currently active.  Please turn off any outputs to change video settings."
 
 Settings.Audio="Audio"
-Settings.Audio.DesktopAudioDevice1="Desktop Audio Device 1:"
-Settings.Audio.DesktopAudioDevice2="Desktop Audio Device 2:"
-Settings.Audio.AuxAudioDevice1="Auxilary Audio Device 1:"
-Settings.Audio.AuxAudioDevice2="Auxilary Audio Device 2:"
-Settings.Audio.AuxAudioDevice3="Auxilary Audio Device 3:"
-Settings.Audio.AuxAudioDevice4="Auxilary Audio Device 4:"

+ 1 - 1
libobs/obs-source.c

@@ -100,7 +100,7 @@ bool obs_source_init(struct obs_source *source,
 {
 	source->refs = 1;
 	source->user_volume = 1.0f;
-	source->present_volume = 1.0f;
+	source->present_volume = 0.0f;
 	source->sync_offset = 0;
 	pthread_mutex_init_value(&source->filter_mutex);
 	pthread_mutex_init_value(&source->video_mutex);

+ 38 - 21
libobs/obs.c

@@ -1033,6 +1033,25 @@ float obs_get_present_volume(void)
 	return obs ? obs->audio.present_volume : 0.0f;
 }
 
+obs_source_t obs_load_source(obs_data_t source_data)
+{
+	obs_source_t source;
+	const char   *name    = obs_data_getstring(source_data, "name");
+	const char   *id      = obs_data_getstring(source_data, "id");
+	obs_data_t   settings = obs_data_getobj(source_data, "settings");
+	double       volume;
+
+	source = obs_source_create(OBS_SOURCE_TYPE_INPUT, id, name, settings);
+
+	obs_data_set_default_double(source_data, "volume", 1.0);
+	volume = obs_data_getdouble(source_data, "volume");
+	obs_source_setvolume(source, (float)volume);
+
+	obs_data_release(settings);
+
+	return source;
+}
+
 void obs_load_sources(obs_data_array_t array)
 {
 	size_t count;
@@ -1045,19 +1064,12 @@ void obs_load_sources(obs_data_array_t array)
 	pthread_mutex_lock(&obs->data.user_sources_mutex);
 
 	for (i = 0; i < count; i++) {
-		obs_data_t source_data = obs_data_array_item(array, i);
+		obs_data_t   source_data = obs_data_array_item(array, i);
+		obs_source_t source      = obs_load_source(source_data);
 
-		const char *name    = obs_data_getstring(source_data, "name");
-		const char *id      = obs_data_getstring(source_data, "id");
-		obs_data_t settings = obs_data_getobj(source_data, "settings");
-		obs_source_t source;
-
-		source = obs_source_create(OBS_SOURCE_TYPE_INPUT, id, name,
-				settings);
 		obs_add_source(source);
-		obs_source_release(source);
 
-		obs_data_release(settings);
+		obs_source_release(source);
 		obs_data_release(source_data);
 	}
 
@@ -1068,23 +1080,26 @@ void obs_load_sources(obs_data_array_t array)
 	pthread_mutex_unlock(&obs->data.user_sources_mutex);
 }
 
-static void save_source_data(obs_data_array_t array, obs_source_t source)
+obs_data_t obs_save_source(obs_source_t source)
 {
-	obs_data_t       source_data = obs_data_create();
-	obs_data_t       settings    = obs_source_getsettings(source);
-	const char       *name       = obs_source_getname(source);
-	const char       *id;
+	obs_data_t source_data = obs_data_create();
+	obs_data_t settings    = obs_source_getsettings(source);
+	float      volume      = obs_source_getvolume(source);
+	const char *name       = obs_source_getname(source);
+	const char *id;
+
+	obs_source_save(source);
 
 	obs_source_gettype(source, NULL, &id);
 
 	obs_data_setstring(source_data, "name",     name);
 	obs_data_setstring(source_data, "id",       id);
 	obs_data_setobj   (source_data, "settings", settings);
+	obs_data_setdouble(source_data, "volume",   volume);
 
-	obs_data_array_push_back(array, source_data);
-
-	obs_data_release(source_data);
 	obs_data_release(settings);
+
+	return source_data;
 }
 
 obs_data_array_t obs_save_sources(void)
@@ -1099,9 +1114,11 @@ obs_data_array_t obs_save_sources(void)
 	pthread_mutex_lock(&obs->data.user_sources_mutex);
 
 	for (i = 0; i < obs->data.user_sources.num; i++) {
-		obs_source_t source = obs->data.user_sources.array[i];
-		obs_source_save(source);
-		save_source_data(array, source);
+		obs_source_t source      = obs->data.user_sources.array[i];
+		obs_data_t   source_data = obs_save_source(source);
+
+		obs_data_array_push_back(array, source_data);
+		obs_data_release(source_data);
 	}
 
 	pthread_mutex_unlock(&obs->data.user_sources_mutex);

+ 6 - 0
libobs/obs.h

@@ -357,6 +357,12 @@ EXPORT float obs_get_master_volume(void);
 /** Gets the master presentation volume */
 EXPORT float obs_get_present_volume(void);
 
+/** Saves a source to settings data */
+EXPORT obs_data_t obs_save_source(obs_source_t source);
+
+/** Loads a source from settings data */
+EXPORT obs_source_t obs_load_source(obs_data_t data);
+
 /** Loads sources from a data array */
 EXPORT void obs_load_sources(obs_data_array_t array);
 

+ 6 - 0
libobs/util/windows/ComPtr.hpp

@@ -16,6 +16,9 @@
 
 #pragma once
 
+/* Oh no I have my own com pointer class, the world is ending, how dare you
+ * write your own! */
+
 template<typename T> class ComPtr {
 	T *ptr;
 
@@ -77,6 +80,9 @@ public:
 
 	inline T *Get() const              {return ptr;}
 
+	/* nabbed this one from virtualdub */
+	inline T **operator~()             {return Assign();}
+
 	inline    operator T*() const      {return ptr;}
 	inline T *operator->() const       {return ptr;}
 

+ 2 - 0
obs/CMakeLists.txt

@@ -59,6 +59,7 @@ set(obs_SOURCES
 	window-basic-properties.cpp
 	window-namedialog.cpp
 	properties-view.cpp
+	volume-control.cpp
 	qt-wrappers.cpp)
 
 set(obs_HEADERS
@@ -71,6 +72,7 @@ set(obs_HEADERS
 	window-namedialog.hpp
 	properties-view.hpp
 	display-helpers.hpp
+	volume-control.hpp
 	qt-display.hpp
 	qt-wrappers.hpp)
 

+ 269 - 188
obs/forms/OBSBasic.ui

@@ -54,7 +54,7 @@
       </property>
       <property name="minimumSize">
        <size>
-        <width>620</width>
+        <width>720</width>
         <height>0</height>
        </size>
       </property>
@@ -78,225 +78,294 @@
         <number>0</number>
        </property>
        <item>
-        <layout class="QVBoxLayout" name="verticalLayout_2">
-         <item>
-          <widget class="QLabel" name="label">
-           <property name="text">
-            <string>Scenes</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QFrame" name="frame_2">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="frameShape">
-            <enum>QFrame::StyledPanel</enum>
-           </property>
-           <property name="frameShadow">
-            <enum>QFrame::Sunken</enum>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_3">
-            <property name="spacing">
-             <number>0</number>
-            </property>
-            <property name="leftMargin">
-             <number>0</number>
+        <widget class="QWidget" name="widget_5" native="true">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>150</width>
+           <height>0</height>
+          </size>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_2">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label">
+            <property name="text">
+             <string>Scenes</string>
             </property>
-            <property name="topMargin">
-             <number>0</number>
+           </widget>
+          </item>
+          <item>
+           <widget class="QFrame" name="frame_2">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
             </property>
-            <property name="rightMargin">
-             <number>0</number>
+            <property name="frameShape">
+             <enum>QFrame::StyledPanel</enum>
             </property>
-            <property name="bottomMargin">
-             <number>0</number>
+            <property name="frameShadow">
+             <enum>QFrame::Sunken</enum>
             </property>
-            <item>
-             <widget class="QListWidget" name="scenes">
-              <property name="enabled">
-               <bool>true</bool>
-              </property>
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Ignored" vsizetype="Expanding">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="frameShape">
-               <enum>QFrame::NoFrame</enum>
-              </property>
-              <property name="frameShadow">
-               <enum>QFrame::Plain</enum>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QToolBar" name="toolBar">
-              <property name="iconSize">
-               <size>
-                <width>16</width>
-                <height>16</height>
-               </size>
-              </property>
-              <property name="floatable">
-               <bool>false</bool>
-              </property>
-              <addaction name="actionAddScene"/>
-              <addaction name="actionRemoveScene"/>
-              <addaction name="actionSceneProperties"/>
-              <addaction name="separator"/>
-              <addaction name="actionSceneUp"/>
-              <addaction name="actionSceneDown"/>
-             </widget>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
+            <layout class="QVBoxLayout" name="verticalLayout_3">
+             <property name="spacing">
+              <number>0</number>
+             </property>
+             <property name="leftMargin">
+              <number>0</number>
+             </property>
+             <property name="topMargin">
+              <number>0</number>
+             </property>
+             <property name="rightMargin">
+              <number>0</number>
+             </property>
+             <property name="bottomMargin">
+              <number>0</number>
+             </property>
+             <item>
+              <widget class="QListWidget" name="scenes">
+               <property name="enabled">
+                <bool>true</bool>
+               </property>
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Ignored" vsizetype="Expanding">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="frameShape">
+                <enum>QFrame::NoFrame</enum>
+               </property>
+               <property name="frameShadow">
+                <enum>QFrame::Plain</enum>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QToolBar" name="toolBar">
+               <property name="iconSize">
+                <size>
+                 <width>16</width>
+                 <height>16</height>
+                </size>
+               </property>
+               <property name="floatable">
+                <bool>false</bool>
+               </property>
+               <addaction name="actionAddScene"/>
+               <addaction name="actionRemoveScene"/>
+               <addaction name="actionSceneProperties"/>
+               <addaction name="separator"/>
+               <addaction name="actionSceneUp"/>
+               <addaction name="actionSceneDown"/>
+              </widget>
+             </item>
+            </layout>
+           </widget>
+          </item>
+         </layout>
+        </widget>
        </item>
        <item>
-        <layout class="QVBoxLayout" name="verticalLayout_5">
-         <item>
-          <widget class="QLabel" name="label_2">
-           <property name="text">
-            <string>Sources</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QFrame" name="frame_3">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="frameShape">
-            <enum>QFrame::StyledPanel</enum>
-           </property>
-           <property name="frameShadow">
-            <enum>QFrame::Sunken</enum>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_4">
-            <property name="spacing">
-             <number>0</number>
-            </property>
-            <property name="leftMargin">
-             <number>0</number>
-            </property>
-            <property name="topMargin">
-             <number>0</number>
+        <widget class="QWidget" name="widget_3" native="true">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="minimumSize">
+          <size>
+           <width>150</width>
+           <height>0</height>
+          </size>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_5">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_2">
+            <property name="text">
+             <string>Sources</string>
             </property>
-            <property name="rightMargin">
-             <number>0</number>
+           </widget>
+          </item>
+          <item>
+           <widget class="QFrame" name="frame_3">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
             </property>
-            <property name="bottomMargin">
-             <number>0</number>
+            <property name="frameShape">
+             <enum>QFrame::StyledPanel</enum>
             </property>
-            <item>
-             <widget class="QListWidget" name="sources">
-              <property name="sizePolicy">
-               <sizepolicy hsizetype="Ignored" vsizetype="Expanding">
-                <horstretch>0</horstretch>
-                <verstretch>0</verstretch>
-               </sizepolicy>
-              </property>
-              <property name="frameShape">
-               <enum>QFrame::NoFrame</enum>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QToolBar" name="toolBar_2">
-              <property name="iconSize">
-               <size>
-                <width>16</width>
-                <height>16</height>
-               </size>
-              </property>
-              <property name="floatable">
-               <bool>false</bool>
-              </property>
-              <addaction name="actionAddSource"/>
-              <addaction name="actionRemoveSource"/>
-              <addaction name="actionSourceProperties"/>
-              <addaction name="separator"/>
-              <addaction name="actionSourceUp"/>
-              <addaction name="actionSourceDown"/>
-             </widget>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </item>
-       <item>
-        <layout class="QVBoxLayout" name="verticalLayout_9">
-         <item>
-          <widget class="QLabel" name="label_3">
-           <property name="text">
-            <string>Volume</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <widget class="QScrollArea" name="scrollArea">
-           <property name="sizePolicy">
-            <sizepolicy hsizetype="Ignored" vsizetype="Expanding">
-             <horstretch>0</horstretch>
-             <verstretch>0</verstretch>
-            </sizepolicy>
-           </property>
-           <property name="widgetResizable">
-            <bool>true</bool>
-           </property>
-           <widget class="QWidget" name="volumeWidgets">
-            <property name="geometry">
-             <rect>
-              <x>0</x>
-              <y>0</y>
-              <width>147</width>
-              <height>131</height>
-             </rect>
+            <property name="frameShadow">
+             <enum>QFrame::Sunken</enum>
             </property>
-            <layout class="QVBoxLayout" name="verticalLayout_6">
+            <layout class="QVBoxLayout" name="verticalLayout_4">
              <property name="spacing">
-              <number>6</number>
+              <number>0</number>
              </property>
              <property name="leftMargin">
-              <number>2</number>
+              <number>0</number>
              </property>
              <property name="topMargin">
-              <number>2</number>
+              <number>0</number>
              </property>
              <property name="rightMargin">
-              <number>2</number>
+              <number>0</number>
              </property>
              <property name="bottomMargin">
-              <number>2</number>
+              <number>0</number>
              </property>
+             <item>
+              <widget class="QListWidget" name="sources">
+               <property name="sizePolicy">
+                <sizepolicy hsizetype="Ignored" vsizetype="Expanding">
+                 <horstretch>0</horstretch>
+                 <verstretch>0</verstretch>
+                </sizepolicy>
+               </property>
+               <property name="frameShape">
+                <enum>QFrame::NoFrame</enum>
+               </property>
+              </widget>
+             </item>
+             <item>
+              <widget class="QToolBar" name="toolBar_2">
+               <property name="iconSize">
+                <size>
+                 <width>16</width>
+                 <height>16</height>
+                </size>
+               </property>
+               <property name="floatable">
+                <bool>false</bool>
+               </property>
+               <addaction name="actionAddSource"/>
+               <addaction name="actionRemoveSource"/>
+               <addaction name="actionSourceProperties"/>
+               <addaction name="separator"/>
+               <addaction name="actionSourceUp"/>
+               <addaction name="actionSourceDown"/>
+              </widget>
+             </item>
             </layout>
            </widget>
-          </widget>
-         </item>
-        </layout>
+          </item>
+         </layout>
+        </widget>
+       </item>
+       <item>
+        <widget class="QWidget" name="widget_4" native="true">
+         <layout class="QVBoxLayout" name="verticalLayout_9">
+          <property name="leftMargin">
+           <number>0</number>
+          </property>
+          <property name="topMargin">
+           <number>0</number>
+          </property>
+          <property name="rightMargin">
+           <number>0</number>
+          </property>
+          <property name="bottomMargin">
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_3">
+            <property name="text">
+             <string>Volume</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QScrollArea" name="scrollArea">
+            <property name="verticalScrollBarPolicy">
+             <enum>Qt::ScrollBarAlwaysOn</enum>
+            </property>
+            <property name="widgetResizable">
+             <bool>true</bool>
+            </property>
+            <widget class="QWidget" name="volumeWidgets">
+             <property name="geometry">
+              <rect>
+               <x>0</x>
+               <y>0</y>
+               <width>233</width>
+               <height>16</height>
+              </rect>
+             </property>
+             <property name="sizePolicy">
+              <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+               <horstretch>0</horstretch>
+               <verstretch>0</verstretch>
+              </sizepolicy>
+             </property>
+             <layout class="QVBoxLayout" name="verticalLayout_6">
+              <property name="spacing">
+               <number>0</number>
+              </property>
+              <property name="leftMargin">
+               <number>0</number>
+              </property>
+              <property name="topMargin">
+               <number>0</number>
+              </property>
+              <property name="rightMargin">
+               <number>0</number>
+              </property>
+              <property name="bottomMargin">
+               <number>0</number>
+              </property>
+             </layout>
+            </widget>
+           </widget>
+          </item>
+         </layout>
+        </widget>
        </item>
        <item alignment="Qt::AlignTop">
         <widget class="QWidget" name="widget_2" native="true">
          <property name="sizePolicy">
-          <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+          <sizepolicy hsizetype="Maximum" vsizetype="Minimum">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="minimumSize">
           <size>
-           <width>0</width>
+           <width>150</width>
            <height>0</height>
           </size>
          </property>
@@ -446,6 +515,9 @@
    </property>
   </action>
   <action name="actionSceneUp">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
    <property name="icon">
     <iconset resource="obs.qrc">
      <normaloff>:/res/images/up.ico</normaloff>:/res/images/up.ico</iconset>
@@ -455,6 +527,9 @@
    </property>
   </action>
   <action name="actionSourceUp">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
    <property name="icon">
     <iconset resource="obs.qrc">
      <normaloff>:/res/images/up.ico</normaloff>:/res/images/up.ico</iconset>
@@ -464,6 +539,9 @@
    </property>
   </action>
   <action name="actionSceneDown">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
    <property name="icon">
     <iconset resource="obs.qrc">
      <normaloff>:/res/images/down.ico</normaloff>:/res/images/down.ico</iconset>
@@ -473,6 +551,9 @@
    </property>
   </action>
   <action name="actionSourceDown">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
    <property name="icon">
     <iconset resource="obs.qrc">
      <normaloff>:/res/images/down.ico</normaloff>:/res/images/down.ico</iconset>

+ 6 - 0
obs/forms/OBSBasicSettings.ui

@@ -10,6 +10,12 @@
     <height>602</height>
    </rect>
   </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
   <property name="windowTitle">
    <string>Settings</string>
   </property>

+ 89 - 0
obs/volume-control.cpp

@@ -0,0 +1,89 @@
+#include "volume-control.hpp"
+#include "qt-wrappers.hpp"
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QSlider>
+#include <QLabel>
+#include <string>
+
+using namespace std;
+
+void VolControl::OBSVolumeChanged(void *data, calldata_t calldata)
+{
+	VolControl *volControl = static_cast<VolControl*>(data);
+	int vol = (int)(calldata_float(calldata, "volume") * 100.0f + 0.5f);
+
+	QMetaObject::invokeMethod(volControl, "VolumeChanged",
+			Q_ARG(int, vol));
+}
+
+void VolControl::VolumeChanged(int vol)
+{
+	signalChanged = false;
+	slider->setValue(vol);
+	signalChanged = true;
+}
+
+void VolControl::SliderChanged(int vol)
+{
+	if (signalChanged) {
+		signal_handler_disconnect(obs_source_signalhandler(source),
+				"volume", OBSVolumeChanged, this);
+
+		obs_source_setvolume(source, float(vol)*0.01f);
+
+		signal_handler_connect(obs_source_signalhandler(source),
+				"volume", OBSVolumeChanged, this);
+	}
+	volLabel->setText(QString::number(vol));
+}
+
+VolControl::VolControl(OBSSource source_)
+	: source        (source_),
+	  signalChanged (true)
+{
+	QVBoxLayout *mainLayout = new QVBoxLayout();
+	QHBoxLayout *textLayout = new QHBoxLayout();
+	int         vol         = int(obs_source_getvolume(source) * 100.0f);
+
+	nameLabel = new QLabel();
+	volLabel  = new QLabel();
+	slider    = new QSlider(Qt::Horizontal);
+
+	QFont font = nameLabel->font();
+	font.setPointSize(font.pointSize()-1);
+
+	nameLabel->setText(obs_source_getname(source));
+	nameLabel->setFont(font);
+	volLabel->setText(QString::number(vol));
+	volLabel->setFont(font);
+	slider->setMinimum(0);
+	slider->setMaximum(100);
+	slider->setValue(vol);
+	//slider->setMaximumHeight(16);
+
+	textLayout->setContentsMargins(0, 0, 0, 0);
+	textLayout->addWidget(nameLabel);
+	textLayout->addWidget(volLabel);
+	textLayout->setAlignment(nameLabel, Qt::AlignLeft);
+	textLayout->setAlignment(volLabel,  Qt::AlignRight);
+
+	mainLayout->setContentsMargins(4, 4, 4, 4);
+	mainLayout->setSpacing(2);
+	mainLayout->addItem(textLayout);
+	mainLayout->addWidget(slider);
+
+	setLayout(mainLayout);
+
+	signal_handler_connect(obs_source_signalhandler(source),
+			"volume", OBSVolumeChanged, this);
+
+	QWidget::connect(slider, SIGNAL(valueChanged(int)),
+			this, SLOT(SliderChanged(int)));
+}
+
+VolControl::~VolControl()
+{
+	signal_handler_disconnect(obs_source_signalhandler(source),
+			"volume", OBSVolumeChanged, this);
+}

+ 32 - 0
obs/volume-control.hpp

@@ -0,0 +1,32 @@
+#pragma once
+
+#include <obs.hpp>
+#include <QWidget>
+
+/* TODO: Make a real volume control that isn't terrible */
+
+class QLabel;
+class QSlider;
+
+class VolControl : public QWidget {
+	Q_OBJECT
+
+private:
+	OBSSource source;
+	QLabel    *nameLabel;
+	QLabel    *volLabel;
+	QSlider   *slider;
+	bool      signalChanged;
+
+	static void OBSVolumeChanged(void *param, calldata_t calldata);
+
+private slots:
+	void VolumeChanged(int vol);
+	void SliderChanged(int vol);
+
+public:
+	VolControl(OBSSource source);
+	~VolControl();
+
+	inline obs_source_t GetSource() const {return source;}
+};

+ 142 - 11
obs/window-basic-main.cpp

@@ -32,6 +32,7 @@
 #include "window-basic-properties.hpp"
 #include "qt-wrappers.hpp"
 #include "display-helpers.hpp"
+#include "volume-control.hpp"
 
 #include "ui_OBSBasic.h"
 
@@ -47,13 +48,13 @@ Q_DECLARE_METATYPE(OBSSceneItem);
 
 OBSBasic::OBSBasic(QWidget *parent)
 	: OBSMainWindow (parent),
+	  properties    (nullptr),
 	  streamOutput  (nullptr),
 	  service       (nullptr),
 	  aac           (nullptr),
 	  x264          (nullptr),
 	  sceneChanging (false),
 	  resizeTimer   (0),
-	  properties    (nullptr),
 	  ui            (new Ui::OBSBasic)
 {
 	ui->setupUi(this);
@@ -66,6 +67,20 @@ OBSBasic::OBSBasic(QWidget *parent)
 	});
 }
 
+static void SaveAudioDevice(const char *name, int channel, obs_data_t parent)
+{
+	obs_source_t source = obs_get_output_source(channel);
+	if (!source)
+		return;
+
+	obs_data_t data = obs_save_source(source);
+
+	obs_data_setobj(parent, name, data);
+
+	obs_data_release(data);
+	obs_source_release(source);
+}
+
 static obs_data_t GenerateSaveData()
 {
 	obs_data_t       saveData     = obs_data_create();
@@ -73,6 +88,12 @@ static obs_data_t GenerateSaveData()
 	obs_source_t     currentScene = obs_get_output_source(0);
 	const char       *sceneName   = obs_source_getname(currentScene);
 
+	SaveAudioDevice(DESKTOP_AUDIO_1, 1, saveData);
+	SaveAudioDevice(DESKTOP_AUDIO_2, 2, saveData);
+	SaveAudioDevice(AUX_AUDIO_1,     3, saveData);
+	SaveAudioDevice(AUX_AUDIO_2,     4, saveData);
+	SaveAudioDevice(AUX_AUDIO_3,     5, saveData);
+
 	obs_data_setstring(saveData, "current_scene", sceneName);
 	obs_data_setarray(saveData, "sources", sourcesArray);
 	obs_data_array_release(sourcesArray);
@@ -81,6 +102,18 @@ static obs_data_t GenerateSaveData()
 	return saveData;
 }
 
+void OBSBasic::ClearVolumeControls()
+{
+	VolControl *control;
+
+	for (size_t i = 0; i < volumes.size(); i++) {
+		control = volumes[i];
+		delete control;
+	}
+
+	volumes.clear();
+}
+
 void OBSBasic::Save(const char *file)
 {
 	obs_data_t saveData  = GenerateSaveData();
@@ -93,6 +126,45 @@ void OBSBasic::Save(const char *file)
 	obs_data_release(saveData);
 }
 
+static void LoadAudioDevice(const char *name, int channel, obs_data_t parent)
+{
+	obs_data_t data = obs_data_getobj(parent, name);
+	if (!data)
+		return;
+
+	obs_source_t source = obs_load_source(data);
+	if (source) {
+		obs_set_output_source(channel, source);
+		obs_source_release(source);
+	}
+
+	obs_data_release(data);
+}
+
+void OBSBasic::CreateDefaultScene()
+{
+	obs_scene_t  scene  = obs_scene_create(Str("Studio.Basic.Scene"));
+	obs_source_t source = obs_scene_getsource(scene);
+
+	obs_add_source(source);
+
+#ifdef __APPLE__
+	source = obs_source_create(OBS_SOURCE_TYPE_INPUT, "display_capture",
+			Str("Studio.Basic.DisplayCapture"), NULL);
+
+	if (source) {
+		sourceSceneRefs[source] = 0;
+
+		obs_scene_add(scene, source);
+		obs_add_source(source);
+		obs_source_release(source);
+	}
+#endif
+
+	obs_set_output_source(0, obs_scene_getsource(scene));
+	obs_scene_release(scene);
+}
+
 void OBSBasic::Load(const char *file)
 {
 	if (!file) {
@@ -101,14 +173,22 @@ void OBSBasic::Load(const char *file)
 	}
 
 	BPtr<char> jsonData = os_quick_read_utf8_file(file);
-	if (!jsonData)
+	if (!jsonData) {
+		CreateDefaultScene();
 		return;
+	}
 
 	obs_data_t       data       = obs_data_create_from_json(jsonData);
 	obs_data_array_t sources    = obs_data_getarray(data, "sources");
 	const char       *sceneName = obs_data_getstring(data, "current_scene");
 	obs_source_t     curScene;
 
+	LoadAudioDevice(DESKTOP_AUDIO_1, 1, data);
+	LoadAudioDevice(DESKTOP_AUDIO_2, 2, data);
+	LoadAudioDevice(AUX_AUDIO_1,     3, data);
+	LoadAudioDevice(AUX_AUDIO_2,     4, data);
+	LoadAudioDevice(AUX_AUDIO_3,     5, data);
+
 	obs_load_sources(sources);
 
 	curScene = obs_get_source_by_name(sceneName);
@@ -317,8 +397,24 @@ bool OBSBasic::InitBasicConfig()
 	return InitBasicConfigDefaults();
 }
 
+void OBSBasic::InitOBSCallbacks()
+{
+	signal_handler_connect(obs_signalhandler(), "source_add",
+			OBSBasic::SourceAdded, this);
+	signal_handler_connect(obs_signalhandler(), "source_remove",
+			OBSBasic::SourceRemoved, this);
+	signal_handler_connect(obs_signalhandler(), "channel_change",
+			OBSBasic::ChannelChanged, this);
+	signal_handler_connect(obs_signalhandler(), "source_activate",
+			OBSBasic::SourceActivated, this);
+	signal_handler_connect(obs_signalhandler(), "source_deactivate",
+			OBSBasic::SourceDeactivated, this);
+}
+
 void OBSBasic::OBSInit()
 {
+	BPtr<char> savePath(os_get_config_path("obs-studio/basic/scenes.json"));
+
 	/* make sure it's fully displayed before doing any initialization */
 	show();
 	App()->processEvents();
@@ -332,12 +428,7 @@ void OBSBasic::OBSInit()
 	if (!ResetAudio())
 		throw "Failed to initialize audio";
 
-	signal_handler_connect(obs_signalhandler(), "source_add",
-			OBSBasic::SourceAdded, this);
-	signal_handler_connect(obs_signalhandler(), "source_remove",
-			OBSBasic::SourceRemoved, this);
-	signal_handler_connect(obs_signalhandler(), "channel_change",
-			OBSBasic::ChannelChanged, this);
+	InitOBSCallbacks();
 
 	/* TODO: this is a test, all modules will be searched for and loaded
 	 * automatically later */
@@ -364,9 +455,7 @@ void OBSBasic::OBSInit()
 	if (!InitService())
 		throw "Failed to initialize service";
 
-	BPtr<char> savePath(os_get_config_path("obs-studio/basic/scenes.json"));
 	Load(savePath);
-
 	ResetAudioDevices();
 }
 
@@ -381,6 +470,7 @@ OBSBasic::~OBSBasic()
 
 	/* free the lists before shutting down to remove the scene/item
 	 * references */
+	ClearVolumeControls();
 	ui->sources->clear();
 	ui->scenes->clear();
 	obs_shutdown();
@@ -519,6 +609,25 @@ void OBSBasic::UpdateSceneSelection(OBSSource source)
 	}
 }
 
+void OBSBasic::ActivateAudioSource(OBSSource source)
+{
+	VolControl *vol = new VolControl(source);
+
+	volumes.push_back(vol);
+	ui->volumeWidgets->layout()->addWidget(vol);
+}
+
+void OBSBasic::DeactivateAudioSource(OBSSource source)
+{
+	for (size_t i = 0; i < volumes.size(); i++) {
+		if (volumes[i]->GetSource() == source) {
+			delete volumes[i];
+			volumes.erase(volumes.begin() + i);
+			break;
+		}
+	}
+}
+
 /* OBS Callbacks */
 
 void OBSBasic::SceneItemAdded(void *data, calldata_t params)
@@ -561,6 +670,28 @@ void OBSBasic::SourceRemoved(void *data, calldata_t params)
 				Q_ARG(OBSSource, OBSSource(source)));
 }
 
+void OBSBasic::SourceActivated(void *data, calldata_t params)
+{
+	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
+	uint32_t     flags  = obs_source_get_output_flags(source);
+
+	if (flags & OBS_SOURCE_AUDIO)
+		QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
+				"ActivateAudioSource",
+				Q_ARG(OBSSource, OBSSource(source)));
+}
+
+void OBSBasic::SourceDeactivated(void *data, calldata_t params)
+{
+	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
+	uint32_t     flags  = obs_source_get_output_flags(source);
+
+	if (flags & OBS_SOURCE_AUDIO)
+		QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
+				"DeactivateAudioSource",
+				Q_ARG(OBSSource, OBSSource(source)));
+}
+
 void OBSBasic::ChannelChanged(void *data, calldata_t params)
 {
 	obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
@@ -700,7 +831,7 @@ void OBSBasic::ResetAudioDevice(const char *sourceId, const char *deviceName,
 		obs_data_t settings = obs_data_create();
 		obs_data_setstring(settings, "device_id", deviceId);
 		source = obs_source_create(OBS_SOURCE_TYPE_INPUT,
-				sourceId, deviceName, settings);
+				sourceId, Str(deviceName), settings);
 		obs_data_release(settings);
 
 		obs_set_output_source(channel, source);

+ 22 - 1
obs/window-basic-main.hpp

@@ -19,6 +19,7 @@
 
 #include <obs.hpp>
 #include <unordered_map>
+#include <vector>
 #include <memory>
 #include "window-main.hpp"
 #include "window-basic-properties.hpp"
@@ -28,15 +29,26 @@
 #include <QPointer>
 
 class QListWidgetItem;
+class VolControl;
 
 #include "ui_OBSBasic.h"
 
+#define DESKTOP_AUDIO_1 Str("DesktopAudioDevice1")
+#define DESKTOP_AUDIO_2 Str("DesktopAudioDevice2")
+#define AUX_AUDIO_1     Str("AuxAudioDevice1")
+#define AUX_AUDIO_2     Str("AuxAudioDevice2")
+#define AUX_AUDIO_3     Str("AuxAudioDevice3")
+
 class OBSBasic : public OBSMainWindow {
 	Q_OBJECT
 
 private:
 	std::unordered_map<obs_source_t, int> sourceSceneRefs;
 
+	std::vector<VolControl*> volumes;
+
+	QPointer<OBSBasicProperties> properties;
+
 	obs_output_t  streamOutput;
 	obs_service_t service;
 	obs_encoder_t aac;
@@ -50,7 +62,9 @@ private:
 
 	ConfigFile    basicConfig;
 
-	QPointer<OBSBasicProperties> properties;
+	void          CreateDefaultScene();
+
+	void          ClearVolumeControls();
 
 	void          Save(const char *file);
 	void          Load(const char *file);
@@ -65,6 +79,8 @@ private:
 	bool          InitBasicConfigDefaults();
 	bool          InitBasicConfig();
 
+	void          InitOBSCallbacks();
+
 	OBSScene      GetCurrentScene();
 	OBSSceneItem  GetCurrentSceneItem();
 
@@ -92,12 +108,17 @@ private slots:
 	void RemoveScene(OBSSource source);
 	void UpdateSceneSelection(OBSSource source);
 
+	void ActivateAudioSource(OBSSource source);
+	void DeactivateAudioSource(OBSSource source);
+
 private:
 	/* OBS Callbacks */
 	static void SceneItemAdded(void *data, calldata_t params);
 	static void SceneItemRemoved(void *data, calldata_t params);
 	static void SourceAdded(void *data, calldata_t params);
 	static void SourceRemoved(void *data, calldata_t params);
+	static void SourceActivated(void *data, calldata_t params);
+	static void SourceDeactivated(void *data, calldata_t params);
 	static void ChannelChanged(void *data, calldata_t params);
 	static void RenderMain(void *data, uint32_t cx, uint32_t cy);
 

+ 1 - 1
plugins/rtmp-services/rtmp-common.c

@@ -13,7 +13,7 @@ static const char *rtmp_common_getname(const char *locale)
 	UNUSED_PARAMETER(locale);
 
 	/* TODO: locale */
-	return "Other Streaming Services";
+	return "Streaming Services";
 }
 
 static void rtmp_common_update(void *data, obs_data_t settings)

+ 27 - 0
vs/2013/obs-studio/obs-studio.vcxproj

@@ -131,6 +131,24 @@
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
       <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
     </CustomBuild>
+    <CustomBuild Include="..\..\..\obs\volume-control.hpp">
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing volume-control.hpp...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing volume-control.hpp...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing volume-control.hpp...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
+      <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
+      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing volume-control.hpp...</Message>
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe"  "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp"  -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs"</Command>
+    </CustomBuild>
     <ClInclude Include="GeneratedFiles\ui_NameDialog.h" />
     <ClInclude Include="GeneratedFiles\ui_OBSBasic.h" />
     <ClInclude Include="GeneratedFiles\ui_OBSBasicProperties.h" />
@@ -177,6 +195,7 @@
     <ClCompile Include="..\..\..\obs\platform-windows.cpp" />
     <ClCompile Include="..\..\..\obs\properties-view.cpp" />
     <ClCompile Include="..\..\..\obs\qt-wrappers.cpp" />
+    <ClCompile Include="..\..\..\obs\volume-control.cpp" />
     <ClCompile Include="..\..\..\obs\window-basic-main.cpp" />
     <ClCompile Include="..\..\..\obs\window-basic-properties.cpp" />
     <ClCompile Include="..\..\..\obs\window-basic-settings.cpp" />
@@ -193,6 +212,10 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="GeneratedFiles\Debug\moc_volume-control.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="GeneratedFiles\Debug\moc_window-basic-main.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
@@ -235,6 +258,10 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_volume-control.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="GeneratedFiles\Release\moc_window-basic-main.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

+ 12 - 0
vs/2013/obs-studio/obs-studio.vcxproj.filters

@@ -74,6 +74,9 @@
     <CustomBuild Include="..\..\..\obs\properties-view.hpp">
       <Filter>Header Files</Filter>
     </CustomBuild>
+    <CustomBuild Include="..\..\..\obs\volume-control.hpp">
+      <Filter>Header Files</Filter>
+    </CustomBuild>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\obs\platform.hpp">
@@ -177,6 +180,15 @@
     <ClCompile Include="..\..\..\obs\properties-view.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="GeneratedFiles\Debug\moc_volume-control.cpp">
+      <Filter>Generated Files\Debug</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneratedFiles\Release\moc_volume-control.cpp">
+      <Filter>Generated Files\Release</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\obs\volume-control.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <Image Include="..\..\..\obs\forms\images\add.ico">