You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
3.7KB

  1. #pragma once
  2. #include <common.hpp>
  3. #include <engine/Light.hpp>
  4. namespace rack {
  5. namespace engine {
  6. static const int PORT_MAX_CHANNELS = 16;
  7. struct alignas(32) Port {
  8. /** Voltage of the port. */
  9. union {
  10. /** Unstable API. Use getVoltage() and setVoltage() instead. */
  11. float voltages[PORT_MAX_CHANNELS] = {};
  12. /** DEPRECATED. Unstable API. Use getVoltage() and setVoltage() instead. */
  13. float value;
  14. };
  15. union {
  16. /** Number of polyphonic channels
  17. Unstable API. Use set/getChannels() instead.
  18. May be 0 to PORT_MAX_CHANNELS.
  19. */
  20. uint8_t channels = 0;
  21. /** DEPRECATED. Unstable API. Use isConnected() instead. */
  22. uint8_t active;
  23. };
  24. /** For rendering plug lights on cables.
  25. Green for positive, red for negative, and blue for polyphonic.
  26. */
  27. Light plugLights[3];
  28. void setVoltage(float voltage, int channel = 0) {
  29. voltages[channel] = voltage;
  30. }
  31. /** Returns the voltage of the given channel.
  32. Because of proper bookkeeping, all channels higher than the input port's number of channels should be 0V.
  33. */
  34. float getVoltage(int channel = 0) {
  35. return voltages[channel];
  36. }
  37. /** Returns the given channel's voltage if the port is polyphonic, otherwise returns the first voltage (channel 0). */
  38. float getPolyVoltage(int channel) {
  39. return (channels == 1) ? getVoltage(0) : getVoltage(channel);
  40. }
  41. /** Returns the voltage if a cable is connected, otherwise returns the given normal voltage. */
  42. float getNormalVoltage(float normalVoltage, int channel = 0) {
  43. return isConnected() ? getVoltage(channel) : normalVoltage;
  44. }
  45. float getNormalPolyVoltage(float normalVoltage, int channel) {
  46. return isConnected() ? getPolyVoltage(channel) : normalVoltage;
  47. }
  48. /** Returns a pointer to the array of voltages beginning with firstChannel.
  49. The pointer can be used for reading and writing.
  50. Useful for SIMD.
  51. */
  52. float *getVoltages(int firstChannel = 0) {
  53. return &voltages[firstChannel];
  54. }
  55. /** Copies the port's voltages to an array of size at least `channels`. */
  56. void readVoltages(float *v) {
  57. for (int c = 0; c < channels; c++) {
  58. v[c] = voltages[c];
  59. }
  60. }
  61. /** Copies an array of size at least `channels` to the port's voltages.
  62. Remember to set the number of channels *before* calling this method.
  63. */
  64. void writeVoltages(const float *v) {
  65. for (int c = 0; c < channels; c++) {
  66. voltages[c] = v[c];
  67. }
  68. }
  69. void clearVoltages() {
  70. for (int c = 0; c < channels; c++) {
  71. voltages[c] = 0.f;
  72. }
  73. }
  74. /** Returns the sum of all voltages. */
  75. float getVoltageSum() {
  76. float sum = 0.f;
  77. for (int c = 0; c < channels; c++) {
  78. sum += voltages[c];
  79. }
  80. return sum;
  81. }
  82. /** Sets the number of polyphony channels.
  83. Also clears voltages of higher channels.
  84. If disconnected, this does nothing (`channels` remains 0).
  85. If 0 is given, `channels` is set to 1 but all voltages are cleared.
  86. */
  87. void setChannels(int channels) {
  88. // If disconnected, keep the number of channels at 0.
  89. if (this->channels == 0) {
  90. return;
  91. }
  92. // Set higher channel voltages to 0
  93. for (int c = channels; c < this->channels; c++) {
  94. voltages[c] = 0.f;
  95. }
  96. // Don't allow caller to set port as disconnected
  97. if (channels == 0) {
  98. channels = 1;
  99. }
  100. this->channels = channels;
  101. }
  102. int getChannels() {
  103. return channels;
  104. }
  105. /** Returns if a cable is connected to the Port.
  106. You can use this for skipping code that generates output voltages.
  107. */
  108. bool isConnected() {
  109. return channels > 0;
  110. }
  111. bool isMonophonic() {
  112. return channels == 1;
  113. }
  114. bool isPolyphonic() {
  115. return channels > 1;
  116. }
  117. void process(float deltaTime);
  118. /** Use getNormalVoltage() instead. */
  119. DEPRECATED float normalize(float normalVoltage) {
  120. return getNormalVoltage(normalVoltage);
  121. }
  122. };
  123. struct Output : Port {};
  124. struct Input : Port {};
  125. } // namespace engine
  126. } // namespace rack