TK.

MIDIbox KB

182 posts in this topic

The calibration feature for the wheels sounds great! Will an AINSer be supported for this as well? I don't trust the onboard a-d conversion of the LPC17 so much..

 

Actually the wheel calibration is one of the main reasons I want to upgrade my existing controller keyboard to a MB KB version. I had to change the pots of my pitch- and modwheels because they were worn out. I put in pots with the same values, but since every pot has a (slightly) different curve, they don't send the full range of CCs anymore and the mod wheels is jittering now quite heavy. There is no way of calibrating this, so...

 

MB KB to the rescue!   :smile:

Share this post


Link to post
Share on other sites

Yes, I could support the AINSER as well. But the remaining analog inputs won't be fully configurable, because such a function would conflict with the MBNG features where I did it better (than before ;).

 

I also would like to evaluate, if the MBKB could be merged with MBNG - this would be the most simple way to maintain the project, and it would give us the highest flexibility.

 

We would have the drawback that the minimum latency increases from ca. 130 uS to ca. 2 mS for a Fatar 61 Keyboard in worst case (to 1 mS if the optimized scan is used).

The latency would be higher, since MBNG requires more headroom for all the other functions which are running in parallel.

 

Would such a high latency be acceptable?

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Its always hard to accept higher latencies mentally, though in practice it  often makes less difference that you think (esp. when its <5ms total). I am and  will be using the KB through the SEQ which I assume adds 2ms to live notes forwarded through to synths (then latency of the actual synth added to this..) 

Am I correct in understanding that using optimized scan on a NG based KB may add only 800 or 900us to the total latency?

Share this post


Link to post
Share on other sites
Am I correct in understanding that using optimized scan on a NG based KB may add only 800 or 900us to the total latency?

 

yes

 

The increased latency will mainly affect the accuracy of the velocity values.

Currently the measured delay ranges from 50...1000, with a 10 times slower scan we would only measure delays between 5..100 anymore.

It depends on the outcome with your "velocity curve" implementation if a difference can really be notified.

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Hard to tell in theory. Do we have any numbers of other (commercial) midi keyboards to compare with? For me an added latency of max. 1ms still sounds fast, at least for normal (non-percussive) keyboard operation.

I'm thinking of a real world example: Say you want to build a midi keyboard with a few pots, encoders etc., so you add a LPC17 with MBKB software for super low latency. Then you add another LPC17 (with MBNG) for the rest of the controllers. If you want to use only a single USB port (for convenience) to connect your computer, you would have to merge (e.g. via Midi I/O #4) the MBKB midi data with the MBNG controller data in the MBNG, right? Would this process also add latency, maybe even more than 1ms?

So from this point of view a merge between MBKB and MBNG would be much more convenient, and performance-wise on the same level.

But this is all (my) theory, maybe it's best to try it out: If we'd have a beta version of an KB-enhanced MBNG, we could compare these two and see if it "feels" different.

(BTW I'm just waiting for my DIO_Matrix module to arrive from Smash_TV, than I'll try MBKB asap..)

Cheers
Lars

Share this post


Link to post
Share on other sites

The velocity values would be a lot more "granular" i.e would encompass the range 1 to 127 but certain values would never appear on the output because it would map 5..100 onto 127..1. With nonlinear scaling it would invariably reduce the total number of values that appear on the output. 

Would it ever be noticed? (imho) no, does it bother me (mentally) that the velocity output would be granular, yes :hmm: .

 

Personally (subject to change, of course!) I might entertain the idea of developing on a small STM32 "minicore" (minimal MB Core32)  that does nothing more than scan the keyboard(s) apply velocity scaling, then forward midi events to a uart (maybe at higher baud, for direct connect with an NG?).  

Share this post


Link to post
Share on other sites

Hey,

 

I've managed to install MB_KB today. I spent half a day to measure the matrix layout / connections of my old miditech keyboard, just find out that ....

 

... the two cables with DIL16 headers coming from the miditech match exactly the two DIL16 sockets on the DIO Matrix. So it is a 1:1 connection, I didn't have to resolder a single cable!!! That was really PLUG'N'PLAY!!

 

Could have saved my about 5 hours if I just tried to connect them and see what happens, but anyway...  :rolleyes:

 

So far everything's working great. Ready to try MB_NG+KB ... :smile:

 

Cheers

Lars

Share this post


Link to post
Share on other sites

I suppose the keyboard has a Fatar 61 note keybed?

Share this post


Link to post
Share on other sites

"Meifa CO., Ltd. © Copyright Keyboard-R" is printed on the backpanel.

Maybe it's a Fatar clone or something..

Share this post


Link to post
Share on other sites
Could have saved my about 5 hours if I just tried to connect them and see what happens, but anyway...  :rolleyes:

 

:thumbsup:

 

 

So far everything's working great. Ready to try MB_NG+KB ...  :smile:

 

We can give it a trial run this weekend. :)

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites
I spent half a day to measure the matrix layout / connections of my old miditech keyboard, just find out that ....

 

... the two cables with DIL16 headers coming from the miditech match exactly the two DIL16 sockets on the DIO Matrix. So it is a 1:1 connection, I didn't have to resolder a single cable!!!

 

Would that be the same Miditech / Midiplus keybed that I aquired some time ago? That would be sweet, would save me from measuring that shiz as well :w00t:

Share this post


Link to post
Share on other sites

If there are two cables with DIL16 headers coming from your keybed, I'd say yes. Just order a DIO_Matrix module and give it a go.. ;)

Share this post


Link to post
Share on other sites

Dear Thorsten

I successfully installed the precompiled MIDIBOX_kb_V1_007 .hex file on my LPC17xx system.
Everything worked as expected:

  • Terminal commands etc.
  • Keyboard setup for Fatar DF88 Keyb. Minor issue: set kb 1 note_offset 24 (C-0) should be 21 (a-1)
  • optimize option works perfect:
    180 (6*30) us for a all 88 keys in steady state !!!
    360 (12*30) us if all Dins (lower & upper half) change at once (very rarely)!

some ideas and findings:

  • delay_fastest should be made separate for white and black keys, because the lever of the black keys is shorter than the lever of the white keys.
    With the Fatar TP9-88 I could generate shortest delay of 40 ticks on black keys, with the white ones I never came under 57 ticks.
  • delay_slowest can be made fixed, since it determines the latency of the sent MIDI cmd,
    eg. delay_slowest = delay_fastest + 127 * 8 => 31,7 ms latency.
  • kc->break_inverted seems not to be initialized in KEYBOARD_Init().
  • In fct: void KEYBOARD_SRIO_ServicePrepare(void) which is called every 30 us:

    // optional scan optimization for break/make: if break not active, we don't need to scan make
    if( kc->scan_velocity && !kc->break_inverted && kc->scan_optimized ) {...

    // can ber replaced by :
    if( kc->scan_optimized ) { ...

    If the remaining conditions are checked in KEYBOARD_Init() and the related Set_..() functions


Before I intended to modify the code, I build the project from the Reposity with Rev 1633 and loaded it into the platform.
Everything went as expected until I pressed one of the two rightmost keys (B-6 & C-7):


The System crashed with "!! HARD FAULT !! at PC = 0x000064d8"


Since I haven´t any debugger I decided to go the hard way and did some version comparisons...

I went back to Rev 1632 which was the the revision of your Build V1.007 and everything works without crashes.
I checked the differencies to Rev 1633 and found out that app_lcd for universal lcd was changed, but this should not have any influence on the code.
But then I realized that the terminal.c code was updated for all apps except for the Keyboard.

So after modifying terminal.c the crashes were gone.
I´m not 100% sure if I made the changes at the right places in terminal.c, so it would be fine if you can review the attached terminal.c and update the repository

Thanks very much and best regards
Jo
 

terminal.zip

Edited by nlate

Share this post


Link to post
Share on other sites

Hi Jo,

thanks for the feedback!

I will check your findings & proposals this evening.

To the changes in terminal.c: they can't be the reason for such a crash, the root cause must be somewhere else - e.g. a stack overflow or something similar. I will try to reproduce this.

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Dear Thorsten

Thanks in advance for your investigations.

In the meantime I made some measurements with my USB logic analyzer.
They may be helpful for the MBKB project documentation.
I attached them as screenshots, the titles are hopefully self-explainining.

  • MBKB_1RowScan.jpg                                      Detail, how the Dout registers are controlled for one row.
  • MBKB_ScanNonOptimizedOnly.jpg                 Timing for non optimized row scan without key press
  • MBKB_ScanOptimizedOnly.jpg                        Same as above but with optimized row scan
  • MBKB_ScanNonOptimizedC-0pressed.jpg      Timing for 1 Key press C-0 non optimized scan
  • MBKB_ScanOptimizedC-0pressed.jpg             Same as above but with optimized scan
  • MBKB_ScanOptimizedC-0_D-3pressed.jpg      2 keys pressed on Left and Right half of the 88 key Fatar keyboard with optimized row scan.
  • MBKB_ScanOptimizedLhRhChordPressed.jpg 6-key Cord press with optimized row scan


I also added the timing files in the zip archive the can be viewed in with the
Analyzer SW available at http://www.pctestinstruments.com/downloads.htm running in Demo mode
 

Best regards

Jo

post-6136-0-20946500-1358695948_thumb.jp

post-6136-0-32845000-1358696044_thumb.jp

post-6136-0-37766700-1358696115_thumb.jp

post-6136-0-65689500-1358696185_thumb.jp

post-6136-0-04840200-1358696233_thumb.jp

post-6136-0-99711700-1358696277_thumb.jp

post-6136-0-39859800-1358696324_thumb.jp

MBKBtimings.zip

Share this post


Link to post
Share on other sites

Thanks for the sanity check, very useful! :smile:

The scan rate is lower than specified at the MBKB page since I had to decrease the SPI rate after it turned out, that a too fast SPI overloads the application too much so that USB transfer were delayed by several mS - I aligned the latency values at the MBKB page now.

 

To your proposals:

 

 

  • delay_fastest should be made separate for white and black keys, because the lever of the black keys is shorter than the lever of the white keys.

    With the Fatar TP9-88 I could generate shortest delay of 40 ticks on black keys, with the white ones I never came under 57 ticks

 

 It's possible to specify a separate delay_fastest_black_keys now. It's taken on black keys when the specified value is > 0

Currently the value is not stored in EEPROM, because I would like to wait for more potential parameters before changing the storage structure.

The changes are available in the repository.

 

 

  • delay_slowest can be made fixed, since it determines the latency of the sent MIDI cmd,

    eg. delay_slowest = delay_fastest + 127 * 8 => 31,7 ms latency

 

I guess that with "made fixed" you mean, that the same value can be taken for black and white keys?

 

 

  • kc->break_inverted seems not to be initialized in KEYBOARD_Init().

 

done (but this was uncritical, since the runtime environment will initialize all variables with 0 anyhow

 

 

  • In fct: void KEYBOARD_SRIO_ServicePrepare(void) which is called every 30 us:

    // optional scan optimization for break/make: if break not active, we don't need to scan make

    if( kc->scan_velocity && !kc->break_inverted && kc->scan_optimized ) {...

    // can ber replaced by :

    if( kc->scan_optimized ) { ...

    If the remaining conditions are checked in KEYBOARD_Init() and the related Set_..() functions

 

I will keep this conditional check as it is - at a single place.

Otherwise I would have to do similar checks at multiple places, which leads to more error prone code.

 

In addition, it could be that in future kc->break_inverted could be considered for the optimized scan (which is only a testing issue - very hard if I don't own such an exotic keyboard...)

 

 

 

The System crashed with "!! HARD FAULT !! at PC = 0x000064d8"
 

I'm not able to reproduce this (neither with the latest revision, nor with r1633)

 

Are you using the MIOS32 toolchain? (ensures that you are using the same compiler + newlib version)

 

The PC indicates, that an unintended write operation into the FreeRTOS variable range happened.

But I haven't found a place where this could happen.

 

Anyhow, I added a check for an "invalid" read operation (kc->prev_row != 0xff) - which won't solve the problem, but is just more clean.

And I added a check for the key number boundary (key >= KEYBOARD_NUM_PINS) for the case that I overlooked something during the key number calculation.

 

Could you please check if the firmware still crashes with these changes when the upper notes are played?

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Dear Thorsten

I updated my MIOS32 folder to the current Rev. 1663,

built the project as always with the MIOS32 Toolchain under WinXP,

installed the firmware with MIOS Studio and started the KB V1.008:

The aforementioned crashes didn´t occur anymore over the whole keyrange!!!

Thank You very much!

I agree with all points you mentioned!

Your question about delay_slowest:

Yes, I mean the same value for both black and white keys.

Fixed means imho that it depends only on the Users preferences,

how much latency he would accept for NoteOn generation (about 31,7 ms in my example).

Imho it´s not dependent on the actual keybed.

Thanks again and regards

Jo

Edited by nlate

Share this post


Link to post
Share on other sites

Hi Jo,

 

great that the crash issue is solved! :)

 

The delay_slowest value not only affects the latency, but also the (linear) velocity calculation.

With higher values the velocity will get "stronger" earlier.

This dependency could change once a non-linear velocity curve is available.

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

The keyboard driver is now integrated into MIDIbox NG V1.014:

 

I'm looking forward to your feedback! :)

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Dear Thorsten,
Dear MIDIBOXers

During the recent weeks I extended the midibox_kb project for detecting also
release velocity if the keybed is able to detect it like the FATAR DF xx types.

Additionally EEPROM preset system is also extended to cope with the additional parameters.

Initially I also revised the parameter documentation on http://ucapps.de/midibox_kb.html and I propose some minor additions/corrections for the FATAR DF type keybeds:
e.g:

- set kb <1|2> note_offset <0-127>:
  21 for 88 keys (a-1);
  28 for 76 keys (E-0);
  36 for 61 keys & 49 keys (C-1);
  48 for 25 keys (C-2)
- set kb <1|2> din_key_offset <0-127>:
  32 for 61 keys and 76 keys;
  40 for 88 keys ;


The below proposed code changes/additions don´t generate noticable performance losses during my testing with a FATAR DF TP9/88 keybed.
But I´m not completely sure if the changes behaves as expected with other separate Break/Make contact keybeds.
So feel free to use inspect the code in your MIDI_KB project.
 

Mios32\modules\keyboard\keyboard.h:
typedef struct {
  .....
  u8  scan_release_velocity:1;
  .....
  .....
  u16 delay_fastest_release;
  u16 delay_fastest_release_black_keys;
  ......
  u16 delay_slowest_release;
  ......
} keyboard_config_t;


Mios32\modules\keyboard\keyboard.c:
 

// removal of:
static u8 key_note_on_sent[KEYBOARD_NUM][KEYBOARD_NUM_PINS / 8];
static u8 key_note_off_sent[KEYBOARD_NUM][KEYBOARD_NUM_PINS / 8];
// not used anymore (s. below)

s32 KEYBOARD_Init(u32 mode)
{
  init of the additional structure members (s. above)
}

void KEYBOARD_SRIO_ServicePrepare(void)
{
  // modified increment timestamp for velocity delay measurements
  // but skip 0, which is used as reset of  *ts_make  and *ts_break values
   if ( !(++timestamp))
    ++timestamp;
  ...
}
void KEYBOARD_SRIO_ServiceFinish(void)
{
  ....
// use of timestamp ptrs instead of values
  u16 *ts_ptr = (u16 *)&din_activated_timestamp[kb][prev_row * MATRIX_NUM_ROWS];
  ...
  *ts_ptr == 0 // as additional condition to get updated in the for(..) loops
  ...
// additional for(..) loop to handle release timestamps
  ...
}

static void KEYBOARD_NotifyToggle(u8 kb, u8 row, u8 column, u8 depressed)
{
// modified debounce processing
// check for *ts_break_ptr and *ts_make_ptr instead of *note_on_sent and *note_off_sent
// all access to the content of timestamp pointers is secured by
      MIOS32_IRQ_Disable();
      ....
      MIOS32_IRQ_Enable();
  ...
// black key handling modified depending on kc->note_offset because this
// offset determs the key to normalized note and not to the evtl. transposed MIDI note.
// not every keybed starts with ´C´!
  ...
// branch depending on pressed or released key
// additional released key processing
}

// additional help fct.:
static int KEYBOARD_GetVelocity(s16 delay, u16 delay_slowest, u16 delay_fastest)
{
}

// modified help fct. with additional parameter u8 depressed
static s32 KEYBOARD_MIDI_SendNote(u8 kb, u8 note_number, u8 velocity, u8 depressed)
{
}

// additional release velocity dependent parameters in:
s32 KEYBOARD_TerminalHelp(void *_output_function)
{
}
// and
s32 KEYBOARD_TerminalParseLine(char *input, void *_output_function)
{
}
// and
s32 KEYBOARD_TerminalPrintConfig(int kb, void *_output_function)
{
}


In MIOS32\apps\controllers\midibox_kb_v1\src\presets.h:
 

// additional offset definitions at the end of:
..
#define PRESETS_ADDR_KB1_DELAY_FASTEST_BLACK_KEYS         (0xd1 + 0*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xd1
#define PRESETS_ADDR_KB1_DELAY_FASTEST_RELEASE            (0xd2 + 0*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xd2
#define PRESETS_ADDR_KB1_DELAY_FASTEST_RELEASE_BLACK_KEYS (0xd3 + 0*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xd3
#define PRESETS_ADDR_KB1_DELAY_SLOWEST_RELEASE            (0xd4 + 0*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xd4
...
// and
...
#define PRESETS_ADDR_KB2_DELAY_FASTEST_BLACK_KEYS         (0xd1 + 1*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xf1
#define PRESETS_ADDR_KB2_DELAY_FASTEST_RELEASE            (0xd2 + 1*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xf2
#define PRESETS_ADDR_KB2_DELAY_FASTEST_RELEASE_BLACK_KEYS (0xd3 + 1*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xf3
#define PRESETS_ADDR_KB2_DELAY_SLOWEST_RELEASE            (0xd4 + 1*PRESETS_OFFSET_BETWEEN_KB_RECORDS) // 0xf4


In Mios32\apps\controllers\midibox_kb_v1\src\presets.c:

// modified fcts:
s32 PRESETS_Init(u32 mode)
{
  ...
// added bit at the end!
  kc->scan_release_velocity = (misc & (1 << 4)) ? 1 : 0;
  ...
// added parameters at the end!
  kc->delay_fastest_black_keys         = PRESETS_Read16(PRESETS_ADDR_KB1_DELAY_FASTEST_BLACK_KEYS + offset);
  kc->delay_fastest_release            = PRESETS_Read16(PRESETS_ADDR_KB1_DELAY_FASTEST_RELEASE + offset);
  kc->delay_fastest_release_black_keys = PRESETS_Read16(PRESETS_ADDR_KB1_DELAY_FASTEST_RELEASE_BLACK_KEYS + offset);
  kc->delay_slowest_release        = PRESETS_Read16(PRESETS_ADDR_KB1_DELAY_SLOWEST_RELEASE + offset);
  ...
}

s32 PRESETS_StoreAll(void)
{
  ...
//added bitfield at the end!
  u16 misc =
    ...
    (kc->scan_release_velocity << 4);
  status |= PRESETS_Write16(PRESETS_ADDR_KB1_MISC + offset, misc);
  ...
//added parameters at the end!
  status |= PRESETS_Write16(PRESETS_ADDR_KB1_DELAY_FASTEST_BLACK_KEYS + offset, kc->delay_fastest_black_keys);
  status |= PRESETS_Write16(PRESETS_ADDR_KB1_DELAY_FASTEST_RELEASE + offset, kc->delay_fastest_release);
  status |= PRESETS_Write16(PRESETS_ADDR_KB1_DELAY_FASTEST_RELEASE_BLACK_KEYS + offset, kc->delay_fastest_release_black_keys);
  status |= PRESETS_Write16(PRESETS_ADDR_KB1_DELAY_SLOWEST_RELEASE + offset, kc->delay_slowest_release);
  ...
}

Have fun :rolleyes:

 

Regards,

Jo

Midibox_kb_relVelocity.zip

Share this post


Link to post
Share on other sites

That's really cool.

 

I'm not sure whether my Synths (Virus B and C) can do anything with release velocity, perhaps Native Instruments VSTi do?

 

I have a MBKB with a dual Fatar 66 keybeds.

 

Anyhow, well done.

Share this post


Link to post
Share on other sites

Thanks a lot for your contribution!  :smile:

 

I tested the new option with my cannibalized Korg Microkontrol keyboard, it's working fine!

So, I took over your code almost 1:1, and only changed back the default delay values to the "less elaborated" ones to get a good starting point for all keyboard types.

 

I also updated the documentation based on your input: http://www.ucapps.de/midibox_kb.html

 

And I released a new version:

MIDIbox KB V1.009
~~~~~~~~~~~~~~~~~

   o support for the "single_usb" option, which can be enabled with the
     bootloader update application V1.012 ("set usb_single 1")

     Use this option if you are working with a Windows PC which can't handle
     the 4 USB ports correctly (e.g. stucking MIDI, Filebrowser operations are failing, etc.)

   o support for Note Off velocity (implemented by Jo aka. Nlate).
     This feature has to be enabled with the release_velocity parameter. In addition, some
     suitable delay values have to be specified, such as:
       set kb 1 release_velocity on
       set kb 1 delay_fastest_release 100
       set kb 1 delay_fastest_release_black_keys 80
       set kb 1 delay_slowest_release 1000 

 

One thing puzzles me a bit: why are you writing "0xff == prev_row" instead of "prev_row == 0xff"?

Both expressions should be equal, but the original expression is better to read (from my point of view)

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Dear Thorsten,

Thanks for adding the release velocity to the repository, and for updating the documenation.

 

One thing puzzles me a bit: why are you writing "0xff == prev_row" instead of "prev_row == 0xff"?

Both expressions should be equal, but the original expression is better to read (from my point of view)

 

This is a result of experience with hard to find bugs in production quality code.

suppose the coder intents to write:

if( variable_x == CONST_A){
  expression();
}

but makes a typo of:

if( variable_x = CONST_A){
  expression();
}

both variants are valid c code, and rarly generate wrong results, if the variable_x has the value CONST_A most of the time!

if you write:

if( CONST_A == varable_x){
  expression();
}

with the same typo:

if( CONST_A = variable_x){
  expression();
}

you will get a compiler error, and your typo is easily detected by the compiler!

Just my two cents for writing robust code.

Cheers,
Jo
 

Edited by nlate

Share this post


Link to post
Share on other sites

Interesting!

 

gcc outputs a warning if I would write variable_x = CONST_A

/Users/TK/svn/mios32/trunk/modules/keyboard/keyboard.c:307:5: warning: suggest parentheses around assignment used as truth value

 

But since parentheses are sometimes used in such expressions as well, the programming error wouldn't be recognized (no warning).

Seems that I should change my habits as well ;)

 

Best Regards, Thorsten.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now