134 lines
4.2 KiB
C++
134 lines
4.2 KiB
C++
|
/*
|
||
|
* openmpt123_mmio.hpp
|
||
|
* -------------------
|
||
|
* Purpose: libopenmpt command line player
|
||
|
* Notes : (currently none)
|
||
|
* Authors: OpenMPT Devs
|
||
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||
|
*/
|
||
|
|
||
|
#ifndef OPENMPT123_MMIO_HPP
|
||
|
#define OPENMPT123_MMIO_HPP
|
||
|
|
||
|
#include "openmpt123_config.hpp"
|
||
|
#include "openmpt123.hpp"
|
||
|
|
||
|
#if defined(MPT_WITH_MMIO)
|
||
|
|
||
|
namespace openmpt123 {
|
||
|
|
||
|
class mmio_stream_raii : public file_audio_stream_base {
|
||
|
private:
|
||
|
std::ostream & log;
|
||
|
commandlineflags flags;
|
||
|
WAVEFORMATEX waveformatex;
|
||
|
HMMIO mmio;
|
||
|
MMCKINFO WAVE_chunk;
|
||
|
MMCKINFO fmt__chunk;
|
||
|
MMCKINFO data_chunk;
|
||
|
MMIOINFO data_info;
|
||
|
private:
|
||
|
void CHECKED( HRESULT err ) {
|
||
|
if ( err != 0 ) {
|
||
|
throw exception( "error writing wave file" );
|
||
|
}
|
||
|
}
|
||
|
void UNCHECKED( HRESULT err ) {
|
||
|
if ( err != 0 ) {
|
||
|
log << "error writing wave file" << std::endl;
|
||
|
}
|
||
|
}
|
||
|
public:
|
||
|
mmio_stream_raii( const std::string & filename, const commandlineflags & flags_, std::ostream & log_ ) : log(log_), flags(flags_), mmio(NULL) {
|
||
|
|
||
|
ZeroMemory( &waveformatex, sizeof( WAVEFORMATEX ) );
|
||
|
waveformatex.cbSize = 0;
|
||
|
waveformatex.wFormatTag = flags.use_float ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
|
||
|
waveformatex.nChannels = static_cast<WORD>( flags.channels );
|
||
|
waveformatex.nSamplesPerSec = flags.samplerate;
|
||
|
waveformatex.wBitsPerSample = flags.use_float ? 32 : 16;
|
||
|
waveformatex.nBlockAlign = static_cast<WORD>( flags.channels * ( waveformatex.wBitsPerSample / 8 ) );
|
||
|
waveformatex.nAvgBytesPerSec = waveformatex.nSamplesPerSec * waveformatex.nBlockAlign;
|
||
|
|
||
|
#if defined(WIN32) && defined(UNICODE)
|
||
|
wchar_t * tmp = _wcsdup( mpt::transcode<std::wstring>( mpt::common_encoding::utf8, filename ).c_str() );
|
||
|
mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE );
|
||
|
free( tmp );
|
||
|
tmp = 0;
|
||
|
#else
|
||
|
char * tmp = strdup( filename.c_str() );
|
||
|
mmio = mmioOpen( tmp, NULL, MMIO_ALLOCBUF | MMIO_READWRITE | MMIO_CREATE );
|
||
|
free( tmp );
|
||
|
tmp = 0;
|
||
|
#endif
|
||
|
|
||
|
ZeroMemory( &WAVE_chunk, sizeof( MMCKINFO ) );
|
||
|
WAVE_chunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
|
||
|
CHECKED(mmioCreateChunk( mmio, &WAVE_chunk, MMIO_CREATERIFF ));
|
||
|
|
||
|
ZeroMemory( &fmt__chunk, sizeof( MMCKINFO ) );
|
||
|
fmt__chunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
|
||
|
fmt__chunk.cksize = sizeof( WAVEFORMATEX );
|
||
|
CHECKED(mmioCreateChunk( mmio, &fmt__chunk, 0 ));
|
||
|
|
||
|
mmioWrite( mmio, (const char*)&waveformatex, sizeof( WAVEFORMATEX ) );
|
||
|
|
||
|
CHECKED(mmioAscend( mmio, &fmt__chunk, 0 ));
|
||
|
|
||
|
ZeroMemory( &data_chunk, sizeof( MMCKINFO ) );
|
||
|
data_chunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
|
||
|
data_chunk.cksize = 0;
|
||
|
CHECKED(mmioCreateChunk( mmio, &data_chunk, 0 ));
|
||
|
|
||
|
ZeroMemory( &data_info, sizeof( MMIOINFO ) );
|
||
|
CHECKED(mmioGetInfo( mmio, &data_info, 0 ));
|
||
|
|
||
|
}
|
||
|
|
||
|
void write( const std::vector<float*> buffers, std::size_t frames ) override {
|
||
|
for ( std::size_t frame = 0; frame < frames; frame++ ) {
|
||
|
for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) {
|
||
|
if ( data_info.pchEndWrite - data_info.pchNext < static_cast<long>( sizeof( float ) ) ) {
|
||
|
data_info.dwFlags |= MMIO_DIRTY;
|
||
|
CHECKED(mmioAdvance( mmio, &data_info, MMIO_WRITE ));
|
||
|
}
|
||
|
std::memcpy( data_info.pchNext, &( buffers[channel][frame] ), sizeof( float ) );
|
||
|
data_info.pchNext += sizeof( float );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void write( const std::vector<std::int16_t*> buffers, std::size_t frames ) override {
|
||
|
for ( std::size_t frame = 0; frame < frames; frame++ ) {
|
||
|
for ( std::size_t channel = 0; channel < buffers.size(); channel++ ) {
|
||
|
if ( data_info.pchEndWrite - data_info.pchNext < static_cast<long>( sizeof( std::int16_t ) ) ) {
|
||
|
data_info.dwFlags |= MMIO_DIRTY;
|
||
|
CHECKED(mmioAdvance( mmio, &data_info, MMIO_WRITE ));
|
||
|
}
|
||
|
std::memcpy( data_info.pchNext, &( buffers[channel][frame] ), sizeof( std::int16_t ) );
|
||
|
data_info.pchNext += sizeof( std::int16_t );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~mmio_stream_raii() {
|
||
|
|
||
|
data_info.dwFlags |= MMIO_DIRTY;
|
||
|
UNCHECKED(mmioSetInfo( mmio, &data_info, 0 ));
|
||
|
|
||
|
UNCHECKED(mmioAscend( mmio, &data_chunk, 0 ));
|
||
|
|
||
|
UNCHECKED(mmioAscend( mmio, &WAVE_chunk, 0 ));
|
||
|
|
||
|
UNCHECKED(mmioClose( mmio, 0 ));
|
||
|
mmio = NULL;
|
||
|
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace openmpt123
|
||
|
|
||
|
#endif // MPT_WITH_MMIO
|
||
|
|
||
|
#endif // OPENMPT123_MMIO_HPP
|