USB MIDI Interface

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
horo
Rank 2
Rank 2
Posts: 63
Joined: Tue Mar 04, 2008 2:26 pm
Location: Berlin & Lindau, Germany

Re: USB MIDI Interface

Post by horo » Sat May 30, 2009 11:38 am

Hi muntablues,

how do you send data to the device?
I connected it as an midi out and sent midi notes from my vkeybd (virtual midi keyboard application). I also connected the output from V-USB-MIDI to its input and got the leds blinking at the turn op the pots. I tested at my linux box, running jack and qjackctl as a midi patchfield.
I have actually no access to my hardware - but I'll check it again next week.

So long - ciao
Martin

muntablues
Posts: 4
Joined: Tue Mar 03, 2009 1:42 pm

Re: USB MIDI Interface

Post by muntablues » Sat May 30, 2009 8:07 pm

Hi Martin

I have tested the whole thing with this http://www.codeproject.com/KB/audio-video/MIDIToolkit.aspx

The testsoftware sends some notes to the defined midi device. I can also send a whole midi file to the device but there is no reaction on my testboard.

If you could test it again it would be great.

TU ans best wishes

MB

horo
Rank 2
Rank 2
Posts: 63
Joined: Tue Mar 04, 2008 2:26 pm
Location: Berlin & Lindau, Germany

Re: USB MIDI Interface

Post by horo » Mon Jun 22, 2009 4:13 pm

Hi muntablues,

back at my hardware I've checked again, at receive of midi signals from pc my test led at PORT C.5 toggles (in usbFunctionWriteOut). I'm running this test on a debian linux with kernel 2.6.29.4-rt16.

Ciao Martin

Hnns

Re: USB MIDI Interface

Post by Hnns » Mon Jun 22, 2009 6:54 pm

Hi,

i build a midi foot controller based on the v-midi schematics and Driver, with an atmega8 at 16mhz and 5v.
Its appearance as a usb deivice is unstable. It appears not everytime if connect it, an if its connected it only stays connected as long as i push some buttons/generate miditraffic, if i stop making usbmidi data longer than about 5 secs its down. As long as it works, it is transferring correct midi values.
The osx usb prober doesnt report any errors.
Sometimes it does appear as a "composite device" in the os x system with unknown name.

does anyone experienced simillar problems?

Thanks

Hannes

eclipso_1
Posts: 6
Joined: Fri May 01, 2009 10:06 pm

Re: USB MIDI Interface

Post by eclipso_1 » Tue Jun 30, 2009 1:56 am

Hannes,

If your running at 5 volt you need to use 3.6v zener diodes on the signal lines.
Read the docs for the v-usb driver by Christian. He has example circuits.

Laters, Dave

EDIT:

http://vusb.wikidot.com/hardware

Solution B works for me at 5v for the higher clock rates.

12Mhz with the voltage drop diodes per Horo should be plenty for a midi control
device as you described. Anyhow, please try the the zeners and report back since
your the first OSX poster.

midiman
Posts: 1
Joined: Fri Jul 03, 2009 4:24 am

Re: USB MIDI Interface

Post by midiman » Fri Jul 03, 2009 4:32 am

hi all

does anyone know how to change the name of interface
from USB Audio Device to other name?

now I can change only Device name that show when first connect only.

but when I use in other MIDI program, it show "USB Audio Device"


thank you

hnns
Posts: 1
Joined: Mon Jun 22, 2009 9:03 pm

Re: USB MIDI Interface

Post by hnns » Sun Jul 05, 2009 5:33 pm

Hi Dave,

I didnt mention it in my post but iused the zeners already for a level conversion.
The problem was a little piece of solder, wich caused a short line from d- to GND.
s**t. that happens.
so now it works fine in OS X as a midi input device!
The circuit and code design is based on Horos V-usb-midi. He has done a really great job!

But i have a new challenge: i tried to use the Timer0 for time measuring purposes but that disturbed somehow its recognition as a usb device.
Is this possible?

Hannes

eclipso_1
Posts: 6
Joined: Fri May 01, 2009 10:06 pm

Re: USB MIDI Interface

Post by eclipso_1 » Fri Jul 10, 2009 7:45 am

Hi Hannes,

Thanks for the update. That means this project works on all major operating systems! :D
On your other issue...
Perhaps there is a conflict with v-usb's interrupt? I do know timing is critical in v-usb.

Hi midiman,

I'm assuming that you're using Windows (XP?). That is the generic name that windows gives this
composite device. I can't say for sure but I think you need to make an .inf file to change the name
that shows up in the device manager. The AVR-CDC project (also uses v-usb) has .inf files that
you could use as an example/template. I hope this steers you in the right direction.

Laters Dave

eclipso_1
Posts: 6
Joined: Fri May 01, 2009 10:06 pm

Re: USB MIDI Interface

Post by eclipso_1 » Fri Aug 21, 2009 8:20 pm

Bump

If you had one of those cheap drum sets from those rock/hero games couldn't you hook up the piezos in the drums to the ADC pins on the AVR? How would you go about this? Do the piezos act as a voltage output like a mic or could you use them as a variable resistor? Sorry for all the questions. Just trying to provoke thought here. Theoretically you should be able to collect note/drum and velocity data and send it up the usb to your application. :?

Dave

K-Duke
Posts: 7
Joined: Wed Sep 23, 2009 9:28 pm

Re: USB MIDI Interface

Post by K-Duke » Wed Sep 23, 2009 10:18 pm

Hello people,

I discovered V-USB two weeks ago and it's just great! Well, enough for the praise... let me get to the point.
Based on your great work, I tried to get AVR-MIDI running for e-drums. I got the piezo well set up between some rubber foam between two wood plates and using the V-USB I confirmed the signal being correctly recognized by the AVR.

So going on to convert the ADC-measurements to midi messages I got stuck.
Most probably it's because how I forge the midiMsg. As well I would like to ask you what the heck this static uchar sendEmptyFrame is used for? Using a "find in files"-tool i searched for it's occurences though I only found it's definition and some assignments though no read access onto it. So why is it actually in the code?

To get back to my problem... I will be so naughty to directly post my code for lookup in my first post here on the forum.

I use an Atmega8 at 16Mhz. Of course I adjusted the DDRX and the pin-config as well as the khz-config in usbconfig.h accordingly.
I added additional comments to the code to increase the probability you can understand my %/§&%" code.

Code: Select all

int main(void)
{
    uchar midiMsg[8];
    uchar msgByteCounter = 0;
    uchar adcBuffer[6] = { 0, 0, 0, 0, 0, 0 };
   uchar channel = 0;
   uchar whichDrum = 0;
   uchar velocity = 0;
   uchar lastDrum = 0;

   wdt_enable(WDTO_1S);
   hardwareInit();
   odDebugInit();
   usbInit();

   sendEmptyFrame = 0;

   sei();

   for (;;) {      /* main event loop */
      wdt_reset();
      usbPoll();

        msgByteCounter = 0;
        sendEmptyFrame = 0;
        if(usbInterruptIsReady())
        { /** OK! We need to send the message! */

          if(whichDrum > 0) /** We really got a hit! */
          {
            midiMsg[msgByteCounter++] = 0x09; /** 0x09 High nybble is the cable number (we only have one) the second is the event code -> 9 = NOTE-ON */
            midiMsg[msgByteCounter++] = 0x90; /** 0x9 = NOTE-ON, 0x0 = Channel 0 */
            midiMsg[msgByteCounter++] = 48 + whichDrum; /** which note to send */
            midiMsg[msgByteCounter++] = velocity; /** and how hard */
            midiMsg[msgByteCounter++] = 0; /** padding zeros to get a complete package */
            midiMsg[msgByteCounter++] = 0;
            midiMsg[msgByteCounter++] = 0;
            midiMsg[msgByteCounter++] = 0;

            sendEmptyFrame = 1;
            usbSetInterrupt(midiMsg, msgByteCounter);
            /** activate the pull-up on the specified channel so the potential is higher than the buffer condensator. Otherwise the C would get deloaded.
                  Though as this pin is decoupled by a diode it won't load the C either.*/
            PORTB |= (1 << whichDrum);
            lastDrum = whichDrum; /** So we can turn off the note next time */
            whichDrum = 0;
          }
          else
          {
              if( lastDrum > 0)
              {
                midiMsg[msgByteCounter++] = 0x08; /** 0x08 High nybble is the cable number (we only have one) the second is the event code -> 8 = NOTE-OFF */
                midiMsg[msgByteCounter++] = 0x80; /** 0x8 = NOTE-OFF, 0x0 = Channel 0 */
                midiMsg[msgByteCounter++] = 48 + whichDrum; /** which note to send */
                midiMsg[msgByteCounter++] = velocity; /** and how hard */
                midiMsg[msgByteCounter++] = 0; /** padding zeros to get a complete package */
                midiMsg[msgByteCounter++] = 0;
                midiMsg[msgByteCounter++] = 0;
                midiMsg[msgByteCounter++] = 0;

                sendEmptyFrame = 1;
                usbSetInterrupt(midiMsg, msgByteCounter);
                lastDrum = 0;
              }
          }
        }
        else /** Allright! USB isn't ready yet! We can do other things */
        {
            /** adcPreBuffer is used for temporarily storing the ADC-results. I modified the function to directy return an uchar value */
            uchar adcPreBuffer = adc( channel); /** channel currently is only 0 for first channel */

            if( adcPreBuffer > 5) /** The value has to be greater than five to filter out noise */
            {
                if( adcPreBuffer > adcBuffer[ channel])   /** If the voltage on the channel increased compared to the last time... */
                    adcBuffer[channel] = adcPreBuffer;  /**...  save the new value */

                /** I call it a hit if the voltage decreased compared to the last time. I as well check if a drum-hit is to be  send, as while
                     this value is != 0 the piezo trigger is grounded and therefore the adc will only read 0 */
                else if( adcPreBuffer <= adcBuffer[channel] && whichDrum == 0) 
                {
                    /** Alright we recognized a hit! First off pull the appropriate channel resetter to low */
                    PORTB &= ~(1 << channel); /** This unloads the buffer ceramic condensator at the piezo trigger */
                    /** OK. Now saving which drum */
                    whichDrum = channel + 1; /** saving which not to send based on the adc-channel */
                    /** How hard has it been hit? */
                    velocity = adcBuffer[channel]; /** practically the adc-value equals the velocity */
                    /** Last but not least reset the buffer */
                    adcBuffer[channel] = 0x00; /** we don't want to get a false hit recognition! */
                }
            }

            /** increase channel counter (or reset to first channel if on last one) */
            /* currently testing. Only drum 1 (channel = 0) connected! Therfore no change is done to the varible channel */
            if( channel < 5)
                channel++;
            else
                channel = 0;
            */
        }
   }
   return 0;
}


@ eclipso (and any other interested)
You can't put it directly onto the AVR. You have to condition the piezo's signal so the avr can handle it.
Here is a nice link for it http://leucos.lstilde.org/wp/2009/06/piezo-transducer-signal-conditioning/.

Additionally I used another (german) resource. As the site really is not up to date (last update was almost 5 years ago) I will link to it as well as putting a translation here because I really don't feel like waiting for a reply of the maintainer when asking beforehand. First of the link http://ispf.de/modules.php?name=News&file=article&sid=6&page=1 (first of go there as you will need the image there as reference)

Here comes the translation. The translations starts on "Die beim Anschlag [...]" in the original.

Guido Naruhn (http://www.ispf.de) wrote:[...] The signal created by hitting the piezo gets over R1 and D1 to the buffer, consisting of C1 and R2. With R1 <A/N: which is a potentiometer> you can regulate the sensitivity of the single pad. C1 holds the voltage pretty long and gets deloaded after a succesfull measurement by pulling the appropriate pin to low.

<A/N: Here would be the circuit for a single piezo connection. Though I don't want to directly link the image so get to see it in the provided link above>

The software reads the appropriate channels endlessly and compares the value to the ones made before. If the value is greater than the old one it gets bufferd as new value. As soon as the value drops below the current maximum a note is recognized as played [...]

horo
Rank 2
Rank 2
Posts: 63
Joined: Tue Mar 04, 2008 2:26 pm
Location: Berlin & Lindau, Germany

Re: USB MIDI Interface

Post by horo » Thu Sep 24, 2009 2:51 pm

Hi K-Duke,

welcome, nice that you build a drum device, good link to the hardware interfacing. I know it's frustrating if a new project doesn't work as expected. Don't worry. Well, let me try to bring some light into the darkness ;)

1. The suspicious "sendEmptyFrame" originates from the AVR-CDC project and I copied it stupidly into my project. You don't need it!
V-USB sends longer messages chopped into 8-bytes-packages. The end of message is indicated by a package shorter than 8 bytes. If you have a message len that's a multiple of 8 you need an additional empty package as an end marker.
But USB MIDI messages contain either 4 or 8 bytes, so there's no need for an end marker. (CHRISTIAN, IS THIS TRUE???)

2. If you send a 4 byte package you'll need no end marker - for sure:

Code: Select all

...         
  midiMsg[0] = 0x09; /** 0x09 High nybble is the cable number (we only have one) the second is the event code -> 9 = NOTE-ON */
  midiMsg[1] = 0x90; /** 0x9 = NOTE-ON, 0x0 = Channel 0 */
  midiMsg[2] = 48 + whichDrum; /** which note to send */
  midiMsg[3] = velocity; /** and how hard */
  usbSetInterrupt(midiMsg, 4);
...
 


I studied your code and have three questions/remarks.

1. The part "(if whichDrum > 0)..." sends a NOTE-ON event, remembers lastDrum=whichDrum and sets whichDrum=0. Next time you loop around you'll execute the "(if lastDrum > 0)..." part, but you send a NOTE-OFF event for whichDrum (which is 0).

2. Velocity must be in the range 0..127.

3. You send NOTE-OFF with velocity, dunno if this affects the release time.

Perhaps you can describe your problem a bit more exactly - no signal, wrong signal, only one event? Is your circuit recognized by your computer?

Ciao Martin

EDIT: typo
Last edited by horo on Thu Nov 26, 2009 7:27 pm, edited 1 time in total.

K-Duke
Posts: 7
Joined: Wed Sep 23, 2009 9:28 pm

Re: USB MIDI Interface

Post by K-Duke » Thu Sep 24, 2009 5:32 pm

Doh... if a simple package with less than 8 bytes is the stop signal... well this explains a lot!

1. Doh! Curse copy&paste!
2. Don't worry. The adc()-functions already returns a value in this range.
3. See 1. This is not interpreted as velocity but rather as another note for the NOTE-OFF event.

Well to your questions... the circuit is properly detected, enumerated and installed (with generic drivers) on windows.

Although I fixed the (actually obvious) issues you mentioned the problem is still that I don't get no signals at all but for those sending the device class descriptor and the other stuff done in init. Well I do get the interrupt on both data lines though when looking into them with an audioscope (soundcard <mis>used as oszilloscope).

Should I put up some images of the signals?

Last but not least. Thank you very much for your freetime you are sacrificing for helping a stranger :D .

K-Duke
Posts: 7
Joined: Wed Sep 23, 2009 9:28 pm

Re: USB MIDI Interface

Post by K-Duke » Sat Sep 26, 2009 1:31 pm

Hi pankajnagarkoti,

well actually you could boost up the speed a little bit. like transfering up to about 125 commands every 2 ms. Although you still have a "big" delay of 2 ms. you don't have to wait 4 ms for 2 commands. you can pack it into into the first package. Hope that gets clear.

Here the mathemathically background.
MIDI --> 31250 baud rate --> divided by 8 --> about 4 kilobytes per second.
V-USB --> 500 polls per second à 255 bytes -> 127500 baud rate -> divided by 8 --> about 16 kilobytes per second. (notice!: V-USB-MIDI uses descriptors for sending data! Thats a maximum of 8 Bytes per 2ms)

You just gotta make sure the microcontroller fetches all events in the 2ms timeframe and sends them all by usb.
Theorethically you can speed it up even more if you get V-USB to run at a 1ms polling interval (which I couldn't).

solata10
Posts: 13
Joined: Sun Dec 13, 2009 3:09 pm

Re: USB MIDI Interface

Post by solata10 » Tue Dec 22, 2009 3:59 pm

hello.

i also created a drumset based on your code, and it works ok, however i would like to be able to set few paramaters from computer,
like limit at which the note-on gets sent, smoothing level, boost for each drum, note for each drum.

does anybody know, what would be the best way to do it ? i want it to be possible without a driver,
so i'm not sure, can i send things to device of this class ? can i make a composite device (midi & hid) ?

any help would be apreciated.

psc
Rank 1
Rank 1
Posts: 32
Joined: Sat Nov 15, 2008 9:51 pm

Re: USB MIDI Interface

Post by psc » Tue Dec 22, 2009 5:57 pm

solata10,

V-USB-MIDI can send but also receive midi:

Code: Select all

void usbFunctionWriteOut(uchar * data, uchar len) {
     //if(data[0] == 11 && data[3] == 99 && data[2] == 1) {...
}

i would recommend to use MIDI Non-Registered Parameters:
http://www.philrees.co.uk/nrpnq.htm

don't forget to:
#define USB_CFG_IMPLEMENT_FN_WRITEOUT 1
in usbconfig.h

have fun

Post Reply