Subversion Repositories svn.mios32

Rev

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