Compare commits

..

2 Commits

Author SHA1 Message Date
Nekojimi d7c48b38fa Add debug method. 2022-06-19 00:00:45 +01:00
Nekojimi 795e31aa62 Fix playback issues caused by new track player.
Submitted ByteBuffer needed to be rewound, and provide method should return true until there are zero bytes left in the buffer.
2022-06-19 00:00:15 +01:00
3 changed files with 104 additions and 33 deletions

View File

@ -5,15 +5,15 @@
*/ */
package moe.nekojimi.chords; package moe.nekojimi.chords;
import java.io.Closeable; import java.io.*;
import java.io.IOException; import moe.nekojimi.chords.Util;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Queue; import java.util.Queue;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.sound.sampled.UnsupportedAudioFileException; import javax.sound.sampled.*;
import net.dv8tion.jda.api.audio.AudioSendHandler; import net.dv8tion.jda.api.audio.AudioSendHandler;
import org.apache.commons.io.input.buffer.CircularByteBuffer; import org.apache.commons.io.input.buffer.CircularByteBuffer;
@ -27,7 +27,7 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer<Song>
private final LinkedList<Song> songQueue = new LinkedList<>(); private final LinkedList<Song> songQueue = new LinkedList<>();
// private final Queue<byte[]> queue = new ConcurrentLinkedQueue<>(); // private final Queue<byte[]> queue = new ConcurrentLinkedQueue<>();
private final CircularByteBuffer audioBuffer = new CircularByteBuffer(3840 * 1024); private final CircularByteBuffer audioBuffer = new CircularByteBuffer(3840 * 1024);
private boolean playing = true; private boolean playing = true;
private int byteCount; private int byteCount;
private boolean arrayErr = false; private boolean arrayErr = false;
@ -35,8 +35,22 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer<Song>
private Song currentSong; private Song currentSong;
private TrackPlayer player; private TrackPlayer player;
private File debugOutFile;
private BufferedOutputStream debugOut;
public MusicHandler() public MusicHandler()
{ {
try
{
debugOutFile = new File("debug.wav");
if (debugOutFile.exists())
debugOutFile.delete();
debugOutFile.createNewFile();
debugOut = new BufferedOutputStream(new FileOutputStream(debugOutFile));
} catch (IOException ex)
{
Logger.getLogger(MusicHandler.class.getName()).log(Level.SEVERE, null, ex);
}
} }
public void addSong(Song song) public void addSong(Song song)
@ -94,7 +108,11 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer<Song>
} }
currentSong = songQueue.poll(); currentSong = songQueue.poll();
if (currentSong == null) if (currentSong == null)
{
System.out.println("End of queue.");
debugOut.flush();
return false; return false;
}
System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath()); System.out.println("Playing song " + currentSong.getLocation().getAbsolutePath());
arrayErr = false; arrayErr = false;
byteCount = 3840; byteCount = 3840;
@ -125,7 +143,7 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer<Song>
@Override @Override
public boolean canProvide() public boolean canProvide()
{ {
return player != null && player.has(byteCount); return player != null && player.has(1);
// If we have something in our buffer we can provide it to the send system // If we have something in our buffer we can provide it to the send system
// return audioBuffer.getCurrentNumberOfBytes() > byteCount && playing; // return audioBuffer.getCurrentNumberOfBytes() > byteCount && playing;
} }
@ -136,25 +154,32 @@ public class MusicHandler implements AudioSendHandler, Closeable, Consumer<Song>
ByteBuffer ret = ByteBuffer.allocate(byteCount); ByteBuffer ret = ByteBuffer.allocate(byteCount);
while (ret.position() < byteCount && player != null) while (ret.position() < byteCount && player != null)
{ {
System.out.println("Position: " + ret.position() + " Remaining: " + ret.remaining()); // System.out.println("Position: " + ret.position() + " Remaining: " + ret.remaining());
ByteBuffer read = player.read(ret.remaining()); try
if (read != null)
{ {
ByteBuffer read = player.read(ret.remaining());
// System.out.println("SAMPLES from player: " + Util.printSamples(read));
System.out.println("Read: " + read.remaining()); System.out.println("Read: " + read.remaining());
ret.put(read); ret.put(read);
} else if (!nextSong()) } catch (TrackPlayer.OutOfInputException | IOException ex)
{ {
System.out.println("Out of songs!"); System.out.println("Track ended, starting next.");
break; boolean foundNext = nextSong();
if (!foundNext)
{
System.out.println("Out of tracks!");
break;
}
} }
} }
System.out.println("Buffer filled, submitting.");
ret.rewind(); // required apparently, if returned buf has pos > 0 you get silence
assert ret.hasArray(); // output MUST be array backed
return ret; return ret;
// fillBuffer(true);
// byte[] data = new byte[byteCount];
// audioBuffer.read(data, 0, data.length);
//// byte[] data = queue.poll();
// return ByteBuffer.wrap(data); // Wrap this in a java.nio.ByteBuffer
} }
// private void fillBuffer(boolean canSkip) // private void fillBuffer(boolean canSkip)

View File

@ -25,7 +25,7 @@ public class TrackPlayer implements Closeable
{ {
private static final int DESIRED_BUFFER_SIZE = 3840 * 500; private static final int DESIRED_BUFFER_SIZE = 3840 * 500;
private static final int MAX_READ_FAILS = 100; private static final int MAX_READ_FAILS = 3;
private final CircularByteBuffer audioBuffer = new CircularByteBuffer(3840 * 1024); private final CircularByteBuffer audioBuffer = new CircularByteBuffer(3840 * 1024);
@ -41,7 +41,7 @@ public class TrackPlayer implements Closeable
fillBuffer(false); fillBuffer(false);
} }
public TrackPlayer(AudioInputStream input) public TrackPlayer(AudioInputStream input) throws IOException
{ {
this.input = input; this.input = input;
fillBuffer(false); fillBuffer(false);
@ -49,22 +49,33 @@ public class TrackPlayer implements Closeable
boolean has(int byteCount) boolean has(int byteCount)
{ {
return audioBuffer.getCurrentNumberOfBytes() > byteCount; // return true;
return audioBuffer.getCurrentNumberOfBytes() >= byteCount;
} }
public ByteBuffer read(int length) public ByteBuffer read(int length) throws IOException
{ {
boolean filled = fillBuffer(true); boolean filled = fillBuffer(true);
if (!filled) // if (!filled)
// throw new OutOfInputException();
int toRead = Math.min(length, audioBuffer.getCurrentNumberOfBytes());
System.out.println("To read: " + toRead + " from " + audioBuffer.getCurrentNumberOfBytes());
if (toRead <= 0)
throw new OutOfInputException(); throw new OutOfInputException();
byte[] data = new byte[length]; byte[] data = new byte[toRead];
audioBuffer.read(data, 0, data.length); audioBuffer.read(data, 0, data.length);
// byte[] data = queue.poll(); // byte[] data = queue.poll();
return ByteBuffer.wrap(data); // Wrap this in a java.nio.ByteBuffer return ByteBuffer.wrap(data); // Wrap this in a java.nio.ByteBuffer
} }
private boolean fillBuffer(boolean canSkip) /**
*
* @param canSkip
* @return true if the buffer is not empty; false otherwise
*/
private boolean fillBuffer(boolean canSkip) throws IOException
{ {
int fails = 0; int fails = 0;
// use what we have in our buffer to send audio as PCM // use what we have in our buffer to send audio as PCM
@ -81,7 +92,11 @@ public class TrackPlayer implements Closeable
return true; return true;
} }
private boolean readData() /**
*
* @return true if any data was read; false otherwise
*/
private boolean readData() throws IOException
{ {
if (input == null) if (input == null)
return false; return false;
@ -106,19 +121,13 @@ public class TrackPlayer implements Closeable
// queue.add(bytes); // queue.add(bytes);
audioBuffer.add(bytes, 0, read); audioBuffer.add(bytes, 0, read);
} catch (IOException ex) // System.out.println("SAMPLES player buff: " + Util.printSamples(audioBuffer));
{
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
return false;
} catch (ArrayIndexOutOfBoundsException ex) } catch (ArrayIndexOutOfBoundsException ex)
{ {
if (!arrayErr) if (!arrayErr)
arrayErr = true; arrayErr = true;
else else
{ throw ex;
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
} }
return true; return true;
} }

View File

@ -0,0 +1,37 @@
package moe.nekojimi.chords;
import java.nio.ByteBuffer;
/*
* Copyright (C) 2022 jimj316
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
* @author jimj316
*/
public class Util
{
public static String printSamples(ByteBuffer buf)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buf.limit(); i += 128)
{
sb.append(String.format("%x ", buf.get(i)));
}
return sb.toString();
}
}