forked from MinecraftForge/MinecraftForge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPlayer.java
132 lines (121 loc) · 3.64 KB
/
Player.java
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
122
123
124
125
126
127
128
129
130
131
132
package ibxm;
import java.io.*;
import javax.sound.sampled.*;
public class Player {
private Thread play_thread;
private IBXM ibxm;
private Module module;
private int song_duration, play_position;
private boolean running, loop;
private byte[] output_buffer;
private SourceDataLine output_line;
/**
Simple command-line test player.
*/
public static void main( String[] args ) throws Exception {
if( args.length < 1 ) {
System.err.println( "Usage: java ibxm.Player <module file>" );
System.exit( 0 );
}
FileInputStream file_input_stream = new FileInputStream( args[ 0 ] );
Player player = new Player();
player.set_module( Player.load_module( file_input_stream ) );
file_input_stream.close();
player.play();
}
/**
Decode the data in the specified InputStream into a Module instance.
@param input an InputStream containing the module file to be decoded.
@throws IllegalArgumentException if the data is not recognised as a module file.
*/
public static Module load_module( InputStream input ) throws IllegalArgumentException, IOException {
DataInputStream data_input_stream = new DataInputStream( input );
/* Check if data is in XM format.*/
byte[] xm_header = new byte[ 60 ];
data_input_stream.readFully( xm_header );
if( FastTracker2.is_xm( xm_header ) )
return FastTracker2.load_xm( xm_header, data_input_stream );
/* Check if data is in ScreamTracker 3 format.*/
byte[] s3m_header = new byte[ 96 ];
System.arraycopy( xm_header, 0, s3m_header, 0, 60 );
data_input_stream.readFully( s3m_header, 60, 36 );
if( ScreamTracker3.is_s3m( s3m_header ) )
return ScreamTracker3.load_s3m( s3m_header, data_input_stream );
/* Check if data is in ProTracker format.*/
byte[] mod_header = new byte[ 1084 ];
System.arraycopy( s3m_header, 0, mod_header, 0, 96 );
data_input_stream.readFully( mod_header, 96, 988 );
return ProTracker.load_mod( mod_header, data_input_stream );
}
/**
Instantiate a new Player.
*/
public Player() throws LineUnavailableException {
ibxm = new IBXM( 48000 );
set_loop( true );
output_line = AudioSystem.getSourceDataLine( new AudioFormat( 48000, 16, 2, true, true ) );
output_buffer = new byte[ 1024 * 4 ];
}
/**
Set the Module instance to be played.
*/
public void set_module( Module m ) {
if( m != null ) module = m;
stop();
ibxm.set_module( module );
song_duration = ibxm.calculate_song_duration();
}
/**
If loop is true, playback will continue indefinitely,
otherwise the module will play through once and stop.
*/
public void set_loop( boolean loop ) {
this.loop = loop;
}
/**
Open the audio device and begin playback.
If a module is already playing it will be restarted.
*/
public void play() {
stop();
play_thread = new Thread( new Driver() );
play_thread.start();
}
/**
Stop playback and close the audio device.
*/
public void stop() {
running = false;
if( play_thread != null ) {
try {
play_thread.join();
} catch( InterruptedException ie ) {}
}
}
private class Driver implements Runnable {
public void run() {
if( running ) return;
try {
output_line.open();
output_line.start();
play_position = 0;
running = true;
while( running ) {
int frames = song_duration - play_position;
if( frames > 1024 ) frames = 1024;
ibxm.get_audio( output_buffer, frames );
output_line.write( output_buffer, 0, frames * 4 );
play_position += frames;
if( play_position >= song_duration ) {
play_position = 0;
if( !loop ) running = false;
}
}
output_line.drain();
output_line.close();
} catch( LineUnavailableException lue ) {
lue.printStackTrace();
}
}
}
}