switched back to old system dependent audio method; updated libgdx
framework; added ashley
This commit is contained in:
parent
4321a07f66
commit
bf94851e06
32
build.gradle
32
build.gradle
@ -42,10 +42,10 @@ project(":desktop") {
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation project(":core")
|
||||
implementation "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
|
||||
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
|
||||
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
|
||||
compile project(":core")
|
||||
compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
|
||||
compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
|
||||
compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
|
||||
|
||||
}
|
||||
}
|
||||
@ -56,15 +56,15 @@ project(":android") {
|
||||
configurations { natives }
|
||||
|
||||
dependencies {
|
||||
implementation project(":core")
|
||||
implementation "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
|
||||
compile project(":core")
|
||||
compile "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86"
|
||||
natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64"
|
||||
implementation "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
compile "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-armeabi-v7a"
|
||||
natives "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-arm64-v8a"
|
||||
@ -79,16 +79,12 @@ project(":core") {
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||
implementation "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
|
||||
implementation "org.apache.commons:commons-math3:3.2"
|
||||
implementation "com.github.rwl:jtransforms:2.4.0"
|
||||
implementation group: 'fr.delthas', name: 'javamp3', version: '1.0.1'
|
||||
implementation "org:jaudiotagger:2.0.3"
|
||||
implementation group: 'org.apache.tika', name: 'tika-parsers', version: '1.18'
|
||||
|
||||
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||
compile "com.badlogicgames.ashley:ashley:$ashleyVersion"
|
||||
compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||
compile "com.github.rwl:jtransforms:2.4.0"
|
||||
compile "org.apache.commons:commons-math3:3.2"
|
||||
compile group: 'org.apache.tika', name: 'tika-parsers', version: '1.18'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,150 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
import com.badlogic.gdx.utils.FloatArray;
|
||||
|
||||
public class AudioDataPackage {
|
||||
private FloatArray bassPeaks;
|
||||
private FloatArray mPeaks;
|
||||
private FloatArray umPeaks;
|
||||
|
||||
private MusicManager musicInfo;
|
||||
|
||||
private float bassMaxVal, bassAvg;
|
||||
private float mMaxVal, mAvg;
|
||||
private float uMMaxval, uMAvg;
|
||||
|
||||
private int PUID;
|
||||
private float secPerWin;
|
||||
private float avgSPB;
|
||||
/**
|
||||
* Sets the bass data
|
||||
* @param bassPeaks
|
||||
* @param bassMaxVal
|
||||
* @param bassAvg
|
||||
*/
|
||||
public void setBassData(FloatArray bassPeaks, float bassMaxVal, float bassAvg) {
|
||||
if (this.bassPeaks != null) {
|
||||
throw new InvalidParameterException("The bass peaks of this audio pack has already been set.");
|
||||
}
|
||||
this.bassPeaks = bassPeaks;
|
||||
this.bassMaxVal = bassMaxVal;
|
||||
this.bassAvg = bassAvg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the midrange data
|
||||
* @param mPeaks
|
||||
* @param mMaxVal
|
||||
* @param mAvg
|
||||
*/
|
||||
public void setmData(FloatArray mPeaks, float mMaxVal, float mAvg) {
|
||||
if (this.mPeaks != null) {
|
||||
throw new InvalidParameterException("The midrange peaks of this audio pack has already been set.");
|
||||
}
|
||||
|
||||
this.mPeaks = mPeaks;
|
||||
this.mMaxVal = mMaxVal;
|
||||
this.mAvg = mAvg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the upper-midrange data
|
||||
* @param umPeaks
|
||||
* @param uMMaxVal
|
||||
* @param uMAvg
|
||||
*/
|
||||
public void setUmData(FloatArray umPeaks, float uMMaxVal, float uMAvg) {
|
||||
if (this.umPeaks != null) {
|
||||
throw new InvalidParameterException("The upper midrange peaks have already been set.");
|
||||
}
|
||||
this.umPeaks = umPeaks;
|
||||
this.uMMaxval = uMMaxVal;
|
||||
this.uMAvg = uMAvg;
|
||||
}
|
||||
|
||||
public void setMusicInfo(MusicManager musicInfo) {
|
||||
if (this.musicInfo != null) {
|
||||
throw new InvalidParameterException("There is already music information in this package.");
|
||||
}
|
||||
this.musicInfo = musicInfo;
|
||||
}
|
||||
|
||||
public void setPUID(int pUID) {
|
||||
PUID = pUID;
|
||||
}
|
||||
|
||||
public void setAvgSPB(float avgSPB) {
|
||||
this.avgSPB = avgSPB;
|
||||
}
|
||||
|
||||
public void setSecPerWin(float secPerWin) {
|
||||
this.secPerWin = secPerWin;
|
||||
}
|
||||
|
||||
//All the get methods...
|
||||
public FloatArray getBassPeaks() {
|
||||
if (bassPeaks != null) {
|
||||
return bassPeaks;
|
||||
} else {
|
||||
throw new NullPointerException("Bass peaks currently null. This pack hasn't been properly packed!");
|
||||
}
|
||||
}
|
||||
|
||||
public FloatArray getmPeaks() {
|
||||
if (mPeaks != null) {
|
||||
return mPeaks;
|
||||
} else {
|
||||
throw new NullPointerException("midrange peaks currently null. This pack hasn't been properly packed!");
|
||||
}
|
||||
}
|
||||
|
||||
public FloatArray getuMPeaks() {
|
||||
if (umPeaks != null) {
|
||||
return umPeaks;
|
||||
} else {
|
||||
throw new NullPointerException("Upper midrange peaks currently null. This pack hasn't been properly packed!");
|
||||
}
|
||||
}
|
||||
|
||||
public MusicManager getMusicInfo() {
|
||||
if (musicInfo == null) {
|
||||
throw new NullPointerException("Music info hasn't been baked in...");
|
||||
}
|
||||
return musicInfo;
|
||||
}
|
||||
|
||||
public float getBassMaxVal() {
|
||||
return bassMaxVal;
|
||||
}
|
||||
public float getBassAvg() {
|
||||
return bassAvg;
|
||||
}
|
||||
|
||||
public float getmAvg() {
|
||||
return mAvg;
|
||||
}
|
||||
public float getmMaxVal() {
|
||||
return mMaxVal;
|
||||
}
|
||||
|
||||
public float getuMMaxval() {
|
||||
return uMMaxval;
|
||||
}
|
||||
public float getuMAvg() {
|
||||
return uMAvg;
|
||||
}
|
||||
|
||||
public int getPUID() {
|
||||
return PUID;
|
||||
}
|
||||
|
||||
public float getAvgSPB() {
|
||||
return avgSPB;
|
||||
}
|
||||
|
||||
public float getSecPerWin() {
|
||||
return secPerWin;
|
||||
}
|
||||
}
|
@ -1,154 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jaudiotagger.audio.AudioFile;
|
||||
import org.jaudiotagger.audio.AudioFileIO;
|
||||
import org.jaudiotagger.audio.exceptions.CannotReadException;
|
||||
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
|
||||
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
|
||||
import org.jaudiotagger.audio.mp3.MP3File;
|
||||
import org.jaudiotagger.audio.wav.WavTag;
|
||||
import org.jaudiotagger.tag.FieldKey;
|
||||
import org.jaudiotagger.tag.TagException;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.Preferences;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.PixmapIO;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public class MusicInfo implements Disposable {
|
||||
|
||||
private long durationInSeconds;
|
||||
private String songName;
|
||||
private String author;
|
||||
private int previousTop;
|
||||
private int ratedDifficulty;
|
||||
private boolean invalidMusic;
|
||||
|
||||
private boolean containsInfo;
|
||||
|
||||
private FileHandle musicFile;
|
||||
private Preferences musicAnnotation;
|
||||
|
||||
public MusicInfo(FileHandle musicFile, Preferences musicAnnotation) {
|
||||
this.musicFile = musicFile;
|
||||
this.musicAnnotation = musicAnnotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* loads the information for this song.
|
||||
* should be called in non-render thread as is blocking and depends on IO speed.
|
||||
*/
|
||||
public void loadInfo() {
|
||||
if (musicFile.extension().toLowerCase().equals("mp3")) {
|
||||
MP3File mp3File;
|
||||
try {
|
||||
mp3File = new MP3File(musicFile.file());
|
||||
durationInSeconds = mp3File.getAudioHeader().getTrackLength();
|
||||
|
||||
if (mp3File.getTag() != null && mp3File.getTag().getFirstArtwork() != null) {
|
||||
if (!Gdx.files.external("RhythmBullet/AlbumArt/" + musicFile.name() + ".png").exists()) {
|
||||
byte[] albumWorkBytes = mp3File.getTag().getFirstArtwork().getBinaryData();
|
||||
Pixmap pixmap = new Pixmap(albumWorkBytes, 0, albumWorkBytes.length);
|
||||
PixmapIO.writePNG(Gdx.files.external("RhythmBullet/AlbumArt/" + musicFile.name() + ".png"), pixmap);
|
||||
pixmap.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
songName = mp3File.getTag().getFirst(FieldKey.TITLE);
|
||||
author = mp3File.getTag().getFirst(FieldKey.ARTIST);
|
||||
} catch (IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
AudioFile audioFile = AudioFileIO.read(musicFile.file());
|
||||
WavTag wavTag = (WavTag) AudioFileIO.read(musicFile.file()).getTag();
|
||||
songName = wavTag.getFirst(FieldKey.TITLE);
|
||||
author = wavTag.getFirst(FieldKey.ARTIST);
|
||||
durationInSeconds = audioFile.getAudioHeader().getTrackLength();
|
||||
} catch (CannotReadException | IOException | TagException | ReadOnlyFileException
|
||||
| InvalidAudioFrameException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (durationInSeconds > 60 * 5) {
|
||||
invalidMusic = true;
|
||||
}
|
||||
|
||||
if (songName == null || songName.isEmpty()) {
|
||||
songName = musicFile.nameWithoutExtension();
|
||||
}
|
||||
|
||||
previousTop = musicAnnotation.getInteger(songName + ":previous top", -1);
|
||||
ratedDifficulty = musicAnnotation.getInteger(songName + ":difficulty", -1);
|
||||
|
||||
if (author == null || author.isEmpty()) {
|
||||
author = "N/A";
|
||||
}
|
||||
|
||||
containsInfo = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The album art as a texture.
|
||||
* Can return null if contains info is false.
|
||||
* Not automatically disposed.
|
||||
* @return
|
||||
*/
|
||||
public Texture loadTexture() {
|
||||
Gdx.app.debug("MusicInfo", "Texture loading for music: " + getMusicName());
|
||||
if (Gdx.files.external("RhythmBullet/AlbumArt/" + musicFile.name() + ".png").exists()) {
|
||||
return new Texture(Gdx.files.external("RhythmBullet/AlbumArt/" + musicFile.name() + ".png"));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public long getDurationInSeconds() {
|
||||
return durationInSeconds;
|
||||
}
|
||||
|
||||
public String getMusicName() {
|
||||
return songName.replace('_', ' ');
|
||||
}
|
||||
|
||||
public String getAuthor() {
|
||||
return author;
|
||||
}
|
||||
|
||||
public int getPreviousTop() {
|
||||
return previousTop == -1 ? 0 : previousTop;
|
||||
}
|
||||
|
||||
public int getRatedDifficulty() {
|
||||
return ratedDifficulty;
|
||||
}
|
||||
|
||||
public boolean isInvalidMusic() {
|
||||
return invalidMusic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks if this contains information.
|
||||
* @return whether this contains data
|
||||
*/
|
||||
public boolean hasInformation() {
|
||||
return containsInfo;
|
||||
}
|
||||
|
||||
public FileHandle getMusicFile() {
|
||||
return musicFile;
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import com.badlogic.gdx.audio.Music;
|
||||
import com.badlogic.gdx.audio.Music.OnCompletionListener;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
@Deprecated
|
||||
public interface MusicManager extends Disposable {
|
||||
/**
|
||||
* sets a integer variable to the current window of audio data the playback is at.
|
||||
* Useful for efficiency because we compute once for that frame then get the values every time it is required instead of calculating every time we get the index.
|
||||
* @return the playback window index.
|
||||
*/
|
||||
public int playbackIndexUpdate();
|
||||
|
||||
/**
|
||||
* Gets the current position in seconds
|
||||
* @return the current frame of audio.
|
||||
*/
|
||||
public int getPlaybackIndexPosition();
|
||||
|
||||
/**
|
||||
* returns the read window size.
|
||||
* @return
|
||||
*/
|
||||
public int getReadWindowSize();
|
||||
|
||||
/**
|
||||
* read in samples and fills the array.
|
||||
* @param samples the array that should contain said samples
|
||||
* @return amount read. Will return 0 if end of stream.
|
||||
*/
|
||||
public int readSampleFrames(float[] samples);
|
||||
|
||||
/**
|
||||
* returns sample count.
|
||||
* Can be inaccurate.
|
||||
* @return
|
||||
*/
|
||||
public long getSampleCount();
|
||||
|
||||
/**
|
||||
* returns duration of song in seconds
|
||||
* @return
|
||||
*/
|
||||
public float getDuration();
|
||||
|
||||
/**
|
||||
* returns sample rate
|
||||
* @return sample rate as float
|
||||
*/
|
||||
public float getSampleRate();
|
||||
|
||||
public void pause();
|
||||
|
||||
public void play();
|
||||
|
||||
public boolean isPlaying();
|
||||
|
||||
public float getPositionInSeconds();
|
||||
|
||||
public void setPosition(float position);
|
||||
|
||||
public void setOnCompletionListener(OnCompletionListener listener);
|
||||
|
||||
public void setVolume(float percent);
|
||||
|
||||
/**
|
||||
* @return the amount of channels this audio file has.
|
||||
*/
|
||||
public int getChannelCount();
|
||||
/**
|
||||
* If the the properties of the song are done loading
|
||||
* @return whether its done loading
|
||||
*/
|
||||
public boolean isFinishedLoading();
|
||||
|
||||
/**
|
||||
* Basic song name is the name of the file of the song, meaning we do not check tags for proper song name.
|
||||
* Thats left up to the song info object.
|
||||
* @return basic song name
|
||||
*/
|
||||
public String getBasicSongName();
|
||||
|
||||
/**
|
||||
* @return the song filehandle.
|
||||
*/
|
||||
public FileHandle getMusicFile();
|
||||
|
||||
/**
|
||||
* @return the amount of windows that have been read.
|
||||
*/
|
||||
public int framesRead();
|
||||
|
||||
public Music getMusic();
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.audio.AudioDevice;
|
||||
import com.badlogic.gdx.audio.Music;
|
||||
import com.badlogic.gdx.audio.Music.OnCompletionListener;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.processor.PCMProcessor;
|
||||
|
||||
public class RhythmBulletAudioThread extends Thread {
|
||||
private AudioDevice ad;
|
||||
private PCMProcessor sp;
|
||||
private Music music;
|
||||
private volatile OnCompletionListener ocl;
|
||||
private short[] pcm;
|
||||
private volatile boolean terminated;
|
||||
private volatile boolean playing;
|
||||
private volatile long framesPlayed;
|
||||
private volatile float framesToSkip;
|
||||
|
||||
public RhythmBulletAudioThread(int windowSize, VisualizableMusic vm) {
|
||||
music = vm;
|
||||
this.sp = vm.getSampleProcessor();
|
||||
pcm = new short[(sp.isStereo() ? 2 : 1)*windowSize];
|
||||
setName("RhythmBullet-AudioPlayback-Thread");
|
||||
play();
|
||||
start();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
sp.initiate();
|
||||
this.ad = Gdx.audio.newAudioDevice(sp.getSampleRate(), !sp.isStereo());
|
||||
|
||||
while (!terminated && sp.readSamples(pcm, this) > 0) {
|
||||
ad.writeSamples(pcm, 0, pcm.length);
|
||||
}
|
||||
|
||||
if (ocl != null) {
|
||||
ocl.onCompletion(music);
|
||||
}
|
||||
|
||||
|
||||
super.run();
|
||||
}
|
||||
|
||||
public synchronized void play() {
|
||||
playing = true;
|
||||
notify();
|
||||
}
|
||||
|
||||
public synchronized void pause() {
|
||||
playing = false;
|
||||
while (!playing) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized short[] getPcm() {
|
||||
return pcm;
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
terminated = true;
|
||||
}
|
||||
|
||||
public boolean isTerminated() {
|
||||
return terminated;
|
||||
}
|
||||
|
||||
public boolean isPlaying() {
|
||||
return playing;
|
||||
}
|
||||
|
||||
public void setOnCompletionListener(OnCompletionListener ocl) {
|
||||
this.ocl = ocl;
|
||||
}
|
||||
|
||||
public void jumpToFrame(long frame) {
|
||||
if (framesPlayed > frame) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,117 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
import com.badlogic.gdx.audio.Music;
|
||||
|
||||
import zero1hd.rhythmbullet.audio.processor.MP3PCMProcessor;
|
||||
import zero1hd.rhythmbullet.audio.processor.PCMProcessor;
|
||||
import zero1hd.rhythmbullet.audio.processor.WAVPCMProcessor;
|
||||
|
||||
public class VisualizableMusic implements Music {
|
||||
private int windowSize = 1024;
|
||||
private OnCompletionListener ocl;
|
||||
private boolean looping;
|
||||
private RhythmBulletAudioThread rat;
|
||||
private String fileLoc;
|
||||
private PCMProcessor sampleProcessor;
|
||||
|
||||
public VisualizableMusic(String fileLoc) {
|
||||
this.fileLoc = fileLoc;
|
||||
if (fileLoc.toLowerCase().endsWith("wav")) {
|
||||
try {
|
||||
sampleProcessor = new WAVPCMProcessor(Paths.get(fileLoc), windowSize);
|
||||
} catch (IOException | UnsupportedAudioFileException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (fileLoc.toLowerCase().endsWith("mp3")) {
|
||||
sampleProcessor = new MP3PCMProcessor(Paths.get(fileLoc), windowSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void play() {
|
||||
if (rat == null) {
|
||||
rat = new RhythmBulletAudioThread(windowSize, this);
|
||||
rat.setOnCompletionListener(ocl);
|
||||
rat.start();
|
||||
} else {
|
||||
rat.play();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause() {
|
||||
rat.pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
rat.terminate();
|
||||
rat = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlaying() {
|
||||
return rat.isPlaying();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLooping(boolean isLooping) {
|
||||
looping = isLooping;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLooping() {
|
||||
return looping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
sampleProcessor.setVolume(volume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVolume() {
|
||||
return sampleProcessor.getVolume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPan(float pan, float volume) {
|
||||
sampleProcessor.setPan(pan);
|
||||
sampleProcessor.setVolume(volume);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPosition(float position) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPosition() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnCompletionListener(OnCompletionListener listener) {
|
||||
this.ocl = listener;
|
||||
if (rat != null) {
|
||||
rat.setOnCompletionListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
protected PCMProcessor getSampleProcessor() {
|
||||
return sampleProcessor;
|
||||
}
|
||||
}
|
4
core/src/zero1hd/rhythmbullet/audio/processor/AudioProcessor.java
Executable file
4
core/src/zero1hd/rhythmbullet/audio/processor/AudioProcessor.java
Executable file
@ -0,0 +1,4 @@
|
||||
package zero1hd.rhythmbullet.audio.processor;
|
||||
|
||||
public interface AudioProcessor {
|
||||
}
|
@ -1,107 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio.processor;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import fr.delthas.javamp3.Sound;
|
||||
|
||||
public class MP3PCMProcessor implements PCMProcessor {
|
||||
private boolean stereo;
|
||||
private int sampleRate;
|
||||
private volatile float volume, pan;
|
||||
private boolean initiated;
|
||||
private Sound audioInputStream;
|
||||
private Path path;
|
||||
private byte[] buffer;
|
||||
|
||||
public MP3PCMProcessor(Path path, int windowSize) {
|
||||
try(Sound sound = new Sound(new BufferedInputStream(Files.newInputStream(path)))) {
|
||||
sampleRate = sound.getSamplingFrequency();
|
||||
stereo = sound.isStereo();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initiate() {
|
||||
try {
|
||||
audioInputStream = new Sound(new BufferedInputStream(Files.newInputStream(path)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
buffer = new byte[audioInputStream.getAudioFormat().getFrameSize()];
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStereo() {
|
||||
return stereo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readSamples(short[] pcm, Object syncObj) {
|
||||
if (initiated) {
|
||||
synchronized (syncObj) {
|
||||
int framesRead = 0;
|
||||
for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
|
||||
try {
|
||||
if (audioInputStream.read(buffer) > 0) {
|
||||
pcm[sampleID] = (short) ((buffer[1] << 8) + (buffer[0] & 0x00ff));
|
||||
pcm[sampleID] *= volume * (Math.min(1-pan, 1));
|
||||
if (stereo) {
|
||||
short secondChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
|
||||
secondChan *= volume * (Math.min(1+pan, 1));
|
||||
sampleID++;
|
||||
pcm[sampleID] = secondChan;
|
||||
}
|
||||
framesRead++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return framesRead;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Stream has not been initialized.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPan(float pan) {
|
||||
this.pan = pan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPan() {
|
||||
return pan;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
audioInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio.processor;
|
||||
|
||||
import com.badlogic.gdx.utils.Disposable;
|
||||
|
||||
public interface PCMProcessor extends Disposable {
|
||||
|
||||
/**
|
||||
* Called once, contains the initiation to the stream, only called when play-back begins.
|
||||
* Not thread safe as it should be the first thing to be called during read process.
|
||||
*/
|
||||
public void initiate();
|
||||
|
||||
/**
|
||||
* @return number of channels
|
||||
*/
|
||||
public boolean isStereo();
|
||||
|
||||
/**
|
||||
* @return sample rate
|
||||
*/
|
||||
public int getSampleRate();
|
||||
|
||||
/**
|
||||
* <b>Thread safe</b>
|
||||
* Reads samples (NOT FRAMES) with interwoven data for stereo.
|
||||
* stored in 16 bit format (first 8 are the first byte of data while the second 8 are the second byte of data that composes a short value)
|
||||
* @param pcm the array the samples should fill
|
||||
* @param syncObj the object that this object should use to synchronize multiple threads.
|
||||
* @return the amount of samples read.
|
||||
*/
|
||||
public int readSamples(short[] pcm, Object syncObj);
|
||||
|
||||
/**
|
||||
* <b>Thread safe</b>
|
||||
* ranges from 0 to 1.
|
||||
* @param volume the volume to set
|
||||
*/
|
||||
public void setVolume(float volume);
|
||||
|
||||
/**
|
||||
* <b>Thread safe</b>
|
||||
* @return the volume ranging from 0 to 1
|
||||
*/
|
||||
public float getVolume();
|
||||
|
||||
/**
|
||||
* <b>Thread safe</b>
|
||||
* sets the pan from the left channel to the right.
|
||||
* ranges from -1 to 1.
|
||||
* Default is 0, -1 is left, 1 is right.
|
||||
* @param pan
|
||||
*/
|
||||
public void setPan(float pan);
|
||||
|
||||
/**
|
||||
* <b>Thread safe</b>
|
||||
* Returns the pan value from -1 to 1.
|
||||
* see {@link #setPan(float)} for more information.
|
||||
* @return the pan value.
|
||||
*/
|
||||
public float getPan();
|
||||
|
||||
/**
|
||||
* resets the current input stream to the beginning.
|
||||
* Not thread safe and should be called in the same thread as the one doing the playback.
|
||||
*/
|
||||
public void resetStream();
|
||||
|
||||
/**
|
||||
* Skip this amount of frames.
|
||||
* Not thread safe since this should be called in the same thread as the one doing the playback.
|
||||
* @param framesToSkip
|
||||
*/
|
||||
public void skipFrames(long framesToSkip);
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package zero1hd.rhythmbullet.audio.processor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.UnsupportedAudioFileException;
|
||||
|
||||
public class WAVPCMProcessor implements PCMProcessor {
|
||||
private boolean stereo;
|
||||
private int sampleRate;
|
||||
private byte[] buffer;
|
||||
private Path path;
|
||||
private AudioInputStream audioInputStream;
|
||||
private volatile float volume, pan;
|
||||
private boolean initiated;
|
||||
|
||||
public WAVPCMProcessor(Path path, int windowSize) throws IOException, UnsupportedAudioFileException {
|
||||
this.path = path;
|
||||
AudioFormat format = AudioSystem.getAudioFileFormat(path.toFile()).getFormat();
|
||||
stereo = format.getChannels() > 1 ? true : false;
|
||||
sampleRate = (int) format.getSampleRate();
|
||||
volume = 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initiate() {
|
||||
try {
|
||||
audioInputStream = AudioSystem.getAudioInputStream(path.toFile());
|
||||
} catch (UnsupportedAudioFileException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
buffer = new byte[audioInputStream.getFormat().getFrameSize()];
|
||||
initiated = true;
|
||||
}
|
||||
|
||||
public boolean isStereo() {
|
||||
return stereo;
|
||||
}
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readSamples(short[] pcm, Object syncObj) {
|
||||
if (initiated) {
|
||||
synchronized (syncObj) {
|
||||
int framesRead = 0;
|
||||
for (int sampleID = 0; sampleID < pcm.length; sampleID++) {
|
||||
try {
|
||||
if (audioInputStream.read(buffer) > 0) {
|
||||
pcm[sampleID] = (short) ((buffer[1] << 8) + (buffer[0] & 0x00ff));
|
||||
pcm[sampleID] *= volume * (Math.min(1-pan, 1));
|
||||
if (stereo) {
|
||||
short secondChan = (short) ((buffer[3] << 8) + (buffer[2] & 0x00ff));
|
||||
secondChan *= volume * (Math.min(1+pan, 1));
|
||||
sampleID++;
|
||||
pcm[sampleID] = secondChan;
|
||||
}
|
||||
framesRead++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
return framesRead;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("Stream has not been initialized.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVolume(float volume) {
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVolume() {
|
||||
return volume;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPan(float pan) {
|
||||
this.pan = pan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPan() {
|
||||
return pan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
audioInputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,8 +7,6 @@ import com.badlogic.gdx.utils.Disposable;
|
||||
import edu.emory.mathcs.jtransforms.fft.FloatFFT_1D;
|
||||
import zero1hd.rhythmbullet.audio.MusicManager;
|
||||
|
||||
|
||||
@Deprecated
|
||||
public class MusicManagerFFT implements Disposable {
|
||||
protected MusicManager mm;
|
||||
private FloatFFT_1D fft;
|
||||
|
@ -1,5 +1,3 @@
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
apply plugin: "java"
|
||||
|
||||
sourceCompatibility = 1.6
|
||||
@ -14,9 +12,6 @@ task run(dependsOn: classes, type: JavaExec) {
|
||||
standardInput = System.in
|
||||
workingDir = project.assetsDir
|
||||
ignoreExitValue = true
|
||||
|
||||
if(Os.isFamily(Os.FAMILY_MAC))
|
||||
jvmArgs += "-XstartOnFirstThread"
|
||||
}
|
||||
|
||||
task debug(dependsOn: classes, type: JavaExec) {
|
||||
|
Loading…
Reference in New Issue
Block a user