Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
2635 tk 1
// $Id: seq_file_bm.c 2634 2019-01-05 16:51:12Z tk $
2
/*
3
 * Preset Files access functions
4
 *
5
 * NOTE: before accessing the SD Card, the upper level function should
6
 * synchronize with the SD Card semaphore!
7
 *   MUTEX_SDCARD_TAKE; // to take the semaphore
8
 *   MUTEX_SDCARD_GIVE; // to release the semaphore
9
 *
10
 * ==========================================================================
11
 *
12
 *  Copyright (C) 2008 Thorsten Klose (tk@midibox.org)
13
 *  Licensed for personal non-commercial use only.
14
 *  All other rights reserved.
15
 *
16
 * ==========================================================================
17
 */
18
 
19
/////////////////////////////////////////////////////////////////////////////
20
// Include files
21
/////////////////////////////////////////////////////////////////////////////
22
 
23
#include <mios32.h>
24
 
25
#include <string.h>
26
 
27
#include "file.h"
28
#include "seq_file.h"
29
#include "seq_file_presets.h"
30
 
31
#include "seq_layer.h"
32
#include "seq_ui.h"
33
 
34
 
35
/////////////////////////////////////////////////////////////////////////////
36
// for optional debugging messages via DEBUG_MSG (defined in mios32_config.h)
37
/////////////////////////////////////////////////////////////////////////////
38
 
39
// Note: verbose level 1 is default - it prints error messages!
40
#define DEBUG_VERBOSE_LEVEL 1
41
 
42
 
43
/////////////////////////////////////////////////////////////////////////////
44
// Local definitions
45
/////////////////////////////////////////////////////////////////////////////
46
 
47
// in which subdirectory of the SD card are the preset files located?
48
// use "/" for root
49
// use "/<dir>/" for a subdirectory in root
50
// use "/<dir>/<subdir>/" to reach a subdirectory in <dir>, etc..
51
 
52
#define SEQ_PRESET_FILES_PATH     "/PRESETS"
53
#define SEQ_PRESET_TRKLABEL_PATH  SEQ_PRESET_FILES_PATH "/TRKLABEL.V4P"
54
#define SEQ_PRESET_TRKCATS_PATH   SEQ_PRESET_FILES_PATH "/TRKCATS.V4P"
55
#define SEQ_PRESET_TRKDRUMS_PATH  SEQ_PRESET_FILES_PATH "/TRKDRUMS.V4P"
56
 
57
 
58
/////////////////////////////////////////////////////////////////////////////
59
// Local types
60
/////////////////////////////////////////////////////////////////////////////
61
 
62
// file informations stored in RAM
63
typedef struct {
64
  u8 num_trk_labels;
65
  u8 num_trk_categories;
66
  u8 num_trk_drums;
67
} seq_file_presets_info_t;
68
 
69
 
70
/////////////////////////////////////////////////////////////////////////////
71
// Local prototypes
72
/////////////////////////////////////////////////////////////////////////////
73
 
74
 
75
/////////////////////////////////////////////////////////////////////////////
76
// Local variables
77
/////////////////////////////////////////////////////////////////////////////
78
 
79
static seq_file_presets_info_t seq_file_presets_info;
80
 
81
static const char *default_trk_labels[] = {
82
  "Vintage",
83
  "Synthline",
84
  "Bassline",
85
  "Pads",
86
  "Chords",
87
  "Lovely Arps",
88
  "Electr. Drums",
89
  "Heavy Beats",
90
  "Simple Beats",
91
  "CC Tracks",
92
  "Experiments",
93
  "Live Played",
94
  "Transposer"
95
};
96
 
97
 
98
static const char *default_trk_categories[] = {
99
  "Synth",
100
  "Piano",
101
  "Bass",
102
  "Drums",
103
  "Break",
104
  "MBSID",
105
  "MBFM",
106
  "Ctrl"
107
};
108
 
109
 
110
// must match with seq_layer_preset_table_drum_notes in seq_layer.c
111
static const char default_trk_drums[16][6] = {
112
  " BD  ",
113
  " SD  ",
114
  " CH  ",
115
  " PH  ",
116
  " OH  ",
117
  " MA  ",
118
  " CP  ",
119
  " CY  ",
120
  " LT  ",
121
  " MT  ",
122
  " HT  ",
123
  " RS  ",
124
  " CB  ",
125
  "Smp1 ",
126
  "Smp2 ",
127
  "Smp3 "
128
};
129
 
130
 
131
/////////////////////////////////////////////////////////////////////////////
132
// Initialisation
133
/////////////////////////////////////////////////////////////////////////////
134
s32 SEQ_FILE_PRESETS_Init(u32 mode)
135
{
136
  // invalidate file info
137
  SEQ_FILE_PRESETS_Unload();
138
 
139
  return 0; // no error
140
}
141
 
142
 
143
/////////////////////////////////////////////////////////////////////////////
144
// Loads preset files
145
// Called from SEQ_FILE_CheckSDCard() when the SD card has been connected
146
// returns < 0 on errors
147
/////////////////////////////////////////////////////////////////////////////
148
s32 SEQ_FILE_PRESETS_Load(void)
149
{
150
  s32 status = 0;
151
 
152
  SEQ_FILE_PRESETS_Unload();
153
 
154
  // create default files (if they don't exist)
155
  SEQ_FILE_PRESETS_CreateDefaults();
156
 
157
  // count preset entries for each file
158
  if( (status=SEQ_FILE_PRESETS_TrkLabel_Read(0, NULL)) > 0 ) {
159
    seq_file_presets_info.num_trk_labels = status;
160
  }
161
 
162
  if( (status=SEQ_FILE_PRESETS_TrkCategory_Read(0, NULL)) > 0 ) {
163
    seq_file_presets_info.num_trk_categories = status;
164
  }
165
 
166
  if( (status=SEQ_FILE_PRESETS_TrkDrum_Read(0, NULL, NULL, 1)) > 0 ) {
167
    seq_file_presets_info.num_trk_drums = status;
168
  }
169
 
170
  return status;
171
}
172
 
173
 
174
/////////////////////////////////////////////////////////////////////////////
175
// Unloads preset files
176
// Called from SEQ_FILE_CheckSDCard() when the SD card has been disconnected
177
// returns < 0 on errors
178
/////////////////////////////////////////////////////////////////////////////
179
s32 SEQ_FILE_PRESETS_Unload(void)
180
{
181
  seq_file_presets_info.num_trk_labels = 0;
182
  seq_file_presets_info.num_trk_categories = 0;
183
  seq_file_presets_info.num_trk_drums = 0;
184
 
185
  return 0; // no error
186
}
187
 
188
 
189
 
190
/////////////////////////////////////////////////////////////////////////////
191
// Returns 1 if preset file valid
192
// Returns 0 if preset file not valid
193
/////////////////////////////////////////////////////////////////////////////
194
s32 SEQ_FILE_PRESETS_Valid(void)
195
{
196
  return seq_file_presets_info.num_trk_labels > 0 || seq_file_presets_info.num_trk_categories > 0 || seq_file_presets_info.num_trk_drums > 0;
197
}
198
 
199
 
200
/////////////////////////////////////////////////////////////////////////////
201
// returns number of presets
202
// returns < 0 on errors (error codes are documented in seq_file.h)
203
/////////////////////////////////////////////////////////////////////////////
204
s32 SEQ_FILE_PRESETS_TrkLabel_NumGet(void)
205
{
206
  return seq_file_presets_info.num_trk_labels;
207
}
208
 
209
 
210
/////////////////////////////////////////////////////////////////////////////
211
// help function which reads a given preset from file (if preset_ix == 0: counts all entries)
212
// returns < 0 on errors (error codes are documented in seq_file.h), otherwise number of read entries
213
/////////////////////////////////////////////////////////////////////////////
214
static s32 SEQ_FILE_PRESETS_Hlp_Read(const char* filename, u8 preset_ix, char *dst, int max_len, u8 *value, u8 init_layer_preset_notes)
215
{
216
 
217
  s32 status = 0;
218
  file_t file;
219
 
220
  if( (status=FILE_ReadOpen(&file, (char *)filename)) < 0 ) {
221
#if DEBUG_VERBOSE_LEVEL >= 2
222
    DEBUG_MSG("[SEQ_FILE_PRESETS] failed to open '%s', status: %d\n", filename, status);
223
#endif
224
    return SEQ_FILE_PRESETS_ERR_READ;
225
  }
226
 
227
  u32 ix = 0;
228
  char line_buffer[128];
229
  do {
230
    status=FILE_ReadLine((u8 *)line_buffer, 128);
231
 
232
    if( status > 1 ) {
233
 
234
      if( line_buffer[0] == '#' ) {
235
    // ignore comments
236
      } else {
237
    size_t len = strlen(line_buffer);
238
 
239
    // comma separated?
240
    int pos;
241
    char *brkt = NULL;
242
    for(pos=0; pos<len; ++pos) {
243
      if( line_buffer[pos] == ',' ) {
244
        line_buffer[pos] = 0;
245
        len = pos;
246
        brkt = &line_buffer[pos+1];
247
        break;
248
      }
249
    }
250
 
251
    while( (len >= 1) && (line_buffer[len-1] == ' ') ) { // strip
252
      line_buffer[len-1] = 0;
253
      --len;
254
    }
255
 
256
    if( len > max_len ) {
257
#if DEBUG_VERBOSE_LEVEL >= 1
258
      DEBUG_MSG("[SEQ_FILE_PRESETS:%s] WARNING: line too long, %d chars max: %s", filename, max_len, line_buffer);
259
#endif
260
    }
261
 
262
    ++ix;
263
 
264
    if( ix >= 256 ) {
265
#if DEBUG_VERBOSE_LEVEL >= 1
266
      DEBUG_MSG("[SEQ_FILE_PRESETS:%s] WARNING: maximum number of items (256) reached!", filename);
267
#endif
268
      break;
269
    }
270
 
271
    if( dst ) {
272
      strncpy(dst, line_buffer, max_len+1);
273
    }
274
 
275
    if( value && !brkt ) {
276
#if DEBUG_VERBOSE_LEVEL >= 1
277
      DEBUG_MSG("[SEQ_FILE_PRESETS:%s] WARNING: no comma separated value found in %s", filename, line_buffer);
278
#endif
279
    } else if( brkt ) {
280
      char *next;
281
      long l = strtol(brkt, &next, 0);
282
 
283
      if( brkt == next || l < 0 || l >= 256 ) {
284
#if DEBUG_VERBOSE_LEVEL >= 1
285
        DEBUG_MSG("[SEQ_FILE_PRESETS:%s] WARNING: invalid value: %s", filename, line_buffer);
286
#endif
287
      } else {
288
        if( value ) {
289
          *value = l;
290
        }
291
 
292
        if( init_layer_preset_notes ) {
293
          SEQ_LAYER_PresetDrumNoteSet(ix-1, l);
294
        }
295
      }
2637 tk 296
    }
2635 tk 297
 
2637 tk 298
    if( ix == preset_ix ) // consider that 0 will return number of all labels
299
      break;
2635 tk 300
      }
301
    }
302
  } while( status >= 1 );
303
 
304
  // close file
305
  status |= FILE_ReadClose(&file);
306
 
307
  if( status < 0 ) {
308
#if DEBUG_VERBOSE_LEVEL >= 2
309
    DEBUG_MSG("[SEQ_FILE_PRESETS] errors while parsing '%s'\n", filename);
310
#endif
311
    return SEQ_FILE_PRESETS_ERR_FORMAT;
312
  }
313
 
314
#if DEBUG_VERBOSE_LEVEL >= 2
315
  if( preset_ix == 0 ) {
316
    DEBUG_MSG("[SEQ_FILE_PRESETS] found %d items in '%s'\n", ix, filename);
317
  }
318
#endif
319
 
320
  return ix; // no error
321
}
322
 
323
 
324
 
325
/////////////////////////////////////////////////////////////////////////////
326
// reads a given preset from file (if preset_ix == 0: counts all entries)
327
// dst should be able to store up to 16 chars (15 chars + zero limiter)
328
// returns < 0 on errors (error codes are documented in seq_file.h), otherwise number of read entries
329
/////////////////////////////////////////////////////////////////////////////
330
s32 SEQ_FILE_PRESETS_TrkLabel_Read(u8 preset_ix, char *dst)
331
{
332
  return SEQ_FILE_PRESETS_Hlp_Read(SEQ_PRESET_TRKLABEL_PATH, preset_ix, dst, 15, NULL, 0);
333
}
334
 
335
 
336
/////////////////////////////////////////////////////////////////////////////
337
// returns number of presets (if preset_ix == 0: counts all entries)
338
// returns < 0 on errors (error codes are documented in seq_file.h), otherwise number of read entries
339
/////////////////////////////////////////////////////////////////////////////
340
s32 SEQ_FILE_PRESETS_TrkCategory_NumGet(void)
341
{
342
  return seq_file_presets_info.num_trk_categories;
343
}
344
 
345
/////////////////////////////////////////////////////////////////////////////
346
// reads a given preset from file
347
// returns < 0 on errors (error codes are documented in seq_file.h)
348
/////////////////////////////////////////////////////////////////////////////
349
s32 SEQ_FILE_PRESETS_TrkCategory_Read(u8 preset_ix, char *dst)
350
{
351
  return SEQ_FILE_PRESETS_Hlp_Read(SEQ_PRESET_TRKCATS_PATH, preset_ix, dst, 5, NULL, 0);
352
}
353
 
354
 
355
/////////////////////////////////////////////////////////////////////////////
356
// returns number of presets
357
// returns < 0 on errors (error codes are documented in seq_file.h)
358
/////////////////////////////////////////////////////////////////////////////
359
s32 SEQ_FILE_PRESETS_TrkDrum_NumGet(void)
360
{
361
  return seq_file_presets_info.num_trk_drums;
362
}
363
 
364
/////////////////////////////////////////////////////////////////////////////
365
// reads a given preset from file (if preset_ix == 0: counts all entries)
366
// returns < 0 on errors (error codes are documented in seq_file.h), otherwise number of read entries
367
/////////////////////////////////////////////////////////////////////////////
368
s32 SEQ_FILE_PRESETS_TrkDrum_Read(u8 preset_ix, char *dst, u8 *note, u8 init_layer_preset_notes)
369
{
370
  return SEQ_FILE_PRESETS_Hlp_Read(SEQ_PRESET_TRKDRUMS_PATH, preset_ix, dst, 5, note, init_layer_preset_notes);
371
}
372
 
373
 
374
 
375
/////////////////////////////////////////////////////////////////////////////
376
// creates default content of preset files
377
// returns < 0 on errors (error codes are documented in seq_file.h)
378
/////////////////////////////////////////////////////////////////////////////
379
extern s32 SEQ_FILE_PRESETS_CreateDefaults(void)
380
{
381
  s32 status = 0;
382
 
383
  char line_buffer[200];
384
#define FLUSH_BUFFER { status |= FILE_WriteBuffer((u8 *)line_buffer, strlen(line_buffer)); }
385
 
386
  status = FILE_MakeDir(SEQ_PRESET_FILES_PATH); // create directory if it doesn't exist
387
  status = FILE_DirExists(SEQ_PRESET_FILES_PATH);
388
 
389
  if( status < 0 ) {
390
#if DEBUG_VERBOSE_LEVEL >= 1
391
    DEBUG_MSG("[SEQ_FILE_PRESETS] ERROR couldn't create " SEQ_PRESET_FILES_PATH "\n");
392
#endif
393
    return SEQ_FILE_PRESETS_ERR_NO_FILE;
394
  }
395
 
396
  if( FILE_FileExists(SEQ_PRESET_TRKLABEL_PATH) < 1 ) {
397
    if( (status=FILE_WriteOpen(SEQ_PRESET_TRKLABEL_PATH, 1)) < 0 ) {
398
#if DEBUG_VERBOSE_LEVEL >= 1
399
      DEBUG_MSG("[SEQ_FILE_PRESETS] Failed to open/create '" SEQ_PRESET_TRKLABEL_PATH "', status: %d\n", status);
400
#endif
401
      FILE_WriteClose(); // important to free memory given by malloc
402
      return SEQ_FILE_PRESETS_ERR_WRITE;
403
    }
404
 
405
    sprintf(line_buffer, "##########################################################\n");
406
    FLUSH_BUFFER;
407
    sprintf(line_buffer, "# Following labels can be selected for tracks and patterns\n");
408
    FLUSH_BUFFER;
409
    sprintf(line_buffer, "# Each Label can have 15 characters max!\n");
410
    FLUSH_BUFFER;
411
    sprintf(line_buffer, "##########################################################\n");
412
    FLUSH_BUFFER;
413
    sprintf(line_buffer, "\n");
414
    FLUSH_BUFFER;
415
    sprintf(line_buffer, "#------------->\n");
416
    FLUSH_BUFFER;
417
 
418
    int i;
419
    u32 num = sizeof(default_trk_labels) / 4;
420
    for(i=0; i<num; ++i) {
421
      sprintf(line_buffer, "%s\n", default_trk_labels[i]);
422
      FLUSH_BUFFER;
423
    }
424
 
425
    // close file
426
    status |= FILE_WriteClose();
427
 
428
#if DEBUG_VERBOSE_LEVEL >= 1
429
    if( status < 0 ) {
430
      DEBUG_MSG("[SEQ_FILE_PRESETS] ERROR couldn't create " SEQ_PRESET_TRKLABEL_PATH "\n");
431
    } else {
432
      DEBUG_MSG("[SEQ_FILE_PRESETS] created " SEQ_PRESET_TRKLABEL_PATH " with %d items\n", num);
433
    }
434
#endif
435
  }
436
 
437
 
438
  if( FILE_FileExists(SEQ_PRESET_TRKCATS_PATH) < 1 ) {
439
    if( (status=FILE_WriteOpen(SEQ_PRESET_TRKCATS_PATH, 1)) < 0 ) {
440
#if DEBUG_VERBOSE_LEVEL >= 1
441
      DEBUG_MSG("[SEQ_FILE_PRESETS] Failed to open/create '" SEQ_PRESET_TRKCATS_PATH "', status: %d\n", status);
442
#endif
443
      FILE_WriteClose(); // important to free memory given by malloc
444
      return SEQ_FILE_PRESETS_ERR_WRITE;
445
    }
446
 
447
    sprintf(line_buffer, "##############################################################\n");
448
    FLUSH_BUFFER;
449
    sprintf(line_buffer, "# Following categories can be selected for tracks and patterns\n");
450
    FLUSH_BUFFER;
451
    sprintf(line_buffer, "# Each category name can have 5 characters max!\n");
452
    FLUSH_BUFFER;
453
    sprintf(line_buffer, "##############################################################\n");
454
    FLUSH_BUFFER;
455
    sprintf(line_buffer, "\n");
456
    FLUSH_BUFFER;
457
    sprintf(line_buffer, "#--->\n");
458
    FLUSH_BUFFER;
459
 
460
    int i;
461
    u32 num = sizeof(default_trk_categories) / 4;
462
    for(i=0; i<num; ++i) {
463
      sprintf(line_buffer, "%s\n", default_trk_categories[i]);
464
      FLUSH_BUFFER;
465
    }
466
 
467
    // close file
468
    status |= FILE_WriteClose();
469
 
470
#if DEBUG_VERBOSE_LEVEL >= 1
471
    if( status < 0 ) {
472
      DEBUG_MSG("[SEQ_FILE_PRESETS] ERROR couldn't create " SEQ_PRESET_TRKCATS_PATH "\n");
473
    } else {
474
      DEBUG_MSG("[SEQ_FILE_PRESETS] created " SEQ_PRESET_TRKCATS_PATH " with %d items\n", num);
475
    }
476
#endif
477
  }
478
 
479
 
480
  if( FILE_FileExists(SEQ_PRESET_TRKDRUMS_PATH) < 1 ) {
481
    if( (status=FILE_WriteOpen(SEQ_PRESET_TRKDRUMS_PATH, 1)) < 0 ) {
482
#if DEBUG_VERBOSE_LEVEL >= 1
483
      DEBUG_MSG("[SEQ_FILE_PRESETS] Failed to open/create '" SEQ_PRESET_TRKDRUMS_PATH "', status: %d\n", status);
484
#endif
485
      FILE_WriteClose(); // important to free memory given by malloc
486
      return SEQ_FILE_PRESETS_ERR_WRITE;
487
    }
488
 
489
    sprintf(line_buffer, "##############################################################################\n");
490
    FLUSH_BUFFER;
491
    sprintf(line_buffer, "# Following drums can be selected in track instrument configuration.\n");
492
    FLUSH_BUFFER;
493
    sprintf(line_buffer, "# The first 16 definitions are taken by default whenever track is initialized.\n");
494
    FLUSH_BUFFER;
495
    sprintf(line_buffer, "# Each item contains a name and the note number (separated with a comma)\n");
496
    FLUSH_BUFFER;
497
    sprintf(line_buffer, "##############################################################################\n");
498
    FLUSH_BUFFER;
499
    sprintf(line_buffer, "\n");
500
    FLUSH_BUFFER;
501
    sprintf(line_buffer, "#--->,note\n");
502
    FLUSH_BUFFER;
503
 
504
    int i;
505
    u32 num = sizeof(default_trk_drums) / 6;
506
    for(i=0; i<num; ++i) {
507
      sprintf(line_buffer, "%s,%d\n", default_trk_drums[i], SEQ_LAYER_PresetDrumNoteGet(i));
508
      FLUSH_BUFFER;
509
    }
510
 
511
    // close file
512
    status |= FILE_WriteClose();
513
 
514
#if DEBUG_VERBOSE_LEVEL >= 1
515
    if( status < 0 ) {
516
      DEBUG_MSG("[SEQ_FILE_PRESETS] ERROR couldn't create " SEQ_PRESET_TRKDRUMS_PATH "\n");
517
    } else {
518
      DEBUG_MSG("[SEQ_FILE_PRESETS] created " SEQ_PRESET_TRKDRUMS_PATH " with %d items\n", num);
519
    }
520
#endif
521
  }
522
 
523
  return status;
524
}