This project has moved. For the latest updates, please go here.

Naudio InnerException MIDI

Jun 16, 2011 at 3:44 PM

Hello, i have Exception problem when try rsend MIDI in background.
 
System.Runtime.InteropServices.SEHException was unhandled by user code
  Message=External component has thrown an exception.
  Source=NAudio
  ErrorCode=-2147467259
  StackTrace:
       at NAudio.Midi.MidiInterop.midiOutClose(IntPtr hMidiOut)
       at NAudio.Midi.MidiOut.Dispose(Boolean disposing)
       at NAudio.Midi.MidiOut.Dispose()
       at NAudio.Midi.MidiOut.Close()
       at window8.Slider1.RunInBackground(Object sender, DoWorkEventArgs e) in C:\Code\1.5.1\window8\Slider.xaml.cs:line 129
       at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
       at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
  InnerException:
 
        private void RunInBackground(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            int OldValue = endvalue;
            int OldMax = oldmaxim;
            int OldMin = 0;
            int NewMax = 127;
            int NewMin = 0;
            int OldRange = (OldMax - OldMin);
            int NewRange = (NewMax - NewMin);
            NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin;
            MidiOut midiOut = new MidiOut(MIDIPORT);
            midiOut.Send(MidiMessage.StartNote(0, NewValue, CH1).RawData);
            midiOut.Close();
            midiOut.Dispose();
            backgroundWorker.Dispose();

        }


I try handle exception doing this:


     private void RunInBackground(object sender, System.ComponentModel.DoWorkEventArgs e)
{
int OldValue = endvalue;
int OldMax = oldmaxim;
int OldMin = 0;
int NewMax = 127;
int NewMin = 0;
int OldRange = (OldMax - OldMin);
int NewRange = (NewMax - NewMin);
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin;

try
{
MidiOut midiOut = new MidiOut(MIDIPORT);
midiOut.Send(MidiMessage.StartNote(0, NewValue, CH1).RawData);
midiOut.Close(); midiOut.Dispose();
backgroundWorker.Dispose();
}
cacth
{
}

}

If i do that my appz freeze and now have error in output debug window?

A first chance exception of type 'NAudio.MmException' occurred in NAudio.dll


Please can check this problem?
I ned run naudio in background (another thread separate to  UI threads)  for make my appz more responsive.

 

Finally, one more question.
Is possible send MIDI CC instead of MIDI notes?
How?

 

Coordinator
Jun 16, 2011 at 3:51 PM

I'm not sure MidiOut likes to be closed so soon after calling send. I would try at the very least putting some delays in.

I also don't think you should call background worker.dispose

To send CC, create a ControlChangeEvent and then call GetAsShortMessage on it to get the message to pass to MidiOut.Send

Mark

Jun 16, 2011 at 4:19 PM
Edited Jun 16, 2011 at 4:27 PM

Thankyou for faster repply !!
Im tryintg to contact to you. for days  : ) your gmail account not work or not is used?


About backgroundWorker.Dispose(); yes, is anmistake when i copy paste, i nto call backgroundWorker.Dispose();
This is how i use:

private void RunInBackground(object sender, System.ComponentModel.DoWorkEventArgs e)
{
int OldValue = endvalue;
int OldMax = oldmaxim;
int OldMin = 0;
int NewMax = 127;
int NewMin = 0;
int OldRange = (OldMax - OldMin);
int NewRange = (NewMax - NewMin);
NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin;
MidiOut midiOut = new MidiOut(MIDIPORT);
midiOut.Send(MidiMessage.StartNote(0, NewValue, CH1).RawData);
midiOut.Close();
midiOut.Dispose();
}

You make a comment about delay, can explain delay what and where and how?
Anyqay i try to use Naudio for send midi en real time, add delays result in that delays on MIDI info sended, generating latency.
Can take a look on this for see if possible run in background?





ABout MIDI CC:
Plese can put complete examnple of how should send MIDI CC, really apreciate !!

This is for midi note:

MidiOut midiOut = new MidiOut(1);
midiOut.Send(MidiMessage.StartNote(0, 0, 1).RawData);
midiOut.Close();
midiOut.Dispose();


What is the equivalent for MIDI CC?
Can put example for send MIDI CC  1, VALUE 64 CHANEL 2
I not are the only one trying send MIDI CC, a short article on your blog really be usefull.

Thankyou so much for your help !

Coordinator
Jun 16, 2011 at 4:30 PM

NAudio is just a spare time project. I can't always answer support requests immediately.

You should just create one MidiOut object when your program starts. Then call Send whenever you need to send a MIDI event - don't keep opening and closing it all the time.

Here's how to send a CC:

int channel = 1;
var cc = new ControlChangeEvent(0, channel, MidiController.MainVolume, 80);
midiOut.Send(cc.GetAsShortMessage());

Jun 16, 2011 at 4:52 PM
Edited Jun 16, 2011 at 5:26 PM

Thankyou so much and sorry i no want abuse for your generosity helping.

"You should just create one MidiOut object when your program starts. Then call Send whenever you need to send a MIDI event - don't keep opening and closing it all the time"
Where can find a complete example about this you comment?
WHen dispose and clsoe midi? when clsoe the program?
Really apreciate if can show example about that, or where i can find one : )

 

 

 

 int MIDIPORT = 1;
 int CCNUMBER = 1;
 int CHANNEL  = 1;
 int VALUE    = 80;
 MidiOut midiOut = new MidiOut(MIDIPORT);
 var cc = new ControlChangeEvent(CCNUMBER, CHANEL, MidiController.MainVolume, VALUE);
 midiOut.Send(cc.GetAsShortMessage());
 midiOut.Dispose();

If im not wrong this should send:
PORT 1
CC NUMBER 1
CHANNEL 1
CC VALUE 80
This is correct?
ANyway this not work, i have message error when runt this.
Im trying on a simple button, no in backkground, the error is
at MIDout.Finalize()

Finally, for use your Naudio in a comercial project, how much have to pay for licence?

 

Coordinator
Jun 16, 2011 at 5:23 PM

Look at the NAudioDemo application in source control - the MIDI In demo has a checkbox at the bottom. If you check it it starts sending MIDI out messages on a timer.

In my example, the MIDI CC is MainVolume (whatever number that is, I can't remember at the moment)

The value is 80, and the channel is 1. (the first parameter, absoluteTime, is not relevant for what you are doing so you can ignore it).

NAudio is open source and no fees are required to use it in a commercial project.

Mark

Jun 16, 2011 at 6:17 PM
Edited Jun 16, 2011 at 6:35 PM

Mark i send in the middle of the next month a nice donation : )
You have my word i do that !!
Naudio is exactly what i need. (if can send MIDI CC  : )

I check the examples soon for see how work without close all time MIDI like you suggest.

Ok lest back to MIDI CC isue, i cant make this work,
MIDI CC come in range from 0 to 127 (controllers), i think you know this.
Bye example Mainvolume is MIDI CC  7

Here you can find  a complete list attached to the end of this post, i knwo you know this anyway i post due can be usefull for others.

What i need is send ANY MIDI CC NUMBER.

Example:

int MIDIPORT = 1;
int CCNUMBER = 7;  //Here any value i want choose here from 0 to 127
int CHANNEL  = 1;
int VALUE = 80;
MidiOut midiOut = new MidiOut(MIDIPORT);
var cc = new ControlChangeEvent(0, CHANEL, CCNUMBER, VALUE);
midiOut.Send(cc.GetAsShortMessage());
midiOut.Dispose();

Based on your comment ControlChangeEvent(0,   this first value is absolutetime,  i not use, i ignore and leave to 0.
I cant remplace MidiController by integer (any value form 0 to 127) Error 18 Argument 3: cannot convert from 'int' to 'NAudio.Midi.MidiController' 


Your example only can send limited number of MIDI CC DUE MidiControlle IS LIMITED ONLY TO THIS VALUES:

Modulation  is MIDI CC 1,
MainVolume  is MIDI CC 7,
Pan is MIDI CC 10,
Expression is MIDI CC 11,
Sustain is MIDI CC 64,
ResetAllControllers is MIDI CC 121,
AllNotesOff is MIDI CC 123,


My question is how send any MIDI CC number?
What i need send is:

MIDI CC NUMBER:  any value i select 0 to 127
MIDI CC VALUE: any value from 0 to 127
MIDI PORT
MIDI CHANNEL

Is possible do this?
Can paste a simple  complete example for do this?
Something like this, but working : )





int MIDIPORT = 1; 
int CCNUMBER = 7; //Here any value i want choose here from 0 to 127
int CHANNEL = 1;
int VALUE = 80;
MidiOut midiOut = new MidiOut(MIDIPORT);
var cc = new ControlChangeEvent(0, CHANEL, CCNUMBER, VALUE);
midiOut.Send(cc.GetAsShortMessage());
midiOut.Dispose();
Thankyou for your help !!!

 

 

 

MIDI CC:

00   0   Bank Select (coarse)                    0..127 
01   1   Modulation Wheel (coarse)               0..127
02   2   Breath Control (coarse)                 0..127
03   3   Continuous controller #3                0..127
04   4   Foot Controller (coarse)                0..127
05   5   Portamento Time (coarse)                0..127
06   6   Data Entry Slider (coarse)              0..127
07   7   Main Volume (coarse)                    0..127
08   8   Stereo Balance (coarse)                 0..127
09   9   Continuous controller #9                0..127
0A  10   Pan (coarse)                            0=left 64=center 127=right
0B  11   Expression (sub-Volume) (coarse)        0..127
0C  12   Effect Control 1 (coarse)               0..127
0D  13   Effect Control 2 (coarse)               0..127
0E  14   Continuous controller #14               0..127
0F  15   Continuous controller #15               0..127
10  16   General Purpose Slider 1                0..127
11  17   General Purpose Slider 2                0..127            
12  18   General Purpose Slider 3                0..127
13  19   General Purpose Slider 4                0..127
14  20   Continuous controller #20               0..127
15  21   Continuous controller #21               0..127
16  22   Continuous controller #22               0..127
17  23   Continuous controller #23               0..127
18  24   Continuous controller #24               0..127
19  25   Continuous controller #25               0..127
1A  26   Continuous controller #26               0..127
1B  27   Continuous controller #27               0..127
1C  28   Continuous controller #28               0..127
1D  29   Continuous controller #29               0..127
1E  30   Continuous controller #30               0..127
1F  31   Continuous controller #31               0..127
20  32   Bank Select (fine)                      0..127  usually ignored
21  33   Modulation Wheel (fine)                 0..127 
22  34   Breath Control (fine)                   0..127
23  35   Continuous controller #3 (fine)         0..127
24  36   Foot Controller (fine)                  0..127
25  37   Portamento Time (fine)                  0..127
26  38   Data Entry Slider (fine)                0..127
27  39   Main Volume (fine)                      0..127  usually ignored
28  40   Stereo Balance (fine)                   0..127
29  41   Continuous controller #9 (fine)         0..127 
2A  42   Pan (fine)                              0..127  usually ignored
2B  43   Expression (sub-Volume) (fine)          0..127  usually ignored
2C  44   Effect Control 1 (fine)                 0..127
2D  45   Effect Control 2 (fine)                 0..127
2E  46   Continuous controller #14 (fine)        0..127
2F  47   Continuous controller #15 (fine)        0..127 
30  48   Continuous controller #16               0..127
31  49   Continuous controller #17               0..127
32  50   Continuous controller #18               0..127
33  51   Continuous controller #19               0..127
34  52   Continuous controller #20 (fine)        0..127
35  53   Continuous controller #21 (fine)        0..127
36  54   Continuous controller #22 (fine)        0..127
37  55   Continuous controller #23 (fine)        0..127
38  56   Continuous controller #24 (fine)        0..127
39  57   Continuous controller #25 (fine)        0..127
3A  58   Continuous controller #26 (fine)        0..127
3B  59   Continuous controller #27 (fine)        0..127
3C  60   Continuous controller #28 (fine)        0..127
3D  61   Continuous controller #29 (fine)        0..127
3E  62   Continuous controller #30 (fine)        0..127
3F  63   Continuous controller #31 (fine)        0..127
40  64   Hold pedal (Sustain) on/off             0..63=off  64..127=on
41  65   Portamento on/off                       0..63=off  64..127=on
42  66   Sustenuto Pedal on/off                  0..63=off  64..127=on
43  67   Soft Pedal on/off                       0..63=off  64..127=on
44  68   Legato Pedal on/off                     0..63=off  64..127=on
45  69   Hold Pedal 2 on/off                     0..63=off  64..127=on
46  70   Sound Variation                         0..127
47  71   Sound Timbre                            0..127
48  72   Sound Release Time                      0..127
49  73   Sound Attack Time                       0..127
4A  74   Sound Brighness                         0..127
4B  75   Sound Control 6                         0..127
4C  76   Sound Control 7                         0..127
4D  77   Sound Control 8                         0..127
4E  78   Sound Control 9                         0..127
4F  79   Sound Control 10                        0..127
50  80   General Purpose Button                  0..63=off  64..127=on
51  81   General Purpose Button                  0..63=off  64..127=on
52  82   General Purpose Button                  0..63=off  64..127=on
53  83   General Purpose Button                  0..63=off  64..127=on
54  84   Undefined on/off                        0..63=off  64..127=on
55  85   Undefined on/off                        0..63=off  64..127=on
56  86   Undefined on/off                        0..63=off  64..127=on
57  87   Undefined on/off                        0..63=off  64..127=on
58  88   Undefined on/off                        0..63=off  64..127=on
59  89   Undefined on/off                        0..63=off  64..127=on
5A  90   Undefined on/off                        0..63=off  64..127=on
5B  91   Effects Level                           0..127
5C  92   Tremulo Level                           0..127
5D  93   Chorus Level                            0..127
5E  94   Celeste (Detune) Level                  0..127
5F  95   Phaser Level                            0..127
60  96   Data entry +1                           ignored
61  97   Data entry -1                           ignored
62  98   Non-Registered Parameter Number (coarse)0..127
63  99   Non-Registered Parameter Number (fine)  0..127
64 100   Registered Parameter Number (coarse)    0..127
65 101   Registered Parameter Number (fine)      0..127
66 102   Undefined                               ?
67 103   Undefined                               ?
68 104   Undefined                               ?
69 105   Undefined                               ?
6A 106   Undefined                               ?
6B 107   Undefined                               ?
6C 108   Undefined                               ?
6D 109   Undefined                               ?
6E 110   Undefined                               ?
6F 111   Undefined                               ?
70 112   Undefined                               ?
71 113   Undefined                               ?
72 114   Undefined                               ?
73 115   Undefined                               ?
74 116   Undefined                               ?
75 117   Undefined                               ?
76 118   Undefined                               ?
77 119   Undefined                               ?
78 120   All Sound Off                           ignored
79 121   All Controllers Off                     ignored
7A 122   Local Keyboard On/Off                   0..63=off  64..127=on
7B 123   All Notes Off                           ignored
7C 124   Omni Mode Off                           ignored
7D 125   Omni Mode On                            ignored
7E 126   Monophonic Mode On                      **
7F 127   Polyphonic Mode On (mono=off)           ignored

Coordinator
Jun 16, 2011 at 7:35 PM

the predefined values are only there as helpers. You can pass in any number and just cast it to MidiController. For example:

int channel = 1;
int cc = 53;
var cc = new ControlChangeEvent(0, channel, (MidiController)cc, 80);
midiOut.Send(cc.GetAsShortMessage());
Jun 16, 2011 at 8:29 PM
Edited Jun 16, 2011 at 8:32 PM

I imagine your example have amistake,

int cc
and then
var cc


I corrected and here i show in a example what i need.
I create a simple button, when press run this. 

            int MIDIDEVICE = 1;
            int CHANNEL = 1;            
            int CCNUMBER = 10;
int CCVALUE = 80; MidiOut midiOut = new MidiOut(1); var cc = new ControlChangeEvent(0, CHANNEL, (MidiController)CCNUMBER, CCVALUE); midiOut.Send(cc.GetAsShortMessage()); midiOut.Dispose();

 

This should send  MIDI  to MIDI device 1
CCnumber should be 10, and cc value should ne 80, on channel 1. Using MIDI-OX monitor tool (http://www.midiox.com/) i check wat really send, this is what i have:




Using MIDI-OX monitor tool (http://www.midiox.com/) i check wat really send, this is what i have:



 TIMESTAMP IN PORT STATUS DATA1 DATA2 CHAN NOTE EVENT              
             
 000116FB   1  --     B0    00    00    1  ---  CC: Bank MSB         
 0001170C   1  --     B0    00    00    1  ---  CC: Bank MSB         
 0001171B   1  --     B0    00    00    1  ---  CC: Bank MSB         
 0001172C   1  --     B0    00    00    1  ---  CC: Bank MSB         
 00011731   1  --     B0    00    00    1  ---  CC: Bank MSB         
 00011735   1  --     B0    00    00    1  ---  CC: Bank MSB         
 00011757   1  --     B0    00    00    1  ---  CC: Bank MSB         
 0001175A   1  --     B0    00    00    1  ---  CC: Bank MSB         
 00011778   1  --     B0    00    00    1  ---  CC: Bank MSB         
 0001177B   1  --     B0    00    00    1  ---  CC: Bank MSB         
 0001179A   1  --     B0    00    00    1  ---  CC: Bank MSB         
 000117A1   1  --     B0    00    00    1  ---  CC: Bank MSB         
 000117DD   1  --     B0    00    00    1  ---  CC: Bank MSB    




 

Every line represnt midi data sended every time i press button.Kind of data sended is MIDI CC and that is correct, 
chanel is 1 that is correct, but CCNUMBER is 0 , when should be 10 and CCVALUE is 0 whne should be 80  
What im doing wrong? why not work?   


 

Coordinator
Jun 16, 2011 at 8:53 PM

Hmm, looks like you are the first person to use NAudio to send a CC. There's a bug.

In ControlChangeEvent.cs, it was not including the controller number, just the value. I think it should be something like this:

        /// <summary>
        /// <see cref="MidiEvent.GetAsShortMessage" />
        /// </summary>
        public override int GetAsShortMessage()
        {
            byte c = (byte)controller;
            return base.GetAsShortMessage() + (c << 8) + (controllerValue << 16);
        }

Are you able to test with that change yourself? We can look at the message we are going to send out using hex

Debug.WriteLine(String.Format("{0:X8}",cc.GetAsShortMessage());

Let me know if that works and I can check in the fix

Mark

Jun 16, 2011 at 9:07 PM
Edited Jun 16, 2011 at 9:09 PM



Yahoo !! finally here the reason why i never can make work MIDI CC with NAUDIO !!  : )
I know multiple guys arround the world want use MIDI CC with naudio but all they fail, probably nobody report this beforfe me.
I really like test mysefl the fix, but no idea how and compile the dll again etc etc,
Im not lazy, but i are relative new to, .net, C#, and Visual Studio, all this is a relative new thing for me.

Where i should insert this?
Debug.WriteLine(String.Format("{0:X8}",cc.GetAsShortMessage());

Guide to me please, thinking in 2 things, i are newbie coder to .net, and my native language no is english jijij 

Also this bug affect MIDI OUT only or for reciv MIDI CC info this bug affect too?

My antive language, no is english, aditional to this problem, i think Naudio cant work in multiple theread, the background worker problem originally reported in this large post : )

Im preparing a complete example code for you.
That ilustrate in better way the problem and you cna confirm if is a bug, better than use my words jijijii
Thankyou so much again for your support! 

Coordinator
Jun 16, 2011 at 9:23 PM

Hi,

the NAudio support for MidiIn and MidiOut is very limited. Almost all the MIDI code I wrote was for MIDI File Mapper (http://midifilemapper.codeplex.com/), which focuses on reading and writing MIDI files.

If you don't want to recompile NAudio, then just copy this whole class into your project:

    /// <summary>
    /// Represents a MIDI control change event
    /// </summary>
    public class ControlChangeEvent : MidiEvent
    {
        private MidiController controller;
        private byte controllerValue;

        /// <summary>
        /// Reads a control change event from a MIDI stream
        /// </summary>
        /// <param name="br">Binary reader on the MIDI stream</param>
        public ControlChangeEvent(BinaryReader br)
        {
            byte c = br.ReadByte();
            controllerValue = br.ReadByte();
            if((c & 0x80) != 0)
            {
                // TODO: might be a follow-on
                throw new ApplicationException("Invalid controller");
            }
            controller = (MidiController) c;
            if((controllerValue & 0x80) != 0)
            {
                throw new ApplicationException(String.Format("Invalid controllerValue {0} for controller {1}, Pos 0x{2:X}",controllerValue,controller,br.BaseStream.Position));
            }
        }

        /// <summary>
        /// Creates a control change event
        /// </summary>
        /// <param name="absoluteTime">Time</param>
        /// <param name="channel">MIDI Channel Number</param>
        /// <param name="controller">The MIDI Controller</param>
        /// <param name="controllerValue">Controller value</param>
        public ControlChangeEvent(long absoluteTime, int channel, MidiController controller, int controllerValue)
            : base(absoluteTime,channel,MidiCommandCode.ControlChange)
        {
            this.Controller = controller;
            this.ControllerValue = controllerValue;
        }
       
        /// <summary>
        /// Describes this control change event
        /// </summary>
        /// <returns>A string describing this event</returns>
        public override string ToString()
        {
            return String.Format("{0} Controller {1} Value {2}",
                base.ToString(),
                this.controller,
                this.controllerValue);
        }

        /// <summary>
        /// <see cref="MidiEvent.GetAsShortMessage" />
        /// </summary>
        public override int GetAsShortMessage()
        {
            byte c = (byte)controller;
            return base.GetAsShortMessage() + (c << 8) + (controllerValue << 16);
        }

        /// <summary>
        /// Calls base class export first, then exports the data
        /// specific to this event
        /// <seealso cref="MidiEvent.Export">MidiEvent.Export</seealso>
        /// </summary>
        public override void Export(ref long absoluteTime, BinaryWriter writer)
        {
            base.Export(ref absoluteTime, writer);
            writer.Write((byte)controller);
            writer.Write((byte)controllerValue);
        }

        /// <summary>
        /// The controller number
        /// </summary>
        public MidiController Controller
        {
            get
            {
                return controller;
            }
            set
            {
                if ((int) value < 0 || (int) value > 127)
                {
                    throw new ArgumentOutOfRangeException("Controller number must be in the range 0-127");
                }
                controller = value;
            }
        }

        /// <summary>
        /// The controller value
        /// </summary>
        public int ControllerValue
        {
            get
            {
                return controllerValue;
            }
            set
            {
                if (value < 0 || value > 127)
                {
                    throw new ArgumentOutOfRangeException("Controller Value must be in the range 0-127");
                }
                controllerValue = (byte) value;
            }
        }
    }

The bug won't affect receiving MIDI as GetShortMessage is never called when receiving MIDI.

There should be no problem working on a background thread. You just need to hold the MIDI out device open,

Mark

Jun 16, 2011 at 9:49 PM
Edited Jun 16, 2011 at 11:47 PM

Yes i send confirmation!
This is now fixed!

When we see the fix on the RC2 version?
I really like no have to insert this class in every parts of my project : )

About Background worker i open a new discusion for not make this ultra large !!

Thankyou for your support.

Jun 19, 2011 at 11:23 PM

Hello Mark.
Please can recompile and upload to some place.
Im trying to compile but have bisual studio express, and lot of errors due version of visual studio i use, etc etc.
I really apreciate this.

Best regards!

Jun 21, 2011 at 10:44 PM

Sorry for insist, i know Mark is very bussy and this project is part time.
I cnat compile the last source code available,
Please can somebody compile and upload in some place.
Really apreciated.
Best regards !

Jul 1, 2011 at 7:13 AM

Hello Mark.
Please can recompile and upload to some place.
Im trying to compile but have bisual studio express, and lot of errors due version of visual studio i use, etc etc.
I really apreciate this.

Best regards!