1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 samples.c
6
7 Sound device for sample playback.
8
9 ****************************************************************************
10
11 Playback of pre-recorded samples. Used for high-level simulation of
12 discrete sound circuits where proper low-level simulation isn't
13 available. Also used for tape loops and similar.
14
15 Current limitations
16 - Only supports single channel samples!
17
18 Considerations
19 - Maybe this should be part of the presentation layer
20 (artwork etc.) with samples specified in .lay files instead of
21 in drivers?
22
23 ***************************************************************************/
24
25 #include "emu.h"
26 #include "samples.h"
27
28 #include "emuopts.h"
29
30 #include "flac.h"
31
32
33 //**************************************************************************
34 // GLOBAL VARIABLES
35 //**************************************************************************
36
37 // device type definition
38 DEFINE_DEVICE_TYPE(SAMPLES, samples_device, "samples", "Samples")
39
40
41
42 //**************************************************************************
43 // LIVE DEVICE
44 //**************************************************************************
45
46 //-------------------------------------------------
47 // samples_device - constructors
48 //-------------------------------------------------
49
samples_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)50 samples_device::samples_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
51 : samples_device(mconfig, SAMPLES, tag, owner, clock)
52 {
53 }
54
samples_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)55 samples_device::samples_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
56 : device_t(mconfig, type, tag, owner, clock)
57 , device_sound_interface(mconfig, *this)
58 , m_channels(0)
59 , m_names(nullptr)
60 , m_samples_start_cb(*this)
61 {
62 }
63
64
65 //**************************************************************************
66 // PUBLIC INTERFACE
67 //**************************************************************************
68
69 //-------------------------------------------------
70 // start - start playing a loaded sample
71 //-------------------------------------------------
72
start(uint8_t channel,uint32_t samplenum,bool loop)73 void samples_device::start(uint8_t channel, uint32_t samplenum, bool loop)
74 {
75 // if samples are disabled, just return quietly
76 if (m_sample.empty())
77 return;
78
79 assert(samplenum < m_sample.size());
80 assert(channel < m_channels);
81
82 // force an update before we start
83 channel_t &chan = m_channel[channel];
84 chan.stream->update();
85
86 // update the parameters
87 sample_t &sample = m_sample[samplenum];
88 chan.source = (sample.data.size() > 0) ? &sample.data[0] : nullptr;
89 chan.source_num = (chan.source_len > 0) ? samplenum : -1;
90 chan.source_len = sample.data.size();
91 chan.pos = 0;
92 chan.basefreq = sample.frequency;
93 chan.curfreq = sample.frequency;
94 chan.loop = loop;
95 }
96
97
98 //-------------------------------------------------
99 // start_raw - start playing an externally
100 // provided sample
101 //-------------------------------------------------
102
start_raw(uint8_t channel,const int16_t * sampledata,uint32_t samples,uint32_t frequency,bool loop)103 void samples_device::start_raw(uint8_t channel, const int16_t *sampledata, uint32_t samples, uint32_t frequency, bool loop)
104 {
105 assert(channel < m_channels);
106
107 // force an update before we start
108 channel_t &chan = m_channel[channel];
109 chan.stream->update();
110
111 // update the parameters
112 chan.source = sampledata;
113 chan.source_num = -1;
114 chan.source_len = samples;
115 chan.pos = 0;
116 chan.basefreq = frequency;
117 chan.curfreq = frequency;
118 chan.loop = loop;
119 }
120
121
122 //-------------------------------------------------
123 // set_frequency - set the playback frequency of
124 // a sample
125 //-------------------------------------------------
126
set_frequency(uint8_t channel,uint32_t freq)127 void samples_device::set_frequency(uint8_t channel, uint32_t freq)
128 {
129 assert(channel < m_channels);
130
131 // force an update before we start
132 channel_t &chan = m_channel[channel];
133 chan.stream->update();
134 chan.curfreq = freq;
135 }
136
137
138 //-------------------------------------------------
139 // set_volume - set the playback volume of a
140 // sample
141 //-------------------------------------------------
142
set_volume(uint8_t channel,float volume)143 void samples_device::set_volume(uint8_t channel, float volume)
144 {
145 assert(channel < m_channels);
146
147 // force an update before we start
148 set_output_gain(channel, volume);
149 }
150
151
152 //-------------------------------------------------
153 // pause - pause playback on a channel
154 //-------------------------------------------------
155
pause(uint8_t channel,bool pause)156 void samples_device::pause(uint8_t channel, bool pause)
157 {
158 assert(channel < m_channels);
159
160 // force an update before we start
161 channel_t &chan = m_channel[channel];
162 chan.paused = pause;
163 }
164
165
166 //-------------------------------------------------
167 // stop - stop playback on a channel
168 //-------------------------------------------------
169
stop(uint8_t channel)170 void samples_device::stop(uint8_t channel)
171 {
172 assert(channel < m_channels);
173
174 // force an update before we start
175 channel_t &chan = m_channel[channel];
176 chan.source = nullptr;
177 chan.source_num = -1;
178 }
179
180
181 //-------------------------------------------------
182 // stop_all - stop playback on all channels
183 //-------------------------------------------------
184
stop_all()185 void samples_device::stop_all()
186 {
187 // just iterate over channels and stop them
188 for (uint8_t channel = 0; channel < m_channels; channel++)
189 stop(channel);
190 }
191
192
193 //-------------------------------------------------
194 // base_frequency - return the base frequency of
195 // a channel being played
196 //-------------------------------------------------
197
base_frequency(uint8_t channel) const198 uint32_t samples_device::base_frequency(uint8_t channel) const
199 {
200 assert(channel < m_channels);
201 return m_channel[channel].basefreq;
202 }
203
204
205 //-------------------------------------------------
206 // playing - return true if a sample is still
207 // playing on the given channel
208 //-------------------------------------------------
209
playing(uint8_t channel) const210 bool samples_device::playing(uint8_t channel) const
211 {
212 assert(channel < m_channels);
213
214 // force an update before we start
215 const channel_t &chan = m_channel[channel];
216 chan.stream->update();
217 return (chan.source != nullptr);
218 }
219
220
221
222 //**************************************************************************
223 // DEVICE INTERFACE
224 //**************************************************************************
225
226 //-------------------------------------------------
227 // device_start - handle device startup
228 //-------------------------------------------------
229
device_start()230 void samples_device::device_start()
231 {
232 // read audio samples
233 load_samples();
234
235 // allocate channels
236 m_channel.resize(m_channels);
237 for (int channel = 0; channel < m_channels; channel++)
238 {
239 // initialize channel
240 channel_t &chan = m_channel[channel];
241 chan.stream = stream_alloc(0, 1, SAMPLE_RATE_OUTPUT_ADAPTIVE);
242 chan.source = nullptr;
243 chan.source_num = -1;
244 chan.pos = 0;
245 chan.loop = 0;
246 chan.paused = 0;
247
248 // register with the save state system
249 save_item(NAME(chan.source_num), channel);
250 save_item(NAME(chan.source_len), channel);
251 save_item(NAME(chan.pos), channel);
252 save_item(NAME(chan.loop), channel);
253 save_item(NAME(chan.paused), channel);
254 }
255
256 // initialize any custom handlers
257 m_samples_start_cb.resolve();
258
259 if (!m_samples_start_cb.isnull())
260 m_samples_start_cb();
261 }
262
263
264 //-------------------------------------------------
265 // device_reset - handle device reset
266 //-------------------------------------------------
267
device_reset()268 void samples_device::device_reset()
269 {
270 stop_all();
271 }
272
273
274 //-------------------------------------------------
275 // device_post_load - handle updating after a
276 // restore
277 //-------------------------------------------------
278
device_post_load()279 void samples_device::device_post_load()
280 {
281 // loop over channels
282 for (int channel = 0; channel < m_channels; channel++)
283 {
284 // attach any samples that were loaded and playing
285 channel_t &chan = m_channel[channel];
286 if (chan.source_num >= 0 && chan.source_num < m_sample.size())
287 {
288 sample_t &sample = m_sample[chan.source_num];
289 chan.source = &sample.data[0];
290 chan.source_len = sample.data.size();
291 if (sample.data.empty())
292 chan.source_num = -1;
293 }
294
295 // validate the position against the length in case the sample is smaller
296 double endpos = chan.source_len;
297 if (chan.source != nullptr && chan.pos >= endpos)
298 {
299 if (chan.loop)
300 {
301 double posfloor = floor(chan.pos);
302 chan.pos -= posfloor;
303 chan.pos += double(int32_t(posfloor) % chan.source_len);
304 }
305 else
306 {
307 chan.source = nullptr;
308 chan.source_num = -1;
309 }
310 }
311 }
312 }
313
314
315 //-------------------------------------------------
316 // sound_stream_update - update a sound stream
317 //-------------------------------------------------
318
sound_stream_update(sound_stream & stream,std::vector<read_stream_view> const & inputs,std::vector<write_stream_view> & outputs)319 void samples_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
320 {
321 // find the channel with this stream
322 constexpr stream_buffer::sample_t sample_scale = 1.0 / 32768.0;
323 for (int channel = 0; channel < m_channels; channel++)
324 if (&stream == m_channel[channel].stream)
325 {
326 channel_t &chan = m_channel[channel];
327 auto &buffer = outputs[0];
328
329 // process if we still have a source and we're not paused
330 if (chan.source != nullptr && !chan.paused)
331 {
332 // load some info locally
333 double step = double(chan.curfreq) / double(buffer.sample_rate());
334 double endpos = chan.source_len;
335 const int16_t *sample = chan.source;
336
337 for (int sampindex = 0; sampindex < buffer.samples(); sampindex++)
338 {
339 // do a linear interp on the sample
340 double pos_floor = floor(chan.pos);
341 double frac = chan.pos - pos_floor;
342 int32_t ipos = int32_t(pos_floor);
343
344 stream_buffer::sample_t sample1 = stream_buffer::sample_t(sample[ipos++]);
345 stream_buffer::sample_t sample2 = stream_buffer::sample_t(sample[(ipos + 1) % chan.source_len]);
346 buffer.put(sampindex, sample_scale * ((1.0 - frac) * sample1 + frac * sample2));
347
348 // advance
349 chan.pos += step;
350
351 // handle looping/ending
352 if (chan.pos >= endpos)
353 {
354 if (chan.loop)
355 chan.pos -= endpos;
356 else
357 {
358 chan.source = nullptr;
359 chan.source_num = -1;
360 buffer.fill(0, sampindex);
361 break;
362 }
363 }
364 }
365 }
366 else
367 buffer.fill(0);
368 break;
369 }
370 }
371
372
373
374 //**************************************************************************
375 // INTERNAL HELPERS
376 //**************************************************************************
377
378 //-------------------------------------------------
379 // read_sample - read a WAV or FLAC file as a
380 // sample
381 //-------------------------------------------------
382
read_sample(emu_file & file,sample_t & sample)383 bool samples_device::read_sample(emu_file &file, sample_t &sample)
384 {
385 // read the core header and make sure it's a proper file
386 uint8_t buf[4];
387 uint32_t offset = file.read(buf, 4);
388 if (offset < 4)
389 {
390 osd_printf_warning("Unable to read %s, 0-byte file?\n", file.filename());
391 return false;
392 }
393
394 // look for the appropriate RIFF tag
395 if (memcmp(&buf[0], "RIFF", 4) == 0)
396 return read_wav_sample(file, sample);
397 else if (memcmp(&buf[0], "fLaC", 4) == 0)
398 return read_flac_sample(file, sample);
399
400 // if nothing appropriate, emit a warning
401 osd_printf_warning("Unable to read %s, corrupt file?\n", file.filename());
402 return false;
403 }
404
405
406 //-------------------------------------------------
407 // read_wav_sample - read a WAV file as a sample
408 //-------------------------------------------------
409
read_wav_sample(emu_file & file,sample_t & sample)410 bool samples_device::read_wav_sample(emu_file &file, sample_t &sample)
411 {
412 // we already read the opening 'RIFF' tag
413 uint32_t offset = 4;
414
415 // get the total size
416 uint32_t filesize;
417 offset += file.read(&filesize, 4);
418 if (offset < 8)
419 {
420 osd_printf_warning("Unexpected size offset %u (%s)\n", offset, file.filename());
421 return false;
422 }
423 filesize = little_endianize_int32(filesize);
424
425 // read the RIFF file type and make sure it's a WAVE file
426 char buf[32];
427 offset += file.read(buf, 4);
428 if (offset < 12)
429 {
430 osd_printf_warning("Unexpected WAVE offset %u (%s)\n", offset, file.filename());
431 return false;
432 }
433 if (memcmp(&buf[0], "WAVE", 4) != 0)
434 {
435 osd_printf_warning("Could not find WAVE header (%s)\n", file.filename());
436 return false;
437 }
438
439 // seek until we find a format tag
440 uint32_t length;
441 while (1)
442 {
443 offset += file.read(buf, 4);
444 offset += file.read(&length, 4);
445 length = little_endianize_int32(length);
446 if (memcmp(&buf[0], "fmt ", 4) == 0)
447 break;
448
449 // seek to the next block
450 file.seek(length, SEEK_CUR);
451 offset += length;
452 if (offset >= filesize)
453 {
454 osd_printf_warning("Could not find fmt tag (%s)\n", file.filename());
455 return false;
456 }
457 }
458
459 // read the format -- make sure it is PCM
460 uint16_t temp16;
461 offset += file.read(&temp16, 2);
462 temp16 = little_endianize_int16(temp16);
463 if (temp16 != 1)
464 {
465 osd_printf_warning("unsupported format %u - only PCM is supported (%s)\n", temp16, file.filename());
466 return false;
467 }
468
469 // number of channels -- only mono is supported
470 offset += file.read(&temp16, 2);
471 temp16 = little_endianize_int16(temp16);
472 if (temp16 != 1)
473 {
474 osd_printf_warning("unsupported number of channels %u - only mono is supported (%s)\n", temp16, file.filename());
475 return false;
476 }
477
478 // sample rate
479 uint32_t rate;
480 offset += file.read(&rate, 4);
481 rate = little_endianize_int32(rate);
482
483 // bytes/second and block alignment are ignored
484 offset += file.read(buf, 6);
485
486 // bits/sample
487 uint16_t bits;
488 offset += file.read(&bits, 2);
489 bits = little_endianize_int16(bits);
490 if (bits != 8 && bits != 16)
491 {
492 osd_printf_warning("unsupported bits/sample %u - only 8 and 16 are supported (%s)\n", bits, file.filename());
493 return false;
494 }
495
496 // seek past any extra data
497 file.seek(length - 16, SEEK_CUR);
498 offset += length - 16;
499
500 // seek until we find a data tag
501 while (1)
502 {
503 offset += file.read(buf, 4);
504 offset += file.read(&length, 4);
505 length = little_endianize_int32(length);
506 if (memcmp(&buf[0], "data", 4) == 0)
507 break;
508
509 // seek to the next block
510 file.seek(length, SEEK_CUR);
511 offset += length;
512 if (offset >= filesize)
513 {
514 osd_printf_warning("Could not find data tag (%s)\n", file.filename());
515 return false;
516 }
517 }
518
519 // if there was a 0 length data block, we're done
520 if (length == 0)
521 {
522 osd_printf_warning("empty data block (%s)\n", file.filename());
523 return false;
524 }
525
526 // fill in the sample data
527 sample.frequency = rate;
528
529 // read the data in
530 if (bits == 8)
531 {
532 sample.data.resize(length);
533 file.read(&sample.data[0], length);
534
535 // convert 8-bit data to signed samples
536 uint8_t *tempptr = reinterpret_cast<uint8_t *>(&sample.data[0]);
537 for (int32_t sindex = length - 1; sindex >= 0; sindex--)
538 sample.data[sindex] = int8_t(tempptr[sindex] ^ 0x80) * 256;
539 }
540 else
541 {
542 // 16-bit data is fine as-is
543 sample.data.resize(length / 2);
544 file.read(&sample.data[0], length);
545
546 // swap high/low on big-endian systems
547 if (ENDIANNESS_NATIVE != ENDIANNESS_LITTLE)
548 for (uint32_t sindex = 0; sindex < length / 2; sindex++)
549 sample.data[sindex] = little_endianize_int16(sample.data[sindex]);
550 }
551 return true;
552 }
553
554
555 //-------------------------------------------------
556 // read_flac_sample - read a FLAC file as a sample
557 //-------------------------------------------------
558
read_flac_sample(emu_file & file,sample_t & sample)559 bool samples_device::read_flac_sample(emu_file &file, sample_t &sample)
560 {
561 // seek back to the start of the file
562 file.seek(0, SEEK_SET);
563
564 // create the FLAC decoder and fill in the sample data
565 flac_decoder decoder((util::core_file &)file);
566 sample.frequency = decoder.sample_rate();
567
568 // error if more than 1 channel or not 16bpp
569 if (decoder.channels() != 1)
570 return false;
571 if (decoder.bits_per_sample() != 16)
572 return false;
573
574 // resize the array and read
575 sample.data.resize(decoder.total_samples());
576 if (!decoder.decode_interleaved(&sample.data[0], sample.data.size()))
577 return false;
578
579 // finish up and clean up
580 decoder.finish();
581 return true;
582 }
583
584
585 //-------------------------------------------------
586 // load_samples - load all the samples in our
587 // attached interface
588 // Returns true when all samples were successfully read, else false
589 //-------------------------------------------------
590
load_samples()591 bool samples_device::load_samples()
592 {
593 bool ok = true;
594 // if the user doesn't want to use samples, bail
595 if (!machine().options().samples())
596 return false;
597
598 // iterate over ourself
599 const std::string &basename = machine().basename();
600 samples_iterator iter(*this);
601 const char *altbasename = iter.altbasename();
602
603 // pre-size the array
604 m_sample.resize(iter.count());
605
606 // load the samples
607 int index = 0;
608 for (const char *samplename = iter.first(); samplename != nullptr; index++, samplename = iter.next())
609 {
610 // attempt to open as FLAC first
611 emu_file file(machine().options().sample_path(), OPEN_FLAG_READ);
612 osd_file::error filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.flac", basename, samplename));
613 if (filerr != osd_file::error::NONE && altbasename != nullptr)
614 filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.flac", altbasename, samplename));
615
616 // if not, try as WAV
617 if (filerr != osd_file::error::NONE)
618 filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.wav", basename, samplename));
619 if (filerr != osd_file::error::NONE && altbasename != nullptr)
620 filerr = file.open(util::string_format("%s" PATH_SEPARATOR "%s.wav", altbasename, samplename));
621
622 // if opened, read it
623 if (filerr == osd_file::error::NONE)
624 read_sample(file, m_sample[index]);
625 else if (filerr == osd_file::error::NOT_FOUND)
626 {
627 logerror("%s: Sample '%s' NOT FOUND\n", tag(), samplename);
628 ok = false;
629 }
630 }
631 return ok;
632 }
633