openmpt123_mmio.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * openmpt123_mmio.hpp
  3. * -------------------
  4. * Purpose: libopenmpt command line player
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #ifndef OPENMPT123_MMIO_HPP
  10. #define OPENMPT123_MMIO_HPP
  11. #include "openmpt123_config.hpp"
  12. #include "openmpt123.hpp"
  13. #if defined(MPT_WITH_MMIO)
  14. namespace openmpt123 {
  15. class mmio_stream_raii : public file_audio_stream_base {
  16. private:
  17. std::ostream & log;
  18. commandlineflags flags;
  19. WAVEFORMATEX waveformatex;
  20. HMMIO mmio;
  21. MMCKINFO WAVE_chunk;
  22. MMCKINFO fmt__chunk;
  23. MMCKINFO data_chunk;
  24. MMIOINFO data_info;
  25. private:
  26. void CHECKED( HRESULT err ) {
  27. if ( err != 0 ) {
  28. throw exception( "error writing wave file" );
  29. }
  30. }
  31. void UNCHECKED( HRESULT err ) {
  32. if ( err != 0 ) {
  33. log << "error writing wave file" << std::endl;
  34. }
  35. }
  36. public:
  37. mmio_stream_raii( const std::string & filename, const commandlineflags & flags_, std::ostream & log_ ) : log(log_), flags(flags_), mmio(NULL) {
  38. ZeroMemory( &waveformatex, sizeof( WAVEFORMATEX ) );
  39. waveformatex.cbSize = 0;
  40. waveformatex.wFormatTag = flags.use_float ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
  41. waveformatex.nChannels = static_cast<WORD>( flags.channels );
  42. waveformatex.nSamplesPerSec = flags.samplerate;
  43. waveformatex.wBitsPerSample = flags.use_float ? 32 : 16;
  44. waveformatex.nBlockAlign = static_cast<WORD>( flags.channels * ( waveformatex.wBitsPerSample / 8 ) );
  45. waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign;
  46. #if defined(WIN32) && defined(UNICODE)
  47. wchar_t * tmp = _wcsdup( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ).c_str() );
  48. mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE );
  49. free( tmp );
  50. tmp = 0;
  51. #else
  52. char * tmp = strdup( filename.c_str() );
  53. mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE );
  54. free( tmp );
  55. tmp = 0;
  56. #endif
  57. ZeroMemory( &WAVE_chunk, sizeof( MMCKINFO ) );
  58. WAVE_chunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  59. CHECKED(mmioCreateChunk( mmio, &WAVE_chunk, MMIO_CREATERIFF ));
  60. ZeroMemory( &fmt__chunk, sizeof( MMCKINFO ) );
  61. fmt__chunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  62. fmt__chunk.cksize = sizeof( WAVEFORMATEX );
  63. CHECKED(mmioCreateChunk( mmio, &fmt__chunk, 0 ));
  64. mmioWrite( mmio, (const char*)&waveformatex, sizeof( WAVEFORMATEX ) );
  65. CHECKED(mmioAscend( mmio, &fmt__chunk, 0 ));
  66. ZeroMemory( &data_chunk, sizeof( MMCKINFO ) );
  67. data_chunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  68. data_chunk.cksize = 0;
  69. CHECKED(mmioCreateChunk( mmio, &data_chunk, 0 ));
  70. ZeroMemory( &data_info, sizeof( MMIOINFO ) );
  71. CHECKED(mmioGetInfo( mmio, &data_info, 0 ));
  72. }
  73. void write( const std::vector<float*> buffers, std::size_t frames ) override {
  74. for ( std::size_t frame = 0; frame < frames; frame++ ) {
  75. for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) {
  76. if ( data_info.pchEndWrite - data_info.pchNext < static_cast<long>( sizeof( float ) ) ) {
  77. data_info.dwFlags |= MMIO_DIRTY;
  78. CHECKED(mmioAdvance( mmio, &data_info, MMIO_WRITE ));
  79. }
  80. std::memcpy( data_info.pchNext, &( buffers[channel][frame] ), sizeof( float ) );
  81. data_info.pchNext += sizeof( float );
  82. }
  83. }
  84. }
  85. void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override {
  86. for ( std::size_t frame = 0; frame < frames; frame++ ) {
  87. for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) {
  88. if ( data_info.pchEndWrite - data_info.pchNext < static_cast<long>( sizeof( std::int16_t ) ) ) {
  89. data_info.dwFlags |= MMIO_DIRTY;
  90. CHECKED(mmioAdvance( mmio, &data_info, MMIO_WRITE ));
  91. }
  92. std::memcpy( data_info.pchNext, &( buffers[channel][frame] ), sizeof( std::int16_t ) );
  93. data_info.pchNext += sizeof( std::int16_t );
  94. }
  95. }
  96. }
  97. ~mmio_stream_raii() {
  98. data_info.dwFlags |= MMIO_DIRTY;
  99. UNCHECKED(mmioSetInfo( mmio, &data_info, 0 ));
  100. UNCHECKED(mmioAscend( mmio, &data_chunk, 0 ));
  101. UNCHECKED(mmioAscend( mmio, &WAVE_chunk, 0 ));
  102. UNCHECKED(mmioClose( mmio, 0 ));
  103. mmio = NULL;
  104. }
  105. };
  106. } // namespace openmpt123
  107. #endif // MPT_WITH_MMIO
  108. #endif // OPENMPT123_MMIO_HPP