Subversion Repositories svn.mios32

Rev

Rev 2605 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
184 tk 1
// $Id: seq_pattern.c 2633 2019-01-04 11:10:04Z tk $
2
/*
3
 * Pattern Routines
4
 *
5
 * ==========================================================================
6
 *
7
 *  Copyright (C) 2008 Thorsten Klose (tk@midibox.org)
8
 *  Licensed for personal non-commercial use only.
9
 *  All other rights reserved.
10
 *
11
 * ==========================================================================
12
 */
13
 
14
/////////////////////////////////////////////////////////////////////////////
15
// Include files
16
/////////////////////////////////////////////////////////////////////////////
17
 
18
#include <mios32.h>
19
 
690 tk 20
#include <seq_bpm.h>
21
 
184 tk 22
#include "tasks.h"
23
 
24
#include "seq_pattern.h"
336 tk 25
#include "seq_cc.h"
184 tk 26
#include "seq_core.h"
193 tk 27
#include "seq_ui.h"
1123 tk 28
#include "seq_file.h"
248 tk 29
#include "seq_file_b.h"
944 tk 30
#include "seq_statistics.h"
1117 tk 31
#include "seq_song.h"
1493 tk 32
#include "seq_mixer.h"
184 tk 33
 
34
 
35
/////////////////////////////////////////////////////////////////////////////
36
// Local defines
37
/////////////////////////////////////////////////////////////////////////////
38
 
39
// set this to 1 if performance of pattern handler should be measured with a scope
40
// (LED toggling in APP_Background() has to be disabled!)
290 tk 41
#define LED_PERFORMANCE_MEASURING 0
184 tk 42
 
290 tk 43
// same for measuring with the stopwatch
747 tk 44
// value is visible in INFO->System page (-> press exit button, go to last item)
961 tk 45
#define STOPWATCH_PERFORMANCE_MEASURING 0
184 tk 46
 
47
 
1983 tk 48
// debug messages on pattern req/load for time measurements
49
#define CHECK_PATTERN_REQ_LOAD_TIMINGS 0
50
 
51
 
184 tk 52
/////////////////////////////////////////////////////////////////////////////
53
// Global variables
54
/////////////////////////////////////////////////////////////////////////////
55
 
56
seq_pattern_t seq_pattern[SEQ_CORE_NUM_GROUPS];
788 tk 57
seq_pattern_t seq_pattern_req[SEQ_CORE_NUM_GROUPS];
252 tk 58
char seq_pattern_name[SEQ_CORE_NUM_GROUPS][21];
184 tk 59
 
1454 midilab 60
mios32_sys_time_t seq_pattern_start_time;
61
u8 seq_pattern_mixer_num;
62
u16 seq_pattern_remix_map;
184 tk 63
 
64
/////////////////////////////////////////////////////////////////////////////
65
// Initialisation
66
/////////////////////////////////////////////////////////////////////////////
67
s32 SEQ_PATTERN_Init(u32 mode)
68
{
1454 midilab 69
  seq_pattern_start_time.seconds = 0;
70
  seq_pattern_mixer_num = 0;
71
  seq_pattern_remix_map = 0;
72
 
184 tk 73
  // pre-init pattern numbers
74
  u8 group;
75
  for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
76
    seq_pattern[group].ALL = 0;
249 tk 77
#if 0
184 tk 78
    seq_pattern[group].group = 2*group; // A/C/E/G
249 tk 79
#else
80
    seq_pattern[group].bank = group; // each group has it's own bank
81
#endif
184 tk 82
    seq_pattern_req[group].ALL = 0;
252 tk 83
 
84
#if 0
85
    sprintf((char *)seq_pattern_name[group], "Pattern %c%d          ", ('A'+((pattern>>3)&7)), (pattern&7)+1);
86
#else
87
    // if pattern name only contains spaces, the UI will print 
88
    // the pattern number instead of an empty message
89
    // this ensures highest flexibility (e.g. any pattern can be copied to another slot w/o name inconsistencies)
90
    // -> see SEQ_LCD_PrintPatternName()
91
    int i;
92
    for(i=0; i<20; ++i)
93
      seq_pattern_name[group][i] = ' ';
94
    seq_pattern_name[group][20] = 0;
95
#endif
96
 
184 tk 97
  }
98
 
299 tk 99
#if STOPWATCH_PERFORMANCE_MEASURING
944 tk 100
  SEQ_STATISTICS_StopwatchInit();
299 tk 101
#endif
102
 
184 tk 103
  return 0; // no error
104
}
105
 
106
 
107
/////////////////////////////////////////////////////////////////////////////
280 tk 108
// Returns the name of a pattern (20 characters)
109
/////////////////////////////////////////////////////////////////////////////
110
char *SEQ_PATTERN_NameGet(u8 group)
111
{
112
  if( group >= SEQ_CORE_NUM_GROUPS )
113
    return "<invalid group>     ";
114
  return seq_pattern_name[group];
115
}
116
 
117
 
118
/////////////////////////////////////////////////////////////////////////////
184 tk 119
// Requests a pattern change
120
/////////////////////////////////////////////////////////////////////////////
1117 tk 121
s32 SEQ_PATTERN_Change(u8 group, seq_pattern_t pattern, u8 force_immediate_change)
184 tk 122
{
123
  if( group >= SEQ_CORE_NUM_GROUPS )
124
    return -1; // invalid group
125
 
126
  // change immediately if sequencer not running
1117 tk 127
  if( force_immediate_change || !SEQ_BPM_IsRunning() || SEQ_BPM_TickGet() == 0 || ui_seq_pause ) {
1020 tk 128
    // store requested pattern
129
    portENTER_CRITICAL();
130
    pattern.REQ = 0; // request not required - we load the pattern immediately
131
    seq_pattern_req[group] = pattern;
132
    portEXIT_CRITICAL();
133
 
248 tk 134
#if LED_PERFORMANCE_MEASURING
2605 tk 135
    MIOS32_BOARD_LED_Set(0x00000001, 1);
248 tk 136
#endif
184 tk 137
    SEQ_PATTERN_Load(group, pattern);
248 tk 138
#if LED_PERFORMANCE_MEASURING
2605 tk 139
    MIOS32_BOARD_LED_Set(0x00000001, 0);
248 tk 140
#endif
184 tk 141
  } else {
142
 
143
    // TODO: stall here if previous pattern change hasn't been finished yet!
144
 
399 tk 145
    // in song mode it has to be considered, that this function is called multiple times
146
    // to request pattern changes for all groups
147
 
184 tk 148
    // else request change
318 tk 149
    portENTER_CRITICAL();
184 tk 150
    pattern.REQ = 1;
151
    seq_pattern_req[group] = pattern;
318 tk 152
    portEXIT_CRITICAL();
184 tk 153
 
1319 tk 154
    if( seq_core_options.SYNCHED_PATTERN_CHANGE && !SEQ_SONG_ActiveGet() ) {
752 tk 155
      // done in SEQ_CORE_Tick() when last step reached
156
    } else {
1983 tk 157
#if CHECK_PATTERN_REQ_LOAD_TIMINGS
158
      DEBUG_MSG("[%d] Req G%d %c%d", SEQ_BPM_TickGet(), group+1, 'A'+pattern.group, pattern.num+1);
159
#endif
752 tk 160
      // pregenerate bpm ticks
161
      // (won't be generated again if there is already an ongoing request)
162
      MUTEX_MIDIOUT_TAKE;
1983 tk 163
      s32 delay_ticks = SEQ_CORE_AddForwardDelay(50);
164
      if( delay_ticks >= 0 ) {
165
#if CHECK_PATTERN_REQ_LOAD_TIMINGS
166
    DEBUG_MSG("[%d] Forward Delay %d", SEQ_BPM_TickGet(), delay_ticks);
167
#endif
752 tk 168
      }
169
      MUTEX_MIDIOUT_GIVE;
399 tk 170
    }
184 tk 171
  }
172
 
173
  return 0; // no error
174
}
175
 
176
 
177
/////////////////////////////////////////////////////////////////////////////
178
// This function should be called from a separate task to handle pattern
179
// change requests
180
/////////////////////////////////////////////////////////////////////////////
181
s32 SEQ_PATTERN_Handler(void)
182
{
183
  u8 group;
184
 
185
#if LED_PERFORMANCE_MEASURING
2605 tk 186
  MIOS32_BOARD_LED_Set(0x00000001, 1);
184 tk 187
#endif
188
 
2004 tk 189
  MUTEX_SDCARD_TAKE; // take SD Card Mutex before entering critical section, because within the section we won't get it anymore -> hangup
1983 tk 190
  portENTER_CRITICAL();
184 tk 191
  for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
192
    if( seq_pattern_req[group].REQ ) {
193
      seq_pattern_req[group].REQ = 0;
194
 
1794 tk 195
      if( seq_core_options.PATTERN_MIXER_MAP_COUPLING ) {
196
    u8 mixer_num = 0;
197
    u8 track;
1521 midilab 198
 
1794 tk 199
    if (seq_pattern_req[0].lower) {
200
      mixer_num = ((seq_pattern_req[0].group) * 8) + seq_pattern_req[0].num;
201
    } else {
202
      mixer_num = (((seq_pattern_req[0].group) + 8) * 8) + seq_pattern_req[0].num;
203
    }
1521 midilab 204
 
1794 tk 205
    // setup our requested pattern mixer map
206
    SEQ_MIXER_NumSet(mixer_num);
207
    SEQ_MIXER_Load(mixer_num);
1454 midilab 208
 
1794 tk 209
    // dump mixer for tracks
210
    for(track = group * 4; track<((group+1)*4); ++track) {
1454 midilab 211
 
1794 tk 212
      // if we got the track bit setup inside our remix_map, them do not send mixer data for that track channel, let it be mixed down
213
      if ( ((1 << track) | seq_pattern_remix_map) == seq_pattern_remix_map ) {
214
        // do nothing for now...
215
      } else {
216
        SEQ_MIXER_SendAllByChannel(track);
217
      }
218
    }
219
      }
220
 
1983 tk 221
#if CHECK_PATTERN_REQ_LOAD_TIMINGS
222
      DEBUG_MSG("[%d] Load begin G%d %c%d", SEQ_BPM_TickGet(), group+1, 'A'+seq_pattern_req[group].group, seq_pattern_req[group].num+1);
223
#endif
184 tk 224
      SEQ_PATTERN_Load(group, seq_pattern_req[group]);
1983 tk 225
#if CHECK_PATTERN_REQ_LOAD_TIMINGS
226
      DEBUG_MSG("[%d] Load end G%d %c%d", SEQ_BPM_TickGet(), group+1, 'A'+seq_pattern_req[group].group, seq_pattern_req[group].num+1);
227
#endif
1205 tk 228
 
229
      // restart *all* patterns?
1518 tk 230
      if( seq_core_options.RATOPC ) {
231
    MIOS32_IRQ_Disable(); // must be atomic
232
    seq_core_state.reset_trkpos_req |= (0xf << (4*group));
233
    MIOS32_IRQ_Enable();
234
      }
184 tk 235
    }
236
  }
1983 tk 237
  portEXIT_CRITICAL();
2004 tk 238
  MUTEX_SDCARD_GIVE;
184 tk 239
 
240
#if LED_PERFORMANCE_MEASURING
2605 tk 241
  MIOS32_BOARD_LED_Set(0x00000001, 0);
184 tk 242
#endif
243
 
244
  return 0; // no error
245
}
246
 
247
 
248
/////////////////////////////////////////////////////////////////////////////
290 tk 249
// Load a pattern from SD Card
184 tk 250
/////////////////////////////////////////////////////////////////////////////
290 tk 251
s32 SEQ_PATTERN_Load(u8 group, seq_pattern_t pattern)
184 tk 252
{
248 tk 253
  s32 status;
184 tk 254
 
255
  seq_pattern[group] = pattern;
256
 
290 tk 257
  MUTEX_SDCARD_TAKE;
299 tk 258
 
259
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 260
  SEQ_STATISTICS_StopwatchReset();
299 tk 261
#endif
1454 midilab 262
  if( (status=SEQ_FILE_B_PatternRead(pattern.bank, pattern.pattern, group, seq_pattern_remix_map)) < 0 )
299 tk 263
    SEQ_UI_SDCardErrMsg(2000, status);
1454 midilab 264
 
265
  seq_pattern_start_time = MIOS32_SYS_TimeGet();
299 tk 266
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 267
  SEQ_STATISTICS_StopwatchCapture();
299 tk 268
#endif
269
 
290 tk 270
  MUTEX_SDCARD_GIVE;
248 tk 271
 
2231 tk 272
  // cancel sustain if there are no notes played by the track anymore
273
  {
274
    int i;
275
    u8 track = group * SEQ_CORE_NUM_TRACKS_PER_GROUP;
276
    for(i=0; i<SEQ_CORE_NUM_TRACKS_PER_GROUP; ++i, ++track)
277
      SEQ_CORE_CancelSustainedNotes(track);
278
  }
279
 
2633 tk 280
  // optionally unmute loaded tracks
281
  if( seq_core_options.UNMUTE_ON_PATTERN_CHANGE ) {
282
    u16 pattern = 0xf << (4*group);
283
    portENTER_CRITICAL();
284
    seq_core_trk_muted &= ~pattern;
285
    seq_core_trk_synched_mute &= ~pattern;
286
    seq_core_trk_synched_unmute &= ~pattern;
287
    portEXIT_CRITICAL();
288
  }
289
 
1821 tk 290
  // reset latched PB/CC values (because assignments could change)
2523 tk 291
  if( !seq_core_options.PATTERN_CHANGE_DONT_RESET_LATCHED_PC ) {
292
    SEQ_LAYER_ResetLatchedValues();
293
  }
1821 tk 294
 
2092 tk 295
  // send program change & bank selects
2231 tk 296
  {
297
    MUTEX_MIDIOUT_TAKE;
298
    int i;
299
    u8 track = group * SEQ_CORE_NUM_TRACKS_PER_GROUP;
300
    for(i=0; i<SEQ_CORE_NUM_TRACKS_PER_GROUP; ++i, ++track)
301
      SEQ_LAYER_SendPCBankValues(track, 0, 1);
302
    MUTEX_MIDIOUT_GIVE;
303
  }
2092 tk 304
 
248 tk 305
  return status;
184 tk 306
}
307
 
290 tk 308
/////////////////////////////////////////////////////////////////////////////
309
// Stores a pattern into SD Card
310
/////////////////////////////////////////////////////////////////////////////
311
s32 SEQ_PATTERN_Save(u8 group, seq_pattern_t pattern)
312
{
313
  s32 status;
314
 
315
  MUTEX_SDCARD_TAKE;
299 tk 316
 
317
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 318
  SEQ_STATISTICS_StopwatchReset();
299 tk 319
#endif
320
 
1123 tk 321
  status = SEQ_FILE_B_PatternWrite(seq_file_session_name, pattern.bank, pattern.pattern, group, 1);
299 tk 322
 
323
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 324
  SEQ_STATISTICS_StopwatchCapture();
299 tk 325
#endif
326
 
290 tk 327
  MUTEX_SDCARD_GIVE;
328
 
329
  return status;
330
}
331
 
338 tk 332
 
333
/////////////////////////////////////////////////////////////////////////////
481 tk 334
// Returns pattern name of a bank w/o overwriting RAM
335
/////////////////////////////////////////////////////////////////////////////
336
s32 SEQ_PATTERN_PeekName(seq_pattern_t pattern, char *pattern_name)
337
{
338
  s32 status;
339
 
340
  MUTEX_SDCARD_TAKE;
341
  status = SEQ_FILE_B_PatternPeekName(pattern.bank, pattern.pattern, 0, pattern_name); // always cached!
342
  MUTEX_SDCARD_GIVE;
343
 
344
  return status;
345
}
346
 
347
 
348
/////////////////////////////////////////////////////////////////////////////
338 tk 349
// Fixes a pattern (load/modify/store)
350
// Can be used on format changes
351
// Uses group as temporal "storage"
352
/////////////////////////////////////////////////////////////////////////////
353
s32 SEQ_PATTERN_Fix(u8 group, seq_pattern_t pattern)
354
{
355
  s32 status;
356
 
357
  MUTEX_SDCARD_TAKE;
358
 
359
  MIOS32_MIDI_SendDebugMessage("Loading bank #%d pattern %d\n", pattern.bank+1, pattern.pattern+1);
1454 midilab 360
  if( (status=SEQ_FILE_B_PatternRead(pattern.bank, pattern.pattern, group, 0)) < 0 ) {
338 tk 361
    SEQ_UI_SDCardErrMsg(2000, status);
362
    MIOS32_MIDI_SendDebugMessage("Read failed with status: %d\n", status);
363
  } else {
364
    // insert modification here
365
    int track_i;
366
    int track = group * SEQ_CORE_NUM_TRACKS_PER_GROUP;
367
    for(track_i=0; track_i<SEQ_CORE_NUM_TRACKS_PER_GROUP; ++track_i, ++track) {
368
      // Usage example (disabled as it isn't required anymore)
369
      // seq_cc_trk[track].clkdiv.value = 15; // due to changed resultion
599 tk 370
 
371
#if 0
372
      seq_cc_trk[track].lfo_waveform = 0;
373
      seq_cc_trk[track].lfo_amplitude = 128 + 64;
374
      seq_cc_trk[track].lfo_phase = 0;
375
      seq_cc_trk[track].lfo_steps = 15;
376
      seq_cc_trk[track].lfo_steps_rst = 15;
377
      seq_cc_trk[track].lfo_enable_flags.ALL = 0;
378
      seq_cc_trk[track].lfo_cc = 0;
379
      seq_cc_trk[track].lfo_cc_offset = 64;
380
      seq_cc_trk[track].lfo_cc_ppqn = 6; // 96 ppqn
381
#endif
338 tk 382
    }
383
 
384
    MIOS32_MIDI_SendDebugMessage("Saving bank #%d pattern %d\n", pattern.bank+1, pattern.pattern+1);
1123 tk 385
    if( (status=SEQ_FILE_B_PatternWrite(seq_file_session_name, pattern.bank, pattern.pattern, group, 1)) < 0 ) {
338 tk 386
      SEQ_UI_SDCardErrMsg(2000, status);
387
      MIOS32_MIDI_SendDebugMessage("Write failed with status: %d\n", status);
388
    }
389
  }
390
 
391
  MUTEX_SDCARD_GIVE;
392
 
393
  return status;
394
}
395
 
481 tk 396
 
338 tk 397
/////////////////////////////////////////////////////////////////////////////
398
// Fixes all patterns of all banks
399
/////////////////////////////////////////////////////////////////////////////
400
s32 SEQ_PATTERN_FixAll(void)
401
{
402
  s32 status = 0;
403
 
404
  int bank;
405
  for(bank=0; bank<SEQ_FILE_B_NUM_BANKS; ++bank) {
406
    int pattern_i;
407
    for(pattern_i=0; pattern_i<SEQ_FILE_B_NumPatterns(bank); ++pattern_i) {
408
      seq_pattern_t pattern;
409
      pattern.bank = bank;
410
      pattern.pattern = pattern_i;
411
      if( (status=SEQ_PATTERN_Fix(0, pattern)) < 0 )
412
    return status; // break process
413
    }
414
  }
415
 
416
  return status;
417
}