mirror of
https://github.com/Gigaslav/HL2Overcharged.git
synced 2026-09-09 20:23:02 +03:00
398 lines
14 KiB
C#
398 lines
14 KiB
C#
/*===============================================================================================
|
|
DSP Effect per speaker Example
|
|
Copyright (c), Firelight Technologies Pty, Ltd 2004-2016.
|
|
|
|
This example shows how to manipulate a DSP network and as an example, creates 2 dsp effects,
|
|
and splits a single sound into 2 audio paths, which it then filters seperately.
|
|
To only have each audio path come out of one speaker each, FMOD_DSP_setInputLevels is used just
|
|
before the 2 branches merge back together again.
|
|
|
|
For more speakers:
|
|
1. Use FMOD_System_SetSpeakerMode or FMOD_System_SetOutputFormat.
|
|
2. Create more effects, currently 2 for stereo (reverb and chorus), create one per speaker.
|
|
3. Under the 'Now connect the 2 effects to channeldsp head.' section, connect the extra effects
|
|
by duplicating the code more times.
|
|
4. Filter each effect to each speaker by calling FMOD_DSP_SetInputLevels. Expand the existing code
|
|
by extending the level arrays from 2 to the number of speakers you require, and change the
|
|
numlevels parameter in FMOD_DSP_SetInputLevels from 2 to the correct number accordingly.
|
|
|
|
===============================================================================================*/
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.Windows.Forms;
|
|
using System.Data;
|
|
|
|
namespace dsp_effectperspeaker
|
|
{
|
|
public class Form1 : System.Windows.Forms.Form
|
|
{
|
|
private FMOD.System system = null;
|
|
private FMOD.Sound sound = null;
|
|
private FMOD.Channel channel = null;
|
|
private FMOD.DSP dsplowpass = null, dspchorus = null;
|
|
private FMOD.DSP dsphead = null, dspchannelmixer = null;
|
|
private bool reverbon = false;
|
|
private bool choruson = false;
|
|
private FMOD.DSPConnection dsplowpassconnection = null;
|
|
private FMOD.DSPConnection dspchorusconnection = null;
|
|
|
|
private System.Windows.Forms.Label label;
|
|
private System.Windows.Forms.Timer timer;
|
|
private System.Windows.Forms.Button exit_button;
|
|
private System.Windows.Forms.StatusBar statusBar;
|
|
private System.Windows.Forms.Button reverb;
|
|
private System.Windows.Forms.Button chorus;
|
|
private System.Windows.Forms.TrackBar trackBarPan;
|
|
private System.Windows.Forms.GroupBox groupBox1;
|
|
private System.ComponentModel.IContainer components;
|
|
|
|
public Form1()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
protected override void Dispose( bool disposing )
|
|
{
|
|
if( disposing )
|
|
{
|
|
FMOD.RESULT result;
|
|
|
|
if (sound != null)
|
|
{
|
|
result = sound.release();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
if (dsplowpass != null)
|
|
{
|
|
result = dsplowpass.release();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
if (dspchorus != null)
|
|
{
|
|
result = dspchorus.release();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
if (system != null)
|
|
{
|
|
result = system.close();
|
|
ERRCHECK(result);
|
|
|
|
result = system.release();
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
if (components != null)
|
|
{
|
|
components.Dispose();
|
|
}
|
|
}
|
|
base.Dispose( disposing );
|
|
}
|
|
|
|
#region Windows Form Designer generated code
|
|
/// <summary>
|
|
/// Required method for Designer support - do not modify
|
|
/// the contents of this method with the code editor.
|
|
/// </summary>
|
|
private void InitializeComponent()
|
|
{
|
|
this.components = new System.ComponentModel.Container();
|
|
this.label = new System.Windows.Forms.Label();
|
|
this.timer = new System.Windows.Forms.Timer(this.components);
|
|
this.exit_button = new System.Windows.Forms.Button();
|
|
this.statusBar = new System.Windows.Forms.StatusBar();
|
|
this.reverb = new System.Windows.Forms.Button();
|
|
this.chorus = new System.Windows.Forms.Button();
|
|
this.trackBarPan = new System.Windows.Forms.TrackBar();
|
|
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
|
((System.ComponentModel.ISupportInitialize)(this.trackBarPan)).BeginInit();
|
|
this.SuspendLayout();
|
|
//
|
|
// label
|
|
//
|
|
this.label.Location = new System.Drawing.Point(8, 8);
|
|
this.label.Name = "label";
|
|
this.label.Size = new System.Drawing.Size(264, 32);
|
|
this.label.TabIndex = 10;
|
|
this.label.Text = "Copyright (c) Firelight Technologies 2004-2016";
|
|
this.label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
|
//
|
|
// timer
|
|
//
|
|
this.timer.Enabled = true;
|
|
this.timer.Interval = 10;
|
|
this.timer.Tick += new System.EventHandler(this.timer_Tick);
|
|
//
|
|
// exit_button
|
|
//
|
|
this.exit_button.Location = new System.Drawing.Point(96, 176);
|
|
this.exit_button.Name = "exit_button";
|
|
this.exit_button.Size = new System.Drawing.Size(72, 24);
|
|
this.exit_button.TabIndex = 20;
|
|
this.exit_button.Text = "Exit";
|
|
this.exit_button.Click += new System.EventHandler(this.exit_button_Click);
|
|
//
|
|
// statusBar
|
|
//
|
|
this.statusBar.Location = new System.Drawing.Point(0, 211);
|
|
this.statusBar.Name = "statusBar";
|
|
this.statusBar.Size = new System.Drawing.Size(264, 24);
|
|
this.statusBar.TabIndex = 21;
|
|
//
|
|
// reverb
|
|
//
|
|
this.reverb.Location = new System.Drawing.Point(16, 48);
|
|
this.reverb.Name = "reverb";
|
|
this.reverb.Size = new System.Drawing.Size(104, 32);
|
|
this.reverb.TabIndex = 22;
|
|
this.reverb.Text = "Toggle reverb on left speaker only";
|
|
this.reverb.Click += new System.EventHandler(this.reverb_Click);
|
|
//
|
|
// chorus
|
|
//
|
|
this.chorus.Location = new System.Drawing.Point(144, 48);
|
|
this.chorus.Name = "chorus";
|
|
this.chorus.Size = new System.Drawing.Size(104, 32);
|
|
this.chorus.TabIndex = 23;
|
|
this.chorus.Text = "Toggle chorus on right speaker only";
|
|
this.chorus.Click += new System.EventHandler(this.chorus_Click);
|
|
//
|
|
// trackBarPan
|
|
//
|
|
this.trackBarPan.Location = new System.Drawing.Point(24, 112);
|
|
this.trackBarPan.Maximum = 512;
|
|
this.trackBarPan.Minimum = -512;
|
|
this.trackBarPan.Name = "trackBarPan";
|
|
this.trackBarPan.Size = new System.Drawing.Size(216, 45);
|
|
this.trackBarPan.TabIndex = 24;
|
|
this.trackBarPan.TickStyle = System.Windows.Forms.TickStyle.None;
|
|
this.trackBarPan.Scroll += new System.EventHandler(this.trackBarPan_Scroll);
|
|
//
|
|
// groupBox1
|
|
//
|
|
this.groupBox1.Location = new System.Drawing.Point(8, 88);
|
|
this.groupBox1.Name = "groupBox1";
|
|
this.groupBox1.Size = new System.Drawing.Size(248, 80);
|
|
this.groupBox1.TabIndex = 25;
|
|
this.groupBox1.TabStop = false;
|
|
this.groupBox1.Text = "Pan";
|
|
//
|
|
// Form1
|
|
//
|
|
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
|
|
this.ClientSize = new System.Drawing.Size(264, 235);
|
|
this.Controls.Add(this.trackBarPan);
|
|
this.Controls.Add(this.chorus);
|
|
this.Controls.Add(this.reverb);
|
|
this.Controls.Add(this.statusBar);
|
|
this.Controls.Add(this.exit_button);
|
|
this.Controls.Add(this.label);
|
|
this.Controls.Add(this.groupBox1);
|
|
this.Name = "Form1";
|
|
this.Text = "DSP Effect per speaker example";
|
|
this.Load += new System.EventHandler(this.Form1_Load);
|
|
((System.ComponentModel.ISupportInitialize)(this.trackBarPan)).EndInit();
|
|
this.ResumeLayout(false);
|
|
|
|
}
|
|
#endregion
|
|
|
|
[STAThread]
|
|
static void Main()
|
|
{
|
|
Application.Run(new Form1());
|
|
}
|
|
|
|
private void Form1_Load(object sender, System.EventArgs e)
|
|
{
|
|
uint version = 0;
|
|
FMOD.RESULT result;
|
|
FMOD.DSPConnection dspconnectiontemp = null;
|
|
|
|
/*
|
|
Create a System object and initialize.
|
|
*/
|
|
result = FMOD.Factory.System_Create(ref system);
|
|
ERRCHECK(result);
|
|
|
|
result = system.getVersion(ref version);
|
|
ERRCHECK(result);
|
|
if (version < FMOD.VERSION.number)
|
|
{
|
|
MessageBox.Show("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + FMOD.VERSION.number.ToString("X") + ".");
|
|
Application.Exit();
|
|
}
|
|
|
|
result = system.init(32, FMOD.INITFLAGS.NORMAL, (IntPtr)null);
|
|
ERRCHECK(result);
|
|
|
|
result = system.createSound("../../../../../examples/media/drumloop.wav", FMOD.MODE.SOFTWARE | FMOD.MODE.LOOP_NORMAL, ref sound);
|
|
ERRCHECK(result);
|
|
|
|
result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Create the DSP effects.
|
|
*/
|
|
result = system.createDSPByType(FMOD.DSP_TYPE.LOWPASS, ref dsplowpass);
|
|
ERRCHECK(result);
|
|
|
|
result = system.createDSPByType(FMOD.DSP_TYPE.CHORUS, ref dspchorus);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Connect up the DSP network
|
|
*/
|
|
|
|
/*
|
|
When a sound is played, a subnetwork is set up in the DSP network which looks like this.
|
|
Wavetable is the drumloop sound, and it feeds its data from right to left.
|
|
|
|
[DSPHEAD]<------------[DSPCHANNELMIXER]
|
|
*/
|
|
result = system.getDSPHead(ref dsphead);
|
|
ERRCHECK(result);
|
|
|
|
result = dsphead.getInput(0, ref dspchannelmixer, ref dspconnectiontemp);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Now disconnect channeldsp head from wavetable to look like this.
|
|
|
|
[DSPHEAD] [DSPCHANNELMIXER]
|
|
*/
|
|
result = dsphead.disconnectFrom(dspchannelmixer);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Now connect the 2 effects to channeldsp head.
|
|
|
|
[DSPLOWPASS]
|
|
/
|
|
[DSPHEAD] [DSPCHANNELMIXER]
|
|
\
|
|
[DSPCHORUS]
|
|
*/
|
|
result = dsphead.addInput(dsplowpass, ref dsplowpassconnection);
|
|
ERRCHECK(result);
|
|
result = dsphead.addInput(dspchorus, ref dspchorusconnection);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Now connect the wavetable to the 2 effects
|
|
|
|
[DSPLOWPASS]
|
|
/ \
|
|
[DSPHEAD] [DSPCHANNELMIXER]
|
|
\ /
|
|
[DSPCHORUS]
|
|
*/
|
|
result = dsplowpass.addInput(dspchannelmixer, ref dspconnectiontemp);
|
|
ERRCHECK(result);
|
|
result = dspchorus.addInput(dspchannelmixer, ref dspconnectiontemp);
|
|
ERRCHECK(result);
|
|
|
|
/*
|
|
Now the drumloop will be twice as loud, because it is being split into 2, then recombined at the end.
|
|
What we really want is to only feed the dspchannelmixer->dsplowpass through the left speaker, and
|
|
dspchannelmixer->dspchorus to the right speaker.
|
|
We can do that simply by setting the pan, or speaker levels of the connections.
|
|
|
|
[DSPLOWPASS]
|
|
/1,0 \
|
|
[DSPHEAD] [DSPCHANNELMIXER]
|
|
\0,1 /
|
|
[DSPCHORUS]
|
|
*/
|
|
{
|
|
float[] leftinputon = { 1.0f, 0.0f };
|
|
float[] rightinputon = { 0.0f, 1.0f };
|
|
float[] inputsoff = { 0.0f, 0.0f };
|
|
|
|
result = dsplowpassconnection.setLevels(FMOD.SPEAKER.FRONT_LEFT, leftinputon, 2);
|
|
ERRCHECK(result);
|
|
result = dsplowpassconnection.setLevels(FMOD.SPEAKER.FRONT_RIGHT, inputsoff, 2);
|
|
ERRCHECK(result);
|
|
|
|
result = dsplowpassconnection.setLevels(FMOD.SPEAKER.FRONT_LEFT, inputsoff, 2);
|
|
ERRCHECK(result);
|
|
result = dsplowpassconnection.setLevels(FMOD.SPEAKER.FRONT_RIGHT, rightinputon, 2);
|
|
ERRCHECK(result);
|
|
}
|
|
|
|
result = dsplowpass.setBypass(true);
|
|
result = dspchorus.setBypass(true);
|
|
|
|
result = dsplowpass.setActive(true);
|
|
result = dspchorus.setActive(true);
|
|
|
|
}
|
|
|
|
private void reverb_Click(object sender, System.EventArgs e)
|
|
{
|
|
dsplowpass.setBypass(reverbon);
|
|
|
|
reverbon = !reverbon;
|
|
}
|
|
|
|
private void chorus_Click(object sender, System.EventArgs e)
|
|
{
|
|
dspchorus.setBypass(choruson);
|
|
|
|
choruson = !choruson;
|
|
}
|
|
|
|
private void trackBarPan_Scroll(object sender, System.EventArgs e)
|
|
{
|
|
FMOD.RESULT result;
|
|
|
|
if (channel != null)
|
|
{
|
|
float pan = (float)(trackBarPan.Value) / 512.0f;
|
|
|
|
result = channel.setPan(pan);
|
|
}
|
|
}
|
|
|
|
private void exit_button_Click(object sender, System.EventArgs e)
|
|
{
|
|
Application.Exit();
|
|
}
|
|
|
|
private void timer_Tick(object sender, System.EventArgs e)
|
|
{
|
|
int channelsplaying = 0;
|
|
float pan = 0.0f;
|
|
|
|
if (channel != null)
|
|
{
|
|
channel.getPan(ref pan);
|
|
}
|
|
if (system != null)
|
|
{
|
|
system.getChannelsPlaying(ref channelsplaying);
|
|
system.update();
|
|
}
|
|
|
|
statusBar.Text = "Channels Playing " + channelsplaying + " : Pan = " + pan;
|
|
}
|
|
|
|
private void ERRCHECK(FMOD.RESULT result)
|
|
{
|
|
if (result != FMOD.RESULT.OK)
|
|
{
|
|
timer.Stop();
|
|
MessageBox.Show("FMOD error! " + result + " - " + FMOD.Error.String(result));
|
|
Environment.Exit(-1);
|
|
}
|
|
}
|
|
}
|
|
}
|