began work on integrating analysis system, cleaned up audio system

This commit is contained in:
Harrison Deng 2017-05-12 15:58:44 -05:00
parent cc2d9329b5
commit dce73a662f
15 changed files with 171 additions and 297 deletions

View File

@ -173,6 +173,11 @@ public class Polyjet extends Game {
defaultTextButton.disabled = defaultSkin.getDrawable("default-round-disabled");
defaultSkin.add("default", defaultTextButton);
TextButtonStyle subTextbutton = new TextButtonStyle(defaultTextButton);
subTextbutton.font = defaultSkin.getFont("sub-font");
defaultSkin.add("sub", subTextbutton);
TextButtonStyle textButtonLeft = new TextButtonStyle();
textButtonLeft.up = defaultSkin.getDrawable("left-button");
textButtonLeft.down = defaultSkin.getDrawable("left-button-down");

View File

@ -213,8 +213,8 @@ public class AudioAnalyzer {
overlappedBeats.shrink();
}
public void startAnalyticalThread(final AudioData audiofile) {
public void startAnalyticalThread(AudioData audiofile) {
audioPCM = new float[audiofile.getReadWindowSize()];
fftData = new float[audiofile.getReadWindowSize()];
spectrum = new float[(audiofile.getReadWindowSize()/2)+1];
lastSpectrum = new float[(audiofile.getReadWindowSize()/2)+1];

View File

@ -3,7 +3,6 @@ package zero1hd.polyjet.audio;
import javax.sound.sampled.AudioFormat;
import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.files.FileHandle;
public interface AudioData {
/**
@ -18,11 +17,6 @@ public interface AudioData {
*/
public int getReadIndex();
/**
* Sets the current audio file
*/
public void setAudioFile(FileHandle setAudio);
/**
* Completely resets the current audio data. Think of pooling, except, only one instance which is reused instead of multiple.
*/

View File

@ -23,22 +23,6 @@ public class Mp3AudioData implements AudioData {
public Mp3AudioData(FileHandle setAudio) {
setAudioFile(setAudio);
}
@Override
public void readIndexUpdate() {
readIndex = (int) (playbackMusic.getPosition() * audioFormat.getSampleRate() / readWindowSize);
}
@Override
public int getReadIndex() {
return readIndex;
}
@Override
public void setAudioFile(FileHandle setAudio) {
reset();
try {
audStream = AudioSystem.getAudioInputStream(setAudio.file());
@ -51,7 +35,17 @@ public class Mp3AudioData implements AudioData {
playbackMusic = Gdx.audio.newMusic(setAudio);
}
@Override
public void readIndexUpdate() {
readIndex = (int) (playbackMusic.getPosition() * audioFormat.getSampleRate() / readWindowSize);
}
@Override
public int getReadIndex() {
return readIndex;
}
@Override

View File

@ -10,7 +10,6 @@ import com.badlogic.gdx.audio.Music;
import com.badlogic.gdx.files.FileHandle;
import zero1hd.wavedecoder.WavDecoder;
import zero1hd.wavedecoder.WavInfo;
public class WavAudioData implements AudioData {
private int readWindowSize = 1024;
@ -18,15 +17,24 @@ public class WavAudioData implements AudioData {
int readIndex;
Music playbackMusic;
WavDecoder decoder;
WavInfo wavinfo;
public WavAudioData(FileHandle audioFileHandle) {
setAudioFile(audioFileHandle);
public WavAudioData(FileHandle file) {
reset();
try {
decoder = new WavDecoder(file);
decoder.initDataStream();
decoder.getHeaderInfo();
} catch (InvalidParameterException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
playbackMusic = Gdx.audio.newMusic(file);
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, (float) decoder.getSampleRate(), 16, decoder.getChannels(), decoder.getChannels()*2, (float) decoder.getSampleRate(), false);
}
@Override
public void readIndexUpdate() {
readIndex = (int) (playbackMusic.getPosition() * wavinfo.getSampleRate() / readWindowSize);
readIndex = (int) (playbackMusic.getPosition() * decoder.getSampleRate() / readWindowSize);
}
@Override
@ -34,23 +42,6 @@ public class WavAudioData implements AudioData {
return readIndex;
}
public void setInfo(WavInfo wavinfo) {
this.wavinfo = wavinfo;
}
@Override
public void setAudioFile(FileHandle audioFileHandle) {
reset();
try {
decoder.setAudioFile(wavinfo);
} catch (InvalidParameterException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
playbackMusic = Gdx.audio.newMusic(audioFileHandle);
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, (float) wavinfo.getSampleRate(), 16, wavinfo.getChannels(), wavinfo.getChannels()*2, (float) wavinfo.getSampleRate(), false);
}
@Override
public void reset() {
if (playbackMusic != null) {

View File

@ -14,6 +14,7 @@ import zero1hd.polyjet.Polyjet;
import zero1hd.polyjet.audio.AudioAnalyzer;
import zero1hd.polyjet.audio.WavAudioData;
import zero1hd.polyjet.maps.RhythmMap;
import zero1hd.polyjet.ui.pages.AnalyzePage;
import zero1hd.polyjet.ui.pages.MusicSelectionPage;
import zero1hd.polyjet.util.TransitionAdapter;
@ -58,7 +59,7 @@ public class PreGameScreen extends ScreenAdapter implements TransitionAdapter {
cyberCircle1.setPosition(Gdx.graphics.getWidth()-cyberCircle1.getWidth()/2-10, -cyberCircle1.getHeight()*2/4f);
stage.addActor(cyberCircle1);
analyzePage = new AnalyzePage(core.defaultSkin);
analyzePage = new AnalyzePage(core.defaultSkin, cameraTarget);
analyzePage.setPosition(1f*Gdx.graphics.getWidth(), 0);
stage.addActor(analyzePage);

View File

@ -2,6 +2,7 @@ package zero1hd.polyjet.ui.builders;
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;
@ -26,14 +27,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Disposable;
import zero1hd.wavedecoder.WavInfo;
public class MusicSelectable extends Button implements Disposable {
private boolean invalidMusic;
private long durationInSeconds;
private String songName;
private Texture albumCover;
WavInfo wavinfo;
private String author;
private int previousTop;
private int ratedDifficulty;
@ -77,13 +75,13 @@ public class MusicSelectable extends Button implements Disposable {
}
} else {
wavinfo = new WavInfo(musicFile.file());
durationInSeconds = wavinfo.getDurationInSeconds();
try {
WavTag wavTag = (WavTag) AudioFileIO.read(wavinfo.getFile()).getTag();
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
@ -174,10 +172,6 @@ public class MusicSelectable extends Button implements Disposable {
return albumCover;
}
public WavInfo getWavinfo() {
return wavinfo;
}
@Override
public void dispose() {
albumCover.dispose();

View File

@ -1,5 +1,6 @@
package zero1hd.polyjet.screens;
package zero1hd.polyjet.ui.pages;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
@ -9,22 +10,27 @@ import com.badlogic.gdx.utils.SnapshotArray;
import zero1hd.polyjet.audio.AudioAnalyzer;
import zero1hd.polyjet.audio.AudioData;
import zero1hd.polyjet.ui.pages.Page;
public class AnalyzePage extends Page {
AudioAnalyzer audioAnalyzer;
AudioData music;
Vector3 cameraPos;
Table songInfo;
Slider difficultyModifier;
Label difficultyModifierPercentage;
public AnalyzePage(Skin skin) {
public AnalyzePage(Skin skin, Vector3 camPos) {
super("Results", skin);
cameraPos = camPos;
audioAnalyzer = new AudioAnalyzer();
songInfo = new Table(skin);
}
public void setSong(AudioData music, SnapshotArray<Actor> uiMusicInfo) {
cameraPos.x = 1.5f*getWidth();
this.music = music;
audioAnalyzer.startAnalyticalThread(music);
songInfo.add(uiMusicInfo.get(0)).spaceBottom(20f);

View File

@ -14,12 +14,9 @@ import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.Align;
import zero1hd.polyjet.Polyjet;
import zero1hd.polyjet.audio.Audio;
import zero1hd.polyjet.audio.AudioData;
import zero1hd.polyjet.screens.AnalyzePage;
import zero1hd.polyjet.screens.MainMenu;
import zero1hd.polyjet.ui.builders.MusicSelectable;
import zero1hd.polyjet.ui.windows.LoadingWindow;
@ -73,6 +70,7 @@ public class MusicSelectionPage extends Page {
loadingWindow.toFront();
back.toFront();
}
@Override
@ -112,28 +110,8 @@ public class MusicSelectionPage extends Page {
@Override
public void changed(ChangeEvent event, Actor actor) {
final NoticeWindow notice = new NoticeWindow(core.defaultSkin, "tinted", "are you sure?", "Analyze this song?");
notice.setSize(0.3f*getWidth(), 0.3f*getHeight());
notice.setPosition((getWidth()-notice.getWidth())/2f, (getHeight()-notice.getHeight())/2f);
notice.setupButton("cancel", new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
notice.remove();
}
}, Align.left);
notice.setupButton("confirm", new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
ap.setSong(Audio.getAudioData(selectable.getMusicFile()), selectable.getChildren());
}
}, Align.right);
notice.setModal(true);
notice.setMovable(false);
addActor(notice);
back.toFront();
System.out.println();
ap.setSong(Audio.getAudioData(selectable.getMusicFile()), selectable.getChildren());
}
});
}

View File

@ -1,65 +0,0 @@
package zero1hd.polyjet.ui.stages;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import zero1hd.polyjet.Polyjet;
import zero1hd.polyjet.maps.RhythmMap;
public class AnalysisResults extends Stage {
Label DR;
Image circle1;
Image circle2;
Label proceed;
RhythmMap rhythmMap;
public boolean next;
public AnalysisResults(Polyjet core, RhythmMap rhythmMap) {
this.rhythmMap = rhythmMap;
this.DR = new Label("Ready?", core.defaultSkin, "large-font", Color.WHITE);
this.DR.setPosition(Gdx.graphics.getWidth()/2 - this.DR.getWidth()/2, Gdx.graphics.getHeight()/2 - this.DR.getHeight()/2);
proceed = new Label("Waiting for user input...", core.defaultSkin, "small-font", Color.WHITE);
proceed.setPosition((Gdx.graphics.getWidth()-proceed.getWidth())/2, Gdx.graphics.getHeight()-proceed.getHeight()-20);
proceed.addAction(Actions.forever(Actions.sequence(Actions.alpha(0.25f, 0.75f), Actions.alpha(1f, 0.75f))));
circle1 = new Image(core.assetManager.get("circle.png", Texture.class));
circle1.setPosition(0, 0);
circle2 = new Image(core.assetManager.get("circle.png", Texture.class));
circle2.setPosition(Gdx.graphics.getWidth()-circle2.getWidth(), Gdx.graphics.getHeight()-circle2.getHeight());
addActor(circle1);
addActor(circle2);
addActor(this.DR);
addActor(proceed);
addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
next = true;
super.clicked(event, x, y);
}
});
}
@Override
public void act(float delta) {
super.act(delta);
//TODO set text to data difficulty
}
@Override
public void draw() {
// TODO Auto-generated method stub
super.draw();
}
}

View File

@ -17,8 +17,6 @@ import zero1hd.polyjet.Polyjet;
import zero1hd.polyjet.audio.Audio;
import zero1hd.polyjet.audio.AudioAnalyzer;
import zero1hd.polyjet.audio.AudioData;
import zero1hd.polyjet.audio.Mp3AudioData;
import zero1hd.polyjet.audio.WavAudioData;
import zero1hd.polyjet.screens.MainMenu;
import zero1hd.polyjet.ui.windows.BeatViewer;
import zero1hd.polyjet.ui.windows.FPSWindow;

View File

@ -14,7 +14,6 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import zero1hd.polyjet.audio.AudioData;
import zero1hd.polyjet.audio.WavAudioData;
public class MusicController extends Window {
boolean musicReady;

View File

@ -31,7 +31,7 @@ public class NoticeWindow extends Window {
}
public void setupButton(String text, ChangeListener changeListener, int alignment) {
TextButton button = new TextButton(text, skin, "sub-font");
TextButton button = new TextButton(text, skin, "sub");
button.addListener(changeListener);
add(button).align(alignment);
}

View File

@ -1,16 +1,128 @@
package zero1hd.wavedecoder;
import java.io.DataInputStream;
import java.io.IOException;
import java.security.InvalidParameterException;
public class WavDecoder {
private WavInfo initialData;
import com.badlogic.gdx.files.FileHandle;
public void setAudioFile(WavInfo info) throws InvalidParameterException, IOException {
initialData = info;
initialData.initDataStream();
initialData.getHeaderInfo();
public class WavDecoder {
private FileHandle file;
private int channels;
private double sampleRate;
private int dataSize;
private int byteRate;
private DataInputStream readStream;
private String fileName;
public WavDecoder(FileHandle file) throws IOException {
this.file = file;
initDataStream();
getHeaderInfo();
}
public void getHeaderInfo() throws IOException {
if (!readBytesToString(4).equals("RIFF")) { //4 for RIFF tag
throw new InvalidParameterException("RIFF tag not found in header.");
}
dataSize = littleEndianIntBytes(); //4 for Chunk size
if (!readBytesToString(4).equals("WAVE")) { //4 for WAVE tag
throw new InvalidParameterException("WAVE format tag not found.");
}
if (!readBytesToString(4).equals("fmt ")) { //4 for 'fmt '
throw new InvalidParameterException("fmt header not found.");
}
if (littleEndianIntBytes() != 16) { //subchunk1size (4 bytes)
throw new InvalidParameterException("Data not pcm?");
}
if (readStream.readByte() != 1) { //1 pcm
throw new InvalidParameterException("Data not pcm?");
}
readStream.skip(1); //1
channels = readStream.readByte(); //1 channel count
readStream.skip(1); //1
sampleRate = littleEndianIntBytes(); //4 sample rate
byteRate = littleEndianIntBytes(); //4
readStream.skip(4);
String moreInfo = readBytesToString(4);
if (moreInfo.equals("LIST")) { // 4
readStream.skip(30);
if (!readBytesToString(4).equals("data")) {
throw new InvalidParameterException("failed to read data with extra info.");
}
} else if (!moreInfo.equals("data")) {
throw new InvalidParameterException("failed to read data.");
}
readStream.skip(4);
}
public void initDataStream() {
readStream = new DataInputStream(file.read());
}
public void closeStreams() throws IOException {
readStream.close();
}
public String readBytesToString(int bytesToRead) throws IOException {
byte byteString[] = new byte[bytesToRead];
readStream.read(byteString);
return new String(byteString);
}
public int littleEndianIntBytes() throws IOException {
int data = readStream.readInt();
return Integer.reverseBytes(data);
}
public short readLittleEndianShort() throws IOException {
short data = readStream.readShort();
return Short.reverseBytes(data);
}
public DataInputStream getReadStream() {
return readStream;
}
public int getChannels() {
return channels;
}
public int getByteRate() {
return byteRate;
}
public int getDataSize() {
return dataSize;
}
public double getSampleRate() {
return sampleRate;
}
public long getDurationInSeconds() {
return (long) (dataSize/byteRate);
}
public String getFileName() {
return fileName;
}
public FileHandle getFile() {
return file;
}
public int readSamples(float[] samples) {
int samplesRead = 0;
@ -18,15 +130,15 @@ public class WavDecoder {
try {
int currentSample = 0;
for (int channel = 0; channel < initialData.getChannels(); channel++) {
currentSample += initialData.readLittleEndianShort();
for (int channel = 0; channel < getChannels(); channel++) {
currentSample += readLittleEndianShort();
}
currentSample /= initialData.getChannels()*Short.MAX_VALUE+1;
currentSample /= getChannels()*Short.MAX_VALUE+1;
samples[i] = currentSample;
samplesRead++;
} catch (IOException e) {
try {
initialData.closeStreams();
closeStreams();
} catch (IOException e1) {
e1.printStackTrace();
}

View File

@ -1,133 +0,0 @@
package zero1hd.wavedecoder;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.InvalidParameterException;
public class WavInfo {
private int channels;
private double sampleRate;
private int dataSize;
private int byteRate;
private FileInputStream audioFile;
private DataInputStream readStream;
private String fileName;
private File file;
public WavInfo(File file) throws InvalidParameterException {
try {
fileName = file.getName();
this.file = file;
audioFile = new FileInputStream(file);
initDataStream();
getHeaderInfo();
closeStreams();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void getHeaderInfo() throws IOException {
if (!readBytesToString(4).equals("RIFF")) { //4 for RIFF tag
throw new InvalidParameterException("RIFF tag not found in header.");
}
dataSize = littleEndianIntBytes(); //4 for Chunk size
if (!readBytesToString(4).equals("WAVE")) { //4 for WAVE tag
throw new InvalidParameterException("WAVE format tag not found.");
}
if (!readBytesToString(4).equals("fmt ")) { //4 for 'fmt '
throw new InvalidParameterException("fmt header not found.");
}
if (littleEndianIntBytes() != 16) { //subchunk1size (4 bytes)
throw new InvalidParameterException("Data not pcm?");
}
if (readStream.readByte() != 1) { //1 pcm
throw new InvalidParameterException("Data not pcm?");
}
readStream.skip(1); //1
channels = readStream.readByte(); //1 channel count
readStream.skip(1); //1
sampleRate = littleEndianIntBytes(); //4 sample rate
byteRate = littleEndianIntBytes(); //4
readStream.skip(4);
String moreInfo = readBytesToString(4);
if (moreInfo.equals("LIST")) { // 4
readStream.skip(30);
if (!readBytesToString(4).equals("data")) {
throw new InvalidParameterException("failed to read data with extra info.");
}
} else if (!moreInfo.equals("data")) {
throw new InvalidParameterException("failed to read data.");
}
readStream.skip(4);
}
protected void initDataStream() {
readStream = new DataInputStream(audioFile);
}
protected void closeStreams() throws IOException {
readStream.close();
audioFile.close();
}
private String readBytesToString(int bytesToRead) throws IOException {
byte byteString[] = new byte[bytesToRead];
readStream.read(byteString);
return new String(byteString);
}
private int littleEndianIntBytes() throws IOException {
int data = readStream.readInt();
return Integer.reverseBytes(data);
}
protected short readLittleEndianShort() throws IOException {
short data = readStream.readShort();
return Short.reverseBytes(data);
}
protected DataInputStream getReadStream() {
return readStream;
}
public int getChannels() {
return channels;
}
public int getByteRate() {
return byteRate;
}
public int getDataSize() {
return dataSize;
}
public double getSampleRate() {
return sampleRate;
}
public long getDurationInSeconds() {
return (long) (dataSize/byteRate);
}
public String getFileName() {
return fileName;
}
public File getFile() {
return file;
}
}