none
Audio Panorama control! RRS feed

  • Question

  • Hi,

    I would like to know which code is needed to make a PAN control for my sounds?!!

    I have been searching Google with no success : (

    Thank You!

    Monday, June 12, 2017 12:36 PM

Answers

  • so..tell me..have we reached a point where there is no possibility to pan the drums?!!

    I got it working with my code.

    Here are some things I found:

    #1)  I forgot the channels use zero-based numbering... unless the DLL is taking care of that for you, the percussion channel number is probably 9 (for channel 10).

    #2)  It seems that some of the percussion sounds in the Microsoft GS Wavetable Synth are mono and some are stereo.  Depending on which key you are hitting, the sound may or may not pan.  I ran a polyphonic song in the percussion track and could clearly tell that some sounds were not panning (e.g. cymbals).

    Taking #1 into account, I suspect the code will work if you do:

    MidiPlayer.Play(New Controller(0, 9, 10, amount))
    
    Every note after this call should play with the panning in effect, assuming it is not a mono sound.

    Here's the method I added to my code to provide panning:

        Public Sub Pan(channel As Byte, amount As Byte)
            If Device IsNot Nothing Then
                SendMessage(New MidiShortMessage(MidiShortMessage.MessageCommandMask.ControllerChange, channel, 10, amount))
            End If
        End Sub


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by beat assist Wednesday, June 14, 2017 8:15 PM
    Wednesday, June 14, 2017 1:40 PM
    Moderator

All replies

  • Not that I have done it but it appears you can use this api. The second link shows how to use mixercontro apis vb.net. Then you will have to write it for the pan. Possibly adjust left and right at the same time.

    If that's what you mean...

    MIXERCONTROL_CONTROLTYPE_PAN

    https://msdn.microsoft.com/en-us/library/windows/desktop/dd757293(v=vs.85).aspx

    http://www.vbforums.com/showthread.php?684496-manipulate-the-windows-mixer-control


    https://www.codeproject.com/articles/3094/audio-mixer-functions-demo


    • Edited by tommytwotrain Monday, June 12, 2017 1:35 PM change second link
    Monday, June 12, 2017 1:28 PM
  • thanks... i will check it out!
    Monday, June 12, 2017 2:15 PM
  • How are you playing the sounds in the first place?

    What is the overall goal of the application?

    For example, if you use DirectSound for the playback then you can easily set panning as a parameter when playing back the sound buffer and don't need to interact with the system level sound mixer.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Monday, June 12, 2017 2:22 PM
    Moderator
  • hi..

    i checked the links ..but no success..it looks they are for c++..

    I am triggering sounds from keyboard:

        Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            Dim SDrum1 As String = ComboBox2.Text
            Dim SDrum2 As String = ComboBox3.Text
            Dim keyPressed As String = e.KeyData.ToString
            Select Case keyPressed
    
                Case SDrum1
                    Dim vol = volu.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
                Case SDrum2
                    Dim vol = volu2.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.BassDrum, vol))
            End Select
    
        End Sub

    i would like to pan each sound i trigger... : )

    Monday, June 12, 2017 2:32 PM
  • hi..

    i checked the links ..but no success..it looks they are for c++..

    I am triggering sounds from keyboard:

        Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            Dim SDrum1 As String = ComboBox2.Text
            Dim SDrum2 As String = ComboBox3.Text
            Dim keyPressed As String = e.KeyData.ToString
            Select Case keyPressed
    
                Case SDrum1
                    Dim vol = volu.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
                Case SDrum2
                    Dim vol = volu2.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.BassDrum, vol))
            End Select
    
        End Sub

    i would like to pan each sound i trigger... : )

    The second link shows vb examples. But if you have never used the win32 api then it may be hard for you. As I say I just suspect it can be done this way.

    However there may be other ways, there is some other device that can be called I cant think of the .dll right now but Reed and others know I saw it in other threads here when searching.

    Also you might have directx options if you can learn that?

    What is your skill level?

    As I say I think others may know more...

    Monday, June 12, 2017 2:45 PM
  • beat,

    PS where does the sound come from your computer? Is that how you control the volume?

    When you set this

    Dim vol = volu2.Value

    does that change the volume? Then you can just make a vb routine to change those values. I am not sure if your midi volume is controlled by the computer or your keyboard? Do you use an add in card or do you have a hardware mixer in the line in/out?

    etc.

    Oh wait, I though you meant a real music keyboard via midi but I guess you are mean the computer keyboard and you play a midi file? So then that's just the computer vol which is what I was previously talking about. Nevermind. Someone will be along that know more...

    PS I guess you are calling the sound card instruments in the code you show???

    Monday, June 12, 2017 2:53 PM
  • OK so the ultimate goal is a DJ mixer-like application and you are playing MIDI using something called "MidiPlayer".  Is that an instance of MediaPlayer?  If so, it offers Balance control, but not Pan.

    You can use Win32 API calls to interact with the WINMM.DLL and control MIDI playback directly.  This would allow you to send a MIDI pan control message before playing a MIDI track.

    I have some example code here which shows the necessary Win32 imports along with some initialization code you could use.  You wouldn't use the part for generating real-time audio and instead would read an existing MIDI file and then feed the instruction data through a series of MIDI short messages.

    You can use the information here to find the MIDI messages codes and control message codes necessary to send the pan instruction.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Monday, June 12, 2017 2:56 PM
    Moderator
  • i am very basic..i understand snippets and i know how to do the conditions and calls!!!
    Monday, June 12, 2017 3:38 PM
  • it changes Volume/Velocity..as i am working with the keyboard (PC)..there are no velocity control keys so i use it as volume control!
    Monday, June 12, 2017 3:40 PM
  • MidiPlayer is from a bunch of C# codes..it imports Toub.Sound.midi

    here the full code i have for now:

    Imports Toub.Sound.Midi
    
    Public Class Form1
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            MidiPlayer.OpenMidi()
        End Sub
    
        Private Sub Form1_FormClosed(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
            MidiPlayer.CloseMidi()
        End Sub
    
        Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            Dim SDrum1 As String = ComboBox2.Text
            Dim SDrum2 As String = ComboBox3.Text
            Dim keyPressed As String = e.KeyData.ToString
            Select Case keyPressed
    
                Case SDrum1
                    Dim vol = volu.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
                Case SDrum2
                    Dim vol = volu2.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.BassDrum, vol))
            End Select
    
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim vol = volu.Value
            MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            ComboBox3.Enabled = True
            ComboBox2.Enabled = True
        End Sub
    
        Private Sub ComboBox2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox2.SelectedIndexChanged
            ComboBox2.Enabled = False
        End Sub
    
        Private Sub ComboBox3_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox3.SelectedIndexChanged
            ComboBox3.Enabled = False
        End Sub
    End Class
    
    

    this allows me to trigger several percussion sounds ... but i would like to control the pan for each one!!!

    Monday, June 12, 2017 3:43 PM
  • yes tommy .. it looks like so  : )
    Monday, June 12, 2017 4:10 PM
  • yes tommy .. it looks like so  : )

    Then unless Reed or someone has something else I am back to my original answer use apis to change the system vol. assuming that could be made to work.

    Or start over with vb midi api as Reed shows. Convert your c@ to vb etc.

    So you now control your volume with the windows speaker/headphones vol mixer ie right of task bar in win 7 volume control?

    Where does volu.Value come from in your code?

    What is its value when you run the code? How does that work?

    You use your normal computer speakers nothing else?


    Monday, June 12, 2017 4:39 PM
  • the "volu.value" is a value from a trackbar and it controls the drum velocity/volume!

    Could you publish a code where i control the PAN for the Windows mixer?

    If i use that control with diferente values for each sound..what happens if the user plays 2 drums at same time?

    Monday, June 12, 2017 4:50 PM
  • "Could you publish a code where i control the PAN for the Windows mixer?"

    Probably not. But lets see what Reed and others say now.

    "If i use that control with diferente values for each sound..what happens if the user plays 2 drums at same time?"

    LOL that is about the only line I read your .dll said it allows multiple notes to be played.

    "velocity/volume"

    So is that the volume? Seems by adjusting the volumes for each note you play you can achieve what you want? I mean that's what you do now move the slider and the volume goes up and down? Or is that some other volume? 

    Oh, wait, the sounds come out both speakers left and right when you play a note? Is there something in your .dll that allows you to spec left or right? I mean that's what PAN is correct? As Left goes up the right goes down so you move the focus ie sounds like it comes from over there and then moves over here. That's what you want correct?

    Well lets see what others say now...

    Monday, June 12, 2017 4:59 PM
  • "So is that the volume?"

    Yes..actually its Velocity..but i am use it as Volume cause it works!

    "mean that's what you do now move the slider and the volume goes up and down?"

    Yes .. it values from "0" to"127"

    "the sounds come out both speakers left and right when you play a note?"

    Yes!

    "Is there something in your .dll that allows you to spec left or right? "

    Not that i know!... but is possible..i must dig deeper!!!

    "I mean that's what PAN is correct?"

    Yes!

    "That's what you want correct?"

    Yes..different values for each sound"

    Monday, June 12, 2017 5:09 PM
  • Oh, so its a drum-machine-like application, not a DJ-mixer (or this is the drum machine component of a synth system).  I've been playing with similar stuff for a while.  That's what the code I linked to does.  I assumed you were playing existing midi, but you appear to be generating notes like I do.

    Sticking with the code you have now, it looks like that Play() method is just sending MIDI commands so you can simply send the Pan command before turning on the note.  You'll need a different message object than "NoteOn" but I would expect that there is a command message class you can use.  The values to supply that class are found in the MIDI reference material I linked earlier.

    With the code I posted in the other thread you can easily create a new Play() method to turn on your desired note while first sending a Pan command.  Just look at the existing Play method in that code where it is sending the command from each Chord instance.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Monday, June 12, 2017 6:57 PM
    Moderator
  • i am not getting it very well...could you publish the code i need?!

    Sorry..i am not a programmer..i just try to keep my head busy in my sparetime..but i am very basic!!

    Monday, June 12, 2017 7:55 PM
  • i am not getting it very well...could you publish the code i need?!

    Sorry..i am not a programmer..i just try to keep my head busy in my sparetime..but i am very basic!!

    Here is the cs source for your .dll it appears.

    http://freesourcecode.net/vbdotnetprojects/37983/sourcecode/MidiEvent.cs#.WT79aGCGOmQ

    It appears you just need to send the correct midi command to your dll.

    I see things you might use at the end of the midi ref in Reeds link etc.

    I am running your .dll which I dled and scanned from the link I gave and getting a sound from your source and yes that value makes the sound of the note louder but I think what Reed mentions is the way to go this is more an instrument feature ie how hard you hit the drum, as you prob know.

    Looking at the source I see there are various overloads and etc.

    So there is some command perhaps a simple pan or assign a channel and etc. I don't know exactly...

    Monday, June 12, 2017 8:54 PM
  • PS I ran across this doc that might help.

    Your .dll has a routine you can call and it will send the proper midi device codes.

    Your code now plays a note on an instrument. Now you need to send commands to the .dll (however the .dll works) and then the .dll will create and send the proper midi commands to the midi device to adjust the volume. There are even 3d pan things I see. Not that I know how to do it exactly.

     This seems like a good intro to midi commands.

    Here is a clip:

    PS The device needs to support the exact midi function. Ie your computer midi synth needs to support pan. On a real midi keyboard isn't there a lever knob for pan or something? So if the keyboard does not have the knob it ignores the command. Your computer synth needs to support it. I am not sure if the basic windows synth does it all etc.

    Tuesday, June 13, 2017 12:25 AM
  • i am not getting any PAN or Balance control for my .dll .. i think it does not has that function!!!!
    Tuesday, June 13, 2017 11:38 AM
  • i am not getting any PAN or Balance control for my .dll .. i think it does not has that function!!!!

    beat,

    Why do you say that? What have you done to try using Pan with the toub .ddl?

    I am hoping Reed or someone else familiar with midi will be back with an example. I dont know enough about the midi commands to reverse engineer your .dll. I am not expecting you to know how either (but I don't really know what you know).

    Tuesday, June 13, 2017 12:00 PM
  • i have a bunch of c# modules that are used with the Toub.Sound.MIDI ...

    MIDITrack / MIDI Sequence / MIDI Parser etc...

    i have been trying to find a Pan or balance control under this files by writting:

    MIDItrack."control should appear here"

    MIDISequence."control should appear here"

    etc....

    ....and i cannot find a Pan or balance control under any of these!!!

    i think it would be something like: MIDITrack.PAN = "control".value

    Tuesday, June 13, 2017 12:39 PM
  • ...

    i think it would be something like: MIDITrack.PAN = "control".value

    No, its not. 

    As I explained, you simply send the PAN command through the play method.  Since that DLL appears to have a class for each type of command, and we know there is a NoteOn, NoteOff, and ProgramChange class, my guess is that there is also a ControlChange class as well.  We can see this is the name of a message in the Summary of MIDI Messages chart previously linked.

    We can then look at the Control Change Messages chart and find the data code for Pan (10).  So the command probably looks something like:

    MidiPlayer.Play(New ControlChange(10, 64))

    Where the "10" is the pan command (may also be an enum for this) and "64" is the example value to set the Pan level to (the values are 0-127 as shown in the chart).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Tuesday, June 13, 2017 1:11 PM
    Moderator
  • "MidiPlayer.Play(New ControlChange(10, 64))"

    i am not finding anything related to: "ControlChange"

    Tuesday, June 13, 2017 1:31 PM
  • like i said..i guess the .dll does not has this function!!!
    Tuesday, June 13, 2017 1:38 PM
  • ...

    i think it would be something like: MIDITrack.PAN = "control".value

    No, its not. 

    As I explained, you simply send the PAN command through the play method.  Since that DLL appears to have a class for each type of command, and we know there is a NoteOn, NoteOff, and ProgramChange class, my guess is that there is also a ControlChange class as well.  We can see this is the name of a message in the Summary of MIDI Messages chart previously linked.

    We can then look at the Control Change Messages chart and find the data code for Pan (10).  So the command probably looks something like:

    MidiPlayer.Play(New ControlChange(10, 64))

    Where the "10" is the pan command (may also be an enum for this) and "64" is the example value to set the Pan level to (the values are 0-127 as shown in the chart).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Reed,

    It seems this are the methods in the .dll. Does one look related to control change? It seems maybe one has to use midievent and define control change or something like that.

    Well that's why I posted the source as that's what is takes to figure it but I don't know enough to do it. And it might be easier to use the vb code you already have that you showed in your link, Reed. I was hoping you could easily spot a clue whether the .dll actually had it.

    Namespace Toub.Sound.Midi
        Public NotInheritable Class MidiPlayer
            Public Shared Sub CloseMidi()
            Public Shared Sub OpenMidi()
            Public Shared Sub Play(sequence As MidiSequence)
            Public Shared Sub Play(path As String)
            Public Shared Sub Play(ev As MidiEvent)
            Public Shared Sub Play(track As MidiTrack, division As Integer)
            Public Shared Sub Play(events As MidiEventCollection, division As Integer)
        End Class
    End Namespace

    PS I tried this:

    MidiPlayer.Play(New ControlChange(10, 64))

    But it just says ControlChange not defined.


    Tuesday, June 13, 2017 1:58 PM
  • I looked through the source link, Tommy... it is a class simply called "Controller":

    	/// <summary>
    	/// MIDI event to modify the tone with data from a pedal, lever, or other device; 
    	/// also used for miscellaneous controls such as volume and bank select.
    	/// </summary>
    	[Serializable]
    	public sealed class Controller : VoiceMidiEvent
    	{
    		#region Member Variables
    		/// <summary>The type of controller message (0x0 to 0x7F).</summary>
    		private byte _number;
    		/// <summary>The value of the controller message (0x0 to 0x7F).</summary>
    		private byte _value;
    		/// <summary>The category status byte for Controller messages.</summary>
    		private const byte _CATEGORY = 0xB;
    		#endregion

    So he needs to play an instance of this class with the Number set to 10 and the value set to whatever pan he wants to use.  There may be a timing component necessary as well (according to the class constructors), but it may do to simply use a time offset of zero when sending this command prior to playing a note...  I'm not entirely sure of how this DLL was meant to be used (and it looks like it provides a number of options).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 2:16 PM
    Moderator
  • "MidiPlayer.Play(New ControlChange(10, 64))"

    i am not finding anything related to: "ControlChange"


    See below... the author used "Controller" for the name of the class instead of ControlChange.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 2:19 PM
    Moderator
  • i am trying this:

     MidiPlayer.Play(New Controller(0, 1, 10, 127))

    but is not working..i am having error where it says "Controller"

    Tuesday, June 13, 2017 2:23 PM
  • I looked through the source link, Tommy... it is a class simply called "Controller":

    	/// <summary>
    	/// MIDI event to modify the tone with data from a pedal, lever, or other device; 
    	/// also used for miscellaneous controls such as volume and bank select.
    	/// </summary>
    	[Serializable]
    	public sealed class Controller : VoiceMidiEvent
    	{
    		#region Member Variables
    		/// <summary>The type of controller message (0x0 to 0x7F).</summary>
    		private byte _number;
    		/// <summary>The value of the controller message (0x0 to 0x7F).</summary>
    		private byte _value;
    		/// <summary>The category status byte for Controller messages.</summary>
    		private const byte _CATEGORY = 0xB;
    		#endregion

    So he needs to play an instance of this class with the Number set to 10 and the value set to whatever pan he wants to use.  There may be a timing component necessary as well (according to the class constructors), but it may do to simply use a time offset of zero when sending this command prior to playing a note...  I'm not entirely sure of how this DLL was meant to be used (and it looks like it provides a number of options).


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    I saw that and have been trying to figure it out. I just don't know the names of things.

    I have also been trying to do something with the windows mixer vols and have converted to all the proper apis but I still cant set the volume. Part of my problem is I am not sure the device name on my system and also all the old apis shown in the link I gave.

    Is it possible to just set the system speaker vols left and right individual via code? Maybe that's easier.

    Still looking...

    Tuesday, June 13, 2017 2:25 PM
  • i am trying this:

     MidiPlayer.Play(New Controller(0, 1, 10, 127))

    but is not working..i am having error where it says "Controller"

    So what's the error?

    Is channel 1 correct?  Usually your percussion is on channel 10... so I would expect:

    New Controller(0, 10, 10, 127)


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 2:38 PM
    Moderator
  • PS Here is what vs shows.

    Namespace Toub.Sound.Midi
        Public NotInheritable Class Controller
            Inherits VoiceMidiEvent
    
            Public Sub New(deltaTime As Long, channel As Byte, number As Controllers, value As Byte)
            Public Sub New(deltaTime As Long, channel As Byte, number As Byte, value As Byte)
    
            Public Property Number As Byte
            Public Property Value As Byte
            Protected Overrides ReadOnly Property Parameter1 As Byte
            Protected Overrides ReadOnly Property Parameter2 As Byte
    
            Public Overrides Sub Write(outputStream As Stream)
    
            Public Overrides Function ToString() As String
        End Class
    End Namespace


    I have tried this:

       Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            'Dim vol = volu.Value
            Dim vol As Byte = 100  'volu.Value
            MidiPlayer.Play(New Controller(0, 0, 10, 1))
            MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
    
        End Sub

    And get sound but from both left and right equal. I change the last value from 1 to 120 but I don't hear any difference left/right through my big speakers.

    But it seems there needs to be a channel defined somehow for the instrument and then set the vol of that channel? Then patch that channel to left or right. Seems that's what we used to do back in the stone age.

    PS My big speakers are using the headphone line out into my big amp.

    PSS I also don't hear any difference with my speakers in my monitor from the headphone jack. I guess they are stereo but not sure.




    Tuesday, June 13, 2017 2:42 PM
  • ...

    I have also been trying to do something with the windows mixer vols and have converted to all the proper apis but I still cant set the volume. Part of my problem is I am not sure the device name on my system and also all the old apis shown in the link I gave.

    Is it possible to just set the system speaker vols left and right individual via code? Maybe that's easier.

    Still looking...

    That probably isn't going to help because it is only going to make the sound play quieter on one side, it won't actually "drift" the sound from left to right.  Everything that plays will be louder on one side than the other using the Windows balance controls, and even if you turn one side all the way down you will likely still hear some sound from that speaker.

    It has to do with the way the synthesizer creates stereo audio from the MIDI commands.  The pan is what determines how much sound goes to each channel.  Without it you get an even split when the synth tries to make stereo output (with mono voices).  So the balance at the Windows level can only lower a level on one side... it can't completely fade the sound from one side to the other.

    And of course there's the issue that the Windows balance controls will affect all playing channels in the MIDI sequence as opposed to just particular channels.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 3:10 PM
    Moderator
  • Tommy,

    When you use a percussion instrument, that overload of the NoteOn constructor is automatically setting the channel to 10, so you need to pan channel 10.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 3:15 PM
    Moderator
  • hey..trying this but no luck:

     Dim vol As Byte = volu.Value
                    Dim del As Byte = 0
                    Dim chan As Byte = 10
                    Dim pan As Byte = 10
                    Dim val As Byte = hsbPan.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
                    MidiPlayer.Play(New Controller(del, chan, pan, val))



    Tuesday, June 13, 2017 3:15 PM
  • hey..trying this but no luck:

     Dim vol As Byte = volu.Value
                    Dim del As Byte = 0
                    Dim chan As Byte = 0
                    Dim pan As Byte = 20
                    Dim val As Byte = hsbPan.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))
                    MidiPlayer.Play(New Controller(del, chan, pan, val))

    As I've said, the percussion channel is 10 so you need to pan channel 10.  You also need to send the pan command before playing the note.

    The only thing I'm unclear of is the timing and if you need to specify any delay between the controller command and the note command.  Again, I'm not familiar with how this DLL is doing its sequencing.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 3:17 PM
    Moderator
  • you say like this:

            Dim del As Byte = 0
                    Dim chan As Byte = 10
                    Dim pan As Byte = 10
                    Dim val As Byte = hsbPan.Value
                    MidiPlayer.Play(New Controller(del, chan, pan, val))
                    Dim vol As Byte = volu.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))

    its not working : (

    Tuesday, June 13, 2017 3:26 PM
  • you say like this:

            Dim del As Byte = 0
                    Dim chan As Byte = 10
                    Dim pan As Byte = 10
                    Dim val As Byte = hsbPan.Value
                    MidiPlayer.Play(New Controller(del, chan, pan, val))
                    Dim vol As Byte = volu.Value
                    MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, vol))

    its not working : (

    I cant get anything either. I tried channel 10 (for both commands). Tried lots of things. Add some durations which seem to work but I am not sure what time units. Then I went to a piano and channel 1 for both etc. Here is the piano:

            MidiPlayer.Play(New Controller(100, 1, 10, 127))
            MidiPlayer.Play(New NoteOn(100, 1, 50, 100))

    Works but no pan = 10. I also tried balance = 8.

    So if Reed has the time he will figure it out. But its the kind of thing that if its not yours then its hard to spend so many hours on it. It think it might be easier to rewrite it unless Reed can apply his own project to it. I am out of ideas, for now.

    PS This code produces sounds of the instr but it does not pan left/right in case I was not clear.
    Tuesday, June 13, 2017 4:11 PM
  • tommy..why did you used the Delta Time of 100 ?
    Tuesday, June 13, 2017 4:13 PM
  • tommy..why did you used the Delta Time of 100 ?

    Just to make it last longer and because Reed mentioned timing. See if you were playing back a recording then everything has a time/duration, I am no expert.

    Play with it. It appears to check the values.

    PS Interuption... to make the note last longer. ie my last is a piano and 100 units long. You can hear the note fade etc. Different than a drum maybe.
    Tuesday, June 13, 2017 4:17 PM
  • beat,

    In the Visual Studio editor code window click the mouse on the word

    NoteOn

    in the call and then press <shft>+<F2> you will go to the routine. At least what vb shows:

    Namespace Toub.Sound.Midi
        Public NotInheritable Class NoteOn
            Inherits NoteVoiceMidiEvent
    
            Public Sub New(deltaTime As Long, percussion As GeneralMidiPercussion, velocity As Byte)
            Public Sub New(deltaTime As Long, channel As Byte, note As String, velocity As Byte)
            Public Sub New(deltaTime As Long, channel As Byte, note As Byte, velocity As Byte)
    
            Public Property Velocity As Byte
            Protected Overrides ReadOnly Property Parameter2 As Byte
    
            Public Overrides Sub Write(outputStream As Stream)
    
            Public Shared Function Complete(deltaTime As Long, percussion As GeneralMidiPercussion, velocity As Byte, duration As Long) As MidiEventCollection
            Public Shared Function Complete(deltaTime As Long, channel As Byte, note As String, velocity As Byte, duration As Long) As MidiEventCollection
            Public Shared Function Complete(deltaTime As Long, channel As Byte, note As Byte, velocity As Byte, duration As Long) As MidiEventCollection
            Public Overrides Function ToString() As String
        End Class
    End Namespace


    So it gives the ways you can call the routine (over rides) see how one is method you pass the GeneralMidiPercussion, but another you can just use the instr number which is my last example instr = 1` grand piano.

    And then if you look in the cs code you can see the function code and cs is not that different than vb if you ignore all the craze {/// ||| stuff.

    That's the game we play and sometimes its fun and sometimes not.

    PS sorry, that's not the instrument number its the channel number and I guess channel 1 is piano. ???

    Tuesday, June 13, 2017 4:31 PM
  • I haven't had a lot of time to play with it, but it looks like the channel may need to be set into a polyphonic mode, or at least have mono mode turned off.  There may also be some system message necessary to tell the synth to create stereo sound.  Whatever it is, I suspect there's something missing in the messaging but I'm not sure at this point.

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 5:04 PM
    Moderator
  • hey..i tried with the "granpiano" instrument.....it works..

    so YES..the problem its with the poly!!!

    Tuesday, June 13, 2017 5:19 PM
  • hey..i tried with the "granpiano" instrument.....it works..

    so YES..the problem its with the poly!!!

    OK try sending the ControlChange message 127 with a data value of 0.  Per the documentation (near the bottom of the chart), that should set poly mode for the channel.

    What are you controlling with the MIDI commands?  The software synth in your computer, a hardware synth on your PC sound card, or an external piece of hardware?

    If I could get answers to the questions about what you are actually trying to do it would greatly help me narrow down the way in which you are using MIDI commands and what information might be relevant to the problem.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Tuesday, June 13, 2017 7:05 PM
    Moderator
  • "OK try sending the ControlChange message 127 with a data value of 0. .... that should set poly mode for the channel."

    i am not understanding very well!!!

    "What are you controlling with the MIDI commands?  The software synth in your computer, a hardware synth on your PC sound card, or an external piece of hardware?"

    i am just using my PC keyboard keys to trigger the drums : )

    Tuesday, June 13, 2017 7:21 PM
  • "OK try sending the ControlChange message 127 with a data value of 0. .... that should set poly mode for the channel."

    i am not understanding very well!!!

    "What are you controlling with the MIDI commands?  The software synth in your computer, a hardware synth on your PC sound card, or an external piece of hardware?"

    i am just using my PC keyboard keys to trigger the drums : )

    Change the 10 in the message you are using to set the pan to a 127 and use 0 for value:

    pan=127
    val=0
    MidiPlayer.Play(New Controller(del, chan, pan, val))

    OK so you don't have any hardware, just software synth I'm guessing.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Tuesday, June 13, 2017 7:35 PM
    Moderator
  • "MidiPlayer.Play(New Controller(del,chan,pan,val))"

    i am having NO result!!!!!

    i have hardware ( i am a Dj/Producer) but i do not understand how to insert a MIDI Controller (hardware)..in my code..

    Perhaps you could help on that too!!(case you want)...

    For the drums the PC keyboard is ok..but if i would like to make a synth with other instruments..playing from a MIDI controller would be great!!!


    Tuesday, June 13, 2017 7:48 PM
  • PS

    Sorry. Forgot about my bad ear. When I turn the headphones around it sounds the same.

    =============

    This plays on my headphone left side with button 1 and in the center with button 2.

    BTW the duration seems to have no effect.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            '(del, chan, pan, val))
            MidiPlayer.Play(New Controller(10, 10, 10, 0))
            MidiPlayer.Play(New NoteOn(10, GeneralMidiPercussion.AcousticSnare, 100))
    
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            MidiPlayer.Play(New Controller(10, 10, 10, 127))
            MidiPlayer.Play(New NoteOn(10, GeneralMidiPercussion.AcousticSnare, 100))
    
        End Sub

    Tuesday, June 13, 2017 7:53 PM
  • This plays on my headphone left side with button 1 and in the center with button 2.

    BTW the duration seems to have no effect.

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            
            '(del, chan, pan, val))
            MidiPlayer.Play(New Controller(10, 1, 10, 0))
    
            MidiPlayer.Play(New NoteOn(10, 1, 50, 100))
    
    
        End Sub
    
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            MidiPlayer.Play(New Controller(10, 1, 10, 127))
    
            MidiPlayer.Play(New NoteOn(10, 1, 50, 100))
        End Sub


    yes tommy..but it plays the instruments NOT the drums!
    Tuesday, June 13, 2017 7:56 PM


  • yes tommy..but it plays the instruments NOT the drums!

    Yes. Well it should not matter?

    However Sorry I was wrong it sounds the same between the two. I turned the headphones around and now the two buttons sound the same.

    However, it is just one speaker ie one side. Both come from one speaker?? Is that what you hear?

    I changed the two button example code above to the drums. Tell us what you hear, just on side left or right?

    PS Oh wait sorry, forgot these phones have a balance control now I get the same sound in both left and right (no mater what values I use 0-127 for 3rd and 4th fields).

     :)


    PS I deleted a couple of my posts to consolidate.


    Tuesday, June 13, 2017 8:16 PM
  • so..tell me..have we reached a point where there is no possibility to pan the drums?!!
    Wednesday, June 14, 2017 12:37 PM
  • so..tell me..have we reached a point where there is no possibility to pan the drums?!!

    beat,

    No I dont think so. We just dont know how.

    I think Reed can do it.

    I think I could eventually figure it out but I charge $150 /hr for custom programming.

    Reed is probably more $$. 

    Joke Son. Sort of.

    Lets see what Reed says. Also I think there are a couple others that can help but they have to show up and have the time available and be in the mood.

    Part of the problem is we have to be sure our computers support the midi function pan. Could be on a differenct system with a real midi sound card our code is working now.

    I would have to get my music studio working again to test it further. Probably not going to happen.

    I also think we could start over with just the intent to set the pan and not all the other and write our own vb code for it instead of the .dll we are using.

    I also think Reed mentioned he has been working with this and his vb example looks like the same basic thing so maybe he can just do it with his vb version. Plus he knows the midi codes better than you or I.

    But like I said when it is not your project or something one has special intrest in it is hard to justify the time. I have lots of time but Reed does not.

    Wednesday, June 14, 2017 12:48 PM
  • so..tell me..have we reached a point where there is no possibility to pan the drums?!!

    I got it working with my code.

    Here are some things I found:

    #1)  I forgot the channels use zero-based numbering... unless the DLL is taking care of that for you, the percussion channel number is probably 9 (for channel 10).

    #2)  It seems that some of the percussion sounds in the Microsoft GS Wavetable Synth are mono and some are stereo.  Depending on which key you are hitting, the sound may or may not pan.  I ran a polyphonic song in the percussion track and could clearly tell that some sounds were not panning (e.g. cymbals).

    Taking #1 into account, I suspect the code will work if you do:

    MidiPlayer.Play(New Controller(0, 9, 10, amount))
    
    Every note after this call should play with the panning in effect, assuming it is not a mono sound.

    Here's the method I added to my code to provide panning:

        Public Sub Pan(channel As Byte, amount As Byte)
            If Device IsNot Nothing Then
                SendMessage(New MidiShortMessage(MidiShortMessage.MessageCommandMask.ControllerChange, channel, 10, amount))
            End If
        End Sub


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by beat assist Wednesday, June 14, 2017 8:15 PM
    Wednesday, June 14, 2017 1:40 PM
    Moderator
  • so..tell me..have we reached a point where there is no possibility to pan the drums?!!

    I got it working with my code.

    Here are some things I found:

    #1)  I forgot the channels use zero-based numbering... unless the DLL is taking care of that for you, the percussion channel number is probably 9 (for channel 10).

    #2)  It seems that some of the percussion sounds in the Microsoft GS Wavetable Synth are mono and some are stereo.  Depending on which key you are hitting, the sound may or may not pan.  I ran a polyphonic song in the percussion track and could clearly tell that some sounds were not panning (e.g. cymbals).

    Taking #1 into account, I suspect the code will work if you do:

    MidiPlayer.Play(New Controller(0, 9, 10, amount))
    Every note after this call should play with the panning in effect, assuming it is not a mono sound.

    Here's the method I added to my code to provide panning:

        Public Sub Pan(channel As Byte, amount As Byte)
            If Device IsNot Nothing Then
                SendMessage(New MidiShortMessage(MidiShortMessage.MessageCommandMask.ControllerChange, channel, 10, amount))
            End If
        End Sub


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Alright now we are getting somewhere.

    Nowever, the .dll two button example I posted does not work with

       MidiPlayer.Play(New Controller(0, 9, 10, 119))


    and button 2.


       MidiPlayer.Play(New Controller(0, 9, 10, 1))


    I use 1 and 119 because 0 and 120-127 seem to be other.

    I am trying the GeneralMidiPercussion.AcousticSnare, is that stereo for you Reed?

    I tried the pan Controller command just at start of button1 and not button2, also both button1 and 2.

    I will get your vb code Reed and try to add the pan routine and try it here a bit later... time to feed the animals.

    Wednesday, June 14, 2017 2:07 PM
  • MidiPlayer.Play(New Controller(0, 9, 10, amount

    Its working..Thank you!
    Wednesday, June 14, 2017 2:13 PM
  • Just an aside: I was using 0 and 127 and getting full left/right panning.

    I was playing the test music through notes so I'm not sure which one maps to the acoustic snare (I could look it up) but a snare drum should be stereo - it just seemed to be some of the accessories like the wood block and one of the cymbals that wouldn't pan.

    I'm not sure how that DLL is packing the bytes from the message classes to the actual midi message data.  There are only 4 bytes in a MIDI message and the first one uses nibbles to represent both the message category and the target channel.  The second byte is the command id and the third and fourth are parameter bytes specific to the command (many don't use the fourth byte).

    I know that when packed properly, the pan messages work.  Its just a matter of figuring out how this DLL expects you to specify the command.  


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Wednesday, June 14, 2017 2:17 PM
    Moderator
  • MidiPlayer.Play(New Controller(0, 9, 10, amount

    Its working..Thank you!

    Great!

    If your issue is resolved, can you please close the thread by clicking the "Mark as answer" link at the bottom of the relevant posts which solved your issue?

    Thanks!


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Wednesday, June 14, 2017 2:25 PM
    Moderator
  • MidiPlayer.Play(New Controller(0, 9, 10, amount

    Its working..Thank you!

    Great!

    If your issue is resolved, can you please close the thread by clicking the "Mark as answer" link at the bottom of the relevant posts which solved your issue?

    Thanks!


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    beat,

    Please show all your code that works.

    PS Use the two button example if you want as that is easy for others to duplicate.

    Wednesday, June 14, 2017 2:42 PM
  • here..

           Dim vol As Byte = volu.Value
            Dim del As Byte = 0
            Dim chan As Byte = 9
            Dim pan As Byte = 10
            Dim val As Byte = hsbpan.Value
            MidiPlayer.Play(New Controller(del, chan, pan, val))
            MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.BassDrum, vol))

    this is what i am using!!!

    Wednesday, June 14, 2017 7:54 PM
  • Ok I hear the pan. I think one needs multiple notes the two buttons does not cut it to hear it. Especially for me. Plus the pan effect was not as strong as I thought it would be. It is subtle left and right.

    So I made this example that runs on a timer with a beat and I can hear it now! This example has all the controls made just cut and paste into an empty form. Add a ref to the .dll which you have to download at the link in the code. Click play and move the trackbar slider.

    'pan midi example
    'toub.dll download
    'http://grouplab.cpsc.ucalgary.ca/cookbook/index.php/VisualStudio/HowToPlayMIDIInstruments
    'cs source
    'http://freesourcecode.net/vbdotnetprojects/37983/sourcecode/MidiEvent.cs#.WT79aGCGOmQ
    
    Imports Toub.Sound.Midi
    Public Class Form5
    
        Private WithEvents timer1 As New Timer With {.Enabled = False, .Interval = 600}
        Private WithEvents PanTb As New TrackBar With {.Parent = Me, .Location = New Point(30, 50),
                .Maximum = 119, .Minimum = 1, .Value = 60}
        Private Label1 As New Label With {.Parent = Me, .Location = New Point(60, 100), .Text = "60"}
        Private WithEvents Button1 As New Button With {.Parent = Me, .Location = New Point(150, 60),
                .Size = New Size(60, 30), .Text = "Play"}
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            MidiPlayer.OpenMidi()
        End Sub
    
        Private Sub Form1_FormClosed(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
            timer1.Stop()
            MidiPlayer.CloseMidi()
        End Sub
    
        Private Sub TrackBar1_Scroll(sender As Object, e As EventArgs) Handles PanTb.ValueChanged
            Label1.Text = PanTb.Value.ToString
    
        End Sub
    
        Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
    
            Dim del As Byte = 0
            Dim chan As Byte = 9
            Dim pan As Byte = 10
            Dim val As Byte = CByte(PanTb.Maximum - PanTb.Value)
    
            MidiPlayer.Play(New Controller(del, chan, pan, val))
    
            Static flip As Boolean = True
            flip = Not flip
            If flip Then
                MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, 70))
                MidiPlayer.Play(New NoteOff(0, GeneralMidiPercussion.AcousticSnare, 0))
    
                'MidiPlayer.Play(New NoteOn(10, 10, 40, 20))  'to play piano
            Else
                MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.AcousticSnare, 40))
                MidiPlayer.Play(New NoteOff(0, GeneralMidiPercussion.AcousticSnare, 0))
    
                MidiPlayer.Play(New NoteOn(0, GeneralMidiPercussion.BassDrum, 30))
                MidiPlayer.Play(New NoteOff(0, GeneralMidiPercussion.BassDrum, 0))
    
            End If
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If Button1.Text = "Play" Then
                timer1.Start()
                Button1.Text = "Stop"
            Else
                timer1.Stop()
                Button1.Text = "Play"
            End If
        End Sub
    
    End Class


    • Edited by tommytwotrain Thursday, June 15, 2017 12:15 PM add noteoff every note
    Wednesday, June 14, 2017 9:37 PM
  • @Tommy, FWIW:

    I'm pretty sure the specification calls for turning off each note after it has played - I'm not sure what it does to the MIDI stack to keep turning on the same note without turning it off.

    There are two ways to turn off the note: you can use the NoteOff message, or you can specify a volume of 0 with the NoteOn message.  The recommendation for compatibility, I believe, is to use NoteOn with volume 0.

    If you switch to a string instrument (or horn, woodwind, etc.) you should find that it just keeps playing the same note until you do actually turn it off.  The pianos and percussion have fades which is why you don't hear the note continuing to play, but technically it is still "held down".


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"


    Thursday, June 15, 2017 2:55 AM
    Moderator
  • @Tommy, FWIW:

    I'm pretty sure the specification calls for turning off each note after it has played - I'm not sure what it does to the MIDI stack to keep turning on the same note without turning it off.

    There are two ways to turn off the note: you can use the NoteOff message, or you can specify a volume of 0 with the NoteOn message.  The recommendation for compatibility, I believe, is to use NoteOn with volume 0.

    If you switch to a string instrument (or horn, woodwind, etc.) you should find that it just keeps playing the same note until you do actually turn it off.  The pianos and percussion have fades which is why you don't hear the note continuing to play, but technically it is still "held down".


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"



    I tried NoteOff and it definately changes the sound of the note. Now I notice the fade in the note. And maybe the pan is more distict.

    I saw where somethings needed to be activated etc. There at the end of the midi table at 127 where the pan is and then some others follow (3d?) but it mentions calling with 0 and 120-127 for certian setups. A bit confusing what it is.


    I dont seem to be able to get any other instrument than percussion out of the dll calls. Thats what the one we ar using is declared GeneralMidiPercussion, And esing other contstructors only have channel to set only play grand piano. But it sounds good for that.


       MidiPlayer.Play(New NoteOff(0, GeneralMidiPercussion.AcousticSnare, 0))

    Thanks Reed!

    PS I guess one just calls noteoff once after all the noteons for a beat.

    See where I added NoteOff to my timer example.

    PSS I think my timer example also has timing problems as it seems to skip beats. Must be related to duration...

    Fun stuff!

    Thursday, June 15, 2017 4:23 AM
  • @Tommy:

    Any decay that the instrument may provide on a given note would only occur when the note stopped, so it should sound better with the NoteOff command.

    I'm not quite sure which "MIDI Table at 127" you are referring to (link?).  Some options turn on and off with 0 or 127 and any controller numbered 120-127 is a channel mode message which controls the channels operating mode rather than the sound parameters.

    As long as you use channel 10 you are going to get the percussion instrument map.  Just change to any other channel and then the second parameter will change from specifying a particular percussion instrument to specifying a particular note in the current voice.  The default voice for the channel will be grand piano, but you can send a ProgramChange message to change to whatever instrument you want.  Here's an example from my code:

    Public Overridable Sub SetVoice(channel As Byte, voice As InstrumentVoice)
        SendMessage(New MidiShortMessage(MidiShortMessage.MessageCommandMask.ProgramChange, channel, voice, 0))
    End Sub
    

    Voices are numbered 1 thru 128.

    Every note that is turned on needs to be exclusively turned off.  Your example is turning off the AcousticSnare note but not the BassDrum note.

    The skipping beats may be due to the missing note off for the bass drum.  It looks like the NoteOn class can call the Complete() method to get a series of messages which turn the note on and off for a given duration.  The deltaTime parameter may be used to sequence a series of notes created this way (as well as ensuring that the multiple notes of a chord play at the exact same time).  Again, I'm not entirely clear on the intended usage of this library.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Thursday, June 15, 2017 11:59 AM
    Moderator
  • Reed,

    Ok I see. Yes I added note off to my timer example (above) after every noteon and now the note skipping has stopped.

    I meant 127 for poly mode in this table. Also under 127 is the table 3a. As you say sounds like other things besides play note.

    I think I sort of tried what you describe to get a different instrument but will try again. Probably not exactly right.

    :)


    Thursday, June 15, 2017 12:20 PM