📄 soundstudiofrm.cs
字号:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Ernzo.WinForms.Controls;
using Ernzo.Windows.WaveAudio;
using Ernzo.Windows.DirectShowLib.MMStreaming;
using Ernzo.DSP;
using SoundStudioCS.Properties;
namespace SoundStudioCS
{
public partial class SoundStudioFrm : Form, IWaveNotifyHandler
{
private const int WM_USER = 0x0400;
private const int WM_AUDIO_DONE = WM_USER + 0x100;
private const int WM_MIXM_CONTROL_CHANGE = MixerConstants.MM_MIXM_CONTROL_CHANGE;
private const int MAX_BUFFERS = 4;
//private const int MAX_BUFSIZE = 2048;
private const double FFT_SPEED = 0.06;
private const int NUM_FREQUENCY = 19;
private int[] METER_FREQUENCY = new int[NUM_FREQUENCY] { 30, 60, 80, 90, 100, 150, 200, 330, 480, 660, 880, 1000, 1500, 2000, 3000, 5000, 8000, 12000, 16000 };
private int[] _meterData = new int[NUM_FREQUENCY];
private double[] RealIn;
private double[] RealOut;
private double[] ImagOut;
private double[] AmplOut;
private byte[] waveData; // copy of wave data - unless 'unsafe' code is an option
private WaveFormat _wfmt;
private WaveBuffer[] _waveBuffer;
private WaveOutDevice _waveOutput;
private IntPtr _CopyWindowHandle;
private MMAudioStream _AudioStream;
private MultimediaStream _MediaStream;
private uint _bufferSize;
private uint _numSamples;
private int _numOutBuffers;
private WaveMixerDevice _mixerDevice;
private IntPtr _mixerDataPtr;
private int _MuteControlId;
private int _VolumeControlId;
public SoundStudioFrm()
{
InitializeComponent();
_numSamples = 0;
_numOutBuffers = 0;
}
private void Terminate()
{
ReleaseWaveOutput();
ReleaseFFTData();
_CopyWindowHandle = IntPtr.Zero;
this.btnPlay.Enabled = true;
this.btnStop.Enabled = false;
this.btnMute.Enabled = false;
this.ctlVolume.Enabled = false;
}
private void SoundStudioFrm_Load(object sender, EventArgs e)
{
this.peakMeterCtrl1.SetRange(40, 70, 100);
this.peakMeterCtrl1.Start(33);
this.btnPlay.Enabled = true;
this.btnStop.Enabled = false;
this.btnMute.Enabled = false;
this.ctlVolume.Enabled = false;
}
protected override void OnHandleDestroyed(EventArgs e)
{
Terminate();
base.OnHandleDestroyed(e);
}
private void btnQuit_Click(object sender, EventArgs e)
{
this.Close();
}
private void btnBrowse_Click(object sender, EventArgs e)
{
if (openDialog.ShowDialog() == DialogResult.OK)
{
txtFilePath.Text = openDialog.FileName;
}
}
private void btnPlay_Click(object sender, EventArgs e)
{
if (_waveOutput == null)
{
CreateWaveOutput();
}
if (!_waveOutput.IsOpen())
{
_CopyWindowHandle = this.Handle;
try
{
// NOTE: Since our main thread belongs to a Single-thread apartment
// make sure this object is accessed from the same thread
// create multimedia stream object
IMediaStream pAudioStream = null;
_MediaStream = new MultimediaStream();
int mmr = _MediaStream.Initialize(STREAM_TYPE.STREAMTYPE_READ, (int)AMMSF_INIT.AMMSF_NOGRAPHTHREAD, null);
mmr = _MediaStream.AddMediaStream(null, MSPurposeId.PrimaryAudio, 0, out pAudioStream);
MSStatus.ThrowExceptionForHR(mmr);
// open media file
mmr = _MediaStream.OpenFile(this.txtFilePath.Text, (int)AMMSF_OPEN.AMMSF_RUN);
MSStatus.ThrowExceptionForHR(mmr);
_AudioStream = new MMAudioStream();
mmr = _AudioStream.SetMediaStream(pAudioStream);
MSStatus.ThrowExceptionForHR(mmr);
_wfmt = new WaveFormat(_AudioStream.Format);
mmr = _waveOutput.Open(WaveConstants.WAVE_MAPPER, _wfmt);
WaveOutStatus.ThrowExceptionForHR(mmr);
// calculate required buffer
_bufferSize = (uint)FFT.NextPowerOfTwo((uint)(_wfmt.BytesPerSecond * FFT_SPEED));
CreateBuffers();
AllocFFTData();
_numSamples = 0;
_numOutBuffers = 0;
for (int index = 0; index < MAX_BUFFERS; ++index)
{
WaveBuffer curBuffer = _waveBuffer[index];
int dwSize = curBuffer.BufferLength;
mmr = _AudioStream.GetSampleData(curBuffer.AudioData, ref dwSize, (int)COMPLETION_STATUS_FLAGS.COMPSTAT_WAIT, System.Threading.Timeout.Infinite);
MSStatus.ThrowExceptionForHR(mmr);
if (dwSize > 0)
{
mmr = _waveOutput.PrepareBuffer(curBuffer);
mmr = _waveOutput.AddBuffer(curBuffer);
WaveOutStatus.ThrowExceptionForHR(mmr);
Interlocked.Increment(ref _numOutBuffers);
if (index == 0)
{
mmr = _waveOutput.Start();
WaveOutStatus.ThrowExceptionForHR(mmr);
}
}
}
// setup mixer
CreateMixerDevice();
mmr = SetupMixer();
WaveOutStatus.ThrowExceptionForHR(mmr);
btnPlay.Enabled = false;
btnStop.Enabled = true;
btnMute.Enabled = true;
ctlVolume.Enabled = true;
}
catch (Exception ex) // typically: COMException, SystemException (waveout)
{
DumpDebugMessage(ex.Message);
Terminate();
MessageBox.Show(ex.Message);
}
}
}
private void btnStop_Click(object sender, EventArgs e)
{
Terminate();
}
private void btnMute_CheckedChanged(object sender, EventArgs e)
{
if (_mixerDevice != null && _mixerDevice.IsOpen())
{
MixerControlDetails mxcd = new MixerControlDetails();
tMIXERCONTROLDETAILS_BOOLEAN mxMute;
mxMute.fValue = this.btnMute.Checked ? 1 : 0;
Marshal.WriteInt32(_mixerDataPtr, mxMute.fValue);
mxcd.ControlID = _MuteControlId;
mxcd.NumChannels = 1;
mxcd.MultipleItems = 0;
mxcd.CbDetails = (int)Marshal.SizeOf(typeof(tMIXERCONTROLDETAILS_BOOLEAN));
mxcd.DataArray = _mixerDataPtr;
int hr = _mixerDevice.SetControlDetails(ref mxcd, MixerConstants.MIXER_SETCONTROLDETAILSF_VALUE);
}
}
private void ctlVolume_ValueChanged(object sender, EventArgs e)
{
if (_mixerDevice != null && _mixerDevice.IsOpen())
{
MixerControlDetails mxcd = new MixerControlDetails();
tMIXERCONTROLDETAILS_SIGNED mxVolume;
mxVolume.lValue = this.ctlVolume.Value;
Marshal.WriteInt32(_mixerDataPtr, mxVolume.lValue);
mxcd.ControlID = _VolumeControlId;
mxcd.NumChannels = 1;
mxcd.MultipleItems = 0;
mxcd.CbDetails = (int)Marshal.SizeOf(typeof(tMIXERCONTROLDETAILS_SIGNED));
mxcd.DataArray = _mixerDataPtr;
int hr = _mixerDevice.SetControlDetails(ref mxcd, MixerConstants.MIXER_SETCONTROLDETAILSF_VALUE);
}
}
int SetupMixer()
{
int mmr = _mixerDevice.Open((int)_waveOutput.GetId(), WaveConstants.CALLBACK_WINDOW | MixerConstants.MIXER_OBJECTF_HWAVEOUT, this.Handle);
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
MixerLineInfo mxli = new MixerLineInfo();
MixerLineControls mxlcs = new MixerLineControls();
MixerCaps mxcaps = new MixerCaps();
MixerControlDetails mxcd = new MixerControlDetails();
_mixerDataPtr = Marshal.AllocHGlobal(256);
mmr = _mixerDevice.GetDeviceCaps(ref mxcaps);
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
DumpDebugMessage(string.Format("Mixer Caps: {0}, Ver:0x{1:x} (0x{2:x})", mxcaps.ProductName, mxcaps.Version, mxcaps.SupportFlag));
}
mxli.ComponentType = MixerConstants.MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
mmr = _mixerDevice.GetLineInfo(ref mxli, MixerConstants.MIXER_GETLINEINFOF_COMPONENTTYPE);
if (mmr == WaveConstants.MMSYSERR_NOERROR)
{
tMIXERCONTROLW mxc;
Marshal.WriteInt32(_mixerDataPtr, (int)Marshal.OffsetOf(typeof(tMIXERCONTROLW), "cbStruct"), (int)Marshal.SizeOf(typeof(tMIXERCONTROLW)));
mxlcs.LineID = mxli.LineID;
mxlcs.NumControls = 1;
mxlcs.ControlType = MixerConstants.MIXERCONTROL_CONTROLTYPE_MUTE;
mxlcs.CbControl = (int)Marshal.SizeOf(typeof(tMIXERCONTROLW));
mxlcs.DataArray = _mixerDataPtr;
mmr = _mixerDevice.GetLineControls(ref mxlcs, MixerConstants.MIXER_GETLINECONTROLSF_ONEBYTYPE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -