Subversion Repositories svn.mios32

Rev

Rev 1521 | Rev 1821 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
184 tk 1
// $Id: seq_pattern.c 1794 2013-05-31 19:25:43Z 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
 
48
/////////////////////////////////////////////////////////////////////////////
49
// Global variables
50
/////////////////////////////////////////////////////////////////////////////
51
 
52
seq_pattern_t seq_pattern[SEQ_CORE_NUM_GROUPS];
788 tk 53
seq_pattern_t seq_pattern_req[SEQ_CORE_NUM_GROUPS];
252 tk 54
char seq_pattern_name[SEQ_CORE_NUM_GROUPS][21];
184 tk 55
 
1454 midilab 56
mios32_sys_time_t seq_pattern_start_time;
57
u8 seq_pattern_mixer_num;
58
u16 seq_pattern_remix_map;
184 tk 59
 
60
/////////////////////////////////////////////////////////////////////////////
61
// Initialisation
62
/////////////////////////////////////////////////////////////////////////////
63
s32 SEQ_PATTERN_Init(u32 mode)
64
{
1454 midilab 65
  seq_pattern_start_time.seconds = 0;
66
  seq_pattern_mixer_num = 0;
67
  seq_pattern_remix_map = 0;
68
 
184 tk 69
  // pre-init pattern numbers
70
  u8 group;
71
  for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
72
    seq_pattern[group].ALL = 0;
249 tk 73
#if 0
184 tk 74
    seq_pattern[group].group = 2*group; // A/C/E/G
249 tk 75
#else
76
    seq_pattern[group].bank = group; // each group has it's own bank
77
#endif
184 tk 78
    seq_pattern_req[group].ALL = 0;
252 tk 79
 
80
#if 0
81
    sprintf((char *)seq_pattern_name[group], "Pattern %c%d          ", ('A'+((pattern>>3)&7)), (pattern&7)+1);
82
#else
83
    // if pattern name only contains spaces, the UI will print 
84
    // the pattern number instead of an empty message
85
    // this ensures highest flexibility (e.g. any pattern can be copied to another slot w/o name inconsistencies)
86
    // -> see SEQ_LCD_PrintPatternName()
87
    int i;
88
    for(i=0; i<20; ++i)
89
      seq_pattern_name[group][i] = ' ';
90
    seq_pattern_name[group][20] = 0;
91
#endif
92
 
184 tk 93
  }
94
 
299 tk 95
#if STOPWATCH_PERFORMANCE_MEASURING
944 tk 96
  SEQ_STATISTICS_StopwatchInit();
299 tk 97
#endif
98
 
184 tk 99
  return 0; // no error
100
}
101
 
102
 
103
/////////////////////////////////////////////////////////////////////////////
280 tk 104
// Returns the name of a pattern (20 characters)
105
/////////////////////////////////////////////////////////////////////////////
106
char *SEQ_PATTERN_NameGet(u8 group)
107
{
108
  if( group >= SEQ_CORE_NUM_GROUPS )
109
    return "<invalid group>     ";
110
  return seq_pattern_name[group];
111
}
112
 
113
 
114
/////////////////////////////////////////////////////////////////////////////
184 tk 115
// Requests a pattern change
116
/////////////////////////////////////////////////////////////////////////////
1117 tk 117
s32 SEQ_PATTERN_Change(u8 group, seq_pattern_t pattern, u8 force_immediate_change)
184 tk 118
{
119
  if( group >= SEQ_CORE_NUM_GROUPS )
120
    return -1; // invalid group
121
 
122
  // change immediately if sequencer not running
1117 tk 123
  if( force_immediate_change || !SEQ_BPM_IsRunning() || SEQ_BPM_TickGet() == 0 || ui_seq_pause ) {
1020 tk 124
    // store requested pattern
125
    portENTER_CRITICAL();
126
    pattern.REQ = 0; // request not required - we load the pattern immediately
127
    seq_pattern_req[group] = pattern;
128
    portEXIT_CRITICAL();
129
 
248 tk 130
#if LED_PERFORMANCE_MEASURING
131
    MIOS32_BOARD_LED_Set(0xffffffff, 1);
132
#endif
184 tk 133
    SEQ_PATTERN_Load(group, pattern);
248 tk 134
#if LED_PERFORMANCE_MEASURING
135
    MIOS32_BOARD_LED_Set(0xffffffff, 0);
136
#endif
184 tk 137
  } else {
138
 
139
    // TODO: stall here if previous pattern change hasn't been finished yet!
140
 
399 tk 141
    // in song mode it has to be considered, that this function is called multiple times
142
    // to request pattern changes for all groups
143
 
184 tk 144
    // else request change
318 tk 145
    portENTER_CRITICAL();
184 tk 146
    pattern.REQ = 1;
147
    seq_pattern_req[group] = pattern;
318 tk 148
    portEXIT_CRITICAL();
184 tk 149
 
1319 tk 150
    if( seq_core_options.SYNCHED_PATTERN_CHANGE && !SEQ_SONG_ActiveGet() ) {
752 tk 151
      // done in SEQ_CORE_Tick() when last step reached
152
    } else {
153
      // pregenerate bpm ticks
154
      // (won't be generated again if there is already an ongoing request)
155
      MUTEX_MIDIOUT_TAKE;
156
      if( SEQ_CORE_AddForwardDelay(50) >= 0 ) { // mS
1117 tk 157
    // resume low-prio pattern handler
158
    SEQ_TASK_PatternResume();
752 tk 159
      }
160
      MUTEX_MIDIOUT_GIVE;
399 tk 161
    }
184 tk 162
  }
163
 
164
  return 0; // no error
165
}
166
 
167
 
168
/////////////////////////////////////////////////////////////////////////////
169
// This function should be called from a separate task to handle pattern
170
// change requests
171
/////////////////////////////////////////////////////////////////////////////
172
s32 SEQ_PATTERN_Handler(void)
173
{
174
  u8 group;
175
 
176
#if LED_PERFORMANCE_MEASURING
177
  MIOS32_BOARD_LED_Set(0xffffffff, 1);
178
#endif
179
 
180
  for(group=0; group<SEQ_CORE_NUM_GROUPS; ++group) {
181
    if( seq_pattern_req[group].REQ ) {
318 tk 182
      portENTER_CRITICAL();
184 tk 183
      seq_pattern_req[group].REQ = 0;
318 tk 184
      portEXIT_CRITICAL();
184 tk 185
 
1794 tk 186
      if( seq_core_options.PATTERN_MIXER_MAP_COUPLING ) {
187
    u8 mixer_num = 0;
188
    u8 track;
1521 midilab 189
 
1794 tk 190
    if (seq_pattern_req[0].lower) {
191
      mixer_num = ((seq_pattern_req[0].group) * 8) + seq_pattern_req[0].num;
192
    } else {
193
      mixer_num = (((seq_pattern_req[0].group) + 8) * 8) + seq_pattern_req[0].num;
194
    }
1521 midilab 195
 
1794 tk 196
    // setup our requested pattern mixer map
197
    SEQ_MIXER_NumSet(mixer_num);
198
    SEQ_MIXER_Load(mixer_num);
1454 midilab 199
 
1794 tk 200
    // dump mixer for tracks
201
    for(track = group * 4; track<((group+1)*4); ++track) {
1454 midilab 202
 
1794 tk 203
      // 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
204
      if ( ((1 << track) | seq_pattern_remix_map) == seq_pattern_remix_map ) {
205
        // do nothing for now...
206
      } else {
207
        SEQ_MIXER_SendAllByChannel(track);
208
      }
209
    }
210
      }
211
 
184 tk 212
      SEQ_PATTERN_Load(group, seq_pattern_req[group]);
1205 tk 213
 
214
      // restart *all* patterns?
1518 tk 215
      if( seq_core_options.RATOPC ) {
216
    MIOS32_IRQ_Disable(); // must be atomic
217
    seq_core_state.reset_trkpos_req |= (0xf << (4*group));
218
    MIOS32_IRQ_Enable();
219
      }
184 tk 220
    }
221
  }
222
 
223
#if LED_PERFORMANCE_MEASURING
224
  MIOS32_BOARD_LED_Set(0xffffffff, 0);
225
#endif
226
 
227
  return 0; // no error
228
}
229
 
230
 
231
/////////////////////////////////////////////////////////////////////////////
290 tk 232
// Load a pattern from SD Card
184 tk 233
/////////////////////////////////////////////////////////////////////////////
290 tk 234
s32 SEQ_PATTERN_Load(u8 group, seq_pattern_t pattern)
184 tk 235
{
248 tk 236
  s32 status;
184 tk 237
 
238
  seq_pattern[group] = pattern;
239
 
290 tk 240
  MUTEX_SDCARD_TAKE;
299 tk 241
 
242
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 243
  SEQ_STATISTICS_StopwatchReset();
299 tk 244
#endif
1454 midilab 245
  if( (status=SEQ_FILE_B_PatternRead(pattern.bank, pattern.pattern, group, seq_pattern_remix_map)) < 0 )
299 tk 246
    SEQ_UI_SDCardErrMsg(2000, status);
1454 midilab 247
 
248
  seq_pattern_start_time = MIOS32_SYS_TimeGet();
299 tk 249
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 250
  SEQ_STATISTICS_StopwatchCapture();
299 tk 251
#endif
252
 
290 tk 253
  MUTEX_SDCARD_GIVE;
248 tk 254
 
255
  return status;
184 tk 256
}
257
 
290 tk 258
/////////////////////////////////////////////////////////////////////////////
259
// Stores a pattern into SD Card
260
/////////////////////////////////////////////////////////////////////////////
261
s32 SEQ_PATTERN_Save(u8 group, seq_pattern_t pattern)
262
{
263
  s32 status;
264
 
265
  MUTEX_SDCARD_TAKE;
299 tk 266
 
267
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 268
  SEQ_STATISTICS_StopwatchReset();
299 tk 269
#endif
270
 
1123 tk 271
  status = SEQ_FILE_B_PatternWrite(seq_file_session_name, pattern.bank, pattern.pattern, group, 1);
299 tk 272
 
273
#if STOPWATCH_PERFORMANCE_MEASURING == 1
944 tk 274
  SEQ_STATISTICS_StopwatchCapture();
299 tk 275
#endif
276
 
290 tk 277
  MUTEX_SDCARD_GIVE;
278
 
279
  return status;
280
}
281
 
338 tk 282
 
283
/////////////////////////////////////////////////////////////////////////////
481 tk 284
// Returns pattern name of a bank w/o overwriting RAM
285
/////////////////////////////////////////////////////////////////////////////
286
s32 SEQ_PATTERN_PeekName(seq_pattern_t pattern, char *pattern_name)
287
{
288
  s32 status;
289
 
290
  MUTEX_SDCARD_TAKE;
291
  status = SEQ_FILE_B_PatternPeekName(pattern.bank, pattern.pattern, 0, pattern_name); // always cached!
292
  MUTEX_SDCARD_GIVE;
293
 
294
  return status;
295
}
296
 
297
 
298
/////////////////////////////////////////////////////////////////////////////
338 tk 299
// Fixes a pattern (load/modify/store)
300
// Can be used on format changes
301
// Uses group as temporal "storage"
302
/////////////////////////////////////////////////////////////////////////////
303
s32 SEQ_PATTERN_Fix(u8 group, seq_pattern_t pattern)
304
{
305
  s32 status;
306
 
307
  MUTEX_SDCARD_TAKE;
308
 
309
  MIOS32_MIDI_SendDebugMessage("Loading bank #%d pattern %d\n", pattern.bank+1, pattern.pattern+1);
1454 midilab 310
  if( (status=SEQ_FILE_B_PatternRead(pattern.bank, pattern.pattern, group, 0)) < 0 ) {
338 tk 311
    SEQ_UI_SDCardErrMsg(2000, status);
312
    MIOS32_MIDI_SendDebugMessage("Read failed with status: %d\n", status);
313
  } else {
314
    // insert modification here
315
    int track_i;
316
    int track = group * SEQ_CORE_NUM_TRACKS_PER_GROUP;
317
    for(track_i=0; track_i<SEQ_CORE_NUM_TRACKS_PER_GROUP; ++track_i, ++track) {
318
      // Usage example (disabled as it isn't required anymore)
319
      // seq_cc_trk[track].clkdiv.value = 15; // due to changed resultion
599 tk 320
 
321
#if 0
322
      seq_cc_trk[track].lfo_waveform = 0;
323
      seq_cc_trk[track].lfo_amplitude = 128 + 64;
324
      seq_cc_trk[track].lfo_phase = 0;
325
      seq_cc_trk[track].lfo_steps = 15;
326
      seq_cc_trk[track].lfo_steps_rst = 15;
327
      seq_cc_trk[track].lfo_enable_flags.ALL = 0;
328
      seq_cc_trk[track].lfo_cc = 0;
329
      seq_cc_trk[track].lfo_cc_offset = 64;
330
      seq_cc_trk[track].lfo_cc_ppqn = 6; // 96 ppqn
331
#endif
338 tk 332
    }
333
 
334
    MIOS32_MIDI_SendDebugMessage("Saving bank #%d pattern %d\n", pattern.bank+1, pattern.pattern+1);
1123 tk 335
    if( (status=SEQ_FILE_B_PatternWrite(seq_file_session_name, pattern.bank, pattern.pattern, group, 1)) < 0 ) {
338 tk 336
      SEQ_UI_SDCardErrMsg(2000, status);
337
      MIOS32_MIDI_SendDebugMessage("Write failed with status: %d\n", status);
338
    }
339
  }
340
 
341
  MUTEX_SDCARD_GIVE;
342
 
343
  return status;
344
}
345
 
481 tk 346
 
338 tk 347
/////////////////////////////////////////////////////////////////////////////
348
// Fixes all patterns of all banks
349
/////////////////////////////////////////////////////////////////////////////
350
s32 SEQ_PATTERN_FixAll(void)
351
{
352
  s32 status = 0;
353
 
354
  int bank;
355
  for(bank=0; bank<SEQ_FILE_B_NUM_BANKS; ++bank) {
356
    int pattern_i;
357
    for(pattern_i=0; pattern_i<SEQ_FILE_B_NumPatterns(bank); ++pattern_i) {
358
      seq_pattern_t pattern;
359
      pattern.bank = bank;
360
      pattern.pattern = pattern_i;
361
      if( (status=SEQ_PATTERN_Fix(0, pattern)) < 0 )
362
    return status; // break process
363
    }
364
  }
365
 
366
  return status;
367
}