1313#include " lib/fmt/PathFormatter.hxx"
1414#include " lib/fmt/RuntimeError.hxx"
1515#include " io/FileReader.hxx"
16+ #include " util/AllocatedArray.hxx"
1617#include " util/Domain.hxx"
1718#include " util/ScopeExit.hxx"
19+ #include " util/StringCompare.hxx"
1820
1921extern " C" {
2022#include < psgplay/psgplay.h>
@@ -24,13 +26,14 @@ extern "C" {
2426
2527#include < fmt/format.h>
2628
27- #include < fstream>
28- #include < iterator>
29- #include < string>
30- #include < vector>
31-
3229#define SUBTUNE_PREFIX " tune_"
3330
31+ /*
32+ * The Atari ST family of computers has a 24-bit bus,
33+ * so 16 MiB is more than enough for any SNDH file.
34+ */
35+ #define MAX_SNDH_FILE_SIZE 0x1000000
36+
3437static constexpr Domain psgplay_domain (" psgplay" );
3538
3639struct PsgplayGlobal {
@@ -68,28 +71,34 @@ struct PsgplayContainerPath {
6871 unsigned track;
6972};
7073
71- static std::vector< uint8_t >
74+ static AllocatedArray< std::byte >
7275psgplay_read_file (const Path &path_fs)
7376{
74- std::ifstream stream (NarrowPath (path_fs).c_str (),
75- std::ios::in | std::ios::binary);
77+ FileReader file (path_fs);
78+
79+ const size_t size = file.GetSize ();
80+
81+ if (size > MAX_SNDH_FILE_SIZE)
82+ throw FmtRuntimeError (" File larger than {} bytes: {}" ,
83+ MAX_SNDH_FILE_SIZE, path_fs);
84+
85+ AllocatedArray<std::byte> data (size);
7686
77- if (!stream)
78- return { };
87+ if (file.Read (data) != size)
88+ throw FmtRuntimeError (" Failed to read {} bytes: {}" ,
89+ size, path_fs);
7990
80- return std::vector<uint8_t >((std::istreambuf_iterator<char >(stream)),
81- std::istreambuf_iterator<char >());
91+ return data;
8292}
8393
8494[[gnu::pure]]
8595static unsigned
8696psgplay_subtune_track (const char *base) noexcept
8797{
88- if (memcmp (base, SUBTUNE_PREFIX, sizeof (SUBTUNE_PREFIX) - 1 ) != 0 )
98+ base = StringAfterPrefix (base, SUBTUNE_PREFIX);
99+ if (base == nullptr )
89100 return 0 ;
90101
91- base += sizeof (SUBTUNE_PREFIX) - 1 ;
92-
93102 char *endptr;
94103 auto track = strtoul (base, &endptr, 10 );
95104 if (endptr == base || *endptr != ' .' )
@@ -114,7 +123,7 @@ psgplay_container_from_path(Path path_fs) noexcept
114123}
115124
116125static SongTime
117- psgplay_subtune_duration (int subtune, const std::vector< uint8_t > &tune) noexcept
126+ psgplay_subtune_duration (int subtune, const AllocatedArray< std::byte > &tune) noexcept
118127{
119128 float duration;
120129
@@ -127,12 +136,12 @@ psgplay_subtune_duration(int subtune, const std::vector<uint8_t> &tune) noexcept
127136static void
128137psgplay_file_decode (DecoderClient &client, Path path_fs)
129138{
130- const auto container = psgplay_container_from_path (path_fs);
131-
132- const AudioFormat audio_format (44100 , SampleFormat::S16, 2 );
139+ static constexpr AudioFormat audio_format (44100 , SampleFormat::S16, 2 );
133140 assert (audio_format.IsValid ());
134141
135- const std::vector<uint8_t > tune = psgplay_read_file (container.path );
142+ const auto container = psgplay_container_from_path (path_fs);
143+
144+ const AllocatedArray<std::byte> tune = psgplay_read_file (container.path );
136145 if (tune.empty ())
137146 return ;
138147
@@ -151,27 +160,27 @@ psgplay_file_decode(DecoderClient &client, Path path_fs)
151160
152161 client.Ready (audio_format, true , duration);
153162
154- size_t t_samples = 0 ;
163+ size_t t_frames = 0 ;
155164 DecoderCommand cmd;
156165
157166 do {
158167 enum { N = 4096 };
159168 struct psgplay_stereo buffer[N];
160169
161- /* psgplay_read_stereo returns the number of samples */
162- const ssize_t n_samples = psgplay_read_stereo (pp, buffer, N);
163- if (n_samples <= 0 )
170+ /* psgplay_read_stereo returns the number of (stereo) frames */
171+ const ssize_t n_frames = psgplay_read_stereo (pp, buffer, N);
172+ if (n_frames <= 0 )
164173 break ;
165174
166175 cmd = client.SubmitAudio (nullptr ,
167- std::span{buffer, (size_t )n_samples },
176+ std::span{buffer, (size_t )n_frames },
168177 0 );
169- t_samples += n_samples ;
178+ t_frames += n_frames ;
170179
171180 if (cmd == DecoderCommand::SEEK) {
172- const uint64_t s_samples = client.GetSeekFrame ();
181+ const uint64_t s_frames = client.GetSeekFrame ();
173182
174- if (s_samples < t_samples ) {
183+ if (s_frames < t_frames ) {
175184 psgplay_free (pp);
176185
177186 pp = psgplay_init (tune.data (), tune.size (),
@@ -181,17 +190,20 @@ psgplay_file_decode(DecoderClient &client, Path path_fs)
181190 return ;
182191 psgplay_stop_at_time (pp, duration.ToDoubleS ());
183192
184- t_samples = 0 ;
193+ t_frames = 0 ;
185194 }
186195
187- const ssize_t k_samples =
188- psgplay_read_stereo (pp, nullptr ,
189- s_samples - t_samples);
190- if (k_samples <= 0 )
191- break ;
192- t_samples += k_samples;
196+ if (s_frames > t_frames) {
197+ const ssize_t k_frames =
198+ psgplay_read_stereo (pp, nullptr ,
199+ s_frames -
200+ t_frames);
201+ if (k_frames <= 0 )
202+ break ;
203+ t_frames += k_frames;
204+ }
193205
194- if (t_samples != s_samples )
206+ if (t_frames != s_frames )
195207 client.SeekError ();
196208
197209 client.CommandFinished ();
@@ -203,7 +215,7 @@ static void
203215psgplay_tag (enum TagType tag_type, TagHandler &th,
204216 bool (*tag)(char *text, size_t length,
205217 const void *data, const size_t size),
206- const std::vector<uint8_t > &tune) noexcept
218+ const AllocatedArray< std::byte > &tune) noexcept
207219{
208220 char text[256 ];
209221
@@ -212,14 +224,14 @@ psgplay_tag(enum TagType tag_type, TagHandler &th,
212224}
213225
214226static void
215- psgplay_tag_subtune_title (unsigned track, unsigned n_tracks,
227+ psgplay_tag_subtune_name (unsigned track, unsigned n_tracks,
216228 TagHandler &th,
217- const std::vector< uint8_t > &tune) noexcept
229+ const AllocatedArray< std::byte > &tune) noexcept
218230{
219231 char text[256 ];
220232
221- if (sndh_tag_subtune_title (text, sizeof (text), track,
222- tune.data (), tune.size ())) {
233+ if (sndh_tag_subtune_name (text, sizeof (text), track,
234+ tune.data (), tune.size ())) {
223235 th.OnTag (TAG_TITLE, text);
224236 return ;
225237 }
@@ -239,7 +251,7 @@ psgplay_tag_subtune_title(unsigned track, unsigned n_tracks,
239251}
240252
241253static int
242- psgplay_tracks (const std::vector< uint8_t > &tune) noexcept
254+ psgplay_tracks (const AllocatedArray< std::byte > &tune) noexcept
243255{
244256 int n_tracks;
245257
@@ -251,10 +263,10 @@ psgplay_tracks(const std::vector<uint8_t> &tune) noexcept
251263
252264static void
253265psgplay_on_tag (unsigned track, unsigned n_tracks, TagHandler &th,
254- const std::vector< uint8_t > &tune) noexcept
266+ const AllocatedArray< std::byte > &tune) noexcept
255267{
256268 psgplay_tag (TAG_ALBUM, th, sndh_tag_title, tune);
257- psgplay_tag_subtune_title (track, n_tracks, th, tune);
269+ psgplay_tag_subtune_name (track, n_tracks, th, tune);
258270 psgplay_tag (TAG_ARTIST, th, sndh_tag_composer, tune);
259271 psgplay_tag (TAG_DATE, th, sndh_tag_year, tune);
260272
@@ -274,7 +286,7 @@ psgplay_scan_file(Path path_fs, TagHandler &th) noexcept
274286{
275287 const auto container = psgplay_container_from_path (path_fs);
276288
277- const std::vector< uint8_t > tune = psgplay_read_file (container.path );
289+ const AllocatedArray< std::byte > tune = psgplay_read_file (container.path );
278290 if (tune.empty ())
279291 return false ;
280292
@@ -288,7 +300,7 @@ psgplay_container_scan(Path path_fs)
288300{
289301 std::forward_list<DetachedSong> list;
290302
291- const std::vector< uint8_t > tune = psgplay_read_file (path_fs);
303+ const AllocatedArray< std::byte > tune = psgplay_read_file (path_fs);
292304
293305 const int n_tracks = psgplay_tracks (tune);
294306
0 commit comments