Audio plugin host https://kx.studio/carla
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.

153 lines
4.2KB

  1. /* Copyright 2016, Ableton AG, Berlin. All rights reserved.
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. * If you would like to incorporate Link into a proprietary software application,
  17. * please contact <link-devs@ableton.com>.
  18. */
  19. #include "AudioEngine.hpp"
  20. namespace ableton
  21. {
  22. namespace link
  23. {
  24. AudioEngine::AudioEngine(Link& link)
  25. : mLink(link)
  26. , mSharedEngineData({0., false, false, 4., false})
  27. , mLockfreeEngineData(mSharedEngineData)
  28. , mIsPlaying(false)
  29. {
  30. }
  31. void AudioEngine::startPlaying()
  32. {
  33. std::lock_guard<std::mutex> lock(mEngineDataGuard);
  34. mSharedEngineData.requestStart = true;
  35. }
  36. void AudioEngine::stopPlaying()
  37. {
  38. std::lock_guard<std::mutex> lock(mEngineDataGuard);
  39. mSharedEngineData.requestStop = true;
  40. }
  41. bool AudioEngine::isPlaying() const
  42. {
  43. return mLink.captureAppSessionState().isPlaying();
  44. }
  45. double AudioEngine::beatTime() const
  46. {
  47. const auto sessionState = mLink.captureAppSessionState();
  48. return sessionState.beatAtTime(mLink.clock().micros(), mSharedEngineData.quantum);
  49. }
  50. void AudioEngine::setTempo(double tempo)
  51. {
  52. std::lock_guard<std::mutex> lock(mEngineDataGuard);
  53. mSharedEngineData.requestedTempo = tempo;
  54. }
  55. double AudioEngine::quantum() const
  56. {
  57. return mSharedEngineData.quantum;
  58. }
  59. void AudioEngine::setQuantum(double quantum)
  60. {
  61. std::lock_guard<std::mutex> lock(mEngineDataGuard);
  62. mSharedEngineData.quantum = quantum;
  63. }
  64. bool AudioEngine::isStartStopSyncEnabled() const
  65. {
  66. return mLink.isStartStopSyncEnabled();
  67. }
  68. void AudioEngine::setStartStopSyncEnabled(const bool enabled)
  69. {
  70. mLink.enableStartStopSync(enabled);
  71. }
  72. AudioEngine::EngineData AudioEngine::pullEngineData()
  73. {
  74. auto engineData = EngineData{};
  75. if (mEngineDataGuard.try_lock())
  76. {
  77. engineData.requestedTempo = mSharedEngineData.requestedTempo;
  78. mSharedEngineData.requestedTempo = 0;
  79. engineData.requestStart = mSharedEngineData.requestStart;
  80. mSharedEngineData.requestStart = false;
  81. engineData.requestStop = mSharedEngineData.requestStop;
  82. mSharedEngineData.requestStop = false;
  83. mLockfreeEngineData.quantum = mSharedEngineData.quantum;
  84. mLockfreeEngineData.startStopSyncOn = mSharedEngineData.startStopSyncOn;
  85. mEngineDataGuard.unlock();
  86. }
  87. engineData.quantum = mLockfreeEngineData.quantum;
  88. return engineData;
  89. }
  90. void AudioEngine::timelineCallback(const std::chrono::microseconds hostTime, LinkTimeInfo* const info)
  91. {
  92. const auto engineData = pullEngineData();
  93. auto sessionState = mLink.captureAudioSessionState();
  94. if (engineData.requestStart)
  95. {
  96. sessionState.setIsPlaying(true, hostTime);
  97. }
  98. if (engineData.requestStop)
  99. {
  100. sessionState.setIsPlaying(false, hostTime);
  101. }
  102. if (!mIsPlaying && sessionState.isPlaying())
  103. {
  104. // Reset the timeline so that beat 0 corresponds to the time when transport starts
  105. sessionState.requestBeatAtStartPlayingTime(0, engineData.quantum);
  106. mIsPlaying = true;
  107. }
  108. else if (mIsPlaying && !sessionState.isPlaying())
  109. {
  110. mIsPlaying = false;
  111. }
  112. if (engineData.requestedTempo > 0)
  113. {
  114. // Set the newly requested tempo from the beginning of this buffer
  115. sessionState.setTempo(engineData.requestedTempo, hostTime);
  116. }
  117. // Timeline modifications are complete, commit the results
  118. mLink.commitAudioSessionState(sessionState);
  119. // Save session state
  120. info->beatsPerBar = engineData.quantum;
  121. info->beatsPerMinute = sessionState.tempo();
  122. info->beat = sessionState.beatAtTime(hostTime, engineData.quantum);
  123. info->phase = sessionState.phaseAtTime(hostTime, engineData.quantum);
  124. info->playing = mIsPlaying;
  125. }
  126. } // namespace link
  127. } // namespace ableton