Subversion Repositories svn.mios32

Rev

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

Rev Author Line No. Line
2182 hawkeye 1
// $Id: screen.c 1223 2011-06-23 21:26:52Z hawkeye $
2
 
3
#include <mios32.h>
4
 
2183 hawkeye 5
#include <stdarg.h>
2184 hawkeye 6
#include <string.h>
2183 hawkeye 7
 
2182 hawkeye 8
#include <app_lcd.h>
2571 hawkeye 9
#include <seq_bpm.h>
2182 hawkeye 10
 
2571 hawkeye 11
#include "tasks.h"
2183 hawkeye 12
#include "gfx_resources.h"
2571 hawkeye 13
#include "loopa.h"
2182 hawkeye 14
 
15
 
16
// -------------------------------------------------------------------------------------------
17
// SSD 1322 Screen routines by Hawkeye
18
 
2184 hawkeye 19
// --- globals ---
20
 
2182 hawkeye 21
u8 screen[64][128];             // Screen buffer [y][x]
22
 
2184 hawkeye 23
u8 screenShowLoopaLogo_;
2185 hawkeye 24
u8 screenClipNumberSelected_ = 0;
2571 hawkeye 25
u16 screenClipStepPosition_[TRACKS];
2185 hawkeye 26
u32 screenSongStep_ = 0;
2186 hawkeye 27
char screenFlashMessage_[40];
28
u8 screenFlashMessageFrameCtr_;
2571 hawkeye 29
char sceneChangeNotification_[20] = "";
30
u8 screenNewPagePanelFrameCtr_ = 0;
2183 hawkeye 31
 
2184 hawkeye 32
unsigned char* fontptr_ = (unsigned char*) fontsmall_pixdata;
33
u16 fontchar_bytewidth_ = 3;    // bytes to copy for a line of character pixel data
34
u16 fontchar_height_ = 12;      // lines to copy for a full-height character
35
u16 fontline_bytewidth_ = 95*3; // bytes per font pixdata line (character layout all in one line)
2571 hawkeye 36
u8 fontInverted_ = 0;
2184 hawkeye 37
 
38
 
39
/**
40
 * Set the bold font
41
 *
42
 */
43
void setFontBold()
2183 hawkeye 44
{
2184 hawkeye 45
   fontptr_ = (unsigned char*) fontbold_pixdata;
46
   fontchar_bytewidth_ = 5;
47
   fontchar_height_ = 18;
48
   fontline_bytewidth_ = 95 * 5;
2183 hawkeye 49
}
50
// ----------------------------------------------------------------------------------------
51
 
52
 
2184 hawkeye 53
/**
54
 * Set the normal font
55
 *
56
 */
57
void setFontNormal()
2183 hawkeye 58
{
2184 hawkeye 59
   fontptr_ = (unsigned char*) fontnormal_pixdata;
60
   fontchar_bytewidth_ = 5;
61
   fontchar_height_ = 18;
62
   fontline_bytewidth_ = 95 * 5;
2183 hawkeye 63
}
64
// ----------------------------------------------------------------------------------------
65
 
2184 hawkeye 66
 
67
/**
68
 * Set the small font
69
 *
70
 */
71
void setFontSmall()
72
{
73
   fontptr_ = (unsigned char*) fontsmall_pixdata;
74
   fontchar_bytewidth_ = 3;
75
   fontchar_height_ = 12;
76
   fontline_bytewidth_ = 95 * 3;
77
}
78
// ----------------------------------------------------------------------------------------
79
 
80
 
81
/**
2571 hawkeye 82
 * Set font noninverted
83
 * *
84
 */
85
void setFontNonInverted()
86
{
87
   fontInverted_ = 0;
88
}
89
// ----------------------------------------------------------------------------------------
90
 
91
 
92
/**
93
 * Set font inverted
94
 *
95
 */
96
void setFontInverted()
97
{
98
   fontInverted_ = 1;
99
}
100
// ----------------------------------------------------------------------------------------
101
 
102
 
103
/**
2184 hawkeye 104
 * Display the given string at the given pixel coordinates
105
 * output to screen output buffer, the next display() will render it to hardware
106
 * provides clipping support, coordinates can be offscreen/negative for scrolling fx
107
 *
108
 */
2183 hawkeye 109
void printString(int xPixCoord /* even! */, int yPixCoord, const char *str)
110
{
111
   unsigned stringpos = 0;
112
 
113
   while (*str != '\0')
114
   {
115
      int c = *str++;
116
      unsigned x;
117
 
118
      // in-font coordinates
119
      unsigned f_y = 0;
2184 hawkeye 120
      unsigned f_x = (c-32) * fontchar_bytewidth_;
2183 hawkeye 121
 
122
      // screenbuf target coordinates
123
      unsigned s_y = yPixCoord;
2184 hawkeye 124
      unsigned s_x = xPixCoord / 2 + stringpos * fontchar_bytewidth_; // 2 pixels per byte, require even xPixCoord start coordinate
2183 hawkeye 125
 
2184 hawkeye 126
      while (f_y < fontchar_height_)
2183 hawkeye 127
      {
128
         if (s_y >= 0 && s_y < 64) // clip y offscreen
129
         {
130
            unsigned char* sdata = (unsigned char*) screen + s_y * 128 + s_x;
2184 hawkeye 131
            unsigned char* fdata = (unsigned char*) fontptr_ + f_y * fontline_bytewidth_ + f_x;
2183 hawkeye 132
            unsigned c_s_x = s_x;
133
 
2184 hawkeye 134
            for (x = 0; x <fontchar_bytewidth_; x++)
2183 hawkeye 135
            {
136
               if (c_s_x >= 0 && c_s_x < 128)
2571 hawkeye 137
               {
138
                  if (!fontInverted_)
139
                  {
140
                     if (*fdata)
141
                        *sdata = *fdata;  // inner loop: copy 2 pixels, if onscreen
142
                  }
143
                  else
144
                  {
145
                     // "invert" font
146
                     u8 first = *fdata >> 4;
147
                     u8 second = *fdata % 16;
2183 hawkeye 148
 
2571 hawkeye 149
                     first = 15-first;
150
                     second = 15-second;
151
                     *sdata = (first << 4) + second;
152
                  }
153
               }
154
 
2183 hawkeye 155
               c_s_x++;
156
               fdata++;
157
               sdata++;
158
            }
159
         }
160
 
161
         f_y++;
162
         s_y++;
163
      }
164
 
165
      stringpos++;
166
   }
167
}
168
// ----------------------------------------------------------------------------------------
169
 
170
 
2184 hawkeye 171
/**
172
 * Display the given formatted string at the given pixel coordinates
173
 * output to screen output buffer, the next display() will render it to hardware
174
 * provides clipping support, coordinates can be offscreen/negative for scrolling fx
175
 *
176
 */
2183 hawkeye 177
void printFormattedString(int xPixCoord /* even! */, int yPixCoord, const char* format, ...)
178
{
2571 hawkeye 179
   char buffer[64];
2183 hawkeye 180
   va_list args;
181
 
182
   va_start(args, format);
183
   vsprintf((char *)buffer, format, args);
184
   return printString(xPixCoord, yPixCoord, buffer);
185
}
186
// ----------------------------------------------------------------------------------------
187
 
188
 
2571 hawkeye 189
/**
190
 * Display the given formatted string at the given y pixel coordinates, center x
191
 * output to screen output buffer, the next display() will render it to hardware
192
 * provides clipping support, coordinates can be offscreen/negative for scrolling fx
193
 *
194
 */
195
void printCenterFormattedString(int yPixCoord, const char* format, ...)
196
{
197
   char buffer[64];
198
   va_list args;
2184 hawkeye 199
 
2571 hawkeye 200
   va_start(args, format);
201
   vsprintf((char *)buffer, format, args);
202
 
203
   int xPixCoord = 128 - (fontchar_bytewidth_ * strlen(buffer));
204
   return printString(xPixCoord, yPixCoord, buffer);
205
}
206
// ----------------------------------------------------------------------------------------
207
 
208
 
2184 hawkeye 209
/**
210
 * Display a loopa slot time indicator
2185 hawkeye 211
 * Format: [clipPos:clipLength]
2571 hawkeye 212
 *         times are in steps
2184 hawkeye 213
 *
214
 *         the time indicator will be rendered inverted, if this is the selected clip/active clip
215
 *         the display position depends on the slot number, slot #0 is upper left, slot #7 is lower right
216
 *
217
 */
2185 hawkeye 218
void displayClipPosition(u8 clipNumber)
2184 hawkeye 219
{
220
   char buffer[16];
221
 
2571 hawkeye 222
   u16 stepLength = clipSteps_[clipNumber][activeScene_];
2185 hawkeye 223
   u16 stepPos = screenClipStepPosition_[clipNumber];
224
   u8 isSelected = (clipNumber == screenClipNumberSelected_);
2184 hawkeye 225
 
2571 hawkeye 226
   u8 syncedMuteUnmuteInProgress = trackMuteToggleRequested_[clipNumber] && (tickToStep(tick_) % beatLoopSteps_) != 0;
227
 
228
   if (!syncedMuteUnmuteInProgress)
2185 hawkeye 229
   {
230
      if (stepLength == 0)
2571 hawkeye 231
         sprintf((char *)buffer, "       ");
2185 hawkeye 232
      else if (stepLength > 99)
2571 hawkeye 233
         sprintf((char *)buffer, "%03d>%3d", stepPos, stepLength);
2185 hawkeye 234
      else if (stepLength > 9)
2571 hawkeye 235
         sprintf((char *)buffer, " %02d>%2d ", stepPos, stepLength);
236
      else
237
         sprintf((char *)buffer, "  %01d>%1d  ", stepPos, stepLength);
2185 hawkeye 238
   }
239
   else
240
   {
2571 hawkeye 241
      u8 remainSteps = 16 - (tickToStep(tick_) % beatLoopSteps_);
242
 
243
      if (remainSteps > 9)
244
         sprintf((char *)buffer, "  %d   ", remainSteps);
245
      else
246
         sprintf((char *)buffer, "   %d   ", remainSteps);
2185 hawkeye 247
   }
248
 
2571 hawkeye 249
   u8 xPixCoord = clipNumber * 42;
250
   u8 yPixCoord = 56;
2184 hawkeye 251
   u8 fontHeight = 7;
252
   u8 fontByteWidth = 3;
253
   u8 fontLineByteWidth = 16*3;
254
 
255
   char *str = buffer;
256
   u8 stringpos = 0;
257
   while (*str != '\0')
258
   {
259
      int c = *str++;
260
 
261
      if (c == ' ')  // Map string space to font space
262
         c = '/';
263
 
264
      unsigned x;
265
 
266
      // in-font coordinates
267
      unsigned f_y = 0;
268
      unsigned f_x = (c-47) * fontByteWidth;
269
 
270
      // screenbuf target coordinates
271
      unsigned s_y = yPixCoord;
272
      unsigned s_x = xPixCoord / 2 + stringpos * fontByteWidth; // 2 pixels per byte, require even xPixCoord start coordinate
273
 
274
      while (f_y < fontHeight)
275
      {
276
         if (s_y >= 0 && s_y < 64) // clip y offscreen
277
         {
278
            unsigned char* sdata = (unsigned char*) screen + s_y * 128 + s_x;
279
            unsigned char* fdata = (unsigned char*) digitstiny_pixdata + f_y * fontLineByteWidth + f_x;
280
            unsigned c_s_x = s_x;
281
 
282
            for (x = 0; x <fontByteWidth; x++)
283
            {
284
               if (c_s_x >= 0 && c_s_x < 128)
285
               {
286
                  if (!isSelected)
287
                  {
288
                     if (*fdata)
289
                        *sdata = *fdata;  // inner loop: copy 2 pixels, if onscreen
290
                  }
291
                  else
292
                  {
293
                     // "invert" font
294
                     u8 first = *fdata >> 4;
295
                     u8 second = *fdata % 16;
296
 
297
                     first = 15-first;
298
                     second = 15-second;
299
                     *sdata = (first << 4) + second;
300
                  }
301
               }
302
 
303
               c_s_x++;
304
               fdata++;
305
               sdata++;
306
            }
307
         }
308
 
309
         f_y++;
310
         s_y++;
311
      }
312
 
313
      stringpos++;
314
   }
315
}
316
// ----------------------------------------------------------------------------------------
317
 
318
 
319
/**
320
 * If showLogo is true, draw the MBLoopa Logo (usually during unit startup)
321
 *
322
 */
323
void screenShowLoopaLogo(u8 showLogo)
324
{
325
   screenShowLoopaLogo_ = showLogo;
326
}
327
// ----------------------------------------------------------------------------------------
328
 
329
 
330
/**
331
 * Set the currently selected clip
332
 *
333
 */
334
void screenSetClipSelected(u8 clipNumber)
335
{
2185 hawkeye 336
   screenClipNumberSelected_ = clipNumber;
2184 hawkeye 337
}
338
// ----------------------------------------------------------------------------------------
339
 
340
 
341
/**
2571 hawkeye 342
 * Set the position info of a clip
2184 hawkeye 343
 *
344
 */
2571 hawkeye 345
void screenSetClipPosition(u8 clipNumber, u16 stepPosition)
2184 hawkeye 346
{
2571 hawkeye 347
   // DEBUG_MSG("[screenSetClipPosition] clip: %u stepPosition: %u", clipNumber, stepPosition);
348
   screenClipStepPosition_[clipNumber] = stepPosition;
349
}
350
// ----------------------------------------------------------------------------------------
351
 
352
 
353
/**
354
 * Set the global song step position (e.g. for displaying the recording-clip step)
355
 *
356
 */
357
void screenSetSongStep(u32 stepPosition)
358
{
359
   screenSongStep_ = stepPosition;
360
}
361
// ----------------------------------------------------------------------------------------
362
 
363
 
364
/**
365
 * Flash a short-lived message to the center of the screen
366
 *
367
 */
368
void screenFormattedFlashMessage(const char* format, ...)
369
{
370
   va_list args;
371
 
372
   va_start(args, format);
373
   vsprintf((char *)screenFlashMessage_, format, args);
374
   screenFlashMessageFrameCtr_ = 10;
375
}
376
// ----------------------------------------------------------------------------------------
377
 
378
 
379
/**
380
 * Set scene change notification message (change in ticks)
381
 *
382
 */
383
void screenSetSceneChangeInTicks(u8 ticks)
384
{
385
   if (ticks)
386
      sprintf((char *)sceneChangeNotification_, " [...%d]", ticks);
2185 hawkeye 387
   else
2571 hawkeye 388
      strcpy(sceneChangeNotification_, "");
2184 hawkeye 389
}
390
// ----------------------------------------------------------------------------------------
391
 
392
 
393
/**
2571 hawkeye 394
 * Notify, that a screen page change has occured (flash a page descriptor for a while)
2185 hawkeye 395
 *
396
 */
2571 hawkeye 397
void screenNotifyPageChanged()
2185 hawkeye 398
{
2571 hawkeye 399
   screenNewPagePanelFrameCtr_ = 20;
2185 hawkeye 400
}
401
// ----------------------------------------------------------------------------------------
402
 
403
 
404
/**
2571 hawkeye 405
 * Convert note length to pixel width
406
 * if ticksLength == 0 (still recording),
2184 hawkeye 407
 *
408
 */
2571 hawkeye 409
u16 noteLengthPixels(u32 ticksLength)
2184 hawkeye 410
{
2571 hawkeye 411
   return tickToStep(ticksLength);
2184 hawkeye 412
}
413
// ----------------------------------------------------------------------------------------
414
 
415
 
2185 hawkeye 416
/**
2571 hawkeye 417
 * Display the note data of a clip
2185 hawkeye 418
 *
419
 */
2571 hawkeye 420
void displayClip(u8 clip)
2185 hawkeye 421
{
2571 hawkeye 422
   u16 x;
423
   u8 y;
424
   u16 i;
425
   u16 mult = 128/clipSteps_[clip][activeScene_];  // horizontal multiplier to make clips as wide as the screen
426
 
427
   u16 curStep = ((u32)boundTickToClipSteps(tick_, clip) * mult) / 24;
428
 
429
   // Render vertical 1/4th note indicators
430
   for (i=0; i<clipSteps_[clip][activeScene_] / 4; i++)
431
   {
432
      x = i * 4 * mult;
433
      if (x < 128)
434
         for (y=12; y<52; y++)
435
               screen[y][x] = i % 4 == 0 ? 0x60 : 0x50;
436
   }
437
 
438
   // Render vertical time indicator line (if seq is playing)
439
   if (SEQ_BPM_IsRunning() && curStep < 128)
440
      for (y=0; y<64; y++)
441
         screen[y][curStep] = 0x88;
442
 
443
 
444
   // Render note data
445
   for (i=0; i < clipNotesSize_[clip][activeScene_]; i++)
446
   {
447
      s32 transformedStep = (s32)quantizeTransform(clip, i) * mult;
448
 
449
      if (transformedStep >= 0) // if note starts within (potentially reconfigured) clip length
450
      {
451
         u16 step = transformedStep / 24;
452
 
453
         s16 note = clipNotes_[clip][activeScene_][i].note + clipTranspose_[clip][activeScene_];
454
         note = note < 0 ? 0 : note;
455
         note = note > 127 ? 127 : note;
456
         u8 y = (127 - note) / 2;
457
 
458
         if (y < 64)
459
         {
460
            u16 len = noteLengthPixels(clipNotes_[clip][activeScene_][i].length * mult);
461
 
462
            if (clipNotes_[clip][activeScene_][i].length == 0 && curStep > step)
463
            {
464
               // still recording (also check for boundary wrapping, disabled right now)
465
               len = curStep - step;
466
            }
467
 
468
            for (x = step; x <= step + len; x++)
469
            {
470
               if (clipNotes_[clip][activeScene_][i].velocity > 0)
471
               {
472
                  u8 color;
473
                  if (!trackMute_[clip])
474
                     color = x == step ? 0xFF
475
                                       : 0x99;  // The modulo only works if we are not scrolling and screen width = clip length
476
                  else
2577 hawkeye 477
                     color = x == step ? 0x88
478
                                       : 0x66;  // The modulo only works if we are not scrolling and screen width = clip length
2571 hawkeye 479
 
480
                  screen[y][x % 128] = color;
481
 
482
                  if (page_ == PAGE_NOTES && i == clipActiveNote_[clip][activeScene_])
483
                  {
484
                     // render cursor for selected note
485
                     u8 cursorX = x % 128;
486
                     u8 cursorY = y;
487
 
488
                     if (cursorY > 2 && cursorX < 126)
489
                        screen[cursorY - 2][cursorX + 2] = 0x0F;
490
 
491
                     if (cursorY > 2 && cursorX > 2)
492
                        screen[cursorY - 2][cursorX - 2] = 0xF0;
493
 
494
                     if (cursorY < 62 && cursorX < 126)
495
                        screen[cursorY + 2][cursorX + 2] = 0x0F;
496
 
497
                     if (cursorY < 62 && cursorX > 2)
498
                        screen[cursorY + 2][cursorX - 2] = 0xF0;
499
                  }
500
               }
501
            }
502
         }
503
      }
504
   }
2185 hawkeye 505
}
506
// ----------------------------------------------------------------------------------------
507
 
508
 
509
/**
2571 hawkeye 510
 * Display the normal loopa view (PAGE_TRACK)
2186 hawkeye 511
 *
512
 */
2571 hawkeye 513
void displayPageTrack(void)
2186 hawkeye 514
{
2571 hawkeye 515
   setFontSmall();
2186 hawkeye 516
 
2571 hawkeye 517
   if (screenNewPagePanelFrameCtr_ > 0)
518
   {
519
      setFontInverted();
520
      printString(250, 8, "M");
521
      printString(250, 20, "U");
522
      printString(250, 32, "T");
523
      printString(250, 44, "E");
524
      setFontNonInverted();
525
      screenNewPagePanelFrameCtr_--;
526
   }
527
 
528
   if (trackMute_[activeTrack_])
2577 hawkeye 529
      printCenterFormattedString(0, "[Clip %d Scene %c [muted]%s]", activeTrack_ + 1, 'A' + activeScene_, sceneChangeNotification_);
2571 hawkeye 530
   else
2577 hawkeye 531
      printCenterFormattedString(0, "[Clip %d Scene %c%s]", activeTrack_ + 1, 'A' + activeScene_, sceneChangeNotification_);
2571 hawkeye 532
 
533
   u8 clip;
534
   for (clip = 0; clip < TRACKS; clip++)
535
   {
536
      if (clip == activeTrack_ || clipNotesSize_[clip] > 0 || trackMuteToggleRequested_[clip])
537
         displayClipPosition(clip);  // only display clip position indicators, if it is the active clip or it has notes
538
   }
539
 
540
   displayClip(activeTrack_);
2186 hawkeye 541
}
542
// ----------------------------------------------------------------------------------------
543
 
544
 
2571 hawkeye 545
/**
546
 * Display the edit clip page (PAGE_EDIT)
547
 *
548
 */
549
void displayPageEdit(void)
550
{
551
   setFontSmall();
2186 hawkeye 552
 
2571 hawkeye 553
   if (screenNewPagePanelFrameCtr_ > 0)
554
   {
555
      setFontInverted();
556
      printString(250, 8, "E");
557
      printString(250, 20, "D");
558
      printString(250, 32, "I");
559
      printString(250, 44, "T");
560
      setFontNonInverted();
561
      screenNewPagePanelFrameCtr_--;
562
   }
563
 
2577 hawkeye 564
   printCenterFormattedString(0, "Edit Settings [Clip %d Scene %c%s]", activeTrack_ + 1, 'A' + activeScene_, sceneChangeNotification_);
2571 hawkeye 565
 
566
   command_ == COMMAND_CLIPLEN ? setFontInverted() : setFontNonInverted();
567
   if (clipSteps_[activeTrack_][activeScene_] < 100)
568
      printFormattedString(0, 54, "Len %d", clipSteps_[activeTrack_][activeScene_]);
569
   else
570
      printFormattedString(0, 54, "Le %d", clipSteps_[activeTrack_][activeScene_]);
571
 
572
   command_ == COMMAND_QUANTIZE ? setFontInverted() : setFontNonInverted();
573
   switch (clipQuantize_[activeTrack_][activeScene_])
574
   {
575
      case 3: printFormattedString(42, 54, "Q1/128"); break;
576
      case 6: printFormattedString(42, 54, "Qu1/64"); break;
577
      case 12: printFormattedString(42, 54, "Qu1/32"); break;
578
      case 24: printFormattedString(42, 54, "Qu1/16"); break;
579
      case 48: printFormattedString(42, 54, "Qu 1/8"); break;
580
      case 96: printFormattedString(42, 54, "Qu 1/4"); break;
581
      case 192: printFormattedString(42, 54, "Qu 1/2"); break;
582
      case 384: printFormattedString(42, 54, "Qu 1/1"); break;
583
      default: printFormattedString(42, 54, "Qu OFF"); break;
584
   }
585
 
586
   command_ == COMMAND_TRANSPOSE ? setFontInverted() : setFontNonInverted();
587
   printFormattedString(84, 54, "Trn %d", clipTranspose_[activeTrack_][activeScene_]);
588
 
589
   command_ == COMMAND_SCROLL ? setFontInverted() : setFontNonInverted();
590
   printFormattedString(126, 54, "Scr %d", clipScroll_[activeTrack_][activeScene_]);
591
 
592
   command_ == COMMAND_STRETCH ? setFontInverted() : setFontNonInverted();
593
   switch (clipStretch_[activeTrack_][activeScene_])
594
   {
595
      case 1: printFormattedString(168, 54, "Zo 1/16"); break;
596
      case 2: printFormattedString(168, 54, "Zo 1/8"); break;
597
      case 4: printFormattedString(168, 54, "Zo 1/4"); break;
598
      case 8: printFormattedString(168, 54, "Zo 1/2"); break;
599
      case 16: printFormattedString(168, 54, "Zoom 1"); break;
600
      case 32: printFormattedString(168, 54, "Zoom 2"); break;
601
      case 64: printFormattedString(168, 54, "Zoom 4"); break;
602
      case 128: printFormattedString(168, 54, "Zoom 8"); break;
603
   }
604
 
605
   command_ == COMMAND_CLEAR ? setFontInverted() : setFontNonInverted();
606
   printFormattedString(210, 54, "Clear");
607
 
608
   setFontNonInverted();
609
   displayClip(activeTrack_);
610
}
611
// ----------------------------------------------------------------------------------------
612
 
613
 
2186 hawkeye 614
/**
2571 hawkeye 615
 * Numeric note to note string helper
2185 hawkeye 616
 *
617
 */
2571 hawkeye 618
static void stringNote(char *label, u8 note)
619
{
620
   const char noteTab[12][3] = { "C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-" };
621
 
622
   // print "---" if note number is 0
623
   if (note == 0)
624
      sprintf(label, "---  ");
625
   else
626
   {
627
      u8 octave = note / 12;
628
      note %= 12;
629
 
630
      // print semitone and octave (-2): up to 4 chars
631
      sprintf(label, "%s%d  ",
632
              noteTab[note],
633
              (int)octave-2);
634
   }
635
}
636
// ----------------------------------------------------------------------------------------
637
 
638
 
639
/**
640
 * Display the note editor (PAGE_NOTES)
641
 *
642
 */
643
void displayPageNotes(void)
644
{
645
   setFontSmall();
646
 
647
   if (screenNewPagePanelFrameCtr_ > 0)
648
   {
649
      setFontInverted();
650
      printString(250, 8, "N");
651
      printString(250, 20, "O");
652
      printString(250, 32, "T");
653
      printString(250, 44, "E");
654
      setFontNonInverted();
655
      screenNewPagePanelFrameCtr_--;
656
   }
657
 
2577 hawkeye 658
   printCenterFormattedString(0, "Note Editor [Clip %d Scene %c%s]", activeTrack_ + 1, 'A' + activeScene_, sceneChangeNotification_);
2571 hawkeye 659
 
660
   if (clipNotesSize_[activeTrack_][activeScene_] > 0)
661
   {
662
 
663
      u16 activeNote = clipActiveNote_[activeTrack_][activeScene_];
664
 
665
      if (activeNote >= clipNotesSize_[activeTrack_][activeScene_]) // necessary e.g. for clip change
666
         activeNote = 0;
667
 
668
      u16 pos = (clipNotes_[activeTrack_][activeScene_][activeNote].tick) / 24;
669
      u16 length = clipNotes_[activeTrack_][activeScene_][activeNote].length;
670
      u8 note = clipNotes_[activeTrack_][activeScene_][activeNote].note;
671
      u8 velocity = clipNotes_[activeTrack_][activeScene_][activeNote].velocity;
672
 
673
      command_ == COMMAND_POSITION ? setFontInverted() : setFontNonInverted();
674
      if (pos < 100)
675
         printFormattedString(0, 54, "Pos %d", pos);
676
      else
677
         printFormattedString(0, 54, "Po %d", pos);
678
 
679
      command_ == COMMAND_NOTE ? setFontInverted() : setFontNonInverted();
680
 
681
      char noteStr[8];
682
      stringNote(noteStr, note);
683
      printFormattedString(42, 54, "%s", noteStr);
684
 
685
      command_ == COMMAND_VELOCITY ? setFontInverted() : setFontNonInverted();
686
      printFormattedString(84, 54, "Vel %d", velocity);
687
 
688
      command_ == COMMAND_LENGTH ? setFontInverted() : setFontNonInverted();
689
      printFormattedString(126, 54, "Len %d", length);
690
 
691
      command_ == COMMAND_CLEAR ? setFontInverted() : setFontNonInverted();
692
      printFormattedString(210, 54, "Delete");
693
 
694
      setFontNonInverted();
695
   }
696
   else
697
   {
698
      printCenterFormattedString(54, "No notes recorded, yet");
699
   }
700
   displayClip(activeTrack_);
701
}
702
// ----------------------------------------------------------------------------------------
703
 
704
 
705
/**
706
 * Display the track midi settings page (PAGE_MIDI)
707
 *
708
 */
709
void displayPageMidi(void)
710
{
711
   setFontSmall();
712
 
713
   if (screenNewPagePanelFrameCtr_ > 0)
714
   {
715
      setFontInverted();
716
      printString(250, 8, "M");
717
      printString(250, 20, "I");
718
      printString(250, 32, "D");
719
      printString(250, 44, "I");
720
      setFontNonInverted();
721
      screenNewPagePanelFrameCtr_--;
722
   }
723
 
724
   printCenterFormattedString(0, "MIDI Parameters [Track %d]", activeTrack_ + 1);
725
 
726
   command_ == COMMAND_PORT ? setFontInverted() : setFontNonInverted();
727
   switch (trackMidiPort_[activeTrack_])
728
   {
729
      case 0x20: printFormattedString(0, 54, " OUT1 "); break;
730
      case 0x21: printFormattedString(0, 54, " OUT2 "); break;
731
      case 0x22: printFormattedString(0, 54, " OUT3 "); break;
732
      case 0x23: printFormattedString(0, 54, " OUT4 "); break;
733
   }
734
 
735
   command_ == COMMAND_CHANNEL ? setFontInverted() : setFontNonInverted();
736
   printFormattedString(42, 54, " Chn %d ", trackMidiChannel_[activeTrack_] + 1);
737
 
738
   setFontNonInverted();
739
   displayClip(activeTrack_);
740
}
741
// ----------------------------------------------------------------------------------------
742
 
743
 
744
/**
745
 * Display the main menu (PAGE_DISK)
746
 *
747
 */
748
void displayPageDisk(void)
749
{
750
   setFontSmall();
751
 
752
   if (screenNewPagePanelFrameCtr_ > 0)
753
   {
754
      setFontInverted();
755
      printString(250, 8, "D");
756
      printString(250, 20, "I");
757
      printString(250, 32, "S");
758
      printString(250, 44, "K");
759
      setFontNonInverted();
760
      screenNewPagePanelFrameCtr_--;
761
   }
762
 
2577 hawkeye 763
   printCenterFormattedString(0, "Disk Operations");
2571 hawkeye 764
 
765
   command_ == COMMAND_SAVE ? setFontInverted() : setFontNonInverted();
766
   printFormattedString(0, 54, "Save");
767
 
768
   command_ == COMMAND_LOAD ? setFontInverted() : setFontNonInverted();
769
   printFormattedString(42, 54, "Load");
770
 
771
   command_ == COMMAND_NEW ? setFontInverted() : setFontNonInverted();
772
   printFormattedString(84, 54, "New");
773
 
774
 
775
   setFontNonInverted();
776
   setFontBold();
777
   printFormattedString(82, 16, "Session %d", sessionNumber_);
778
 
779
   setFontNormal();
780
   if (sessionExistsOnDisk_)
781
      printFormattedString(82, 32, "(on disk)", sessionNumber_);
782
   else
783
      printFormattedString(106, 32, "(new)", sessionNumber_);
784
 
785
   setFontSmall();
786
}
787
// ----------------------------------------------------------------------------------------
788
 
789
 
790
/**
791
 * Display the bpm settings page (PAGE_BPM)
792
 *
793
 */
794
void displayPageBpm(void)
795
{
796
   setFontSmall();
2576 hawkeye 797
 
2571 hawkeye 798
   if (screenNewPagePanelFrameCtr_ > 0)
799
   {
800
      setFontInverted();
801
      printString(250, 14, "B");
802
      printString(250, 26, "P");
803
      printString(250, 38, "M");
804
      setFontNonInverted();
805
      screenNewPagePanelFrameCtr_--;
806
   }
807
 
808
   printCenterFormattedString(0, "Tempo Settings", activeTrack_ + 1, activeScene_ + 1);
809
 
810
   command_ == COMMAND_BPM ? setFontInverted() : setFontNonInverted();
811
   u16 bpm = SEQ_BPM_IsMaster() ? bpm_ : SEQ_BPM_Get();
812
   printFormattedString(0, 54, "%d BPM", bpm);
813
 
814
   setFontNonInverted();
815
   displayClip(activeTrack_);
816
}
817
// ----------------------------------------------------------------------------------------
818
 
819
 
820
/**
821
 * Display the current screen buffer (once per frame, called in app.c scheduler)
822
 *
823
 */
2182 hawkeye 824
void display(void)
825
{
826
   u8 i, j;
827
 
2184 hawkeye 828
   if (screenShowLoopaLogo_)
829
   {
830
      // Startup/initial session loading: Render the MBLoopa Logo
2571 hawkeye 831
 
832
      setFontBold();  // width per letter: 10px (for center calculation)
2572 hawkeye 833
      printFormattedString(78, 2, "LoopA V2.01");
2571 hawkeye 834
 
835
      setFontSmall(); // width per letter: 6px
836
      printFormattedString(28, 20, "(C) Hawkeye, latigid on, TK. 2018");
837
      printFormattedString(52, 32, "MIDIbox hardware platform");
838
 
839
      setFontBold(); // width per letter: 10px;
840
      printFormattedString(52, 44, "www.midiphy.com");
2184 hawkeye 841
   }
842
   else
843
   {
2571 hawkeye 844
      // Display page content...
845
      switch (page_)
846
      {
847
         case PAGE_TRACK:
848
            displayPageTrack();
849
            break;
2183 hawkeye 850
 
2571 hawkeye 851
         case PAGE_EDIT:
852
            displayPageEdit();
853
            break;
2184 hawkeye 854
 
2571 hawkeye 855
         case PAGE_NOTES:
856
            displayPageNotes();
857
            break;
858
 
859
         case PAGE_MIDI:
860
            displayPageMidi();
861
            break;
862
 
863
         case PAGE_DISK:
864
            displayPageDisk();
865
            break;
866
 
867
         case PAGE_BPM:
868
            displayPageBpm();
869
            break;
870
      }
2184 hawkeye 871
   }
872
 
2571 hawkeye 873
   // Display flash notification
2186 hawkeye 874
   if (screenFlashMessageFrameCtr_)
875
   {
876
      setFontNormal();
877
      u8 len = strlen(screenFlashMessage_);
878
      u8 xpos = 128 - len * 5;
879
      u16 displacement = 10 - screenFlashMessageFrameCtr_;
880
      displacement = (displacement * displacement) / 3;
881
      printFormattedString(xpos, 26 - displacement, screenFlashMessage_);
882
 
883
      screenFlashMessageFrameCtr_--;
884
   }
885
 
2571 hawkeye 886
   u8 flash = 0;
887
   // no flashing for now :)
888
   //if (oledBeatFlashState_ > 0)
889
   //   flash = oledBeatFlashState_ == 1 ? 0x44 : 0x66;
890
 
891
   // Push screen buffer to screen
2182 hawkeye 892
   for (j = 0; j < 64; j++)
893
   {
894
      APP_LCD_Cmd(0x15);
895
      APP_LCD_Data(0+0x1c);
896
 
897
      APP_LCD_Cmd(0x75);
898
      APP_LCD_Data(j);
899
 
900
      APP_LCD_Cmd(0x5c);
901
 
2571 hawkeye 902
      u8 bgcol = 0;
2182 hawkeye 903
      for (i = 0; i < 128; i++)
904
      {
2571 hawkeye 905
         // first two pixels...
906
         u8 out = screen[j][i];
907
         if (flash && out == 0)
908
            APP_LCD_Data(flash); // normally raise dark level slightly, but more intensively after 16 16th notes during flash
909
         else
910
            APP_LCD_Data(out);
911
 
912
         screen[j][i] = bgcol; // clear written pixels
913
 
914
         // next two pixels
2182 hawkeye 915
         i++;
2571 hawkeye 916
         out = screen[j][i];
917
 
918
         if (flash && out == 0)
919
            APP_LCD_Data(flash); // normally raise dark level slightly, but more intensively after 16 16th notes during flash
920
         else
921
            APP_LCD_Data(out);
922
 
923
         screen[j][i] = bgcol; // clear written pixels
2182 hawkeye 924
      }
925
   }
926
 
2571 hawkeye 927
   if (flash)
928
      oledBeatFlashState_ = 0;
2182 hawkeye 929
}
930
// ----------------------------------------------------------------------------------------
931
 
932
 
2185 hawkeye 933
/**
934
 * Render test screen, one half is "full on" for flicker tests
935
 * one half contains a color gradient pattern
936
 *
937
 */
2182 hawkeye 938
void testScreen()
939
{
940
  u16 x = 0;
941
  u16 y = 0;
942
 
943
  for (y = 0; y < 64; y++)
944
  {
945
     APP_LCD_Cmd(0x15);
946
     APP_LCD_Data(0x1c);
947
 
948
     APP_LCD_Cmd(0x75);
949
     APP_LCD_Data(y);
950
 
951
     APP_LCD_Cmd(0x5c);
952
 
953
     for (x = 0; x < 64; x++)
954
     {
955
        if (x < 32)
956
        {  // half screen pattern
957
 
958
           if (x || 4 == 0 || y || 4 == 0)
959
           {
960
              APP_LCD_Data(y & 0x0f);
961
              APP_LCD_Data(0);
962
           }
963
           else
964
           {
965
              APP_LCD_Data(0x00);
966
              APP_LCD_Data(0x00);
967
           }
968
        }
969
        else // half screen "white"
970
        {
971
           APP_LCD_Data(0xff);
972
           APP_LCD_Data(0xff);
973
        }
974
     }
975
  }
976
 
977
  while(1);
978
}
979
// -------------------------------------------------------------------------------------------