Jump to content

julienvoirin

Programmer
  • Posts

    790
  • Joined

  • Last visited

  • Days Won

    3

Everything posted by julienvoirin

  1. i advise you to get the same as those used on Pioneer mixers (sorry don't know the ref) : they are in metal and D shaft east oriented the panasonic's center detent ones used in x0xb0x are too soft
  2. did you mesure with load ? Just verify its DC ; but for me 12,3V is OK as i've have supplied 8580 with 12V and they did not fried ! It would have been easier to follow the regular stuff with voltage regulators
  3. good job :thumbsup: how did ya silkscreening white on black ?
  4. it is clear that having the controller done first and then coding is the easiest way of making things ... If you don't have an easy way to manufacture PCB, i advise you to get smash tv kits, then build your control surface on veroboard, then link midibox PCB to your control surface with wires, as i did for my Matrix controller. It is the fastest ! take a look in the chaosmatrix tread :thumbsup: btw, it is better to develop the code with a switch(pin) statement in the DIN section. you should have a look in the user project, i had developped a generic keyboard ('voirinov')with a 3 states LED controlled by a single push button (1st push = green, second = red, 3rd = yellow) switch (pin) : case 0 : // soit la 1ere entrée du SR if (!pin_value) // si pine_velue change d'état led_state_osc1 ++; // incrémenter la valeur de led_state_osc1 if (led_state_osc1 >3) led_state_osc1 = 0; // si la valeur attend 4 on repart à 0 case 1 : // 2eme entrée du SR if(!pin_value) led_state_osc2++; etc ... ailleurs dans le code, tu définis : led_state_osc1 = 0 => allumer la led bleue de l'osc1 led_state_osc1 = 1 => allumer la led rouge de l'osc1 etc .. ed_state_osc2 = 0 => allumer la led bleue de l'osc2 led_state_osc2 = 1 => allumer la led rouge de l'osc2 etc ..
  5. just an example on the fly : unsigned char LED1; #define pin 1 // led connected to shift register 1 , second out ///////////////////////////////////////////////////////////////////////////// //lighting LED ///////////////////////////////////////////////////////////////////////////// void LED() { if (LED1 == 1) // Note Off MIOS_DOUT_PinSet(pin, 1); } else { MIOS_DOUT_PinSet(pin, 0); } } ///////////////////////////////////////////////////////////////////////////// // 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 { MIOS_MIDI_TxBufferPut(0xb0); // CC at channel #1 MIOS_MIDI_TxBufferPut(pin); // just forward the pin number (0..127) MIOS_MIDI_TxBufferPut(pin_value ? 0x00 : 0x7f); // = 0x7f when // button pressed, else 0x00 pin_value++; // you can add a restrictive condition like if x>3 then x = 0 so that it cycle between 0,1,2 values LED1 = pin_value; } LED() function must be in the mainloop (when mios is idle) le mieux est de coder ton fonctionnement d'algorithme de manière générale et ensuite d'affecter les boutons et les leds à des états de diverses variables : si osc = sin alors led sin osc allumée donc led x allumée (voir le code du chaosmatrix)
  6. this seems a nice project, for a so rare synth .. IMO, you should have a look at this whole thread : From that, you could adapt some code (CC instead of SysEx) blocks
  7. you will have to implement a sequencer inside, based on clockbox, so that the midi note is played when you are at the beginning of a bar ; where you are not, the note must be stocked inside a memory space, ready to be released
  8. Dear Guys I've enhanced a controller for Oberheim Matrix 1000/6 developped by Jackchaos I'd like to code a rather basic arpeggiator as those used in Juno 60. As of today, I've "stolen" some code blocks from jambonbill and done an arpeggio : it is automatically synced to external beatclock (if received), UP and DOWN patterns work, speed can be controlled. I'd like to implement : UPDOWN patterns, and random gate time, hold button. Here are some relevant extracts of the complete project : device .c (routing midi received notes) //////////////////////////////////////////////////////////////////////////// // Router with arpegiator /////////////////////////////////////////////////////////////////////////// void Router_Arp(unsigned char evnt0, unsigned char evnt1, unsigned char evnt2) { // check if note on or off event at channel 1 has been received if( evnt0 == 0x80 || evnt0 == 0x90 ) { // if note off event: force evnt2 to 0 for easier handling of 'LED off' if(evnt0 == 0x80) evnt2 = 0; } if(router_arp_tag == 1){ // arp is activated MIOS_MIDI_InterfaceSet(router_device); // set IIC interface switch( evnt0 & 0xf0 ) { case 0x80: // Note-Off: 3 bytes rem_arp(evnt0, evnt1, evnt2);//REMOVE NOTE FROM ARP BUFFER return; break; case 0x90: // Note-On: 3 bytes add_arp(evnt0, evnt1, evnt2); // ADD NOTE FROM ARP BUFFER return; break; case 0xa0: // Aftertouch: 3 bytes case 0xb0: // CC: 3 bytes case 0xe0: // Pitchbend: 3 bytes MIOS_MIDI_TxBufferPut(evnt0); MIOS_MIDI_TxBufferPut(evnt1); MIOS_MIDI_TxBufferPut(evnt2); break; //case 0xc0: // Program Change: 2 bytes :: ignore program change for the moment, will be managed by Chaosmatrix case 0xd0: // Poly Aftertouch: 2 bytes MIOS_MIDI_TxBufferPut(evnt0); MIOS_MIDI_TxBufferPut(evnt1); break; default: // note: status messages must be handled within MPROC_NotifyReceivedByte() break; } MIOS_MIDI_InterfaceAutoSet(); // switch back to default interface : is in rem_arp MIDI_Incoming = 1; } if(router_arp_tag == 0){ // arp is desactivated switch( evnt0 & 0xf0 ) { case 0x80: // Note-Off: 3 bytes case 0x90: // Note-On: 3 bytes MIOS_MIDI_InterfaceSet(router_device); // set IIC interface MIOS_MIDI_TxBufferPut(evnt0); MIOS_MIDI_TxBufferPut(evnt1); MIOS_MIDI_TxBufferPut(evnt2); MIOS_MIDI_InterfaceAutoSet(); // switch back to default interface MIDI_Incoming = 1; break; case 0xa0: // Aftertouch: 3 bytes case 0xb0: // CC: 3 bytes case 0xe0: // Pitchbend: 3 bytes MIOS_MIDI_InterfaceSet(router_device); // set IIC interface MIOS_MIDI_TxBufferPut(evnt0); MIOS_MIDI_TxBufferPut(evnt1); MIOS_MIDI_TxBufferPut(evnt2); MIOS_MIDI_InterfaceAutoSet(); // switch back to default interface MIDI_Incoming = 1; break; //case 0xc0: // Program Change: 2 bytes :: ignore program change for the moment, will be managed by Chaosmatrix case 0xd0: // Poly Aftertouch: 2 bytes MIOS_MIDI_InterfaceSet(router_device); // set IIC interface MIOS_MIDI_TxBufferPut(evnt0); MIOS_MIDI_TxBufferPut(evnt1); MIOS_MIDI_InterfaceAutoSet(); // switch back to default interface MIDI_Incoming = 1; break; default: // note: status messages must be handled within MPROC_NotifyReceivedByte() break; } } // notify display handler in DISPLAY_Tick() that DOUT value has changed last_dout_pin = evnt1; } arp.c (UP & DOWN algo) #include <cmios.h> #include "main.h" #include "arp.h" #include "mclock.h" #include "midi.h" #include "din.h" unsigned char arp_speed; unsigned char arp_motif; unsigned char arp_buffer[32]; // Arp buffer ( 32 should be enough ;) ) unsigned char arp_step; // Arp position (pointer) unsigned char arp_n; // Arp length unsigned char arp_tik; // Seq position (ppqn) unsigned char last_arp; // Last played note unsigned char add_arp_velocity; // for ARP() et add_arp functions unsigned char last_played_note; unsigned char new_note; unsigned char router_arp_tag; // tag which indicates if arp if active while routing midi events ////////////////////////////////////////////////////////////////////////////////////// /// This function activate the arpegiator ////////////////////////////////////////////////////////////////////////////////////// void Active_Arp(unsigned char state) { switch (state){ case active_arp_on: MCLOCK_DoPlay(); router_arp_tag = 1; break; case active_arp_off: MCLOCK_DoStop(); router_arp_tag = 0; break; } } ////////////////////////////////////////////////////////////////////////////////////////// // Arp function // THIS FUNCTION IS CALLED PERIODICALY BY THE CLOCKBOX /////////////////////////////////////////////////////////////////////////////////////////////// void ARP() { if(arp_n == 0){ // here we could stop the clockbox ;), and restart synced it when buffer != empty return; // ARP BUFFER IS EMPTY } arp_tik++; if(arp_tik >= arp_speed){ // arp speeds : 1/3/6/12/24) :: unsigned char arp_speed is arp_sync_tempo in ui_arp.c arp_tik = 0; //reset // KILL LAST PLAYED NOTE if(last_arp < 0x80){ MIOS_MIDI_TxBufferPut(last_played_note); // Note on MIOS_MIDI_TxBufferPut(last_arp); MIOS_MIDI_TxBufferPut(0x00); // velocity null (note off) } // PLAY NEW NOTE MIOS_MIDI_TxBufferPut(new_note); // Note on MIOS_MIDI_TxBufferPut(arp_buffer[arp_step]); //MIOS_MIDI_TxBufferPut(80); // VELOCITY MAX MIOS_MIDI_TxBufferPut(add_arp_velocity); last_arp = arp_buffer[arp_step]; // SAVE LAST PLAYED NOTE arp_step++; // PUSH ARP POINTER if(arp_step >= arp_n) arp_step = 0; // LOOP ARP POINTER } return; } ///////////////////////////////////////////////////////////////////////////////////// // ADD NOTE TO ARPEGGIO ///////////////////////////////////////////////////////////////////////////////////// void add_arp(unsigned char evnt0, unsigned char note, unsigned char evnt2) { unsigned char i; unsigned char swap; new_note = evnt0; // 1st define the velocity of the note in the arp add_arp_velocity = evnt2; // I SORT NOTES TO GET INTERESTING RESULTS // switch(arp_motif){ if (arp_motif>3) arp_motif = 0; case 0: // up pattern : tested :) for(i=0; i<arp_n; i++){ if(note < arp_buffer[i]){ // swap swap = arp_buffer[i]; arp_buffer[i] = note; note = swap; } } break; case 1: // down pattern : tested :) for(i=0; i<arp_n; i++){ if(note > arp_buffer[i]){ // swap swap = arp_buffer[i]; arp_buffer[i] = note; note = swap; } } break; case 2: // play order : tested :) for(i=0; i<arp_n; i++){ if(note < arp_buffer[i]){ // swap swap = arp_buffer[i-1]; // a->b arp_buffer[i-1] = note; // b->c note = swap; // c->a } } break; default: break; } /* // updown pattern : to test if(note > arp_buffer[i]){ // swap swap = arp_buffer[i]; arp_buffer[i] = note; note = swap; } if(note < arp_buffer[i]){ // swap swap = arp_buffer[i-1]; arp_buffer[i-1] = note; note = swap; } } */ arp_buffer[arp_n] = note; arp_n++; // INCREMENT ARP NOTE NUMBER COUNTER #if DEBUG MIOS_LCD_CursorSet(0xc0 + LCD_Offset); MIOS_LCD_PrintCString("ARP_LEN:"); MIOS_LCD_PrintBCD2(arp_n); // SHOW ARP LENGTH #endif return; } ///////////////////////////////////////////////////////////////////////////////////// //REMove NOTE FROM ARPEGGIO ///////////////////////////////////////////////////////////////////////////////////// void rem_arp(unsigned char evnt0, unsigned char note, unsigned char evnt2) { unsigned char i; last_played_note = evnt0; for(i=0; i < arp_n; i++) { if(arp_buffer[i] >= note) arp_buffer[i] = arp_buffer[i+1]; // unstack (swap) } arp_n--; // DECREMENT ARP NOTE NUMBER COUNTER if(arp_n == 0){ // Kill last played note MIOS_MIDI_TxBufferPut(evnt0); // Note MIOS_MIDI_TxBufferPut(last_arp); // Note Number MIOS_MIDI_TxBufferPut(0x00); // Velocity null last_arp = 0x80; // null note } #if DEBUG MIOS_LCD_CursorSet(0xc0 + LCD_Offset); MIOS_LCD_PrintCString("ARP_LEN:"); MIOS_LCD_PrintBCD2(arp_n);//ARP LENGTH #endif return; } ui_arp.c (buttons definition of the control surface) unsigned char enc_value; // general purpose value for test unsigned char arp_on; // launch clockbox (PLAY/STOP) unsigned char arp_mode; // up, down, up-down1, updown2, play_order, random, chord unsigned char arp_sync_tempo; // 1/32 ... 1 bar unsigned char arp_gate; // gate time unsigned char arp_pattern; // defined pattern unsigned char arp_keysync; // on/off unsigned char arp_oct; // 1,2,3, octaves ///////////////////////////////////////////////////////////////////////////// // Display Arp pages, // page 1 // page 2 // page 3 ///////////////////////////////////////////////////////////////////////////// void UI_Display_Arp() { switch(SoftPanel.Page) { case SOFT_PAGE1: /* ARP PAGE 1 [] [] [ ] [] [] 01234567890123456789 BPM Arpeg Speed ___ On Off d 1/8 u */ MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_PATCH].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_EDIT].dout_pin); // off MIOS_DOUT_PinSet1(DIN_ConfigMap[DIN_ARP].dout_pin); // ON MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_OSCILLATORS].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_FILTER].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_ENVELOPES].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_KEYBOARD].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_MATRIX].dout_pin); // off MIOS_DOUT_PinSet1(DIN_ConfigMap[DIN_PAGE].dout_pin); // on MIOS_LCD_Clear(); //1st line MIOS_LCD_CursorSet(0 + LCD_Offset); MIOS_LCD_PrintCString("BPM Arpeg Speed "); MIOS_LCD_CursorSet(64 + LCD_Offset); if (external_clk_received == 1){ MIOS_LCD_PrintCString("EXT"); // print EXT for BPM }else{ MIOS_LCD_PrintBCD3(bpm); } MIOS_LCD_CursorSet(69 + LCD_Offset); MIOS_LCD_PrintCString("On Off"); MIOS_LCD_CursorSet(64+14 + LCD_Offset); MIOS_LCD_PrintBCD2(arp_speed); MIOS_LCD_CursorSet(64+13 + LCD_Offset); MIOS_LCD_PrintChar(CHAR_DOWN); MIOS_LCD_CursorSet(64+19 + LCD_Offset); MIOS_LCD_PrintChar(CHAR_UP); break; case SOFT_PAGE2: /* ARP PAGE 2 [] [] [ ] [] [] 01234567890123456789 BPM Oct - Motif ___ On Off d Up u */ MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_PATCH].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_EDIT].dout_pin); // off MIOS_DOUT_PinSet1(DIN_ConfigMap[DIN_ARP].dout_pin); // ON MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_OSCILLATORS].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_FILTER].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_ENVELOPES].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_KEYBOARD].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_MATRIX].dout_pin); // off MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_PAGE].dout_pin); // off MIOS_LCD_Clear(); //1st line MIOS_LCD_CursorSet(0 + LCD_Offset); MIOS_LCD_PrintCString("BPM Oct - Motif "); MIOS_LCD_CursorSet(64 + LCD_Offset); if (external_clk_received == 1){ MIOS_LCD_PrintCString("EXT"); // print EXT for BPM }else{ MIOS_LCD_PrintBCD3(bpm); } //MIOS_LCD_PrintBCD3(bpm); MIOS_LCD_CursorSet(69 + LCD_Offset); MIOS_LCD_PrintBCD1(arp_oct); MIOS_LCD_CursorSet(64+14 + LCD_Offset); MIOS_LCD_PrintBCD2(arp_motif); MIOS_LCD_CursorSet(64+13 + LCD_Offset); MIOS_LCD_PrintChar(CHAR_DOWN); MIOS_LCD_CursorSet(64+19 + LCD_Offset); MIOS_LCD_PrintChar(CHAR_UP); break; } } ///////////////////////////////////////////////////////////////////////////// // Configure Arp pages ///////////////////////////////////////////////////////////////////////////// void UI_Handle_Arp() { if(SoftPanel.Page == SOFT_PAGE1){ switch (SoftPanel.Button){ case DIN_PAGE: SoftPanel.Page = SOFT_PAGE2; break; case SOFT_EDIT_1: // // do stuff break; case SOFT_EDIT_2: // // do stuff Active_Arp(active_arp_on); break; case SOFT_EDIT_3: // // do stuff Active_Arp(active_arp_off); break; case SOFT_EDIT_4: // // do stuff arp_speed--; break; case SOFT_EDIT_5: // // do stuff arp_speed++; break; case SOFT_EDIT_INC: // increment // break; case SOFT_EDIT_DEC: // decrement // break; } // encoder : set BPM :: WORK :) if(bpm < 50) bpm = 50; if(bpm > 250) bpm = 250; bpm += SoftPanel.EncoderValue; bpm = (unsigned int)MCLOCK_BPMGet()-48; MCLOCK_BPMSet((unsigned char)bpm+48) ; // realtime display feature app_flags.Display_DIN_Req = 1; // MUST HAVE or BPM encoder value not realtime print } else { switch (SoftPanel.Button){ case DIN_PAGE: SoftPanel.Page = SOFT_PAGE1; break; case SOFT_EDIT_5: // increment arp_motif arp_motif++; if(arp_motif > 5) arp_motif = 5; break; case SOFT_EDIT_4: // decrement arp_motif arp_motif--; if(arp_motif > 5) arp_motif = 0; break; case SOFT_EDIT_INC: // increment // do stuff break; case SOFT_EDIT_DEC: // decrement // do stuff break; } // encoder : set BPM :: WORK :) if(bpm < 50) bpm = 50; if(bpm > 250) bpm = 250; bpm += SoftPanel.EncoderValue; bpm = (unsigned int)MCLOCK_BPMGet()-48; MCLOCK_BPMSet((unsigned char)bpm+48) ; // realtime display feature app_flags.Display_DIN_Req = 1; // MUST HAVE or BPM encoder value not realtime print } } mclock.c (the seq core) copied to TK basic clockbox ///////////////////////////////////////////////////////////////////////////// // Include files ///////////////////////////////////////////////////////////////////////////// #include <cmios.h> #include <pic18fregs.h> #include "main.h" #include "mclock.h" #include "device.h" #include "arp.h" #include "din.h" ///////////////////////////////////////////////////////////////////////////// // Global variables ///////////////////////////////////////////////////////////////////////////// mclock_state_t mclock_state; // the mclock state variable mclock_pin_state_t mclock_pin_state; // state of the clock output pin unsigned char mclock_tick_ctr; // requests MIDI clocks unsigned char external_clk_received; // external clock event tag unsigned char bpm; // holds the current BPM setting unsigned char mclock_ctr_24; // counts from 0..23 unsigned char mclock_ctr_beats; // counts the quarter notes 0..3 unsigned char mclock_ctr_measures; // counts the measures (up to 65535) ///////////////////////////////////////////////////////////////////////////// // Local variables ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // This function initializes the MIDI clock module ///////////////////////////////////////////////////////////////////////////// void MCLOCK_Init(void) { mclock_state.ALL = 0; mclock_pin_state.ALL = 0; mclock_tick_ctr = 0; MCLOCK_ResetMeter(); } ///////////////////////////////////////////////////////////////////////////// // This function should be called from USER_Tick to send MIDI clock and // MIDI Clock Start/Stop/Continue ///////////////////////////////////////////////////////////////////////////// void MCLOCK_Tick(void) { // start request? Send 0xfa and enter RUN mode if( mclock_state.START_REQ ) { mclock_state.START_REQ = 0; MIOS_MIDI_TxBufferPut(0xfa); mclock_state.RUN = 1; // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } // continue request? Send 0xfb and release pause if( mclock_state.CONT_REQ ) { mclock_state.CONT_REQ = 0; MIOS_MIDI_TxBufferPut(0xfb); mclock_state.PAUSE = 0; // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } // stop request? Send 0xfc and leave RUN mode if( mclock_state.STOP_REQ ) { mclock_state.STOP_REQ = 0; MIOS_MIDI_TxBufferPut(0xfc); mclock_state.RUN = 0; mclock_state.PAUSE = 0; mclock_tick_ctr = 0; // prevent that any requested 0xf8 will be sent // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } // send 0xf8 until counter is 0 while( mclock_tick_ctr ) { //-------> do not send midi clock to i2c to avoid problem with M1000 : it doesn't like too much data // /* MIOS_MIDI_InterfaceSet(0x00); // route F8 to default midi out MIOS_MIDI_TxBufferPut(0xf8); MIOS_MIDI_InterfaceSet(router_device); */ // decrementing the counter *MUST* be an atomic operation, otherwise it could // conflict with MCLOCK_Timer() // however, I guess that the compiler will generate a single decf instruction, // which is atomic... but better to write it in this way, who knows, how SDCC // will behave in future... INTCONbits.GIE = 0; // disable interrupts --mclock_tick_ctr; INTCONbits.GIE = 1; // enable interrupts // increment the meter counters ARP();//ARPEGGIATOR if( ++mclock_ctr_24 == 24 ) { mclock_ctr_24 = 0; if( ++mclock_ctr_beats == 4 ) { mclock_ctr_beats = 0; ++mclock_ctr_measures; } } // heartbeat tempo led : if(mclock_ctr_24 == 0){ MIOS_DOUT_PinSet1(DIN_ConfigMap[DIN_SHIFT].dout_pin); // HeartBeat }else{ MIOS_DOUT_PinSet0(DIN_ConfigMap[DIN_SHIFT].dout_pin); // indicates Off } // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } } ///////////////////////////////////////////////////////////////////////////// // This function should be called from USER_Timer to update the MIDI clock ///////////////////////////////////////////////////////////////////////////// void MCLOCK_Timer(void) { // just increment a clock counter if in RUN and not in PAUSE mode // it will be decremented in MCLOCK_Tick - each step sends one 0xf8 event // the advantage of this counter is, that a clock event can never get // lost, regardless how much the CPU is loaded // (however, in this application the CPU is very unbusy, but I prepared // this for even more complex programs...) if( mclock_state.RUN && !mclock_state.PAUSE) { ++mclock_tick_ctr; mclock_pin_state.CLK_REQ = 1; } } ///////////////////////////////////////////////////////////////////////////// // This internal function divides 3125000 / BPM // The formula: // -> delay = 60 / BPM * 24 // timer is clocked at 10 MHz, and we are using a 1:8 prescaler // -> timer cycles = ((60/BPM*24)/8) / 100E-9 // -> 3125000 / BPM // // the 24 Bit / 16 Bit division routine has been created by Nikolai Golovchenko, // and is published at: // http://www.piclist.org/techref/microchip/math/div/24by16.htm ///////////////////////////////////////////////////////////////////////////// unsigned char AARGB0; unsigned char AARGB1; unsigned char AARGB2; unsigned char BARGB0; unsigned char BARGB1; unsigned char LOOPCOUNT; unsigned char REMB0; unsigned char REMB1; unsigned int MCLOCK_GetTimerValue(unsigned char bpm) { //;Inputs: //; Dividend - AARGB0:AARGB1:AARGB2 (0 - most significant!) //; Divisor - BARGB0:BARGB1 //;Temporary: //; Counter - LOOPCOUNT //; Remainder- REMB0:REMB1 //;Output: //; Quotient - AARGB0:AARGB1:AARGB2 LOOPCOUNT = 24; AARGB0 = (unsigned char)(3125000L >> 16L); AARGB1 = (unsigned char)(3125000L >> 8L); AARGB2 = (unsigned char)(3125000L >> 0L); BARGB0 = 0; BARGB1 = bpm; REMB0 = 0; REMB0 = 1; __asm banksel _LOOPCOUNT; CLRF _REMB0 CLRF _REMB1 MOVLW 24 MOVWF _LOOPCOUNT LOOPU2416: RLCF _AARGB2, W ;shift dividend left to move next bit to remainder RLCF _AARGB1, F ; RLCF _AARGB0, F ; RLCF _REMB1, F ;shift carry (next dividend bit) into remainder RLCF _REMB0, F RLCF _AARGB2, F ;finish shifting the dividend and save carry in AARGB2.0, ;since remainder can be 17 bit long in some cases ;(e.g. 0x800000/0xFFFF). This bit will also serve ;as the next result bit. MOVF _BARGB1, W ;substract divisor from 16-bit remainder SUBWF _REMB1, F ; MOVF _BARGB0, W ; SKPC ; INCFSZ _BARGB0, W ; SUBWF _REMB0, F ; ;here we also need to take into account the 17th bit of remainder, which ;is in AARGB2.0. If we dont have a borrow after subtracting from lower ;16 bits of remainder, then there is no borrow regardless of 17th bit ;value. But, if we have the borrow, then that will depend on 17th bit ;value. If it is 1, then no final borrow will occur. If it is 0, borrow ;will occur. These values match the borrow flag polarity. SKPNC ;if no borrow after 16 bit subtraction BSF _AARGB2, 0 ;then there is no borrow in result. Overwrite ;AARGB2.0 with 1 to indicate no ;borrow. ;if borrow did occur, AARGB2.0 already ;holds the final borrow value (0-borrow, ;1-no borrow) BTFSC _AARGB2, 0 ;if no borrow after 17-bit subtraction BRA UOK46LL ;skip remainder restoration. ADDWF _REMB0, F ;restore higher byte of remainder. (w ;contains the value subtracted from it ;previously) MOVF _BARGB1, W ;restore lower byte of remainder ADDWF _REMB1, F ; UOK46LL: DECFSZ _LOOPCOUNT, f ;decrement counter BRA LOOPU2416 ;and repeat the loop if not zero. movff _AARGB1, _PRODL movf _AARGB2, W return __endasm; return 0; // dummy return } ///////////////////////////////////////////////////////////////////////////// // These functions are used to set/query the BPM ///////////////////////////////////////////////////////////////////////////// void MCLOCK_BPMSet(unsigned char _bpm) { // re-init timer depending on new BPM value bpm = _bpm; MIOS_TIMER_ReInit(3, MCLOCK_GetTimerValue(bpm)); } unsigned char MCLOCK_BPMGet(void) { return bpm; } ///////////////////////////////////////////////////////////////////////////// // This function resets the mclock_ctr variables ///////////////////////////////////////////////////////////////////////////// void MCLOCK_ResetMeter(void) { mclock_ctr_24 = 0; mclock_ctr_beats = 0; mclock_ctr_measures = 0; } ///////////////////////////////////////////////////////////////////////////// // This function sends the current song position ///////////////////////////////////////////////////////////////////////////// void MCLOCK_SendMeter(void) { unsigned int songpos = (mclock_ctr_beats << 2) | (mclock_ctr_measures << 4); MIOS_MIDI_TxBufferPut(0xf2); MIOS_MIDI_TxBufferPut((unsigned char)(songpos & 0x7f)); MIOS_MIDI_TxBufferPut((unsigned char)(songpos >> 7) & 0x7f); } ///////////////////////////////////////////////////////////////////////////// // These functions are used to control the MCLOCK handler from external ///////////////////////////////////////////////////////////////////////////// void MCLOCK_DoStop(void) { if( mclock_state.RUN == 0 ) { // reset song position of already in stop mode MCLOCK_ResetMeter(); // send Song Position //MCLOCK_SendMeter(); } // request stop mclock_state.STOP_REQ = 1; // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } void MCLOCK_DoPause(void) { // if in RUN mode: if( mclock_state.RUN ) { // toggle pause mode if( mclock_state.PAUSE ) { mclock_state.CONT_REQ = 1; } else { mclock_state.PAUSE = 1; } } else { // Stop mode: just toggle PAUSE mclock_state.PAUSE = mclock_state.PAUSE ? 0 : 1; } // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } void MCLOCK_DoPlay(void) { // reset meter counters MCLOCK_ResetMeter(); // send Song Position //MCLOCK_SendMeter(); // request start mclock_state.START_REQ = 1; // request display update app_flags.DISPLAY_UPDATE_REQ = 1; } main.c (get note from external midi keyboard) ///////////////////////////////////////////////////////////////////////////// // This function is called by MIOS in the mainloop when nothing else is to do ///////////////////////////////////////////////////////////////////////////// void Tick(void) __wparam { // the timing of delayed midi transmits is a low priority LivePanel_HandleTransmitDelay(); // live panel MIDI_HandleMatrixModTransmitDelay(); // from soft panel MIDI_HandleDelayedVoiceParam(); // from soft panel MIDI_HandleFilterSustainTransmitDelay(); // from live panel // this routine sends the MIDI clock (and Start/Continue/Stop) if requested MCLOCK_Tick(); } ///////////////////////////////////////////////////////////////////////////// // This function is periodically called by MIOS. The frequency has to be // initialized with MIOS_Timer_Set ///////////////////////////////////////////////////////////////////////////// void Timer(void) __wparam { LivePanel_BlinkLFOs(); LivePanel_BlinkLEDs(); // forward timer event to MIDI clock module (-> mclock.c) if(external_clk_received == 0){ MCLOCK_Timer(); }else{ } } ///////////////////////////////////////////////////////////////////////////// // 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(); // request display update app_flags.Display_Pot_Req = 0; // start by displaying patches app_flags.Display_DIN_Req = 1; last_din_pin = DIN_PATCH; } ///////////////////////////////////////////////////////////////////////////// // This function is called in the mainloop when no temporary message is shown // on screen. Print the realtime messages here // // the live panel should only display on the lcd when we're in patch mode. ///////////////////////////////////////////////////////////////////////////// void DISPLAY_Tick(void) __wparam { // display encoder movements if( app_flags.Display_ENC_Req ) { if(last_encoder == ENCODER_SOFT) { SoftPanel_DisplayHandler(); } else // dco encoders { if (SoftPanel.Mode == Patch) Encoders_DisplayOscFrequency(last_encoder); } app_flags.Display_ENC_Req = 0; // handled } // display analog pot movements if( app_flags.Display_Pot_Req && SoftPanel.Mode == Patch) { LivePanel_DisplayAin(); app_flags.Display_Pot_Req = 0; // handled } // display buttons if( app_flags.Display_DIN_Req ) { if(DIN_ConfigMap[last_din_pin].group == BUTGRP_LIVE && SoftPanel.Mode == Patch ) LivePanel_DisplayDin(last_din_pin); else SoftPanel_DisplayHandler (); app_flags.Display_DIN_Req = 0; // handled } } ///////////////////////////////////////////////////////////////////////////// // 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 { unsigned char evnt0_; // reNormed midi bytes unsigned char evnt2_; // real note off msg (to use a Roland Juno2 as a keyboard for example): switch(evnt0 & 0xf0){ case 0x90: if(evnt2 == 0){ evnt0_ = (evnt0 - 0x10); evnt2_ = evnt2; } else{ evnt0_ = evnt0; evnt2_ = evnt2; } break; default: evnt0_ = evnt0; evnt2_ = evnt2; break; } Router(evnt0_, evnt1, evnt2_); // see -> device.c Router_Arp(evnt0_, evnt1, evnt2_); // see arp.c } ///////////////////////////////////////////////////////////////////////////// // 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 { static unsigned char fx_status; if(MIDI_ReceivingEditBuffer) { MIDI_HandleEditBuffer(byte); // call HandleEdiBuffer to get EditBuffer param/values } else if(MIDI_ReceivingBank) { MIDI_HandleBankDump(byte); // call HandleBankDump to get EditBuffer of Bank patches } else { // normal MIDI events are forwarded in MPROC_NotifyReceivedEvnt // this function handles sysex and realtime messages if( byte & 0x80 ) { // Status message if( byte >= 0xf0 ) MIOS_MIDI_TxBufferPut(byte); // transfer byte if(byte == 0xf8){ external_clk_received = 1; ++mclock_tick_ctr; // to control the arpegiator clock externally }else{ external_clk_received = 0; } // determine status if( byte == 0xf0 ) { fx_status = 0xff; // forward until 0xf7 } else if( byte == 0xf7 ) { fx_status = 0; // f7 reached, no forward } else if( byte == 0xf1 || byte == 0xf3 ) { fx_status = 1; // expecting one additional byte } else if( byte == 0xf2 ) { fx_status = 2; // expecting two additional bytes } else { fx_status = 0; // expecting no additional byte } } else { // check if fx status active if( fx_status ) { // forward data byte MIOS_MIDI_TxBufferPut(byte); // decrement counter if required if( fx_status != 0xff ) --fx_status; } } } // update display // if(!external_clk_received) // app_flags.Display_DIN_Req = 1; // DON'T WORK MAKE DISPLAY SHINING ALL TIME } The whole project code is available below for reference. Thanks for your help and interest :flowers: MatrixBoxSource_JV_beta v0.80_ext_clk.zip
  9. do you have the right config file on sdcard ?
  10. i did this with a midibox CV. SSM PCB are directly connected to CV of AOUTNG. it works and is controlled by Midi CC just configure MBCV preset for (no need to recompile) If you modify the code you can add pots instead of Gates and directly control cutoff and reso . It is "rather" easy user project, just work with MB CV firmware
  11. if i were you i would : 1 - test Y split cable 2 - take wilba's solution 3 - take nILS's solution 2 & 3 require power (5V) just to remember : MIDI is ok with 7m cable. i tested with 10m cable and it works in low electrical noise environnement PS : look at x0b0x schematic, there is a very simple midi thru using some resistors and one transistor (similar to what wilba describes)
  12. there are free EXS24 patches on logic café website, and they sound good !
  13. Hello Boys does someone know more about that : http://www.raspberrypi.org/ ? Best regards
  14. if you have only inverted Oi (i=0 ... i=7) of 74HC595, i think that you can certainly modify it into application declarations (or define) (i will take a fast look) check this section in setup_808_default.asm : ; ========================================================================== ; Following statements are used to assign LED functions to DOUT pins ; ; To enable a LED function, specify the shift register number SR (1-16), ; and the pin number (0-7). ; Note that Pin 0 is D7 of the DOUT register, Pin 1 is D6, ... Pin 7 is D0 ; ; With SR value = 0, the LED function will be disabled ; ========================================================================== ;; SR ignore Pin LED_SECTION_A EQU ((( 2 -1)<<3)+ 6) LED_SECTION_B EQU ((( 2 -1)<<3)+ 5) LED_SECTION_C EQU ((( 2 -1)<<3)+ 3) LED_SECTION_D EQU ((( 2 -1)<<3)+ 1) ;; SR ignore Pin LED_LAYER_GATE EQU ((( 2 -1)<<3)+ 7) LED_LAYER_AUX EQU ((( 2 -1)<<3)+ 0) ;; SR ignore Pin LED_EDIT EQU ((( 7 -1)<<3)+ 3) LED_MUTE EQU ((( 6 -1)<<3)+ 7) LED_PATTERN EQU ((( 7 -1)<<3)+ 1) LED_SONG EQU ((( 7 -1)<<3)+ 2) ;; SR ignore Pin LED_SOLO EQU ((( 0 -1)<<3)+ 0) LED_FAST EQU ((( 0 -1)<<3)+ 0) LED_ALL EQU ((( 0 -1)<<3)+ 0) ;; SR ignore Pin LED_GROUP1 EQU ((( 0 -1)<<3)+ 0) LED_GROUP2 EQU ((( 0 -1)<<3)+ 0) LED_GROUP3 EQU ((( 0 -1)<<3)+ 0) LED_GROUP4 EQU ((( 0 -1)<<3)+ 0) ;; SR ignore Pin LED_SHIFT EQU ((( 6 -1)<<3)+ 2) LED_ALT EQU ((( 6 -1)<<3)+ 1) ;; SR ignore Pin LED_RECORD EQU ((( 7 -1)<<3)+ 4) LED_BEAT EQU ((( 7 -1)<<3)+ 5) ;; SR ignore Pin LED_PLAY EQU ((( 7 -1)<<3)+ 0) LED_STOP EQU ((( 6 -1)<<3)+ 6) LED_PAUSE EQU ((( 0 -1)<<3)+ 0) LED_FWD EQU ((( 6 -1)<<3)+ 5) LED_REW EQU ((( 6 -1)<<3)+ 4) LED_LIVE EQU ((( 6 -1)<<3)+ 3) ;; SR ignore Pin LED_MIDI_RX EQU (((0 -1)<<3)+ 0) ; OPTIONAL! see CHANGELOG.txt LED_MIDI_TX EQU (((0 -1)<<3)+ 0) ; SR=0 -> disabled by default you will have to edit SR and Pin numbers to fit your design, and then recompile if you need to reassign GP_Led, better ask to someone expert with the dedicated code (like TK)
  15. compte tenu du cout de fabrication d'un appareil pour qu'il ait un peu d'allure, de la cote occaze devenue très démocratique et de ton niveau d'anglais, je te conseille de racheter un controleur existant M Audio commercialise un truc à 100€ assez proche de ce que tu recherches
  16. il existe un enorme fichier mouser en pdf qui n'est autre que le catalogue papier version numerique (300 et Mo) ; les "capuchons" (knobs ) sont à la fin perso j'irais voir du coté d'ebay, sauf si tu choisis les memes capuchons que sur la x0x : pas cher, divers coloris, touché "soft" tres agréable tu peux choisir n'importe quel encodeur, il existe aujourd'hui 5 algorithmes traitant la quasi totalité des modeles existants ; le choix se fera à l'edition du fichier main qui devra etre recompilé ensuite. ceux de voti sont vraiment bien, costauds, démontables (et remontables!) pour les rendre "non detented" . on sent qu'ils resistent à la rotation ce qui permet d'etre precis. le choix sera guidé par le nombre d'impulsions par tour, sachant qu'il y a un algo d'accélération sur la vitesse de rotation (si tu donnes un coup rapide à ton potard les valeurs incrementent plus vite que le nb d'impulsions) je te conseille vivement les boutons de la x0xb0x ou du WilbaSeq : la qualité est très bonne, le toucher exemplaire, le design sobre mais pro tu peux prendre n'importe quel potards, l'ideal étant qu'ils aient la meme valeur et soient à comportement linéaire (type B)
  17. get a PATCH and coloured patchcords : costless, easy to integrate, no electronic it took me 5 years to get one and it is my best invest ... sometimes i am a bit dummy
  18. my advice for desoldering is to use a very thin wire like wrapping wire, passing under the legs, fixing it at the one end and pulling it while heating the legs so that the wire pass under each junction and remove the soldering (am i clear??) search for desoldering whick and flux too. adding lots of soldering can also be a solution to desolder dead IC (so that it stays liquid)
  19. SID V3 will now be based on a new ARM dev board. STM32 is obsolete for that hre 's the 3 days ago topic :
  20. NI has really improved Traktor , following users feedback. You should read again the last manual issue, spend some time on NI forum. I've been really impressed by this software, lots of good idea coming from the "old" way of DJing Moreover, there are keyboard shortcuts :thumbsup: which is the best external controller as it is included into your computer ! Keep in mind that midibox is the way to go ONLY when the MIDI controller doesn't exist. Building something clean, with all the necessary features, takes very long time to newbie. I understand that there are tons of midiboxes that make dreaming, but believe my advises. Cheers :smile:
  21. considering the total price (midi interface, frontpanel, time investment in custom code, building), buying the X1 is certainly the best option the last track of the timecoded vinyl allows you to navigate into your playlist wait half a sec and the track is loaded into corresponding deck certainly the same with Timecode CD
  22. what interests are is the different ways of translating OSC into MIDI SysEx messages I've developped an app OSC on Arduino in order to command relays via a network. it works, i use Max to send strings. my idea is to get an iPad with TouchOSC to send OSC Strings and the Core32 to translate it into MIDI SysEx in order to control old synthesizers like Oberheim Matrix1000. the stuff must be bidirectional this way i can design different control surfaces, for diffferent synths
×
×
  • Create New...