Class SampledSound
Bytes are sent to this by "chunks". Each chunk represents a certain number of bytes corresponding to samples that are added to the SSSS. There is a minimum of 2 bytes per chunk (one left, one right) if a single sample is added, and a maximum of (SMSQE SSSS buffer size) bytes if multiple bytes are added to the SSSS.
Internally, each chunk is represented here by an array of bytes. This object creates a very primitive FIFO buffering. This is a achieved via a simple ArrayList of byte[]. If a sample is added to the SSSS, the byte array corresponding to that chunk is added to the end of the ArrayList, and upon playback the first element of the ArrayList is played and removed from the list. (There is an inefficiency in this since each time element 0 is removed from the ArrayList, all other elements are shuffled down. I'm not sure, however, whether this really merits that I implement a real FIFO queue).
Playback is via an independent PlayThread
thread. This thread is created once and, when it
has nothing to do (no sound is to be played) it will just go to sleep. A new thread is NOT created every
time a sound is to be played. The thread feeds data to a SourceDataLine set up here.
The general contract with the SMSQE's SSSS is that whenever a sample is sent to it, SMSQE gets here via the corresponding trap (playsound) and the corresponding chunk is taken from SMSQE's memory and added to the arrayList. Then the independent thread is started or woken, which copies each chunk from this ArrayList to the SourceDataline buffer set up here.
There is a bug in the java SourceDataLine : if one repeatedly sends it small sound samples, the sound is repeated indefintely (in total or in part) until the dataline is closed/stopped. To try to get around this, a special flag may be set that tells that the sound should be stopped if the SSSS is empty, a new vector is introduced into the SSSS in SMSQ/E, that will cause the PlayThread to empty and STOP the SoundDataLine once the queue is empty.
This also handles resampling. The only sound format allowed for the SSSS is 20kHz stereo sound. Some SourceDataLines cannot handle that format (especially under OpenJDK). However, apparently all will handle 22.05 kHz (halve the CD rate), I resample the sound in that case.-
Constructor Summary
ConstructorsConstructorDescriptionSampledSound
(int volume, Warnings warn, String frequency) Creates this object, a DataLine object and an independent thread for filling the DataLine. -
Method Summary
Modifier and TypeMethodDescriptionvoid
addChunk
(byte[] buff) Add a chunk.void
closeSound
(boolean close) Signals that once queue is empty sound should be killed: This tries to get around a java bug.void
fillPointers
(MC68000Cpu cpu) Fill in the pointers to the SSSS buffer.final int
Get the size of the sample still in the queueboolean
isStillPlaying
(MC68000Cpu cpu) Returns true if sound is still playing.void
killSound
(MC68000Cpu cpu) Tries to kill the currently played sound.void
playSample
(MC68000Cpu cpu) This adds a chunk from the SSSS and plays it.boolean
Checks whether sound is set to be killed when queue empty.int
Queries the current volume.void
setVolume
(int percentage) Sets the sound volume.
-
Constructor Details
-
SampledSound
Creates this object, a DataLine object and an independent thread for filling the DataLine.- Parameters:
volume
- the volume the sound is to have : 0 -100.warn
- a flag, iftrue
, warn if sound problems may arise in the future.frequency
- either "22.05" or "20" (any other value will be set to 22.05) : frequency in KHz.
-
-
Method Details
-
fillPointers
Fill in the pointers to the SSSS buffer. Called during SMSQ/E initialization of the SSSS.- Parameters:
cpu
- the smsqmulator.cpu.MC68000Cpu used.
-
setVolume
public void setVolume(int percentage) Sets the sound volume.- Parameters:
percentage
- the volume, from 0 (no sound) to 100 (loudest).
-
killSound
Tries to kill the currently played sound. This is called from the emulation thread.- Parameters:
cpu
- the smsqmulator.cpu.MC68000Cpu used.
-
playSample
This adds a chunk from the SSSS and plays it. It wakes up the PlayThread, if need be (by interrupting it). A1 points to the end of the queue. This is called from the emulation thread.- Parameters:
cpu
- the cpu used.
-
addChunk
public void addChunk(byte[] buff) Add a chunk.- Parameters:
buff
- the chunk to add.
-
queryVolume
public int queryVolume()Queries the current volume. NB contrary to documentation, this doesn't work.- Returns:
- the volume or -1 if line no longer active.
-
getSample
public final int getSample()Get the size of the sample still in the queue- Returns:
- nbr of bytes still in the queue.
-
closeSound
public void closeSound(boolean close) Signals that once queue is empty sound should be killed: This tries to get around a java bug.- Parameters:
close
- set totrue
if the sound should be killed if queue empty.
-
querySoundClose
public boolean querySoundClose()Checks whether sound is set to be killed when queue empty.- Returns:
true
if the sound should be killed if queue empty.
-
isStillPlaying
Returns true if sound is still playing.- Parameters:
cpu
-- Returns:
-