From 3a4784bdea44ace2db2e50b7e73b08d33e4f3ef3 Mon Sep 17 00:00:00 2001 From: BotoX Date: Thu, 20 May 2021 23:03:56 +0200 Subject: [PATCH] better file format? + better silence chunks --- demboyz/io/voicewriter/opusfilewriter.cpp | 57 ++++++++++------------ demboyz/io/voicewriter/opusfilewriter.h | 15 ++---- demboyz/io/voicewriter/voicedatawriter.cpp | 2 +- demopus.py | 32 ++++++++++++ 4 files changed, 65 insertions(+), 41 deletions(-) create mode 100644 demopus.py diff --git a/demboyz/io/voicewriter/opusfilewriter.cpp b/demboyz/io/voicewriter/opusfilewriter.cpp index 8805a81..ed9be98 100644 --- a/demboyz/io/voicewriter/opusfilewriter.cpp +++ b/demboyz/io/voicewriter/opusfilewriter.cpp @@ -3,6 +3,16 @@ #include #include "opusfilewriter.h" +/* +uint8_t header[16] = 'DEMOPUSHEADER_V2' +uint32_t sampleRate +uint64_t samples + +while True: + uint64_t samplesOfs + uint32_t length + uint8_t data[length] +*/ int opus_stream_write(void *user_data, const unsigned char *ptr, opus_int32 len) { @@ -29,6 +39,7 @@ OpusFileWriter::OpusFileWriter() OpusFileWriter::~OpusFileWriter() { assert(!m_Enc); + assert(!m_OutFile); } void OpusFileWriter::Init(const char* file, uint32_t sampleRate) @@ -44,16 +55,16 @@ void OpusFileWriter::Init(const char* file, uint32_t sampleRate) return; } - uint8_t customHeader[16] = {'D', 'E', 'M', 'O', 'P', 'U', 'S', 'H', 'E', 'A', 'D', 'E', 'R', '_', 'V', '1'}; + uint8_t customHeader[16] = {'D', 'E', 'M', 'O', 'P', 'U', 'S', 'H', 'E', 'A', 'D', 'E', 'R', '_', 'V', '2'}; fwrite(customHeader, sizeof(customHeader), 1, m_OutFile); - uint8_t header = HEADER_TYPE_INFO; - fwrite(&header, sizeof(header), 1, m_OutFile); m_InfoStartPos = ftell(m_OutFile); fwrite(&m_SampleRate, sizeof(m_SampleRate), 1, m_OutFile); fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile); m_Comments = ope_comments_create(); + + SwitchState(STATE_SILENCE); } void OpusFileWriter::Close() @@ -61,8 +72,7 @@ void OpusFileWriter::Close() if(!m_OutFile) return; - SwitchState(HEADER_TYPE_INFO); - SwitchState(HEADER_TYPE_DONE); + SwitchState(STATE_DONE); ope_comments_destroy(m_Comments); m_Enc = nullptr; @@ -79,29 +89,27 @@ void OpusFileWriter::SwitchState(int newState) if(m_State == newState) return; - if(m_State == HEADER_TYPE_SILENCE) + if(m_State == STATE_SILENCE) { - fwrite(&m_SilenceSamples, sizeof(m_SilenceSamples), 1, m_OutFile); + fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile); } - else if(m_State == HEADER_TYPE_OPUS) + else if(m_State == STATE_OPUS) { ope_encoder_drain(m_Enc); ope_encoder_destroy(m_Enc); m_Enc = nullptr; - m_DataEndPos = ftell(m_OutFile); + long int dataEndPos = ftell(m_OutFile); fseek(m_OutFile, m_LengthStartPos, SEEK_SET); - uint64_t dataLen = m_DataEndPos - (m_LengthStartPos + sizeof(uint64_t)); + uint32_t dataLen = dataEndPos - (m_LengthStartPos + sizeof(uint32_t)); fwrite(&dataLen, sizeof(dataLen), 1, m_OutFile); - fseek(m_OutFile, m_DataEndPos, SEEK_SET); + fseek(m_OutFile, dataEndPos, SEEK_SET); } - if(newState == HEADER_TYPE_OPUS) + if(newState == STATE_OPUS) { - uint8_t header = HEADER_TYPE_OPUS; - fwrite(&header, sizeof(header), 1, m_OutFile); m_LengthStartPos = ftell(m_OutFile); - uint64_t dataLen = 0; + uint32_t dataLen = 0; fwrite(&dataLen, sizeof(dataLen), 1, m_OutFile); int error; @@ -109,15 +117,10 @@ void OpusFileWriter::SwitchState(int newState) m_Enc = ope_encoder_create_callbacks(&opus_callbacks, (void *)this, m_Comments, m_SampleRate, 1, 0, &error); assert(error == 0); } - else if(newState == HEADER_TYPE_SILENCE) + else if(newState == STATE_SILENCE) { - m_SilenceStart = m_Samples; - m_SilenceSamples = 0; - - uint8_t header = HEADER_TYPE_SILENCE; - fwrite(&header, sizeof(header), 1, m_OutFile); } - else if(newState == HEADER_TYPE_INFO) + else if(newState == STATE_DONE) { long int backup = ftell(m_OutFile); fseek(m_OutFile, m_InfoStartPos, SEEK_SET); @@ -125,11 +128,6 @@ void OpusFileWriter::SwitchState(int newState) fwrite(&m_Samples, sizeof(m_Samples), 1, m_OutFile); fseek(m_OutFile, backup, SEEK_SET); } - else if(newState == HEADER_TYPE_DONE) - { - uint8_t header = HEADER_TYPE_DONE; - fwrite(&header, sizeof(header), 1, m_OutFile); - } m_State = newState; } @@ -150,7 +148,7 @@ void OpusFileWriter::WriteSamples(const int16_t* samples, uint32_t numSamples) if(!m_OutFile) return; - SwitchState(HEADER_TYPE_OPUS); + SwitchState(STATE_OPUS); ope_encoder_write(m_Enc, samples, numSamples); m_Samples += numSamples; @@ -162,8 +160,7 @@ void OpusFileWriter::PadSilence(uint64_t milliseconds) if(!m_OutFile || m_Samples >= numSamples) return; - SwitchState(HEADER_TYPE_SILENCE); + SwitchState(STATE_SILENCE); m_Samples = numSamples; - m_SilenceSamples = m_Samples - m_SilenceStart; } diff --git a/demboyz/io/voicewriter/opusfilewriter.h b/demboyz/io/voicewriter/opusfilewriter.h index fa6db1f..23155f4 100644 --- a/demboyz/io/voicewriter/opusfilewriter.h +++ b/demboyz/io/voicewriter/opusfilewriter.h @@ -7,11 +7,9 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) enum { - HEADER_TYPE_NONE = 0, - HEADER_TYPE_INFO = 0x01, - HEADER_TYPE_OPUS = 0x02, - HEADER_TYPE_SILENCE = 0x03, - HEADER_TYPE_DONE = 0x04 + STATE_DONE = 0, + STATE_SILENCE = 1, + STATE_OPUS = 2 }; class OpusFileWriter @@ -30,13 +28,10 @@ public: int opus_stream_close(); private: FILE *m_OutFile = nullptr; - int m_State = HEADER_TYPE_NONE; + int m_State = STATE_DONE; long int m_InfoStartPos; long int m_LengthStartPos; - long int m_DataEndPos; - - uint64_t m_SilenceStart = 0; - uint64_t m_SilenceSamples = 0; + long int m_SilenceStartPos; OggOpusComments *m_Comments = nullptr; OggOpusEnc *m_Enc = nullptr; diff --git a/demboyz/io/voicewriter/voicedatawriter.cpp b/demboyz/io/voicewriter/voicedatawriter.cpp index 9b6b581..851e997 100644 --- a/demboyz/io/voicewriter/voicedatawriter.cpp +++ b/demboyz/io/voicewriter/voicedatawriter.cpp @@ -198,7 +198,7 @@ void VoiceDataWriter::EndCommandPacket(const PacketTrailingBits& trailingBits) else if(m_isSilenced) { m_isSilenced = false; - m_silence.back().second = m_silenceTicks - m_silenceTicksStart; + m_silence.back().second = m_silenceTicks; } for(auto& state : m_playerVoiceStates) diff --git a/demopus.py b/demopus.py new file mode 100644 index 0000000..9156086 --- /dev/null +++ b/demopus.py @@ -0,0 +1,32 @@ +import struct +import sys + +with open(sys.argv[1], 'rb') as fp: + data = fp.read() + +ofs = 16 +counter = 0 + +srate = struct.unpack('I', data[ofs:ofs+4])[0] +ofs += 4 +samples = struct.unpack('Q', data[ofs:ofs+8])[0] +ofs += 8 +print(f'srate: {srate} | samples: {samples}\n') + +while ofs < len(data): + sampleOfs = struct.unpack('Q', data[ofs:ofs+8])[0] + ofs += 8 + + if ofs >= len(data): + print(f'#END (0) @ {sampleOfs}') + break + + dlen = struct.unpack('I', data[ofs:ofs+4])[0] + ofs += 4 + + with open(f'{sampleOfs}.opus', 'wb') as fp: + fp.write(data[ofs:ofs+dlen]) + ofs += dlen + + counter += 1 + print(f'#{counter} ({dlen}) @ {sampleOfs}')