Changeset 92d4404 in matriseq.lv2


Ignore:
Timestamp:
11/08/15 22:58:14 (22 months ago)
Author:
David Robillard <d@…>
Branches:
master
Children:
53f3999
Parents:
d75f8b9
Message:

Rewrite Matriseq for the Launchpad Pro

git-svn-id: http://svn.drobilla.net/lad/trunk/plugins/matriseq@5817 a436a847-0d15-0410-975c-d299462d15a1

Files:
4 deleted
3 edited

Legend:

Unmodified
Added
Removed
  • matriseq.c

    ra92821a r92d4404  
    11/* 
    2   This file is part of Matriseq. 
    3   Copyright 2007-2012 David Robillard <http://drobilla.net/> 
     2  Matriseq, a simple step sequencer for the Launchpad Pro. 
     3  Copyright 2007-2015 David Robillard <http://drobilla.net/> 
    44 
    55  Matriseq is free software: you can redistribute it and/or modify it under the 
     
    2222#include <string.h> 
    2323 
    24 #include "naub/naub.h" 
    25 #include "zix/thread.h" 
    26 #include "zix/ring.h" 
    27  
    2824#include "lv2/lv2plug.in/ns/ext/atom/forge.h" 
    2925#include "lv2/lv2plug.in/ns/ext/log/log.h" 
     26#include "lv2/lv2plug.in/ns/ext/log/logger.h" 
    3027#include "lv2/lv2plug.in/ns/ext/midi/midi.h" 
    3128#include "lv2/lv2plug.in/ns/ext/time/time.h" 
     
    3835#define GRID_W    8 
    3936#define SEQ_H     (8 * 8) 
     37#define SEQ_W     16 
    4038#define NOTE_MIN  28 
    4139#define STEP_TYPE 16 
    4240#define RING_SIZE 4096 
    4341 
     42static const uint8_t msg_set_col[]   = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xC }; 
     43static const uint8_t msg_set_row[]   = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xD }; 
     44static const uint8_t msg_show_text[] = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0x14 }; 
     45static const uint8_t msg_light_led[] = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xA }; 
     46 
    4447typedef enum { 
    45     MATRISEQ_IN  = 0, 
    46     MATRISEQ_OUT = 1 
     48    BLACK      = 0, 
     49    DARK_GREY  = 1, 
     50    LIGHT_GREY = 2, 
     51    WHITE      = 3, 
     52    RED        = 5, 
     53    YELLOW     = 13, 
     54    DARK_GREEN = 15, 
     55    GREEN      = 21 
     56} Color; 
     57 
     58typedef enum { 
     59    MATRISEQ_CONTROL_IN  = 0, 
     60    MATRISEQ_CONTROL_OUT = 1, 
     61    MATRISEQ_PLAYBACK    = 2 
    4762} PortIndex; 
     63 
     64typedef enum { 
     65    BOTTOM_1 = 1, 
     66    BOTTOM_2 = 2, 
     67    BOTTOM_3 = 3, 
     68    BOTTOM_4 = 4, 
     69    BOTTOM_5 = 5, 
     70    BOTTOM_6 = 6, 
     71    BOTTOM_7 = 7, 
     72    BOTTOM_8 = 8, 
     73    LEFT_1   = 10, 
     74    LEFT_2   = 20, 
     75    LEFT_3   = 30, 
     76    LEFT_4   = 40, 
     77    LEFT_5   = 50, 
     78    LEFT_6   = 60, 
     79    LEFT_7   = 70, 
     80    LEFT_8   = 80, 
     81    RIGHT_1  = 19, 
     82    RIGHT_2  = 29, 
     83    RIGHT_3  = 39, 
     84    RIGHT_4  = 49, 
     85    RIGHT_5  = 59, 
     86    RIGHT_6  = 69, 
     87    RIGHT_7  = 79, 
     88    RIGHT_8  = 89, 
     89    TOP_1    = 91, 
     90    TOP_2    = 92, 
     91    TOP_3    = 93, 
     92    TOP_4    = 94, 
     93    TOP_5    = 95, 
     94    TOP_6    = 96, 
     95    TOP_7    = 97, 
     96    TOP_8    = 98, 
     97    TOP_9    = 99 
     98} ButtonID; 
    4899 
    49100// URIDs used by this plugin 
     
    61112typedef struct { 
    62113    // Port buffers 
    63     LV2_Atom_Sequence* in; 
    64     LV2_Atom_Sequence* out; 
     114    LV2_Atom_Sequence* control_in; 
     115    LV2_Atom_Sequence* control_out; 
     116    LV2_Atom_Sequence* playback; 
    65117 
    66118    // Features 
     
    68120    LV2_Log_Log*  log; 
    69121 
    70     // LV2 stuff 
    71     LV2_Atom_Forge forge; 
     122    LV2_Log_Logger logger; 
     123    LV2_Atom_Forge control_forge; 
     124    LV2_Atom_Forge playback_forge; 
    72125    MatriseqURIs   uris; 
    73  
    74     // USB stuff 
    75     NaubWorld* naub; 
    76     ZixRing*   ring; 
    77     ZixThread  thread; 
    78     bool       exit; 
    79126 
    80127    // State 
     
    87134    uint8_t  page_x; 
    88135    uint8_t  page_y; 
    89     uint32_t seq[SEQ_H][STEP_TYPE]; 
     136    uint32_t seq[SEQ_H][SEQ_W]; 
     137    uint32_t last_inquiry; 
     138    bool     refresh; 
     139    bool     attached; 
    90140} Matriseq; 
    91  
    92 // Log a message to the host if available, or stderr otherwise. 
    93 LV2_LOG_FUNC(3, 4) 
    94 static void 
    95 print(Matriseq* self, LV2_URID type, const char* fmt, ...) 
    96 { 
    97     va_list args; 
    98     va_start(args, fmt); 
    99     if (self->log) { 
    100         self->log->vprintf(self->log->handle, type, fmt, args); 
    101     } else { 
    102         vfprintf(stderr, fmt, args); 
    103     } 
    104     va_end(args); 
    105 } 
    106141 
    107142static LV2_Handle 
     
    125160    } 
    126161    if (!self->map) { 
    127         print(self, self->uris.log_Error, "Missing feature urid:map.\n"); 
     162        lv2_log_error(&self->logger, "Missing feature urid:map\n"); 
    128163        free(self); 
    129164        return NULL; 
     
    140175    self->uris.time_beatsPerMinute = map->map(map->handle, LV2_TIME__beatsPerMinute); 
    141176    self->uris.time_speed          = map->map(map->handle, LV2_TIME__speed); 
    142     lv2_atom_forge_init(&self->forge, self->map); 
    143  
    144     // Initialise USB stuff 
    145     self->naub = NULL; 
    146     self->ring = zix_ring_new(RING_SIZE); 
     177    lv2_atom_forge_init(&self->control_forge, self->map); 
     178    lv2_atom_forge_init(&self->playback_forge, self->map); 
     179    lv2_log_logger_init(&self->logger, self->map, self->log); 
    147180 
    148181    // Initialise state 
    149182    self->rate          = rate; 
    150183    self->bpm           = 140.0f; 
    151     self->speed         = 0.0f; 
     184    //self->speed         = 0.0f; 
     185    self->speed         = 1.0f; 
    152186    self->beats_per_bar = 4; 
    153187    self->page_y        = 1;  // Start at note 36 (kick) 
    154  
    155     zix_ring_mlock(self->ring); 
    156188 
    157189    return (LV2_Handle)self; 
     
    166198 
    167199    switch ((PortIndex)port) { 
    168     case MATRISEQ_IN: 
    169         self->in = (LV2_Atom_Sequence*)data; 
     200    case MATRISEQ_CONTROL_IN: 
     201        self->control_in = (LV2_Atom_Sequence*)data; 
    170202        break; 
    171     case MATRISEQ_OUT: 
    172         self->out = (LV2_Atom_Sequence*)data; 
     203    case MATRISEQ_CONTROL_OUT: 
     204        self->control_out = (LV2_Atom_Sequence*)data; 
    173205        break; 
     206    case MATRISEQ_PLAYBACK: 
     207        self->playback = (LV2_Atom_Sequence*)data; 
     208        break; 
    174209    } 
    175210} 
    176211 
    177212static uint32_t* 
    178 get_cell(Matriseq* self, NaubControlID control) 
    179 { 
    180     const uint32_t x = (self->page_x * GRID_W) + control.x; 
    181     const uint32_t y = (self->page_y * GRID_H) + (7 - control.y); 
    182     return &self->seq[y][x]; 
    183 } 
    184  
    185 static void 
    186 set_button(Matriseq* self, NaubControlID control, bool active) 
    187 { 
    188     int32_t value = 0; 
    189     if (*get_cell(self, control)) { 
    190         value = active ? naub_rgb(1, 0, 0) : naub_rgb(1, 1, 0); 
    191     } else { 
    192         value = active ? naub_rgb(0, 0.4, 0) : naub_rgb(0, 0, 0); 
    193     } 
    194     naub_set_control(self->naub, control, value); 
    195 } 
    196  
    197 static void 
    198 set_column(Matriseq* self, uint32_t step, bool active) 
    199 { 
    200     for (int y = 0; y < 8; ++y) { 
    201         const NaubControlID control = { 0, 0, step % GRID_W, y }; 
    202         set_button(self, control, active); 
    203     } 
    204 } 
    205  
    206 static void 
    207 set_page_indicators(Matriseq* self) 
    208 { 
    209     const NaubControlID page_x_but = { 0, 1, self->page_x, 0 }; 
    210     const NaubControlID page_y_but = { 0, 2, 0, 7 - self->page_y }; 
    211     naub_set_control(self->naub, page_x_but, naub_rgb(0, 1, 0)); 
    212     naub_set_control(self->naub, page_y_but, naub_rgb(0, 1, 0)); 
    213 } 
    214  
    215 static void 
    216 show_page(Matriseq* self) 
    217 { 
     213get_cell(Matriseq* self, uint8_t pad_x, uint8_t pad_y) 
     214{ 
     215    const uint32_t seq_x = (self->page_x * GRID_W) + pad_x; 
     216    const uint32_t seq_y = (self->page_y * GRID_H) + pad_y; 
     217    return &self->seq[seq_y][seq_x]; 
     218} 
     219 
     220static void 
     221on_button(Matriseq* self, uint8_t num, uint8_t value) 
     222{ 
     223    if (!value) { 
     224        return;  // Ignore button release 
     225    } 
     226 
     227    if (num == TOP_1 && self->page_y < 7) {  // Page up 
     228        ++self->page_y; 
     229        self->refresh = true; 
     230    } else if (num == TOP_2 && self->page_y > 0) {  // Page down 
     231        --self->page_y; 
     232        self->refresh = true; 
     233    } else if (num == TOP_3 && self->page_x > 0) {  // Page left 
     234        --self->page_x; 
     235        self->refresh = true; 
     236    } else if (num == TOP_4 && self->page_x < 1) {  // Page right 
     237        ++self->page_x; 
     238        self->refresh = true; 
     239    } else if (num % 10 == 9) {  // Right button column 
     240        self->page_y = num / 10 - 1; 
     241        self->refresh = true; 
     242    } else if (num <= BOTTOM_8) {  // Bottom button row 
     243        if ((num - 1) * GRID_W < SEQ_W) { 
     244            self->page_x = num - 1; 
     245            self->refresh = true; 
     246        } 
     247    } 
     248} 
     249 
     250static void 
     251write_control(Matriseq* self, uint32_t t, const uint8_t* msg, uint32_t n) 
     252{ 
     253    lv2_atom_forge_frame_time(&self->control_forge, t); 
     254    lv2_atom_forge_atom(&self->control_forge, n, self->uris.midi_MidiEvent); 
     255    lv2_atom_forge_write(&self->control_forge, msg, n); 
     256} 
     257 
     258/** Pad on the central 8x8 grid pressed. */ 
     259static void 
     260on_pad(Matriseq* self, uint32_t t, uint8_t x, uint8_t y, uint8_t vel) 
     261{ 
     262    if (vel > 0) { 
     263        // Flip sequence cell 
     264        uint32_t* cell = get_cell(self, x, y); 
     265        *cell = !*cell; 
     266 
     267        // Illuminate pad 
     268        const uint8_t msg[] = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xA, 
     269                                (y + 1) * 10 + x + 1, 
     270                                *cell ? GREEN : BLACK, 
     271                                0xF7 }; 
     272 
     273        write_control(self, t, msg, sizeof(msg)); 
     274    } 
     275} 
     276 
     277static uint8_t 
     278step_button_color(Matriseq* self, uint8_t step, uint8_t col) 
     279{ 
     280    const uint32_t page_begin = self->page_x * 8; 
     281    const uint32_t page_end   = (self->page_x + 1) * 8; 
     282 
     283    if (step >= page_begin && step < page_end && step % 8 == col) { 
     284        return GREEN; 
     285    } else if (self->page_x == col) { 
     286        return DARK_GREY; 
     287    } 
     288    return BLACK; 
     289} 
     290 
     291/** Display scrolling text banner. */ 
     292static void 
     293pad_show_text(Matriseq* self, uint32_t t, const char* text) 
     294{ 
     295    const size_t len = strlen(text); 
     296    uint8_t msg[sizeof(msg_show_text) + 3 + len + 1]; 
     297    memcpy(msg, msg_show_text, sizeof(msg_show_text)); 
     298 
     299    uint8_t* ptr = msg + sizeof(msg_show_text); 
     300    *ptr++ = DARK_GREY;  // Text color 
     301    *ptr++ = 0;          // Loop 
     302    *ptr++ = 7;          // Speed (1-7) 
     303    memcpy((char*)ptr, text, len); 
     304    ptr += len; 
     305    *ptr++ = 0xF7; 
     306    write_control(self, t, msg, sizeof(msg)); 
     307} 
     308 
     309/** Update step indicators when the page has not changed. */ 
     310static void 
     311pad_update_step(Matriseq* self, uint32_t t, uint32_t old_step, uint32_t new_step) 
     312{ 
     313    // Turn off old step indicator 
     314    const uint8_t off_msg[] = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xA, 
     315                                old_step % 8 + 1, 
     316                                step_button_color(self, new_step, old_step % 8), 
     317                                0xF7 }; 
     318    write_control(self, t, off_msg, sizeof(off_msg)); 
     319 
     320    // Turn on new step indicator 
     321    const uint8_t on_msg[] = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xA, 
     322                               new_step % 8 + 1, 
     323                               step_button_color(self, new_step, new_step % 8), 
     324                               0xF7 }; 
     325    write_control(self, t, on_msg, sizeof(on_msg)); 
     326} 
     327 
     328/** Refresh page and step indicators. */ 
     329static void 
     330pad_refresh_position(Matriseq* self, uint32_t t) 
     331{ 
     332    // Set bottom horizontal tick/page indicators 
     333    uint8_t xmsg[sizeof(msg_set_row) + 11]; 
     334    memcpy(xmsg, msg_set_row, sizeof(msg_set_row)); 
     335 
     336    uint8_t* ptr = xmsg + sizeof(msg_set_row); 
     337    *ptr++ = 0;  // Row number 0 (bottom) 
     338    *ptr++ = 0;  // Non-existent bottom left button color 
     339    for (int i = 0; i < 8; ++i) { 
     340        *ptr++ = step_button_color(self, self->step, i); 
     341    } 
     342    *ptr++ = 0xF7; 
     343    write_control(self, t, xmsg, sizeof(xmsg)); 
     344 
     345    // Set right vertical page indicators 
     346    uint8_t ymsg[sizeof(msg_set_col) + 11]; 
     347    memcpy(ymsg, msg_set_col, sizeof(msg_set_col)); 
     348 
     349    ptr = ymsg + sizeof(msg_set_col); 
     350    *ptr++ = 9;  // Column number 9 (right) 
     351    *ptr++ = 0;  // Non-existent bottom right button color 
     352    for (int i = 0; i < 8; ++i) { 
     353        *ptr++ = self->page_y == i ? DARK_GREY : BLACK; 
     354    } 
     355    *ptr++ = 0xF7; 
     356    write_control(self, t, ymsg, sizeof(ymsg)); 
     357} 
     358 
     359static void 
     360pad_clear(Matriseq* self, uint32_t t) 
     361{ 
     362    const uint8_t msg[] = { 0xF0, 0x00, 0x20, 0x29, 0x02, 0x10, 0xE, 0, 0xF7 }; 
     363    write_control(self, t, msg, sizeof(msg)); 
     364} 
     365 
     366static void 
     367pad_refresh_grid(Matriseq* self, uint32_t t) 
     368{ 
     369    uint8_t msg[136]; 
     370    memcpy(msg, msg_light_led, sizeof(msg_light_led)); 
     371    uint8_t* ptr = msg + sizeof(msg_light_led); 
    218372    for (uint32_t y = 0; y < 8; ++y) { 
    219373        for (uint32_t x = 0; x < 8; ++x) { 
    220             const NaubControlID control = { 0, 0, x, y }; 
    221             set_button(self, control, x == self->step); 
     374            const uint32_t gx = (self->page_x * GRID_W) + x; 
     375            const uint32_t gy = (self->page_y * GRID_H) + y; 
     376 
     377            *ptr++ = (y + 1) * 10 + x + 1; 
     378            *ptr++ = self->seq[gy][gx] ? GREEN : BLACK; 
    222379        } 
    223380    } 
    224 } 
    225  
    226 static void 
    227 pad_event(void* instance, const NaubEvent* event) 
    228 { 
    229     Matriseq* self = (Matriseq*)instance; 
    230     if (event->type != NAUB_EVENT_BUTTON) {  // Odd... 
    231         return; 
    232     } 
    233  
    234     const NaubControlID control = event->button.control; 
    235  
    236     if (control.group == 1 && event->button.pressed) { 
    237         const NaubControlID old_page_x_but = { 0, 1, self->page_x, 0 }; 
    238         const NaubControlID old_page_y_but = { 0, 2, 0, 7 - self->page_y }; 
    239         if (control.x == 0 && self->page_y < 7) { 
    240             ++self->page_y; 
    241         } else if (control.x == 1 && self->page_y > 0) { 
    242             --self->page_y; 
    243         } else if (control.x == 2 && self->page_x > 0) { 
    244             --self->page_x; 
    245         } else if (control.x == 3 && self->page_x < 1) { 
    246             ++self->page_x; 
    247         } else { 
    248             return; 
    249         } 
    250  
    251         // Turn off old page indicator buttons 
    252         naub_set_control(self->naub, old_page_x_but, naub_rgb(0, 0, 0)); 
    253         naub_set_control(self->naub, old_page_y_but, naub_rgb(0, 0, 0)); 
    254  
    255         // Turn on new page indicator buttons 
    256         set_page_indicators(self); 
    257  
    258         // Update grid display 
    259         show_page(self); 
    260     } else if (control.group == 0) { 
    261         if (event->button.pressed) { 
    262             naub_set_control(self->naub, control, naub_rgb(1, 0, 0)); 
    263         } else { 
    264             uint32_t* cell = get_cell(self, control); 
    265             *cell = *cell ? 0 : 1; 
    266             set_button(self, control, self->step == control.y); 
    267         } 
    268     } 
    269  
    270     naub_flush(self->naub); 
    271 } 
    272  
    273 static void* 
    274 pad_thread(void* instance) 
    275 { 
    276     Matriseq* self = (Matriseq*)instance; 
    277     uint32_t  step = self->step; 
    278  
    279     // Initialise pad 
    280     set_page_indicators(self); 
    281     set_column(self, step, true); 
    282     naub_flush(self->naub); 
    283  
    284     while (!naub_handle_events_timeout(self->naub, 10) && !self->exit) { 
    285         uint32_t new_step; 
    286         if (zix_ring_read_space(self->ring) >= sizeof(new_step)) { 
    287             zix_ring_read(self->ring, &new_step, sizeof(new_step)); 
    288  
    289             const uint32_t begin = self->page_x * GRID_W; 
    290             const uint32_t end   = (self->page_x + 1) * GRID_W; 
    291  
    292             // De-highlight old active row 
    293             if (step >= begin && step < end) { 
    294                 set_column(self, step, false); 
    295             } 
    296  
    297             // Highlight new active row 
    298             if (new_step >= begin && new_step < end) { 
    299                 set_column(self, new_step, true); 
    300             } 
    301  
    302             // Send bulk update to device 
    303             naub_flush(self->naub); 
    304  
    305             step = new_step; 
    306         } 
    307     } 
    308     return NULL; 
    309 } 
    310  
    311 static void 
    312 activate(LV2_Handle instance) 
    313 { 
    314     Matriseq* self = (Matriseq*)instance; 
    315     self->naub = naub_world_new(self, pad_event); 
    316     if (self->naub) { 
    317         if (!naub_world_open( 
    318                 self->naub, NAUB_VENDOR_NOVATION, NAUB_PRODUCT_LAUNCHPAD)) { 
    319             if (zix_thread_create(&self->thread, 1024, pad_thread, self)) { 
    320                 print(self, self->uris.log_Error, "Failed to create thread\n"); 
    321                 return; 
    322             } 
    323         } else { 
    324             print(self, self->uris.log_Error, "Failed to open controller\n"); 
    325         } 
    326     } 
     381 
     382    *ptr++ = 0xF7; 
     383    write_control(self, t, msg, sizeof(msg)); 
     384} 
     385 
     386static void 
     387send_device_inquiry(Matriseq* self, uint32_t t) 
     388{ 
     389    const uint8_t msg[] = { 0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7 }; 
     390    write_control(self, t, msg, sizeof(msg)); 
     391    self->last_inquiry = self->time_frames; 
    327392} 
    328393 
     
    336401    const float s_per_step = s_per_beat * self->beats_per_bar / STEP_TYPE; 
    337402 
    338     // Prepare for writing to out port 
    339     const uint32_t out_capacity = self->out->atom.size; 
    340     lv2_atom_forge_set_buffer(&self->forge, (uint8_t*)self->out, out_capacity); 
    341  
    342     // Initialise output port to empty sequence 
    343     LV2_Atom_Forge_Frame out_frame; 
    344     lv2_atom_forge_sequence_head(&self->forge, &out_frame, 0); 
     403    // Set output buffers for forges 
     404    lv2_atom_forge_set_buffer( 
     405        &self->control_forge, (uint8_t*)self->control_out, self->control_out->atom.size); 
     406    lv2_atom_forge_set_buffer( 
     407        &self->playback_forge, (uint8_t*)self->playback, self->playback->atom.size); 
     408 
     409    // Initialise outputs to empty sequence 
     410    LV2_Atom_Forge_Frame control_frame; 
     411    LV2_Atom_Forge_Frame playback_frame; 
     412    lv2_atom_forge_sequence_head(&self->control_forge, &control_frame, 0); 
     413    lv2_atom_forge_sequence_head(&self->playback_forge, &playback_frame, 0); 
     414 
     415    if (!self->attached && self->time_frames - self->last_inquiry > self->rate) { 
     416        // Haven't heard from Launchpad, send device inquiry once a second 
     417        send_device_inquiry(self, 0); 
     418    } 
    345419 
    346420    // Work forwards in time frame by frame, handling events as we go 
    347     const LV2_Atom_Sequence* in = self->in; 
     421    const LV2_Atom_Sequence* in = self->control_in; 
    348422    const LV2_Atom_Event*    ev = lv2_atom_sequence_begin(&in->body); 
    349423    for (uint32_t t = 0; t < n_frames; ++t) { 
     
    372446                    } 
    373447                } 
     448            } else if (ev->body.type == uris->midi_MidiEvent) { 
     449                const uint8_t* const msg = (const uint8_t*)(ev + 1); 
     450                switch (lv2_midi_message_type(msg)) { 
     451                case LV2_MIDI_MSG_NOTE_ON: 
     452                    on_pad(self, t, msg[1] % 10 - 1, msg[1] / 10 - 1, msg[2]); 
     453                    break; 
     454                case LV2_MIDI_MSG_CONTROLLER: 
     455                    on_button(self, msg[1], msg[2]); 
     456                    break; 
     457                case LV2_MIDI_MSG_SYSTEM_EXCLUSIVE: 
     458                    if (msg[1] == 0x7E) { 
     459                        // Launchpad responded to device inquiry, initialise 
     460                        pad_clear(self, t); 
     461                        pad_refresh_position(self, t); 
     462                        pad_refresh_grid(self, t); 
     463                        pad_show_text(self, t, "Matriseq"); 
     464                        self->attached = true; 
     465                    } 
     466                default: 
     467                    break; 
     468                } 
    374469            } 
    375470 
     
    381476        if (step != self->step) { 
    382477            // Update step 
     478            const uint32_t last_step = self->step; 
     479            pad_update_step(self, t, self->step, step); 
    383480            self->step = step; 
    384481            if (step == 0) { 
     
    386483            } 
    387484 
    388             // Notify USB thread of new step 
    389             zix_ring_write(self->ring, &self->step, sizeof(self->step)); 
     485            // Send note offs for enabled notes last step 
     486            for (uint32_t y = 0; y < SEQ_H; ++y) { 
     487                if (self->seq[y][last_step]) { 
     488                    const uint8_t off[] = { 0x80, NOTE_MIN + y, 0x40 }; 
     489                    lv2_atom_forge_frame_time(&self->playback_forge, t); 
     490                    lv2_atom_forge_atom(&self->playback_forge, 3, self->uris.midi_MidiEvent); 
     491                    lv2_atom_forge_write(&self->playback_forge, off, 3); 
     492                } 
     493            } 
    390494 
    391495            // Send note ons for enabled notes this step 
     
    393497                if (self->seq[y][step]) { 
    394498                    const uint8_t on[] = { 0x90, NOTE_MIN + y, 0x40 }; 
    395                     lv2_atom_forge_frame_time(&self->forge, t); 
    396                     lv2_atom_forge_atom(&self->forge, 3, self->uris.midi_MidiEvent); 
    397                     lv2_atom_forge_write(&self->forge, on, 3); 
     499                    lv2_atom_forge_frame_time(&self->playback_forge, t); 
     500                    lv2_atom_forge_atom(&self->playback_forge, 3, self->uris.midi_MidiEvent); 
     501                    lv2_atom_forge_write(&self->playback_forge, on, 3); 
    398502                } 
    399503            } 
     
    404508        } 
    405509    } 
    406 } 
    407  
    408 static void 
    409 deactivate(LV2_Handle instance) 
    410 { 
    411     Matriseq* self = (Matriseq*)instance; 
    412     self->exit = true; 
    413     void* thread_ret = NULL; 
    414     zix_thread_join(self->thread, &thread_ret); 
    415     naub_world_free(self->naub); 
    416     self->naub = NULL; 
     510 
     511    if (self->refresh) { 
     512        pad_refresh_position(self, n_frames - 1); 
     513        pad_refresh_grid(self, n_frames - 1); 
     514        self->refresh = false; 
     515    } 
    417516} 
    418517 
     
    420519cleanup(LV2_Handle instance) 
    421520{ 
    422     Matriseq* self = (Matriseq*)instance; 
    423     zix_ring_free(self->ring); 
    424     free(self); 
     521    free(instance); 
    425522} 
    426523 
     
    435532    instantiate, 
    436533    connect_port, 
    437     activate, 
     534    NULL, 
    438535    run, 
    439     deactivate, 
     536    NULL, 
    440537    cleanup, 
    441538    extension_data 
    442539}; 
    443540 
    444 LV2_SYMBOL_EXPORT 
    445 const LV2_Descriptor* 
     541LV2_SYMBOL_EXPORT const LV2_Descriptor* 
    446542lv2_descriptor(uint32_t index) 
    447543{ 
    448     switch (index) { 
    449     case 0: 
    450         return &descriptor; 
    451     default: 
    452         return NULL; 
    453     } 
    454 } 
     544    return (index == 0) ? &descriptor : NULL; 
     545} 
  • matriseq.ttl

    r610ed8d r92d4404  
    66@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . 
    77@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . 
     8@prefix rsz: <http://lv2plug.in/ns/ext/resize-port#> . 
    89@prefix time: <http://lv2plug.in/ns/ext/time#> . 
    910 
     
    2526            atom:AtomPort ; 
    2627        atom:bufferType atom:Sequence ; 
    27         atom:supports time:Position ; 
     28        atom:supports time:Position, midi:MidiEvent ; 
    2829        lv2:index 0 ; 
    29         lv2:symbol "in" ; 
    30         lv2:name "In" 
     30        lv2:symbol "control_in" ; 
     31        lv2:name "Control In" 
    3132    ] , [ 
    3233        a lv2:OutputPort , 
     
    3435        atom:bufferType atom:Sequence ; 
    3536        atom:supports midi:MidiEvent ; 
     37        rsz:minimumSize 4096 ; 
    3638        lv2:index 1 ; 
    37         lv2:symbol "out" ; 
    38         lv2:name "Out" 
     39        lv2:symbol "control_out" ; 
     40        lv2:name "Control Out" ; 
     41    ] , [ 
     42        a lv2:OutputPort , 
     43            atom:AtomPort ; 
     44        atom:bufferType atom:Sequence ; 
     45        atom:supports midi:MidiEvent ; 
     46        rsz:minimumSize 4096 ; 
     47        lv2:index 2 ; 
     48        lv2:symbol "playback" ; 
     49        lv2:name "Playback" 
    3950    ] . 
  • wscript

    rfcb5631 r92d4404  
    11#!/usr/bin/env python 
    22import waflib.extras.autowaf as autowaf 
     3import re 
    34 
    45MATRISEQ_VERSION = '1.0.0' 
     
    2324 
    2425    autowaf.check_pkg(conf, 'lv2', atleast_version='1.0.0', uselib_store='LV2') 
    25     autowaf.check_pkg(conf, 'naub-0', atleast_version='0.0.0', uselib_store='NAUB') 
    26  
    27     # Check for mlock 
    28     conf.check(function_name='mlock', 
    29                header_name='sys/mman.h', 
    30                define_name='HAVE_MLOCK', 
    31                mandatory=False) 
    3226 
    3327    # Set env.pluginlib_PATTERN 
     
    5953            LIB_EXT      = bld.env.pluginlib_EXT) 
    6054 
    61     # Create a build environment that builds module-style library names 
    62     # e.g. matriseq.so instead of libmatriseq.so 
    63     # Note for C++ you must set cxxshlib_PATTERN instead 
    64     penv                = bld.env.derive() 
    65     penv.cshlib_PATTERN = bld.env.pluginlib_PATTERN 
    66  
    6755    # Build plugin library 
    6856    obj = bld(features     = 'c cshlib', 
    69               env          = penv, 
    70               source       = ['matriseq.c', 'zix/ring.c'], 
     57              source       = ['matriseq.c'], 
    7158              name         = 'matriseq', 
    7259              target       = '%s/matriseq' % bundle, 
     
    7461              includes     = ['.'], 
    7562              lib          = ['pthread']) 
    76     autowaf.use_lib(bld, obj, 'LV2 NAUB') 
     63    autowaf.use_lib(bld, obj, 'LV2') 
     64    obj.env.cshlib_PATTERN = re.sub('^lib', '', bld.env.cshlib_PATTERN) 
    7765 
Note: See TracChangeset for help on using the changeset viewer.