📄 toneplayer.java
字号:
/*
* Created on 2005-9-27 by pcy
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package a.a.a.mmedia;
import javax.microedition.media.Player;
import javax.microedition.media.Control;
import javax.microedition.media.MediaException;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.ToneControl;
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Stack;
import java.util.Hashtable;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.BooleanControl;
import javax.sound.sampled.Clip;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
public class TonePlayer extends BasicPlayer implements ToneControl, Runnable {
Clip clip;
double[] degreesPerSample;
AudioFormat pcm;
private int rate=11025;
private int voice=2;
private int channels=1;
private int frameSize=2;
private int sampleSizeInBits=16;
boolean bigendian=false;
Thread thread;
byte[] samples;
double[] harmwave = new double[361];
double[] sinewave = new double[361];
private int[] toneSeq = new int[0];
private int curTime = -1;
private boolean seqChanged = true;
public String getContentType() {
chkClosed(true);
return "audio/x-tone-seq";
}
protected void doRealize() throws MediaException {
curTime = 0;
// if no source stream, player is created from TON_DEVICE_LOCATOR
// simply return it.
if (stream == null){
return;
}
// read the whole sequence from the source stream
int chunksize = 128;
byte[] tmpseqs = new byte[chunksize];
byte[] seqs = null;
// make use of BAOS, since it takes care of growing buffer
ByteArrayOutputStream baos = new ByteArrayOutputStream(chunksize);
try {
int read;
while ((read = stream.read(tmpseqs, 0, chunksize)) != -1) {
baos.write(tmpseqs, 0, read);
}
seqs = baos.toByteArray();
baos.close();
tmpseqs = null;
System.gc();
} catch (IOException ex) {
throw new MediaException("fail to read from source");
}
this.setSequence(seqs);
}
protected void doPrefetch() throws MediaException {
}
public long doGetDuration() {
if (curTime >= 0){
return (long)(curTime * 1000L);
}
else{
return TIME_UNKNOWN;
}
}
protected boolean doStart() {
//System.out.println("start!");
if (seqChanged) {
if(clip!=null){
if(clip.isOpen()){
clip.close();
}
clip=null;
}
harmonics(voice, 0.91, 0.83, 0.75, 0.67);
//harmonics(2, 0.99, 0.90, 0.76, 0.70);
//harmonics(2,0.67,0.54,0.42,0.36);
//harmonics(2,0.36,0.28,0.21,0.16);
toneInitSeq();
seqChanged = false;
}
if(thread!=null){
thread.interrupt();
thread=null;
}
thread=new Thread(this);
thread.start();
return true;
}
/**
* The worker method to stop the player
*/
protected void doStop() {
}
/**
* The worker method to deallocate the player
*/
protected void doDeallocate() {
if(clip!=null&&clip.isOpen()){
clip.close();
}
clip=null;
if(thread!=null){
thread.interrupt();
thread=null;
}
}
/**
* The worker method to close the player
*/
protected void doClose() {
clip.close();
degreesPerSample=null;
samples=null;
harmwave = null;
sinewave = null;
toneSeq = null;
}
/**
* The worker method to actually set player's media time.
*
* @param now The new media time in microseconds.
* @return The actual media time set in microseconds.
* @throws MediaException if an error occurs
* while setting the media time.
*/
protected long doSetMediaTime(long now) throws MediaException {
/*long milli_now = now;
if (getState() == STARTED){
doStop();
}
milli_now = clip.getMicrosecondPosition();
if (getState() == STARTED){
doStart();
}
return milli_now;
*/
clip.setMicrosecondPosition(now);
return now;
}
/**
* Gets this player's current <i>media time</i>
* in microseconds.
*
* @return The current <i>media time</i> in microseconds.
*/
public long doGetMediaTime() {
return clip.getMicrosecondPosition();
}
/**
* The worker method to actually obtain the control.
*
* @param type the class name of the <code>Control</code>.
* @return <code>Control</code> for the class or interface
* name.
*/
protected Control doGetControl(String type) {
if ((getState() >= REALIZED) &&
(type.equals("javax.microedition.media.control.ToneControl") ||
type.equals("javax.microedition.media.control.VolumeControl")))
return this;
return null;
}
public void setSequence(byte[] sequence) {
if (this.getState() >= Player.PREFETCHED){
throw new IllegalStateException("cannot set seq after prefetched");
}
int tempo = 120;
int resolution = 64;
int frac = 1;
int p = 0;
try {
Stack sp = new Stack();
Hashtable blockEnds = new Hashtable();
Hashtable blockStarts = new Hashtable();
boolean inBlock = false;
int found = 0, thisBlockEnd = 0, len;
byte note;
int i;
int startseq = 2;
len = 0;
int tmp = 0;
if (sequence[0] != VERSION || sequence[1] != 1) {
reportErr(6);
}
if (sequence[startseq] == TEMPO) {
if (sequence[startseq+1] < 5) {
reportErr(5);
}
tempo = (sequence[startseq+1] & 0x7f) << 2;
startseq += 2;
}
if (sequence[startseq] == RESOLUTION) {
if (sequence[startseq+1] <= 0){
reportErr(8);
}
resolution = sequence[startseq+1];
startseq += 2;
}
frac = tempo * resolution;
for (i = startseq; i < sequence.length; i += 2) {
note = sequence[i];
if (note < REPEAT ||
((note >= 0 || note == SILENCE) && sequence[i+1] <= 0)) {
reportErr(4);
}
switch (note) {
case BLOCK_START:
if (!inBlock) {
if (sequence[i+1] < 0){
reportErr(7);
}
found = sequence[i+1];
inBlock = true;
blockStarts.put(new Integer(found), new Integer(i));
thisBlockEnd = 0;
continue;
} else {
reportErr(3);
}
break;
case BLOCK_END:
if (inBlock) {// blk end
if (sequence[i+1] == found){
inBlock = false;
blockEnds.put(new Integer(found),
new Integer(thisBlockEnd));
} else {
reportErr(1);
}
continue;
} else {
reportErr(1);
}
break;
case REPEAT:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -