player.ino 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #include <SPI.h>
  2. #include <GD.h>
  3. #include "mont.h"
  4. // visualize voice (v) at amplitude (a) on an 8x8 grid
  5. void visualize(byte v, byte a)
  6. {
  7. int x = 64 + ((v & 7) * 34);
  8. int y = 14 + ((v >> 3) * 34);
  9. byte sprnum = (v << 2); // draw each voice using four sprites
  10. GD.sprite(sprnum++, x + 16, y + 16, a, 0, 0);
  11. GD.sprite(sprnum++, x + 0, y + 16, a, 0, 2);
  12. GD.sprite(sprnum++, x + 16, y + 0, a, 0, 4);
  13. GD.sprite(sprnum++, x + 0, y + 0, a, 0, 6);
  14. }
  15. void setup()
  16. {
  17. int i;
  18. GD.begin();
  19. GD.wr16(RAM_SPRPAL + 2 * 255, TRANSPARENT);
  20. // draw 32 circles into 32 sprite images
  21. for (i = 0; i < 32; i++) {
  22. GD.wr16(RAM_SPRPAL + 2 * i, RGB(8 * i, 64, 255 - 8 * i));
  23. int dst = RAM_SPRIMG + 256 * i;
  24. GD.__wstart(dst);
  25. byte x, y;
  26. int r2 = min(i * i, 256);
  27. for (y = 0; y < 16; y++) {
  28. for (x = 0; x < 16; x++) {
  29. byte pixel;
  30. if ((x * x + y * y) <= r2)
  31. pixel = i; // use color above
  32. else
  33. pixel = 0xff; // transparent
  34. SPI.transfer(pixel);
  35. }
  36. }
  37. GD.__end();
  38. }
  39. Serial.begin(1000000); // JCB
  40. for (i = 0; i < 64; i++)
  41. visualize(i, 0);
  42. }
  43. byte amp[64]; // current voice amplitude
  44. byte target[64]; // target voice amplitude
  45. int shot; // JCB
  46. // Set volume for voice v to a
  47. void setvol(byte v, byte a)
  48. {
  49. GD.__wstart(VOICES + (v << 2) + 2);
  50. SPI.transfer(a);
  51. SPI.transfer(a);
  52. GD.__end();
  53. }
  54. void adsr() // handle ADSR for 64 voices
  55. {
  56. byte v;
  57. for (v = 0; v < 64; v++) {
  58. int d = target[v] - amp[v]; // +ve means need to increase
  59. if (d) {
  60. if (d > 0)
  61. amp[v] += 4; // attack
  62. else
  63. amp[v]--; // decay
  64. setvol(v, amp[v]);
  65. visualize(v, amp[v]);
  66. }
  67. }
  68. }
  69. void loop()
  70. {
  71. flash_uint8_t *pc;
  72. long started = millis();
  73. int ticks = 0;
  74. for (pc = mont; pc < mont + sizeof(mont);) {
  75. byte cmd = pgm_read_byte_near(pc++); // upper 2 bits are command code
  76. if ((cmd & 0xc0) == 0) {
  77. // Command 0x00: pause N*5 milliseconds
  78. ticks += (cmd & 63);
  79. while (millis() < (started + ticks * 5)) {
  80. adsr();
  81. delay(1);
  82. }
  83. // while ((shot*4) < ticks) GD.screenshot(shot++); // JCB
  84. } else {
  85. byte v = (cmd & 63);
  86. byte a;
  87. if ((cmd & 0xc0) == 0x40) {
  88. // Command 0x40: silence voice
  89. target[v] = 0;
  90. } else if ((cmd & 0xc0) == 0x80) {
  91. // Command 0x80: set voice frequency and amplitude
  92. byte flo = pgm_read_byte_near(pc++);
  93. byte fhi = pgm_read_byte_near(pc++);
  94. GD.__wstart(VOICES + 4 * v);
  95. SPI.transfer(flo);
  96. SPI.transfer(fhi);
  97. GD.__end();
  98. target[v] = pgm_read_byte_near(pc++);
  99. }
  100. }
  101. }
  102. }