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.

111 lines
2.3KB

  1. #include "WavWriter.hpp"
  2. #include "write_wav.h"
  3. #include <samplerate.h>
  4. #include <engine.hpp>
  5. #include <iostream>
  6. std::string WavWriter::getErrorText(Errors const error)
  7. {
  8. std::string text;
  9. switch (error)
  10. {
  11. case Errors::BufferOverflow:
  12. text = "buffer overflow";
  13. break;
  14. case Errors::UnableToOpenFile:
  15. text = "unable to open file for writing";
  16. break;
  17. default:
  18. break;
  19. }
  20. return text;
  21. }
  22. WavWriter::WavWriter() :
  23. m_running(false)
  24. {
  25. // The buffer can store 1 seconds
  26. m_buffer.reserve(rack::engineGetSampleRate());
  27. }
  28. WavWriter::~WavWriter()
  29. {
  30. stop();
  31. finishThread();
  32. }
  33. void WavWriter::start(std::string const& outputFilePath)
  34. {
  35. finishThread();
  36. m_error = Errors::NoError;
  37. m_buffer.clear();
  38. m_thread = std::thread(&WavWriter::run, this, outputFilePath);
  39. }
  40. void WavWriter::stop()
  41. {
  42. if (m_running)
  43. {
  44. m_running = false;
  45. }
  46. }
  47. void WavWriter::push(Frame const& frame)
  48. {
  49. std::unique_lock<std::mutex> lock(m_mutexBuffer);
  50. m_buffer.push_back(frame);
  51. }
  52. void WavWriter::run(std::string const& outputFilePath)
  53. {
  54. static std::chrono::milliseconds const WriteTimeInterval{250};
  55. // The internal buffer can store 1 second of audio.
  56. std::vector<short> buffer(rack::engineGetSampleRate() * ChannelCount, 0);
  57. std::chrono::milliseconds elapsedTime{0u};
  58. WAV_Writer writer;
  59. if (Audio_WAV_OpenWriter(&writer, outputFilePath.c_str(), rack::engineGetSampleRate(), ChannelCount) < 0)
  60. {
  61. m_error = Errors::UnableToOpenFile;
  62. return;
  63. }
  64. else
  65. {
  66. m_running = true;
  67. }
  68. while (m_running)
  69. {
  70. std::this_thread::sleep_for(WriteTimeInterval - elapsedTime);
  71. auto currentTime = std::chrono::steady_clock::now();
  72. std::unique_lock<std::mutex> lock(m_mutexBuffer);
  73. auto const frameCount = m_buffer.size();
  74. auto const sampleCount = frameCount * ChannelCount;
  75. if(sampleCount > buffer.size())
  76. {
  77. m_running = false;
  78. m_error = Errors::BufferOverflow;
  79. break;
  80. }
  81. src_float_to_short_array(m_buffer.data()->samples, buffer.data(), sampleCount);
  82. m_buffer.clear();
  83. lock.unlock();
  84. Audio_WAV_WriteShorts(&writer, buffer.data(), sampleCount);
  85. elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - currentTime);
  86. }
  87. Audio_WAV_CloseWriter(&writer);
  88. }
  89. void WavWriter::finishThread()
  90. {
  91. if (m_thread.joinable())
  92. m_thread.join();
  93. }