Skip to content

Commit 8700d2b

Browse files
committed
AudioProcesspr: Implemented working ogg reading and writing
However, loop points were incorrectly converted and it's need to adjust them in slightly different way.
1 parent a68bef8 commit 8700d2b

8 files changed

Lines changed: 566 additions & 44 deletions

File tree

_common/AudioProcessor/audio_processor.cpp

Lines changed: 190 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,46 @@
1818
*/
1919

2020
#include "audio_processor.h"
21+
#include "codec/audio_vorbis.h"
22+
2123
#include <SDL2/SDL.h>
2224

2325

26+
bool MoondustAudioProcessor::init_cvt_stream()
27+
{
28+
const auto &source = m_in_file->getSpec();
29+
const auto &obtained = m_out_file->getSpec();
30+
31+
if(m_cvt_stream)
32+
SDL_FreeAudioStream(m_cvt_stream);
33+
34+
m_cvt_stream = SDL_NewAudioStream(source.m_sample_format, source.m_channels, source.m_sample_rate,
35+
obtained.m_sample_format, obtained.m_channels, obtained.m_sample_rate);
36+
if(!m_cvt_stream)
37+
{
38+
close();
39+
return false;
40+
}
41+
42+
size_t sample_in = (SDL_AUDIO_BITSIZE(source.m_sample_format) / 8) * source.m_channels;
43+
size_t sample_out = (SDL_AUDIO_BITSIZE(obtained.m_sample_format) / 8) * obtained.m_channels;
44+
45+
m_in_buffer.resize(MD_AUDIO_CHUNK_SIZE * sample_in);
46+
m_out_buffer.resize(MD_AUDIO_CHUNK_SIZE * sample_out);
47+
48+
m_numChunks = m_in_buffer.size() / sample_in;
49+
m_curChunk = 0;
50+
51+
return true;
52+
}
53+
2454
MoondustAudioProcessor::MoondustAudioProcessor()
2555
{}
2656

2757
MoondustAudioProcessor::~MoondustAudioProcessor()
28-
{}
58+
{
59+
close();
60+
}
2961

3062
std::string MoondustAudioProcessor::getLastError() const
3163
{
@@ -39,12 +71,93 @@ const MDAudioFileSpec &MoondustAudioProcessor::getInSpec() const
3971

4072
bool MoondustAudioProcessor::openInFile(const std::string &file, int *detectedFormat)
4173
{
42-
return false;
74+
m_in_file.reset(new MDAudioVorbis);
75+
if(m_rw_in)
76+
SDL_RWclose(m_rw_in);
77+
78+
m_rw_in = SDL_RWFromFile(file.c_str(), "rb");
79+
if(!m_rw_in)
80+
{
81+
m_in_file.reset();
82+
return false;
83+
}
84+
85+
m_in_filePath = file;
86+
87+
if(!m_in_file->openRead(m_rw_in))
88+
{
89+
m_in_file.reset();
90+
return false;
91+
}
92+
93+
if(detectedFormat)
94+
*detectedFormat = FORMAT_OGG_VORBIS;
95+
96+
return true;
4397
}
4498

4599
bool MoondustAudioProcessor::openOutFile(const std::string &file, int dstFormat, const MDAudioFileSpec &dstSpec)
46100
{
47-
return false;
101+
if(!m_in_file.get())
102+
return false;
103+
104+
m_out_file.reset(new MDAudioVorbis);
105+
if(m_rw_out)
106+
SDL_RWclose(m_rw_out);
107+
108+
m_rw_out = SDL_RWFromFile(file.c_str(), "wb");
109+
if(!m_rw_out)
110+
{
111+
m_out_file.reset();
112+
return false;
113+
}
114+
115+
m_out_filePath = file;
116+
117+
if(!m_out_file->openWrite(m_rw_out, dstSpec))
118+
{
119+
m_out_file.reset();
120+
return false;
121+
}
122+
123+
if(!init_cvt_stream())
124+
return false;
125+
126+
m_stat_read = 0;
127+
m_stat_write = 0;
128+
129+
return true;
130+
}
131+
132+
void MoondustAudioProcessor::close()
133+
{
134+
if(m_out_file.get())
135+
{
136+
m_out_file->close();
137+
m_out_file.reset();
138+
SDL_RWclose(m_rw_out);
139+
m_rw_out = nullptr;
140+
}
141+
142+
if(m_in_file.get())
143+
{
144+
m_in_file->close();
145+
m_in_file.reset();
146+
SDL_RWclose(m_rw_in);
147+
m_rw_in = nullptr;
148+
}
149+
150+
if(m_cvt_stream)
151+
{
152+
SDL_FreeAudioStream(m_cvt_stream);
153+
m_cvt_stream = nullptr;
154+
}
155+
156+
m_in_filePath.clear();
157+
m_out_filePath.clear();
158+
m_done = false;
159+
m_numChunks = 0;
160+
m_curChunk = 0;
48161
}
49162

50163
uint32_t MoondustAudioProcessor::numChunks() const
@@ -57,9 +170,82 @@ uint32_t MoondustAudioProcessor::curChunk() const
57170
return m_curChunk;
58171
}
59172

173+
int64_t MoondustAudioProcessor::getBytesReadStat() const
174+
{
175+
return m_stat_read;
176+
}
177+
178+
int64_t MoondustAudioProcessor::getBytesWrittenStat() const
179+
{
180+
return m_stat_write;
181+
}
182+
183+
int64_t MoondustAudioProcessor::getSamplesReadStat() const
184+
{
185+
const auto &source = m_in_file->getSpec();
186+
size_t sample_in = (SDL_AUDIO_BITSIZE(source.m_sample_format) / 8) * source.m_channels;
187+
188+
return m_stat_read / sample_in;
189+
}
190+
191+
int64_t MoondustAudioProcessor::getSamplesWrittenStat() const
192+
{
193+
const auto &obtained = m_out_file->getSpec();
194+
size_t sample_out = (SDL_AUDIO_BITSIZE(obtained.m_sample_format) / 8) * obtained.m_channels;
195+
196+
return m_stat_write / sample_out;
197+
}
198+
60199
bool MoondustAudioProcessor::runChunk()
61200
{
62-
return false;
201+
int filled = 0, amount = 0, written = 0, attempts = 10;
202+
bool spec_changed = false;
203+
204+
do
205+
{
206+
filled = SDL_AudioStreamGet(m_cvt_stream, m_out_buffer.data(), m_out_buffer.size());
207+
if(filled != 0)
208+
break;
209+
210+
amount = m_in_file->readChunk(m_in_buffer.data(), m_in_buffer.size(), &spec_changed);
211+
212+
if(amount == ~(size_t)0)
213+
return false;
214+
215+
if(spec_changed) // Re-Init streamer
216+
{
217+
if(!init_cvt_stream())
218+
return false;
219+
}
220+
221+
if(amount > 0)
222+
{
223+
m_stat_read += amount;
224+
m_curChunk++;
225+
if(SDL_AudioStreamPut(m_cvt_stream, m_in_buffer.data(), amount) < 0)
226+
return false;
227+
}
228+
else
229+
{
230+
SDL_AudioStreamFlush(m_cvt_stream);
231+
attempts--;
232+
if(attempts < 0)
233+
{
234+
m_done = true;
235+
return true;
236+
}
237+
}
238+
239+
} while(filled == 0);
240+
241+
written = m_out_file->writeChunk(m_out_buffer.data(), filled);
242+
243+
if(written == 0)
244+
return false;
245+
246+
m_stat_write += written;
247+
248+
return true;
63249
}
64250

65251
bool MoondustAudioProcessor::done() const

_common/AudioProcessor/audio_processor.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,21 @@ struct SDL_RWops;
3131
struct _SDL_AudioStream;
3232
typedef struct _SDL_AudioStream SDL_AudioStream;
3333

34-
#define MD_AUDIO_CHUNK_SIZE 4096
34+
#define MD_AUDIO_CHUNK_SIZE 1024
3535

3636
class MoondustAudioProcessor
3737
{
3838
std::string m_lastError;
3939
std::vector<uint8_t> m_in_buffer;
4040
std::vector<uint8_t> m_out_buffer;
4141

42+
SDL_RWops *m_rw_in = nullptr;
43+
SDL_RWops *m_rw_out = nullptr;
4244
std::unique_ptr<MDAudioFile> m_in_file;
4345
std::unique_ptr<MDAudioFile> m_out_file;
4446

45-
SDL_AudioStream *m_cvt_stream;
47+
SDL_AudioStream *m_cvt_stream = nullptr;
48+
bool init_cvt_stream();
4649

4750
uint32_t m_curChunk = 0;
4851
uint32_t m_numChunks = 0;
@@ -52,6 +55,9 @@ class MoondustAudioProcessor
5255
std::string m_in_filePath;
5356
std::string m_out_filePath;
5457

58+
int64_t m_stat_read = 0;
59+
int64_t m_stat_write = 0;
60+
5561
public:
5662
MoondustAudioProcessor();
5763
~MoondustAudioProcessor();
@@ -63,9 +69,17 @@ class MoondustAudioProcessor
6369
bool openInFile(const std::string &file, int *detectedFormat = nullptr);
6470
bool openOutFile(const std::string &file, int dstFormat, const MDAudioFileSpec &dstSpec);
6571

72+
void close();
73+
6674
uint32_t numChunks() const;
6775
uint32_t curChunk() const;
6876

77+
int64_t getBytesReadStat() const;
78+
int64_t getBytesWrittenStat() const;
79+
80+
int64_t getSamplesReadStat() const;
81+
int64_t getSamplesWrittenStat() const;
82+
6983
bool runChunk();
7084

7185
bool done() const;

_common/AudioProcessor/codec/audio_vorbis.cpp

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,40 @@ bool MDAudioVorbis::updateSection()
5454
return true;
5555
}
5656

57+
void MDAudioVorbis::writeFlush()
58+
{
59+
int eos = 0;
60+
61+
while(vorbis_analysis_blockout(&m_vd, &m_vb) == 1)
62+
{
63+
/* analysis, assume we want to use bitrate management */
64+
vorbis_analysis(&m_vb, nullptr);
65+
vorbis_bitrate_addblock(&m_vb);
66+
67+
while(vorbis_bitrate_flushpacket(&m_vd, &m_op))
68+
{
69+
/* weld the packet into the bitstream */
70+
ogg_stream_packetin(&m_os, &m_op);
71+
72+
/* write out pages (if any) */
73+
while(!eos)
74+
{
75+
int result = ogg_stream_pageout(&m_os, &m_og);
76+
if(result == 0)
77+
break;
78+
79+
SDL_RWwrite(m_file, m_og.header, 1, m_og.header_len);
80+
SDL_RWwrite(m_file, m_og.body, 1, m_og.body_len);
81+
82+
/* this could be set above, but for illustrative purposes, I do
83+
it here (to show that vorbis does know where the stream ends) */
84+
if(ogg_page_eos(&m_og))
85+
eos = 1;
86+
}
87+
}
88+
}
89+
}
90+
5791
MDAudioVorbis::MDAudioVorbis() : MDAudioFile()
5892
{}
5993

@@ -289,6 +323,8 @@ bool MDAudioVorbis::close()
289323
if(m_file)
290324
{
291325
vorbis_analysis_wrote(&m_vd, 0);
326+
writeFlush();
327+
292328
ogg_stream_clear(&m_os);
293329
vorbis_block_clear(&m_vb);
294330
vorbis_dsp_clear(&m_vd);
@@ -321,10 +357,11 @@ size_t MDAudioVorbis::readChunk(uint8_t *out, size_t outSize, bool *spec_changed
321357
#else
322358
amount = (int)ov_read(&m_vf, (char*)out, outSize, SDL_BYTEORDER == SDL_BIG_ENDIAN, 2, 1, &cur_section);
323359
#endif
324-
if (amount < 0)
360+
361+
if(amount < 0)
325362
{
326363
set_ov_error("ov_read", amount);
327-
return 0;
364+
return ~(size_t)0;
328365
}
329366

330367
if(cur_section != m_section)
@@ -344,7 +381,7 @@ size_t MDAudioVorbis::readChunk(uint8_t *out, size_t outSize, bool *spec_changed
344381
size_t MDAudioVorbis::writeChunk(uint8_t *in, size_t inSize)
345382
{
346383
long i;
347-
int eos = 0;
384+
size_t written = 0;
348385
int sample_size = m_spec.m_channels * sizeof(short);
349386
/* expose the buffer to submit data */
350387

@@ -359,36 +396,10 @@ size_t MDAudioVorbis::writeChunk(uint8_t *in, size_t inSize)
359396
buffer[c][i] = *(in_s++) / 32768.f;
360397
}
361398

399+
written += i * sample_size;
362400
vorbis_analysis_wrote(&m_vd, i);
363401

364-
while(vorbis_analysis_blockout(&m_vd, &m_vb) == 1)
365-
{
366-
/* analysis, assume we want to use bitrate management */
367-
vorbis_analysis(&m_vb, nullptr);
368-
vorbis_bitrate_addblock(&m_vb);
369-
370-
while(vorbis_bitrate_flushpacket(&m_vd, &m_op))
371-
{
372-
/* weld the packet into the bitstream */
373-
ogg_stream_packetin(&m_os, &m_op);
374-
375-
/* write out pages (if any) */
376-
while(!eos)
377-
{
378-
int result = ogg_stream_pageout(&m_os, &m_og);
379-
if(result == 0)
380-
break;
381-
382-
SDL_RWwrite(m_file, m_og.header, 1, m_og.header_len);
383-
SDL_RWwrite(m_file, m_og.body, 1, m_og.body_len);
384-
385-
/* this could be set above, but for illustrative purposes, I do
386-
it here (to show that vorbis does know where the stream ends) */
387-
if(ogg_page_eos(&m_og))
388-
eos = 1;
389-
}
390-
}
391-
}
402+
writeFlush();
392403

393-
return 0;
404+
return written;
394405
}

0 commit comments

Comments
 (0)