2 #define WIN32_LEAN_AND_MEAN
8 inline void Sleep(uint32_t ms
)
10 struct timespec ts
, rem
;
11 ts
.tv_sec
= ms
/ 1000;
12 ts
.tv_nsec
= (ms
% 1000) * 1000000;
13 while(nanosleep(&ts
, &rem
) == -1 && errno
== EINTR
)
30 // Some I/O function callback wrappers for DUMB to read from an std::istream
31 static int cb_skip(void *user_data
, long offset
)
33 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
36 if(stream
->seekg(offset
, std::ios_base::cur
))
41 static long cb_read(char *ptr
, long size
, void *user_data
)
43 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
46 stream
->read(ptr
, size
);
47 return stream
->gcount();
50 static int cb_read_char(void *user_data
)
52 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
56 stream
->read(reinterpret_cast<char*>(&ret
), 1);
57 if(stream
->gcount() > 0) return ret
;
61 static int cb_seek(void *user_data
, long n
)
63 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
71 static long cb_get_size(void *user_data
)
73 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
77 std::streampos pos
= stream
->tellg();
78 if(pos
!= -1 && stream
->seekg(0, std::ios::end
))
80 len
= stream
->tellg();
87 // Inherit from alure::Decoder to make a custom decoder (DUMB for this example)
88 class DumbDecoder
: public alure::Decoder
{
89 alure::SharedPtr
<std::istream
> mFile
;
90 std::unique_ptr
<DUMBFILE_SYSTEM
> mDfs
;
93 DUH_SIGRENDERER
*mRenderer
;
95 std::vector
<sample_t
> mSampleBuf
;
99 DumbDecoder(alure::SharedPtr
<std::istream
> file
, std::unique_ptr
<DUMBFILE_SYSTEM
> &&dfs
, DUMBFILE
*dfile
, DUH
*duh
, DUH_SIGRENDERER
*renderer
, ALuint freq
)
100 : mFile(file
), mDfs(std::move(dfs
)), mDumbfile(dfile
), mDuh(duh
), mRenderer(renderer
), mFrequency(freq
),
103 virtual ~DumbDecoder()
105 duh_end_sigrenderer(mRenderer
);
111 dumbfile_close(mDumbfile
);
115 virtual ALuint
getFrequency() const final
116 { return mFrequency
; }
117 virtual alure::ChannelConfig
getChannelConfig() const final
119 // We always have DUMB render to stereo
120 return alure::ChannelConfig_Stereo
;
122 virtual alure::SampleType
getSampleType() const final
124 // DUMB renders to 8.24 normalized fixed point, which we convert to
125 // signed 16-bit samples
126 return alure::SampleType_Int16
;
129 virtual uint64_t getLength() final
131 // Modules have no explicit length, they just keep playing as long as
132 // more samples get generated.
136 virtual uint64_t getPosition() final
141 virtual bool seek(uint64_t) final
147 virtual std::pair
<uint64_t,uint64_t> getLoopPoints() const final
150 return std::make_pair(0, 0);
153 virtual ALuint
read(ALvoid
*ptr
, ALuint count
) final
157 mSampleBuf
.resize(count
*2);
158 sample_t
*samples
[] = {
162 dumb_silence(samples
[0], mSampleBuf
.size());
163 ret
= duh_sigrenderer_generate_samples(mRenderer
, 1.0f
, 65536.0f
/mFrequency
, count
, samples
);
164 for(ALuint i
= 0;i
< ret
*2;i
++)
166 sample_t smp
= samples
[0][i
]>>8;
167 if(smp
< -32768) smp
= -32768;
168 else if(smp
> 32767) smp
= 32767;
169 ((ALshort
*)ptr
)[i
] = smp
;
177 // Inherit from alure::DecoderFactory to use our custom decoder
178 class DumbFactory
: public alure::DecoderFactory
{
179 virtual alure::SharedPtr
<alure::Decoder
> createDecoder(alure::SharedPtr
<std::istream
> file
)
181 static DUH
* (*funcs
[])(DUMBFILE
*) = {
188 std::unique_ptr
<DUMBFILE_SYSTEM
> dfs(new DUMBFILE_SYSTEM
);
191 dfs
->getc
= cb_read_char
;
192 dfs
->getnc
= cb_read
;
193 dfs
->close
= nullptr;
195 dfs
->get_size
= cb_get_size
;
197 DUMBFILE
*dfile
= dumbfile_open_ex(file
.get(), dfs
.get());
198 if(!dfile
) return nullptr;
200 ALuint freq
= alure::Context::GetCurrent()->getDevice()->getFrequency();
201 DUH_SIGRENDERER
*renderer
;
204 for(size_t i
= 0;funcs
[i
];i
++)
206 if((duh
=funcs
[i
](dfile
)) != nullptr)
208 if((renderer
=duh_start_sigrenderer(duh
, 0, 2, 0)) != nullptr)
209 return alure::SharedPtr
<alure::Decoder
>(new DumbDecoder(
210 file
, std::move(dfs
), dfile
, duh
, renderer
, freq
217 dumbfile_seek(dfile
, 0, SEEK_SET
);
220 if((duh
=dumb_read_mod(dfile
, 1)) != nullptr)
222 if((renderer
=duh_start_sigrenderer(duh
, 0, 2, 0)) != nullptr)
223 return alure::SharedPtr
<alure::Decoder
>(new DumbDecoder(
224 file
, std::move(dfs
), dfile
, duh
, renderer
, freq
231 dumbfile_close(dfile
);
239 int main(int argc
, char *argv
[])
241 // Set our custom factory for decoding modules (Alure keeps a reference to the factory
243 alure::RegisterDecoder("dumb", alure::SharedPtr
<alure::DecoderFactory
>(new DumbFactory
));
245 alure::DeviceManager
*devMgr
= alure::DeviceManager::get();
247 alure::Device
*dev
= devMgr
->openPlayback();
248 std::cout
<< "Opened \""<<dev
->getName(alure::PlaybackDevType_Basic
)<<"\"" <<std::endl
;
250 alure::Context
*ctx
= dev
->createContext();
251 alure::Context::MakeCurrent(ctx
);
253 for(int i
= 1;i
< argc
;i
++)
255 alure::SharedPtr
<alure::Decoder
> decoder(ctx
->createDecoder(argv
[i
]));
256 alure::Source
*source
= ctx
->getSource();
257 source
->play(decoder
, 32768, 4);
258 std::cout
<< "Playing "<<argv
[i
]<<" ("<<alure::GetSampleTypeName(decoder
->getSampleType())<<", "
259 <<alure::GetChannelConfigName(decoder
->getChannelConfig())<<", "
260 <<decoder
->getFrequency()<<"hz)" <<std::endl
;
262 float invfreq
= 1.0f
/ decoder
->getFrequency();
263 while(source
->isPlaying())
265 std::cout
<< "\r "<<std::setiosflags(std::ios::fixed
)<<std::setprecision(2)<<
266 (source
->getOffset()*invfreq
)<<" / "<<(decoder
->getLength()*invfreq
);
271 std::cout
<<std::endl
;
278 alure::Context::MakeCurrent(nullptr);