Jump to content

Some advice needed for my app


Rowan
 Share

Recommended Posts

Hi,

I've been playing around with the example C code on uCapps to get a feeling for what does what so that I can write my own app for my Ableton Live controller, and now I have a few questions as to how I should go about achieving something.................. Hum, I think a timing diagram might be less ambiguous  ;)

Here is a timing diagram:

DIN 1                                  __|-|____________________________________________

DIN 2                                  __________________________|-|_______________________

DOUT 1                               __|-|_|-|_|-|_|--------------------------------|______________

DOUT 2                               ----------------|______________|-|_|-|_|-|_|-------------------

Send Note 0 Velocity 127       __|-|_______________________|-|______________________

Receive Note 0 Velocity 127    ____________|-|____________________________________

Recive Note 0 Velocity 0        _____________________________________|-|____________

Sorry if this is a strange way to explain this, but there is a lot happening here and I even started to confuse myself trying to write it.

Any suggestions where I should start ???

Thanks

Rowan

Link to comment
Share on other sites

I'd be glad to help, but at the moment I'm not exactly sure what your question is.

Which example are you looking at?  And perhaps a little explanation of whats going on on the DOUT lines would help (unless this is your question?)

Let me take a crack at this anyway:

The two DIN lines trigger both a note on event and the strange looking "|-|_|-|_|-|_|--------------------------------|" DOUT events,

well.. thats about as far as I get, I don't see the how the Receive lines relate to the rest of the data.. There almost looks like your using a single note on event to toggle a note on and off on the receiving end.. no?

Link to comment
Share on other sites

Your right......my discription is rather unclear.

this is going to be a hard to explain, that's why I went for a timing diagram.

He I go.....

_|-|_|-|_        translate this to off, on, off, on, off

i.e. - = on

    _ = off

    | = transition

    _|-|_ = off, on, off

The hardware set up is two switchs and two LED's

Switch 1 is connected to DIN 1

Switch 2 is connected to DIN 2

LED 1 is connected to DOUT 1

LED 2 is connected to DOUT 2

Events will happen in this order.

When the app is in it's initial state LED 1 is off (DOUT 1 Low) and LED 2 is on (DOUT 2 High).

Press Switch 1 (Close DIN 1), Sends Note on 0 Velocity 127, LED 1 starts to Flash (DOUT 1 Toggles High/Low), LED 2 is on (DIN 2 High).

Core receives Note On 0 Velocity 127, LED 1 goes On (DOUT 1 High), LED 2 goes off (DOUT 2 Low).

Press Switch 2 (Closes DIN 2), Sends Note on 0 Velocity 127, LED 1 Stays on (DOUT 1 High), LED 2 Starts to flash (DOUT 2 toggles high/low).

Core receives Note on 0 Velocity 0, LED 1 goes off (DOUT 1 Low) and LED 2 goes on ( DOUT 2 High).

Switch 1 and 2 both trigger the same note.

Is that any clearer?

Thanks

Rowan

Link to comment
Share on other sites

Hi Rowan,

a few (quick) comments from my side:

(Close DIN 1)

just a tipp: think very soon about the fact, that when a DIN-line is ON (=1) it's unpressed, so I always rather think about OPEN...

- you should split up your needs in some logical subgroups

- maybe it helps, if you would tell us, what exactly are you trying to achive. I made the experience, that for example introducing one more DOUT-LED might help solving hell of a problem. for example your flashing LED requires the setup of a timer and at least two additional variables that keep track of the current state. this is a very complex thing to do for a beginner and a lot of code splitted up in different places, hard to keep an eye on it even for an experienced programmer. in my eyes, these kind of things only make sense if you either have more blinking LEDs that serve a special purpose or just have too much time and like it :) or think about adding special "blinking LEDs"; you can buy them and they blink by default... wait, I got stuck: yeah, if you would instead add a third LED or f.ex. use a bipolar green/red LED, you can save a lot of headaches...

- sending just one midi event (note on) is so fast, you will even don't notice a flashing light!

- rather scribble logic tables than timed views:

(example for use with red/green LEDs to visualize different states:)

[tt]

state LED1 LED2

---------------------

off 0/0 1/0

D1 0/1 1/0

D2 1/0 0/1

nOn 0 1/0 0/0

nOff0 0/0 1/0

[/tt]

now: can you see any pattern in this? can you simplify it or reorder/-arrange it, so it makes a whole lot more sense in a "digital" way?

- you're using switch() cases and if() statements most, whereas if() is typically used to determine one, two or maximum four states, whereas a switch statement is a kind of lookup table for all kinds of events, eg (abstract!):

switch(incomingNoteEvent) {

case(noteON_channel1):

if(velo > 0) {

do this;

} else {

do that;

}

switch that;

break;

}

I hope, this helps a bit :)

Cheers,

Michael

Edit:

...and btw: what have you done to your booty? ;D

Link to comment
Share on other sites

Hi Rowan,

by drawing a diagram and descriping the function you are close to find the algorithm you need.

Now it makes sense to create a state diagram in order to get a better oversight. A description of this technique can be found in Wikipedia (or somewhere else).

Let's work it out together - I can see four different states:

S0: LED1 off, LED2 on

S1: LED1 flashing, LED2 on

S2: LED1 on, LED2 off

S3: LED1 on, LED2 flashing

Now just describe, under which conditions a state transition does happen

Best Regards, Thorsten.

Link to comment
Share on other sites

Receive Note 0 Velocity 127    ____________|-|____________________________________

Recive Note 0 Velocity 0        _____________________________________|-|____________

Yes, I am most curious as well to know the idea behind monitoring the sending and receiving of the midi note.  I don't know a whole lot about Abelton, but it seems to me that this would not be neccessary (?).  I def. don't think you need it to be sure the events got through, but perhaps you have something more complicated brewing here?

Link to comment
Share on other sites

Hi Guys,

Thanks for you input.

S0: LED1 off, LED2 on

S1: LED1 flashing, LED2 on

S2: LED1 on, LED2 off

S3: LED1 on, LED2 flashing

S0 > S1: When Switch 1 is triggered (core sends note on)

S1 > S2: When Note On is recived

S2 > S3: When Switch 2 is triggered (core sends note on)

S3 > S0: When Note off is revived

I would also like to have the LED's flash at a rate derived from a MIDIclock signal, say 1/4 Note.

When I get home from work I'll try to explain in detail why I want to do this.

Regards

Rowan

Link to comment
Share on other sites

So, you've already found the algorithm - implementation is like explained by AC.

LEDs can be flashed synched on the MIDI clock when you are triggering on 0xf8 (MIDI Clock) within the MPROC_NotifyReceivedByte function. A 1/4 note takes 24 clocks, you need to count them. During the first 12 clocks, you can switch the LED on, during the other 12 clocks turn it off. The counter has to be reset when it is >= 24, and with 0xfa (MIDI start event)

Best Regards, Thorsten.

Link to comment
Share on other sites

Hi TK and AC,

I spent some time on reading up on the switch() statement, and how I should use it. I tried to put together a rough example that fits with my understanding of how I should use it.

Please note that I know that the syntax is nowhere near correct, but I want to check that I have the concept  right.

switch (TransLEDhandler) 
	{

		case  S0 > S1 When Switch 1 is triggered (core sends note on):
			 S1: LED1 flashing, LED2 on;
			break;

		case  S1 > S2: When Note On is recived:
			 S2: LED1 on, LED2 off;
			break;

		case  S2 > S3: When Switch 2 is triggered (core sends note on):
			 S2: LED1 on, LED2 off;
			break;

		case  S3 > S0: When Note off is revived:
			 S0: LED1 off, LED2 on;
			break;

		default:
			 S0: LED1 off, LED2 on;
			break;


	}

I have inclued S0 as the default case as this is the state the app should be on start-up.

Am I on the right track?

Thanks

Rowan

Link to comment
Share on other sites

Hi Rowan,

you're halfway there :)

the thing with the switch() is, that you can just evaluate the truth of a setting. that means TransLEDHandler cannot be (S0 > S1).

you could check the contents of a variable with that. in your case you might have to mix if's and switches. the switch example you can find above is perfect to determine incoming midi messages --> switch(message) { case a:, case b:, and so on... }

also think of, that you get your notifications if a button has been pressed!

therefore your code should look more like this:

--> on notify DIN event

if(pin == S0) {  // pin S0

  if(MIOS_DIN_PinGet(S1)) {

    do this

  } else {

    do that

  }

} else { // pin S1

  ...

}

now you can even combine switches and ifs to minimize code size; but try to separate it first, so that you don't get confused!

and one last hint: whenever there are three lines duplicated somewhere, you can think about optimisation!

:)

Cheers,

Michael

Link to comment
Share on other sites

Thanks AC,

I'm at this stage now

switch ( expression ) 
	{

	case 0: // Clip Start button pressed (core sends note on)
			if(MIOS_DIN_PinGET(0) == 0) {
			//LED 1 Flashing
			//LED 2 On
			}
			break;

	case 1: // Note on received
			if(evnt0 == 0x90) {
			MIOS_DOUT_PinSet(0,1); //LED 1 On
			MIOS_DOUT_PinSet(1,0); //LED 2 Off
			}
			break;

	case 2: // Clip stop button pressed (core sends note on)
			if(MIOS_DIN_PinGET(1) == 0) {
			// LED 1 On
			// LED 2 Flashing
			}
			break;

	case 3: //Note off is received
			if(evnt2 == 0x00 || evnt2 == 0x80) {
			MIOS_DOUT_PinSet(0,0); //LED 1 Off
			MIOS_DOUT_PinSet(1,1); //LED 2 On
			}
			break;

	default:
			MIOS_DOUT_PinSet(0,0);
			MIOS_DOUT_PinSet(1,1);

			break;


	}

Is it starting to look any better?

Link to comment
Share on other sites

yeah! :)

now you just have to take care, that you don't mix up the places where these scripts get.

Take a look at the skeleton. You'll find one function that receives MIDI-messages and another one that receives changes at the DIN-ports.

That means, you can't mix up your logic for MIDI-, DIN- and AIN-Events.

isn't that difficult, is it?

Cheers,

ac.

Link to comment
Share on other sites

I'm pleased i'm heading in the right direction.

I see what you are saying about spliting up the code;

Case 0 and Case 2 are controlled by  the DIN_NotifyToggle function?

Case 1 and Case 3 are controlled by the MPROC_NotifyReceivedEvnt function?

Can I split the switch statement over MPROC_NotifyReceivedEvnt and DIN_NotifyToggle? Or have the switch statement spearate from the above two functions?

I starting to get a clear picture of how this should, but as I'm sure you can guess programming is not one of my strong points.

Your help is appreciated A.C.  ;D

Rowan

Link to comment
Share on other sites

you're welcome Rowan :)

as soon as you get the whole picture and get used to programming, you'll surely enjoy it. It's like solving a crossword puzzle by pure logic...

Can I split the switch statement over MPROC_NotifyReceivedEvnt and DIN_NotifyToggle? Or have the switch statement spearate from the above two functions?

no. every function is a space of its own.

just write two separated switch() or if() blocks. as they don't interact with each other anyway, it makes no difference.

and it's good programming practice to separate things and sort them. that's one huge part of what programming is about ;)

best regards,

Michael

Link to comment
Share on other sites

Can I split the switch statement over MPROC_NotifyReceivedEvnt and DIN_NotifyToggle? Or have the switch statement spearate from the above two functions?

You could write a single function that is called by those functions though.... But what AC said is true.

Link to comment
Share on other sites

Rowan,

- you get the state of the LED by calling MIOS_DOUT_PinGet(pin) aka DIN;

- adding an additional function means that the processing time will be slightly (slighty) increased (probably not in your case, but in general!), so there should be a good reason, why?

- as your case statement doesn't mix up the different calls (MIDI/DIN), there's no need, why the case-statement is processed every time when a Midi-Input Event occurs and vice versa;


#define MIDI_NOTE_ON              0x90   // 144, on CH1
#define MIDI_NOTE_OFF             0x80   // 128, on CH1

#define DIN_BUTTON_START       5
#define DIN_BUTTON_STOP         7


// on INIT
MIOS_DOUT_PinSet(0,0);
MIOS_DOUT_PinSet(1,1);


----------------------------------------------------------------
// on NOTIFY_MIDI (MPROC)
switch(evnt1) {
	case MIDI_NOTE_ON: // Note on received
		if(evnt0 == 0x90) {
			MIOS_DOUT_PinSet(0,1); //LED 1 On
			MIOS_DOUT_PinSet(1,0); //LED 2 Off
		}
		break;
	case MIDI_NOTE_OFF: //Note off is received
		if(evnt2 == 0x00 || evnt2 == 0x80) {
			MIOS_DOUT_PinSet(0,0); //LED 1 Off
			MIOS_DOUT_PinSet(1,1); //LED 2 On
		}
		break;
}


----------------------------------------------------------------
// on NOTIFY_DIN
switch(pin) {
	case DIN_BUTTON_START: // Clip Start button pressed (core sends note on)
		if(MIOS_DIN_PinGET(0) == 0) {
			//LED 1 Flashing
			//LED 2 On
		}
		break;
	case DIN_BUTTON_STOP: // Clip stop button pressed (core sends note on)
		if(MIOS_DIN_PinGET(1) == 0) {
			// LED 1 On
			// LED 2 Flashing
		}
		break;
}

avoid unnecessary switches, ifs or functions unless you have a reason to do so.

Cheers,

Michael

Edit: added #defines;

they make your code more readable and just exchange an expression before generating the machine-code

Link to comment
Share on other sites

A.C.

Can you take a look at this and give me a clue where I'm going wrong. The code complies fine, but once I've uploaded it it doesn't do jack  ??? The LED's don't even go to the inital state.

/*
 * MIDIfire Version 0.0.1
 *
 * ==========================================================================
 *
 *  Copyright (C) <2006>  <Rowan Spicer> (******@******.com)
 *  Licensed for personal non-commercial use only.
 *  All other rights reserved.
 * 
 * ==========================================================================
 */

//////////////////////////////////Thanks///////////////////////////////////////
// Thorsten Klose, Audiocommander, Smash TV                                 //
//////////////////////////////////////////////////////////////////////////////

#include "cmios.h"
#include "pic18f452.h"

#define MIDI_NOTE_ON				0x90   // 144, on CH1
#define MIDI_NOTE_OFF				0x80   // 128, on CH1

#define DIN_BUTTON_START			5
#define DIN_BUTTON_STOP				7


/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS after startup to initialize the 
// application
/////////////////////////////////////////////////////////////////////////////
void Init(void) __wparam
{
 // Initialize Clip Launch LED's
 MIOS_DOUT_PinSet(0,0);
 MIOS_DOUT_PinSet(1,1);
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS in the mainloop when nothing else is to do
/////////////////////////////////////////////////////////////////////////////
void Tick(void) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is periodically called by MIOS. The frequency has to be
// initialized with MIOS_Timer_Set
/////////////////////////////////////////////////////////////////////////////
void Timer(void) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when the display content should be 
// initialized. Thats the case during startup and after a temporary message
// has been printed on the screen
/////////////////////////////////////////////////////////////////////////////
void DISPLAY_Init(void) __wparam
{
  MIOS_LCD_Clear();
  MIOS_LCD_CursorSet(0x00);
  MIOS_LCD_PrintCString("Hello World!");
}

/////////////////////////////////////////////////////////////////////////////
//  This function is called in the mainloop when no temporary message is shown
//  on screen. Print the realtime messages here
/////////////////////////////////////////////////////////////////////////////
void DISPLAY_Tick(void) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
//  This function is called by MIOS when a complete MIDI event has been received
/////////////////////////////////////////////////////////////////////////////
void MPROC_NotifyReceivedEvnt(unsigned char evnt0, unsigned char evnt1, unsigned char evnt2) __wparam
{
	switch(evnt1) {
	case MIDI_NOTE_ON: // Note on received
		if(evnt0 == 0x90) {
			MIOS_DOUT_PinSet(0,1); //LED 1 On
			MIOS_DOUT_PinSet(1,0); //LED 2 Off
		}
		break;

	case MIDI_NOTE_OFF: //Note off is received
		if(evnt0 == 0x80 || evnt2 == 0x00) {
			MIOS_DOUT_PinSet(0,0); //LED 1 Off
			MIOS_DOUT_PinSet(1,1); //LED 2 On
		}
		break;
	}
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when a MIDI event has been received
// which has been specified in the MIOS_MPROC_EVENT_TABLE
/////////////////////////////////////////////////////////////////////////////
void MPROC_NotifyFoundEvent(unsigned entry, unsigned char evnt0, unsigned char evnt1, unsigned char evnt2) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when a MIDI event has not been completly
// received within 2 seconds
/////////////////////////////////////////////////////////////////////////////
void MPROC_NotifyTimeout(void) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when a MIDI byte has been received
/////////////////////////////////////////////////////////////////////////////
void MPROC_NotifyReceivedByte(unsigned char byte) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS before the shift register are loaded
/////////////////////////////////////////////////////////////////////////////
void SR_Service_Prepare(void) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS after the shift register have been loaded
/////////////////////////////////////////////////////////////////////////////
void SR_Service_Finish(void) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when an button has been toggled
// pin_value is 1 when button released, and 0 when button pressed
/////////////////////////////////////////////////////////////////////////////
void DIN_NotifyToggle(unsigned char pin, unsigned char pin_value) __wparam
{
switch(pin) {
	case DIN_BUTTON_START: // Clip Start button pressed (core sends note on)
		if(MIOS_DIN_PinGet(0) == 0) {
								//LED 1 Flashing
		MIOS_DOUT_PinSet(1,1);	//LED 2 On
		}
		break;

	case DIN_BUTTON_STOP: // Clip stop button pressed (core sends note on)
		if(MIOS_DIN_PinGet(1) == 0) {
		MIOS_DOUT_PinSet(0,1);	// LED 1 On
								// LED 2 Flashing
		}
		break;
	}
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when an encoder has been moved
// incrementer is positive when encoder has been turned clockwise, else
// it is negative
/////////////////////////////////////////////////////////////////////////////
void ENC_NotifyChange(unsigned char encoder, char incrementer) __wparam
{
}

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when a pot has been moved
/////////////////////////////////////////////////////////////////////////////
void AIN_NotifyChange(unsigned char pin, unsigned int pin_value) __wparam
{
}
I know my hardware is fine as it works with the test apps and C examples. I am also a little confused as to the comments that you added to the defines
#define MIDI_NOTE_ON				0x90   // 144, on CH1

144, on CH1? What does the 144 relate to?

Thanks mate,

Rowan

Link to comment
Share on other sites

Hi Rowan,

please take a look into the Wiki to learn about Midi; this page is currenly in a quite excellent status :)

http://www.midibox.org/dokuwiki/doku.php?id=midi_specification

then you'll know, why your MIDI-In MPROC is never ever been reached (hint: you're checking evnt1!!)

for the DIN_Notification:

you'll have to exchange the numbers of the #defines before, of course!

if you have a START and STOP button on pin 0 and pin 3 of your DIN, its:

#define DIN_BUTTON_START 0

#define DIN_BUTTON_STOP 3

or else: if you got a button that rolls you a cigarrete on pin 24 it's:

#define ROLL_MY_CIGARETTE 24

okay?

The Init() should work, I don't know why you say it isn't working... are the pin-numbers correct?

Maybe you could try the other call:

MIOS_DOUT_PinSet1(pin) and MIOS_DOUT_PinSet0(pin)?

(but I don't think this changes something, both calls should be fine)...

You could experiment setting DOUTs also within MIOSStudio... have you found the "Debug" Window where you can call MIOS-Functions? Just select MIOS_DOUT_PinSet1(pin) and set your pin-number as argument (can't remeber, should be param1 or wreg...)

Cheers,

Michael

Edit: you might also wanna take a look at the midi-overview table:

http://www.midi.org/about-midi/table2.shtml

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...