Go Down

Topic: Code share: some of my util classes (Read 5664 times) previous topic - next topic

obiwanjacobi

#15
Mar 06, 2012, 08:57 pm Last Edit: Mar 06, 2012, 09:00 pm by obiwanjacobi Reason: 1
Attached is a 'port' of the MIDI library 3.2 by Francois Best where I've split up the Midi class into a MidiInPort and a MidiOutPort. I haven't included the midi thru functionality but the rest is as much copy-paste as possible.

The MidiOutPort takes a Stream in the constructor thus allowing a much broader range of output devices (not tied to Hardware Serial anymore). The MidiInPort still uses the USE_SERIAL_PORT macro (because there is no virtual serial device base class I couldn't get rid of the call to Serial.begin(MIDI_BAUDRATE)).

Now I can receive midi on the hardware serial and send midi on the software serial and to multiple outputs.

Here is an example:

Code: [Select]

#include <SoftwareSerial.h>

#include "MidiInPort.h"
#include "MidiOutPort.h"

SoftwareSerial softSerial(2, 4);
MidiInPort midiIn;
MidiOutPort midiOut(&softSerial);

void OnNoteOn(byte channel, byte note, byte velocity)
{
if(velocity == 0)
{
// note off
midiOut.sendNoteOn(channel, note, 0);
}
else
{
velocity = map(velocity, 1, 127, 60, 127);
midiOut.sendNoteOn(note, velocity, channel);
}
}

void OnNoteOff(byte channel, byte note, byte velocity)
{
midiOut.sendNoteOff(note, velocity, channel);
}

void setup()
{
midiIn.setHandleNoteOn(OnNoteOn);
midiIn.setHandleNoteOff(OnNoteOff);

midiIn.begin(MIDI_CHANNEL_OMNI);

softSerial.begin(MIDI_BAUDRATE);
}

void loop()
{
midiIn.read();
}


PS: I could not find any license for the Midi library so I hope this is ok. If not, please delete this posting.

robtillaart


seems you are very productive !

I once had the idea to make a "midi -> arduino -> switch my keyboard light" sketch, with this lib it becomes easy.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

obiwanjacobi

#17
Mar 07, 2012, 09:12 am Last Edit: Mar 07, 2012, 04:08 pm by obiwanjacobi Reason: 1


seems you are very productive !

I once had the idea to make a "midi -> arduino -> switch my keyboard light" sketch, with this lib it becomes easy.


Thanx! And I haven't even shown you all the code. It seems I am slowly building up a new template library ...  XD

Not entirely sure what you mean by 'switch my keyboard light' but I've found that even if you use the standard MIDI library on Hardware serial and only use the input, you're still able to output text to the COM port on the PC calling the normal Serial.Xxxx methods.

So go for it! ;-)

maniacbug


I dont get why an empty program -with just an empty setup and loop method- is still 466 bytes long!?

:smiley-eek:


Here's the linker map of an empty program.  Much of it are the interrupt vectors.  Also, even an empty program still calls main() and init() which set a few things up, and so those are always linked.

Code: [Select]

.text           0x0000000000000000      0x1bc
*(.vectors)
.vectors       0x0000000000000000       0x68 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/../../../../avr/lib/avr5/crtm328p.o
                0x0000000000000000                __vectors
                0x0000000000000000                __vector_default
*(.vectors)
*(.progmem.gcc*)
*(.progmem*)
                0x0000000000000068                . = ALIGN (0x2)
                0x0000000000000068                __trampolines_start = .
*(.trampolines)
.trampolines   0x0000000000000068        0x0 linker stubs
*(.trampolines*)
                0x0000000000000068                __trampolines_end = .
*(.jumptables)
*(.jumptables*)
*(.lowtext)
*(.lowtext*)
                0x0000000000000068                __ctors_start = .
*(.ctors)
                0x0000000000000068                __ctors_end = .
                0x0000000000000068                __dtors_start = .
*(.dtors)
                0x0000000000000068                __dtors_end = .
SORT(*)(.ctors)
SORT(*)(.dtors)
*(.init0)
.init0         0x0000000000000068        0x0 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/../../../../avr/lib/avr5/crtm328p.o
                0x0000000000000068                __init
*(.init0)
*(.init1)
*(.init1)
*(.init2)
.init2         0x0000000000000068        0xc /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/../../../../avr/lib/avr5/crtm328p.o
*(.init2)
*(.init3)
*(.init3)
*(.init4)
.init4         0x0000000000000074       0x10 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/avr5/libgcc.a(_clear_bss.o)
                0x0000000000000074                __do_clear_bss
*(.init4)
*(.init5)
*(.init5)
*(.init6)
*(.init6)
*(.init7)
*(.init7)
*(.init8)
*(.init8)
*(.init9)
.init9         0x0000000000000084        0x8 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/../../../../avr/lib/avr5/crtm328p.o
*(.init9)
*(.text)
.text          0x000000000000008c        0x4 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/../../../../avr/lib/avr5/crtm328p.o
                0x000000000000008c                __vector_22
                0x000000000000008c                __vector_1
                0x000000000000008c                __vector_24
                0x000000000000008c                __vector_12
                0x000000000000008c                __bad_interrupt
                0x000000000000008c                __vector_6
                0x000000000000008c                __vector_3
                0x000000000000008c                __vector_23
                0x000000000000008c                __vector_25
                0x000000000000008c                __vector_11
                0x000000000000008c                __vector_13
                0x000000000000008c                __vector_17
                0x000000000000008c                __vector_19
                0x000000000000008c                __vector_7
                0x000000000000008c                __vector_5
                0x000000000000008c                __vector_4
                0x000000000000008c                __vector_9
                0x000000000000008c                __vector_2
                0x000000000000008c                __vector_21
                0x000000000000008c                __vector_15
                0x000000000000008c                __vector_8
                0x000000000000008c                __vector_14
                0x000000000000008c                __vector_10
                0x000000000000008c                __vector_18
                0x000000000000008c                __vector_20
                0x0000000000000090                . = ALIGN (0x2)
*(.text.*)
.text.setup    0x0000000000000090        0x2 16000000/simple.o
                0x0000000000000090                setup
.text.loop     0x0000000000000092        0x2 16000000/simple.o
                0x0000000000000092                loop
.text.startup.main
                0x0000000000000094       0x1a 16000000/core.a(main.o)
                0x0000000000000094                main
.text.__vector_16
                0x00000000000000ae       0x94 16000000/core.a(wiring.o)
                0x00000000000000ae                __vector_16
.text.init     0x0000000000000142       0x76 16000000/core.a(wiring.o)
                0x0000000000000142                init
                0x00000000000001b8                . = ALIGN (0x2)
*(.fini9)
.fini9         0x00000000000001b8        0x0 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/avr5/libgcc.a(_exit.o)
                0x00000000000001b8                exit
                0x00000000000001b8                _exit
*(.fini9)
*(.fini8)
*(.fini8)
*(.fini7)
*(.fini7)
*(.fini6)
*(.fini6)
*(.fini5)
*(.fini5)
*(.fini4)
*(.fini4)
*(.fini3)
*(.fini3)
*(.fini2)
*(.fini2)
*(.fini1)
*(.fini1)
*(.fini0)
.fini0         0x00000000000001b8        0x4 /home/maniacbug/bin/avr/lib/gcc/avr/4.7.0/avr5/libgcc.a(_exit.o)
*(.fini0)
                0x00000000000001bc                _etext = .

.data           0x0000000000800100        0x0 load address 0x00000000000001bc
                0x0000000000800100                PROVIDE (__data_start, .)
*(.data)
*(.data*)
*(.rodata)
*(.rodata*)
*(.gnu.linkonce.d*)
                0x0000000000800100                . = ALIGN (0x2)
                0x0000000000800100                _edata = .
                0x0000000000800100                PROVIDE (__data_end, .)

.bss            0x0000000000800060        0x9
                0x0000000000800060                PROVIDE (__bss_start, .)
*(.bss)
*(.bss*)
.bss.timer0_millis
                0x0000000000800060        0x4 16000000/core.a(wiring.o)
                0x0000000000800060                timer0_millis
.bss.timer0_overflow_count
                0x0000000000800064        0x4 16000000/core.a(wiring.o)
                0x0000000000800064                timer0_overflow_count
.bss.timer0_fract
                0x0000000000800068        0x1 16000000/core.a(wiring.o)
*(COMMON)
                0x0000000000800069                PROVIDE (__bss_end, .)
                0x00000000000001bc                __data_load_start = LOADADDR (.data)
                0x00000000000001bc                __data_load_end = (__data_load_start + SIZEOF (.data))

.noinit         0x0000000000800069        0x0
                0x0000000000800069                PROVIDE (__noinit_start, .)
*(.noinit*)
                0x0000000000800069                PROVIDE (__noinit_end, .)
                0x0000000000800069                _end = .
                0x0000000000800069                PROVIDE (__heap_start, .)

rbtying


[...]
(because there is no virtual serial device base class I couldn't get rid of the call to Serial.begin(MIDI_BAUDRATE)).
[...]


You can use the magic of OOP and have an overloaded constructor which takes a HardwareSerial*, so that the usage could be either this:

Code: [Select]

MidiOutPort midiOut(&softSerial);


or this:

Code: [Select]

MidiOutPort midiOut(&Serial);


completely transparent to the user. In the library implementation, the easiest way to do this is to encapsulate the write() function, forex:

Code: [Select]

void write(uint8_t b) {
  if (m_hws != NULL) { // set to null in the softwareserial constructor
    m_hws->write(b);
  } else { // not using hardware serial
    m_ss->write(b);
  }
}

obiwanjacobi

The actual call that is the problem is the call to Serial.begin(). That call is not on Stream. All write etc calls are all declared on the Stream class, from which Hardware and Software Serial both derive. If there would be a Serial base class (also derived from stream) that would have a virtual begin - and both Hardware and Software serial would implement that - you could run a MidiInPort on a Software Serial also...

Also, I dont want to maintain a load of pointers from which one is only used - we dont have that much ram... ;D

Go Up