/*
* HalfNES by Andrew Hoffman
* Licensed under the GNU GPL Version 3. See LICENSE file
*/
package com.grapeshot.halfnes.audio;
import com.grapeshot.halfnes.NES;
import com.grapeshot.halfnes.PrefsSingleton;
import com.grapeshot.halfnes.audio.AudioOutInterface;
import com.grapeshot.halfnes.mappers.Mapper;
import javax.sound.sampled.*;
/**
*
* @author Andrew
*/
public class SwingAudioImpl implements AudioOutInterface {
private boolean soundEnable;
private SourceDataLine sdl;
private byte[] audiobuf;
private int bufptr = 0;
private float outputvol;
public SwingAudioImpl(final NES nes, final int samplerate, Mapper.TVType tvtype) {
soundEnable = PrefsSingleton.get().getBoolean("soundEnable", true);
outputvol = (float) (PrefsSingleton.get().getInt("outputvol", 13107) / 16384.);
double fps;
switch (tvtype) {
case NTSC:
default:
fps = 60.;
break;
case PAL:
case DENDY:
fps = 50.;
break;
}
if (soundEnable) {
final int samplesperframe = (int) Math.ceil((samplerate * 2) / fps);
audiobuf = new byte[samplesperframe * 2];
try {
AudioFormat af = new AudioFormat(
samplerate,
16,//bit
2,//channel
true,//signed
false //little endian
//(works everywhere, afaict, but macs need 44100 sample rate)
);
sdl = AudioSystem.getSourceDataLine(af);
sdl.open(af, samplesperframe * 4 * 2 /*ch*/ * 2 /*bytes/sample*/);
//create 4 frame audio buffer
sdl.start();
} catch (LineUnavailableException a) {
System.err.println(a);
nes.messageBox("Unable to inintialize sound.");
soundEnable = false;
} catch (IllegalArgumentException a) {
System.err.println(a);
nes.messageBox("Unable to inintialize sound.");
soundEnable = false;
}
}
}
@Override
public final void flushFrame(final boolean waitIfBufferFull) {
if (soundEnable) {
// if (sdl.available() == sdl.getBufferSize()) {
// System.err.println("Audio is underrun");
// }
if (sdl.available() < bufptr) {
// System.err.println("Audio is blocking");
if (waitIfBufferFull) {
//write to audio buffer and don't worry if it blocks
sdl.write(audiobuf, 0, bufptr);
}
//else don't bother to write if the buffer is full
} else {
sdl.write(audiobuf, 0, bufptr);
}
}
bufptr = 0;
}
@Override
public final void outputSample(int sample) {
if (soundEnable) {
sample *= outputvol;
if (sample < -32768) {
sample = -32768;
//System.err.println("clip");
}
if (sample > 32767) {
sample = 32767;
//System.err.println("clop");
}
//left ch
int lch = sample;
audiobuf[bufptr] = (byte) (lch & 0xff);
audiobuf[bufptr + 1] = (byte) ((lch >> 8) & 0xff);
//right ch
int rch = sample;
audiobuf[bufptr + 2] = (byte) (rch & 0xff);
audiobuf[bufptr + 3] = (byte) ((rch >> 8) & 0xff);
bufptr += 4;
}
}
@Override
public void pause() {
if (soundEnable) {
sdl.flush();
sdl.stop();
}
}
@Override
public void resume() {
if (soundEnable) {
sdl.start();
}
}
@Override
public final void destroy() {
if (soundEnable) {
sdl.stop();
sdl.close();
}
}
public final boolean bufferHasLessThan(final int samples) {
//returns true if the audio buffer has less than the specified amt of samples remaining in it
return (sdl == null) ? false : ((sdl.getBufferSize() - sdl.available()) <= samples);
}
}