Visualizzazione post con etichetta project. Mostra tutti i post
Visualizzazione post con etichetta project. Mostra tutti i post

domenica 15 giugno 2014

Creating the AudioPlayer class for playing music in java

Now that our User Interface it's almost done let's focus on making a class that implements all our player functionality, we'll call this class AudioPlayer. Basically, we are gonna crate a wrapper around a BasicPlayer object, if you don't know basicplayer api, check this page.
BasicPlayer layer is the simple player API of jlGui. These classes are designed to be used in any application that needs simple features (play, stop, pause, resume, seek) to play audio file or stream. It's a high-level API over JavaSound API. 
First off, let's start by defining our class properties, so that our goals are clear, we want to have access to most of this kind of information
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
 //Extension of BasicPlayer
 private static AudioPlayer instance = null;
 private ArrayList<String> playlist = new ArrayList<String>();
 private int index = 0;
 private boolean paused = true;
 private boolean opened = false;
 private boolean isSeeking = false;
 
 //Current Audio Properties
 private float audioDurationInSeconds = 0;
 private int audioFrameSize = 0;
 private float audioFrameRate = 0;
 //Stream info/status
 private byte[] cpcmdata;
 private long csms = 0; //Current Song microseconds
 private int lastSeekMs = 0; //Every time we seek, basic player returns microseconds are resetted
 //we need a var to mantain the position we seeked to
Now let's create the constructor, the class it's an extension from BasicPlayer class, since I'm wrapping it. I've used a singleton here because it's pattern sweets the AudioPlayer propose, we'll need and control only one AudioPlayer object.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 public class AudioPlayer extends BasicPlayer{  
      //Want to use a singleton  
      private AudioPlayer() {  
           super();  
           //Wanna give the AudioPlayer class a basic behaviour  
           this.addBasicPlayerListener(new BasicPlayerListener() {  
                @Override  
                public void stateUpdated(BasicPlayerEvent event) {  
                     if(event.getCode() == BasicPlayerEvent.EOM)  
                     {  
                          lastSeekMs = 0;  
                          paused = true; //reset player state  
                          opened = false;  
                          log("EOM event catched, player resetted.");  
                     }  
                     if(event.getCode() == BasicPlayerEvent.SEEKING)  
                          isSeeking = true;  
                     if(event.getCode() == BasicPlayerEvent.SEEKED)  
                          isSeeking = false;  
                }  
                @Override  
                public void setController(BasicController arg0) {  
                     //No need to use this  
                }  
                @Override  
                public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) {  
                     csms = microseconds;  
                     cpcmdata = pcmdata;  
                }  
                @Override  
                public void opened(Object stream, Map properties) {  
                     log("Opened event caught");  
                     Object[] e = properties.entrySet().toArray();  
                     Object[] k = properties.keySet().toArray();  
                     String line = "Stream properties:";  
                     for(int i = 0; i<properties.size(); i++){  
                          line += "\n\t" + k[i] + ":" + e[i];  
                     }  
                     log(line);  
                     //Set Audio Properties  
                     File file = new File(playlist.get(index));  
                  long audioFileLength = file.length();  
                     int frameSize = (int) properties.get("mp3.framesize.bytes");  
                  float frameRate = (float) properties.get("mp3.framerate.fps");  
                  audioFrameSize = frameSize;  
                  audioFrameRate = frameRate;  
                  audioDurationInSeconds = (audioFileLength / (frameSize * frameRate));  
                  log("\tframesize " + frameSize + " framerate " + frameRate);  
                  log("\tAudio File lenght in seconds is: " + audioDurationInSeconds);  
                }  
           });  
      }  
      public static AudioPlayer getInstance(){  
           if(instance == null)  
                instance = new AudioPlayer();  
           return instance;  
      }  
      /////////////////////////////////////  
 }  
While creating the object, I gave the player some of it's basic functionality, by adding to him a behaviour, I did this by adding a BasicListener with this.addBasicPlayerListener. Function in the listener are automatically called every one in a while by the BasicPlayer class (callback functions). Now follows the other implemented methods.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
 @Override
 public void play() throws BasicPlayerException {
  if(playlist.size() == 0)
   return;
  if(!paused || !opened){
   File f = new File(playlist.get(index));
   log("Opening file... " + f.getAbsolutePath());
   open(f);
   opened = true;
   super.play();
  }
  if(paused)
   super.resume();
  paused = false;
 }
 
 @Override
 public void pause() throws BasicPlayerException {
  log("Paused");
  paused = true;
  super.pause();
 }
 
 @Override
 public void stop() throws BasicPlayerException {
  paused = false;
  super.stop();
 }
 
 public boolean isPaused(){ return paused; }
 
 public boolean isOpenFile() { return opened; }
 
 public ArrayList<String> getPlaylist(){ return playlist; }
 
 public int getIndexSong(){ return index; }
 
 public void setIndexSong(int index){ this.index = index; lastSeekMs = 0; }
 
 public boolean isSeeking() { return isSeeking; }
 
 /**
  * goes to the next song in playlist and plays it
  * @throws BasicPlayerException
  */
 public void nextSong() throws BasicPlayerException{
  if(playlist.size() == 0)
   return;
  lastSeekMs = 0;
  paused = false;
  index = (index+1)%playlist.size();
  play();
 }
 
 /**
  * goes to the previous song and plays it
  * @throws BasicPlayerException
  */
 public void prvSong() throws BasicPlayerException{
  if(playlist.size() == 0)
   return;
  lastSeekMs = 0;
  paused = false;
  index = (index-1)%playlist.size();
  play();
 }
 
 /**
  * Adds a song to the playlist
  * @param songPath
  */
 public void addSong(String songPath) {
  playlist.add(songPath);
 }
 
 /**
  * Remove a song by index
  * @param index
  */
 public void removeSong(int index) {
  playlist.remove(index);
 }
 /**
  * Remove a song by songPath
  * @param songPath
  */
 public void removeSong(String songPath)
 {
  playlist.remove(songPath);
 }
 
 public byte[] getPcmData(){return cpcmdata;}
 
 public long getProgressMicroseconds(){return csms+lastSeekMs;}
 
 public float getAudioDurationSeconds() {return audioDurationInSeconds;}
 
 public float getAudioFrameRate() { return audioFrameRate; }
 
 public float getAudioFrameSize() { return audioFrameSize; }
 
 /**
  * Remembers what's the last position relative to the playing song
  * when seeking
  */
 public void setLastSeekPositionInMs(int seekMs)
 {
  lastSeekMs = seekMs;
 }
 
 
 /**
  * For logging
  * @param line
  */
 private void log(String line)
 {
  System.out.println("AudioPlayer] " + line);
  MainView.stf.addText("AudioPlayer] " + line);
 }
//End of class
As you have already noticed the code it's not that complex since most of the work is done by BasicPlayer, one of the BasicPlayer class though is that after seeking the returned progress in microsecond of the song is reset, as you can see in the code, this problem has been fixed with the use of one variable.

venerdì 4 ottobre 2013

Kagero Project Fan Game [>Download Page<]


--------------------------------------------------------
So, what happened? Why did I make so long to finally publish this thing? Well, not really much happened. I tried co contact Jin until now, twitter, email, IA contact form, nothing. I have to thank a lot of kind people that offered me help and translated stuff from italian to japanese, but in the end, a month passed and still no answer. So what now? I'm releasing a game without the permission of the guy who makes the songs!? Yes.
I'll shut everything down eventually, and it's a fan game I'm not making any money from it.
Anyway, you will notice from the trailer that someone really AWESOME did some audio tracks for the game, yes I'm talking about JubyPhonic. I've to thank her for spreading so much the word about my game, I hope people will be aware of my works in the future.

And now some questions and answers:
-What happened to the android version?
Unfortunately I've to wait for Jin permission for that one, since I plan to publish it on google play in the future.
-There will be more songs in the game?
I don't know. My life is kinda busy at the moment, I would really like to put outer science and sunset yesterday in the game, I think it will depends on how much free time I'll have and how many people are really interested in my game.
-What about iOS version of the game?
Sorry guys, I really don't have the money to buy a mac.
-I like you, I like the game, how can I help?
I doubt someone would like me or my game this much. Anyway, I've made some android application in the past and I'll publish some other games in the market in the future. If you like, give them a try. (You know guys, it's really fun pressing ads on my apps for some reason).

This is it. Have fun with my game.

domenica 15 settembre 2013

Updates on Kagerou Project fan game

Hi guys, just a little update regarding the project. The game is complete I guess, in the past few days I didn't really have much time to work on it, I started working and I've almost finished with my thesis. If was almost complete when I posted the gameplay video. The reason I still didn't have released the game is that I think it's not fair doing this without a replay from Jin and Shido, since I'm using their works. I tried writing to Jin using the contact form from his website, but still no reply. I think the problem is that I try to contact him in english. I tried to ask for help on 2-3 website, only to be turned down. If someone know a bit of japanese please contact me, so that I can get a proper answer.
If I don't get an answer I'll consider to publish the game like any other fan game, hoping it doesn't trouble the owner of the songs. However I don't think I would be able to publish the android version of the game this way. I hope in the future I have a chance to continue with this game, so that I can add more song and features, I really like Outer Science and I want to do something spectacular with it.
Anyway, good news! Here are some of the changes in the new version:
  • You unlock Ayano by getting a good grade in hard mode in any level.
  • The score rating is now better, it's not so insane to get an S.
  • Getting an S in hard mode will unlock a new difficulty.
  • You can skip the logo with back/esc.
Now I don't want this project to die so easily, and I might find the time to fix it while I wait for a reply.
If you want to try the game, contact me. I'll give the windows version to 5 people who have a youtube channel and that can help me by spreading the word posting youtube gameplay videos or review.
Now, thanks again everyone, see you later.

mercoledì 4 settembre 2013

MekakuCityDays project - A rhythmic game

In the last three days I got bored and I started to develop a new rhythmic game with Unity that can work both on pc or android.
Since I'm a fan of kagerou project, a series of japanese songs made by Jin, I decided to make a little fan game.
I'm open for suggestion and I really need someone who can test it. I don't know how much more free time I'll have to spend on it, for now here a pre-alpha: DOWNLOAD
In the .rar there is an .apk if you want to play it on your device.


Featured songs are: Konoha's State of The World, Headphone Actor, Shounen Brave.
UPDATE: Blindfoded Code, Night Talk Deceive
Gameplay: Use they buttons - >
  • A or left arrow : for the left trigger
  • G or down arrow: for the middle trigger
  • L or right arrow: for the right trigger
  • Esc : for the menu/pause
ITA: I tasti da usare sono A,G,L. Il tasto Esc mette in pausa/menu.
Il gioco si ispira alla serie sopra citata in inglese.

UPDATE: Seems like so many people downloaded my game that dropbox decided to lock my public account. Don't worry tough, in the next few days I'll come with a new update featuring one more "hidden" song, so please, stay tuned!
Also, if someone know how to contact Jin regarding this project, please let me know.
See this.