📄 soundstudiofrm.cs
字号:
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
tMIXERCONTROLDETAILS_BOOLEAN mxMute;
mxc = (tMIXERCONTROLW)Marshal.PtrToStructure(_mixerDataPtr, typeof(tMIXERCONTROLW));
_MuteControlId = mxc.dwControlID;
DumpDebugMessage(string.Format("Mute control: {0}", mxc.dwControlID));
mxcd.ControlID = _MuteControlId;
mxcd.NumChannels = 1;
mxcd.MultipleItems = 0;
mxcd.CbDetails = (int)Marshal.SizeOf(typeof(tMIXERCONTROLDETAILS_BOOLEAN));
mxcd.DataArray = _mixerDataPtr;
mmr = _mixerDevice.GetControlDetails(ref mxcd, MixerConstants.MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
mxMute = (tMIXERCONTROLDETAILS_BOOLEAN)Marshal.PtrToStructure(_mixerDataPtr, typeof(tMIXERCONTROLDETAILS_BOOLEAN));
this.btnMute.Checked = (mxMute.fValue != 0);
}
}
mxlcs.LineID = mxli.LineID;
mxlcs.NumControls = 1;
mxlcs.ControlType = MixerConstants.MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlcs.CbControl = (int)Marshal.SizeOf(typeof(tMIXERCONTROLW));
mxlcs.DataArray = _mixerDataPtr;
Marshal.WriteInt32(_mixerDataPtr, (int)Marshal.OffsetOf(typeof(tMIXERCONTROLW), "cbStruct"), (int)Marshal.SizeOf(typeof(tMIXERCONTROLW)));
mmr = _mixerDevice.GetLineControls(ref mxlcs, MixerConstants.MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
tMIXERCONTROLDETAILS_SIGNED mxVolume;
mxc = (tMIXERCONTROLW)Marshal.PtrToStructure(_mixerDataPtr, typeof(tMIXERCONTROLW));
_VolumeControlId = mxc.dwControlID;
DumpDebugMessage(string.Format("Volume control: {0}", mxc.dwControlID));
mxcd.ControlID = _VolumeControlId;
mxcd.NumChannels = 1;
mxcd.MultipleItems = 0;
mxcd.CbDetails = (int)Marshal.SizeOf(typeof(tMIXERCONTROLDETAILS_SIGNED));
mxcd.DataArray = _mixerDataPtr;
mmr = _mixerDevice.GetControlDetails(ref mxcd, MixerConstants.MIXER_GETCONTROLDETAILSF_VALUE);
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
mxVolume = (tMIXERCONTROLDETAILS_SIGNED)Marshal.PtrToStructure(_mixerDataPtr, typeof(tMIXERCONTROLDETAILS_SIGNED));
this.ctlVolume.SetRange(mxc.Bounds.Signed.lMinimum, mxc.Bounds.Signed.lMaximum);
this.ctlVolume.TickFrequency = ((mxc.Bounds.Signed.lMaximum-mxc.Bounds.Signed.lMinimum) / 10);
this.ctlVolume.Value = (int)((ushort)mxVolume.lValue);
}
}
}
}
return mmr;
}
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
// Listen for operating system messages.
switch (m.Msg)
{
// Process audio done message
case WM_AUDIO_DONE:
{
GCHandle gch = (GCHandle)(m.LParam);
WaveBuffer wbuf = gch.Target as WaveBuffer;
if (wbuf != null && _waveOutput != null)
{
try
{
int mmr = _waveOutput.UnprepareBuffer(wbuf);
WaveOutStatus.ThrowExceptionForHR(mmr);
Interlocked.Decrement(ref _numOutBuffers);
WaveStatus status = _waveOutput.GetDeviceStatus();
if (status == WaveStatus.waveStarted)
{
ProcessAudioData(wbuf);
}
}
catch (Exception ex) // typically: COMException, SystemException (waveout)
{
DumpDebugMessage(ex.Message);
}
}
else
{
DumpDebugMessage("WM_AUDIO_DONE - AUDIO STOPPED");
}
if (gch.IsAllocated)
{
gch.Free();
}
return;
}
case WM_MIXM_CONTROL_CHANGE: // MixerConstants.MM_MIXM_CONTROL_CHANGE
{
if (_mixerDevice != null && _mixerDevice.IsOpen())
{
MixerControlDetails mxcd = new MixerControlDetails();
mxcd.ControlID = (int)(m.LParam);
mxcd.NumChannels = 1;
int hr = MSStatus.MS_S_FALSE;
if (mxcd.ControlID == _MuteControlId)
{
mxcd.CbDetails = (int)Marshal.SizeOf(typeof(tMIXERCONTROLDETAILS_BOOLEAN));
mxcd.DataArray = _mixerDataPtr;
hr = MSStatus.MS_S_OK;
}
else if (mxcd.ControlID == _VolumeControlId)
{
mxcd.CbDetails = (int)Marshal.SizeOf(typeof(tMIXERCONTROLDETAILS_SIGNED));
mxcd.DataArray = _mixerDataPtr;
hr = MSStatus.MS_S_OK;
}
if (hr == MSStatus.MS_S_OK)
{
hr = _mixerDevice.GetControlDetails(ref mxcd, MixerConstants.MIXER_GETCONTROLDETAILSF_VALUE);
if (mxcd.ControlID == _MuteControlId)
{
tMIXERCONTROLDETAILS_BOOLEAN mxMute;
mxMute = (tMIXERCONTROLDETAILS_BOOLEAN)Marshal.PtrToStructure(_mixerDataPtr, typeof(tMIXERCONTROLDETAILS_BOOLEAN));
this.btnMute.Checked = (mxMute.fValue != 0);
if (this.btnMute.Checked)
{
this.btnMute.Image = Resources.sound_mute;
}
else
{
this.btnMute.Image = Resources.sound;
}
}
else if (mxcd.ControlID == _VolumeControlId)
{
tMIXERCONTROLDETAILS_SIGNED mxVolume;
mxVolume = (tMIXERCONTROLDETAILS_SIGNED)Marshal.PtrToStructure(_mixerDataPtr, typeof(tMIXERCONTROLDETAILS_SIGNED));
this.ctlVolume.Value = mxVolume.lValue;
}
}
}
return;
}
}
base.WndProc(ref m);
}
private delegate void WndProcCallback(ref Message m);
public void ProcessEvent(IWaveDevice waveDevice, int uMsg, WaveBuffer wbuf)
{
if (waveDevice == _waveOutput)
{
switch (uMsg)
{
case WaveConstants.MM_WOM_OPEN:
DumpDebugMessage("Wave Opened");
break;
case WaveConstants.MM_WOM_DONE:
{
GCHandle gch = GCHandle.Alloc(wbuf);
// Create message
if (this.IsHandleCreated)
{
Message m = Message.Create(_CopyWindowHandle, WM_AUDIO_DONE, IntPtr.Zero, (IntPtr)gch);
WndProcCallback wndCallback = new WndProcCallback(WndProc);
// Ensure all calls will be thread-safe
this.BeginInvoke(wndCallback, m);
}
}
break;
case WaveConstants.MM_WOM_CLOSE:
DumpDebugMessage("Wave Closed");
break;
}
}
}
private void ProcessAudioData(WaveBuffer wbuf)
{
try
{
if (_waveOutput.GetDeviceStatus() == WaveStatus.waveStarted)
{
ComputeFFT(wbuf);
}
int chunkSize = wbuf.BufferLength;
int mmr = _AudioStream.GetSampleData(wbuf.AudioData, ref chunkSize, (int)COMPLETION_STATUS_FLAGS.COMPSTAT_WAIT, System.Threading.Timeout.Infinite);
MSStatus.ThrowExceptionForHR(mmr);
if (mmr == MSStatus.MS_S_OK)
{
// Append silence if necessary
PutAudioData(wbuf.AudioData, wbuf.BufferLength, chunkSize, _wfmt);
mmr = _waveOutput.PrepareBuffer(wbuf);
WaveOutStatus.ThrowExceptionForHR(mmr);
mmr = _waveOutput.AddBuffer(wbuf);
WaveOutStatus.ThrowExceptionForHR(mmr);
Interlocked.Increment(ref _numOutBuffers);
}
else if (_numOutBuffers == 0) // all buffers done
{
// stop
Terminate();
}
}
catch (Exception ex) // typically: COMException, SystemException (waveout)
{
DumpDebugMessage(ex.Message);
}
}
void ComputeFFT(WaveBuffer wbuf)
{
if (GetAudioData(wbuf.AudioData, wbuf.BufferLength, _wfmt))
{
// adjust FFT Sample to next power 2 but fill data with silence
uint pow2Samples = FFT.NextPowerOfTwo(_numSamples);
if (pow2Samples != _numSamples)
{
double dsilence = 0.0;
if (_wfmt.BitsPerSample == 8)
{
dsilence = 128.0;
}
for (uint ii = _numSamples; ii < pow2Samples; ii++)
{
RealIn[ii] = dsilence;
}
_numSamples = pow2Samples;
}
// You may want to add 'USE_FFTLIB' under the project settings (Build->General tab)
// to get better performance
#if USE_FFTLIB
// Do the FFT
FFTLib.ComputeD(_numSamples, RealIn, null, RealOut, ImagOut, false);
// We can skip N/2 to N samples (mirror frequencies) - Digital samples are real integer
FFTLib.NormD(_numSamples / 2, RealOut, ImagOut, AmplOut);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -