main.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. 
  2. /*
  3. TODO:
  4. * Create a visual graph with instruments, filters, speakers and file recorders to test a modular sound engine.
  5. * Allow recording the output of a session into a hi-fi stereo sound buffer, which can later be exported as a file.
  6. * Create a basic compressed music format for looping sounds in different speed and volume from compressed interpolated curves.
  7. * Make a list of named instruments containing a list of voices.
  8. Each voice refers to a sound buffer by index (using names in files) and an envelope for how to play the sound.
  9. Each voice will be played as its own instrument but from the same input for a richer sound without having to duplicate notes.
  10. The sounds can be either embedded into the project (editable for tiny instrument patterns) or refer to external files (for whole music tracks).
  11. */
  12. #include "../../DFPSR/includeFramework.h"
  13. #include "sound.h"
  14. using namespace dsr;
  15. // Global
  16. bool running = true;
  17. Window window;
  18. Component mainPanel;
  19. Component toolPanel;
  20. String interfaceContent =
  21. UR"QUOTE(
  22. Begin : Panel
  23. Name = "mainPanel"
  24. Solid = 0
  25. Begin : Panel
  26. Name = "toolPanel"
  27. Color = 180,180,180
  28. Solid = 1
  29. bottom = 50
  30. End
  31. End
  32. )QUOTE";
  33. static const double pi = 3.1415926535897932384626433832795;
  34. static const double cyclesToRadians = pi * 2.0;
  35. static const int toneCount = 9;
  36. int basicTone, testSound;
  37. int playing[toneCount];
  38. void createTestProject() {
  39. for (int t = 0; t < toneCount; t++) {
  40. playing[t] = -1;
  41. }
  42. // Pure tone
  43. basicTone = generateMonoSoundBuffer(U"sine", 441, 44100, [](double time) -> float {
  44. return sin(time * (cyclesToRadians * 100));
  45. });
  46. // Loaded from file
  47. testSound = loadSoundFromFile(U"Water.wav");
  48. }
  49. static EnvelopeSettings envelope = EnvelopeSettings(0.1, 0.2, 0.8, 0.4, 0.1, -0.02, 0.04, 0.5);
  50. static double previewPressTime = 1.0;
  51. static double previewViewTime = 4.0;
  52. static int selectedBuffer = 0;
  53. static void limitSelection() {
  54. int maxIndex = getSoundBufferCount() - 1;
  55. if (selectedBuffer < 0) selectedBuffer = 0;
  56. if (selectedBuffer > maxIndex) selectedBuffer = maxIndex;
  57. }
  58. DSR_MAIN_CALLER(dsrMain)
  59. void dsrMain(List<String> args) {
  60. // Start sound thread
  61. printText("Initializing sound\n");
  62. sound_initialize();
  63. // Create something to test
  64. printText("Creating test project\n");
  65. createTestProject();
  66. // Create a window
  67. window = window_create(U"Sound generator", 800, 600);
  68. // Load an interface to the window
  69. window_loadInterfaceFromString(window, interfaceContent);
  70. // Find components
  71. mainPanel = window_findComponentByName(window, U"mainPanel");
  72. toolPanel = window_findComponentByName(window, U"toolPanel");
  73. // Bind methods to events
  74. window_setKeyboardEvent(window, [](const KeyboardEvent& event) {
  75. DsrKey key = event.dsrKey;
  76. if (event.keyboardEventType == KeyboardEventType::KeyDown) {
  77. if (key == DsrKey_Escape) {
  78. running = false;
  79. } else if (key >= DsrKey_1 && key <= DsrKey_9) {
  80. int toneIndex = key - DsrKey_1;
  81. playing[toneIndex] = playSound(basicTone, true, 0.25, 0.25, 3.0 + toneIndex * 0.25, envelope);
  82. } else if (key == DsrKey_A) {
  83. playSound(testSound, false, 1.0, 0.0, 1.0);
  84. } else if (key == DsrKey_S) {
  85. playSound(testSound, false, 1.0, 1.0, 1.0);
  86. } else if (key == DsrKey_D) {
  87. playSound(testSound, false, 0.0, 1.0, 1.0);
  88. } else if (key == DsrKey_UpArrow) {
  89. selectedBuffer--;
  90. limitSelection();
  91. } else if (key == DsrKey_DownArrow) {
  92. selectedBuffer++;
  93. limitSelection();
  94. }
  95. } else if (event.keyboardEventType == KeyboardEventType::KeyUp) {
  96. if (key >= DsrKey_1 && key <= DsrKey_9) {
  97. int toneIndex = key - DsrKey_1;
  98. releaseSound(playing[toneIndex]); // Soft stop with following release
  99. } else if (key == DsrKey_Space) {
  100. stopAllSounds();
  101. }
  102. }
  103. });
  104. /*
  105. component_setMouseDownEvent(mainPanel, [](const MouseEvent& event) {
  106. });
  107. component_setMouseMoveEvent(mainPanel, [](const MouseEvent& event) {
  108. });
  109. component_setMouseUpEvent(mainPanel, [](const MouseEvent& event) {
  110. });
  111. */
  112. window_setCloseEvent(window, []() {
  113. running = false;
  114. });
  115. // Execute
  116. while(running) {
  117. // Wait for actions so that we don't render until an action has been recieved
  118. // This will save battery on laptops for applications that don't require animation
  119. while (!window_executeEvents(window)) {
  120. time_sleepSeconds(0.01);
  121. }
  122. // Fill the background
  123. AlignedImageRgbaU8 canvas = window_getCanvas(window);
  124. image_fill(canvas, ColorRgbaI32(64, 64, 64, 255));
  125. int width = image_getWidth(canvas);
  126. // Draw things
  127. drawEnvelope(canvas, IRect(0, 50, width, 100), envelope, previewPressTime, previewViewTime);
  128. // TODO: Group into a visual component for viewing sound buffers.
  129. int top = 150;
  130. for (int s = 0; s < getSoundBufferCount(); s++) {
  131. int height = 100;
  132. drawSound(canvas, IRect(0, top, width, height), s, s == selectedBuffer);
  133. top += height;
  134. }
  135. // Draw interface
  136. window_drawComponents(window);
  137. // Show the final image
  138. window_showCanvas(window);
  139. }
  140. // Close sound thread
  141. printText("Terminating sound\n");
  142. sound_terminate();
  143. }