mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
Add an option for mono mic capture in ZoomIt
This commit is contained in:
@@ -34,13 +34,15 @@ namespace winrt
|
||||
using namespace Windows::Devices::Enumeration;
|
||||
}
|
||||
|
||||
AudioSampleGenerator::AudioSampleGenerator(bool captureMicrophone, bool captureSystemAudio)
|
||||
AudioSampleGenerator::AudioSampleGenerator(bool captureMicrophone, bool captureSystemAudio, bool micMonoMix)
|
||||
: m_captureMicrophone(captureMicrophone)
|
||||
, m_captureSystemAudio(captureSystemAudio)
|
||||
, m_micMonoMix(micMonoMix)
|
||||
{
|
||||
OutputDebugStringA(("AudioSampleGenerator created, captureMicrophone=" +
|
||||
std::string(captureMicrophone ? "true" : "false") +
|
||||
", captureSystemAudio=" + std::string(captureSystemAudio ? "true" : "false") + "\n").c_str());
|
||||
", captureSystemAudio=" + std::string(captureSystemAudio ? "true" : "false") +
|
||||
", micMonoMix=" + std::string(micMonoMix ? "true" : "false") + "\n").c_str());
|
||||
m_audioEvent.create(wil::EventOptions::ManualReset);
|
||||
m_endEvent.create(wil::EventOptions::ManualReset);
|
||||
m_startEvent.create(wil::EventOptions::ManualReset);
|
||||
@@ -631,6 +633,30 @@ void AudioSampleGenerator::OnAudioQuantumStarted(winrt::AudioGraph const& sender
|
||||
uint32_t expectedSamplesPerQuantum = (m_graphSampleRate / 100) * m_graphChannels;
|
||||
uint32_t numMicSamples = audioBuffer.Length() / sizeof(float);
|
||||
|
||||
// Apply mono mixing to microphone audio if enabled
|
||||
// This converts stereo mic input (with same signal on both channels) to true mono
|
||||
// by averaging the channels and writing the result to both channels
|
||||
if (m_micMonoMix && m_captureMicrophone && numMicSamples > 0 && m_graphChannels >= 2)
|
||||
{
|
||||
float* micData = reinterpret_cast<float*>(sampleBuffer.data());
|
||||
uint32_t numFrames = numMicSamples / m_graphChannels;
|
||||
for (uint32_t i = 0; i < numFrames; i++)
|
||||
{
|
||||
// Sum all channels for this frame
|
||||
float sum = 0.0f;
|
||||
for (uint32_t ch = 0; ch < m_graphChannels; ch++)
|
||||
{
|
||||
sum += micData[i * m_graphChannels + ch];
|
||||
}
|
||||
// Power-preserving mix: divide by sqrt(N) to maintain perceived loudness
|
||||
float mono = sum / std::sqrt(static_cast<float>(m_graphChannels));
|
||||
for (uint32_t ch = 0; ch < m_graphChannels; ch++)
|
||||
{
|
||||
micData[i * m_graphChannels + ch] = mono;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drain loopback samples regardless of whether we have mic audio
|
||||
if (m_loopbackCapture)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
class AudioSampleGenerator
|
||||
{
|
||||
public:
|
||||
AudioSampleGenerator(bool captureMicrophone = true, bool captureSystemAudio = true);
|
||||
AudioSampleGenerator(bool captureMicrophone = true, bool captureSystemAudio = true, bool micMonoMix = false);
|
||||
~AudioSampleGenerator();
|
||||
|
||||
winrt::Windows::Foundation::IAsyncAction InitializeAsync();
|
||||
@@ -70,4 +70,5 @@ private:
|
||||
std::atomic<bool> m_started = false;
|
||||
bool m_captureMicrophone = true;
|
||||
bool m_captureSystemAudio = true;
|
||||
bool m_micMonoMix = false;
|
||||
};
|
||||
@@ -861,6 +861,7 @@ VideoRecordingSession::VideoRecordingSession(
|
||||
uint32_t frameRate,
|
||||
bool captureAudio,
|
||||
bool captureSystemAudio,
|
||||
bool micMonoMix,
|
||||
winrt::Streams::IRandomAccessStream const& stream)
|
||||
{
|
||||
m_device = device;
|
||||
@@ -964,7 +965,7 @@ VideoRecordingSession::VideoRecordingSession(
|
||||
winrt::check_hresult(m_d3dDevice->CreateRenderTargetView(backBuffer.get(), nullptr, m_renderTargetView.put()));
|
||||
|
||||
// Always create audio generator for loopback capture; captureAudio controls microphone
|
||||
m_audioGenerator = std::make_unique<AudioSampleGenerator>(captureAudio, captureSystemAudio);
|
||||
m_audioGenerator = std::make_unique<AudioSampleGenerator>(captureAudio, captureSystemAudio, micMonoMix);
|
||||
}
|
||||
|
||||
|
||||
@@ -1112,9 +1113,10 @@ std::shared_ptr<VideoRecordingSession> VideoRecordingSession::Create(
|
||||
uint32_t frameRate,
|
||||
bool captureAudio,
|
||||
bool captureSystemAudio,
|
||||
bool micMonoMix,
|
||||
winrt::Streams::IRandomAccessStream const& stream)
|
||||
{
|
||||
return std::shared_ptr<VideoRecordingSession>(new VideoRecordingSession(device, item, crop, frameRate, captureAudio, captureSystemAudio, stream));
|
||||
return std::shared_ptr<VideoRecordingSession>(new VideoRecordingSession(device, item, crop, frameRate, captureAudio, captureSystemAudio, micMonoMix, stream));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
uint32_t frameRate,
|
||||
bool captureAudio,
|
||||
bool captureSystemAudio,
|
||||
bool micMonoMix,
|
||||
winrt::Streams::IRandomAccessStream const& stream);
|
||||
~VideoRecordingSession();
|
||||
|
||||
@@ -188,6 +189,7 @@ private:
|
||||
uint32_t frameRate,
|
||||
bool captureAudio,
|
||||
bool captureSystemAudio,
|
||||
bool micMonoMix,
|
||||
winrt::Streams::IRandomAccessStream const& stream);
|
||||
void CloseInternal();
|
||||
|
||||
|
||||
@@ -279,6 +279,7 @@ BEGIN
|
||||
LTEXT "To record a specific window, enter the hotkey with the Alt key in the opposite mode.",IDC_STATIC,7,55,251,19
|
||||
CONTROL "Capture &system audio",IDC_CAPTURE_SYSTEM_AUDIO,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,149,83,10
|
||||
CONTROL "&Capture audio input:",IDC_CAPTURE_AUDIO,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,7,161,83,10
|
||||
CONTROL "Mono",IDC_MIC_MONO_MIX,"Button",BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,98,161,30,10
|
||||
COMBOBOX IDC_MICROPHONE,81,176,152,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Microphone:",IDC_MICROPHONE_LABEL,32,178,47,8
|
||||
END
|
||||
|
||||
@@ -51,6 +51,7 @@ DWORD g_RecordScalingMP4 = 100;
|
||||
RecordingFormat g_RecordingFormat = RecordingFormat::MP4;
|
||||
BOOLEAN g_CaptureSystemAudio = TRUE;
|
||||
BOOLEAN g_CaptureAudio = FALSE;
|
||||
BOOLEAN g_MicMonoMix = FALSE;
|
||||
TCHAR g_MicrophoneDeviceId[MAX_PATH] = {0};
|
||||
TCHAR g_RecordingSaveLocationBuffer[MAX_PATH] = {0};
|
||||
TCHAR g_ScreenshotSaveLocationBuffer[MAX_PATH] = {0};
|
||||
@@ -99,6 +100,7 @@ REG_SETTING RegSettings[] = {
|
||||
{ L"RecordScalingMP4", SETTING_TYPE_DWORD, 0, &g_RecordScalingMP4, static_cast<DOUBLE>(g_RecordScalingMP4) },
|
||||
{ L"CaptureAudio", SETTING_TYPE_BOOLEAN, 0, &g_CaptureAudio, static_cast<DOUBLE>(g_CaptureAudio) },
|
||||
{ L"CaptureSystemAudio", SETTING_TYPE_BOOLEAN, 0, &g_CaptureSystemAudio, static_cast<DOUBLE>(g_CaptureSystemAudio) },
|
||||
{ L"MicMonoMix", SETTING_TYPE_BOOLEAN, 0, &g_MicMonoMix, static_cast<DOUBLE>(g_MicMonoMix) },
|
||||
{ L"MicrophoneDeviceId", SETTING_TYPE_STRING, sizeof(g_MicrophoneDeviceId), g_MicrophoneDeviceId, static_cast<DOUBLE>(0) },
|
||||
{ L"RecordingSaveLocation", SETTING_TYPE_STRING, sizeof(g_RecordingSaveLocationBuffer), g_RecordingSaveLocationBuffer, static_cast<DOUBLE>(0) },
|
||||
{ L"ScreenshotSaveLocation", SETTING_TYPE_STRING, sizeof(g_ScreenshotSaveLocationBuffer), g_ScreenshotSaveLocationBuffer, static_cast<DOUBLE>(0) },
|
||||
|
||||
@@ -3840,6 +3840,9 @@ INT_PTR CALLBACK OptionsProc( HWND hDlg, UINT message,
|
||||
CheckDlgButton( g_OptionsTabs[RECORD_PAGE].hPage, IDC_CAPTURE_AUDIO,
|
||||
g_CaptureAudio ? BST_CHECKED: BST_UNCHECKED );
|
||||
|
||||
CheckDlgButton( g_OptionsTabs[RECORD_PAGE].hPage, IDC_MIC_MONO_MIX,
|
||||
g_MicMonoMix ? BST_CHECKED: BST_UNCHECKED );
|
||||
|
||||
//
|
||||
// The framerate drop down list is not used in the current version (might be added in the future)
|
||||
//
|
||||
@@ -4260,6 +4263,7 @@ INT_PTR CALLBACK OptionsProc( HWND hDlg, UINT message,
|
||||
g_ShowExpiredTime = IsDlgButtonChecked( g_OptionsTabs[BREAK_PAGE].hPage, IDC_CHECK_SHOW_EXPIRED ) == BST_CHECKED;
|
||||
g_CaptureSystemAudio = IsDlgButtonChecked(g_OptionsTabs[RECORD_PAGE].hPage, IDC_CAPTURE_SYSTEM_AUDIO) == BST_CHECKED;
|
||||
g_CaptureAudio = IsDlgButtonChecked(g_OptionsTabs[RECORD_PAGE].hPage, IDC_CAPTURE_AUDIO) == BST_CHECKED;
|
||||
g_MicMonoMix = IsDlgButtonChecked(g_OptionsTabs[RECORD_PAGE].hPage, IDC_MIC_MONO_MIX) == BST_CHECKED;
|
||||
GetDlgItemText( g_OptionsTabs[BREAK_PAGE].hPage, IDC_TIMER, text, 3 );
|
||||
text[2] = 0;
|
||||
newTimeout = _tstoi( text );
|
||||
@@ -5605,6 +5609,7 @@ winrt::fire_and_forget StartRecordingAsync( HWND hWnd, LPRECT rcCrop, HWND hWndR
|
||||
g_RecordFrameRate,
|
||||
g_CaptureAudio,
|
||||
g_CaptureSystemAudio,
|
||||
g_MicMonoMix,
|
||||
stream );
|
||||
|
||||
recordingStarted = (g_RecordingSession != nullptr);
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
#define IDC_SMOOTH_IMAGE 1107
|
||||
#define IDC_CAPTURE_SYSTEM_AUDIO 1108
|
||||
#define IDC_MICROPHONE_LABEL 1109
|
||||
#define IDC_MIC_MONO_MIX 1110
|
||||
#define IDC_SAVE 40002
|
||||
#define IDC_COPY 40004
|
||||
#define IDC_RECORD 40006
|
||||
|
||||
Reference in New Issue
Block a user