[sharefunshare] mp3 play mxj~ object

Dec 7, 2009 at 3:07am

[sharefunshare] mp3 play mxj~ object

Hallo, I was sick and tired of the slow, cumbersome spigot~ way of playing mp3s so I developed my own (slighty shonky) mxj~ object to stream mp3s from disk, using jLayer. Don’t know if anyone else will find this useful, but below is the download link. The rar contains the .class, the required .jar file, the source, and an example (max5).
It’s pretty feature slim – play pause seek – but it’s good for what I need it for. If anyone fancies improving/extending it, pm me and i’ll do my best to explain the code (obviously it’s not commented).

http://www.vaetxh.com/stuff/mp3play.rar

Thanks,
Rob

#47078
Jan 1, 2010 at 6:50pm

Hey, I’d love to play around with this. The link is broken, though – is there a new url?

#169251
Jan 14, 2010 at 12:11pm

Sure! I’ll update the link, let me know if you need help. Make sure you read the install.txt cos it contains the example code.

http://vaetxh.com/software/

#169252
Jan 14, 2010 at 4:19pm

thanks! can’t wait to check this out!

#169253
Mar 24, 2010 at 10:07am

Hi,

I’ve tried to use your library, ‘ve followed the install.txt but something goes wrong (see below)

java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:676)
at com.cycling74.max.MXJClassLoaderImpl.doLoadClass(MXJClassLoaderImpl.java:119)
at com.cycling74.max.MXJClassLoader.loadClazz(MXJClassLoader.java:88)
Could not load class ‘mp3play’

The mistake is that there is no code in the file mp3play.java

Does someone have successfully use the object of Brico or find an other way to read mp3 (except import in buffer or the use of spigot).
Best

#169254
Mar 24, 2010 at 2:52pm

And at me similar mistakes (

#169255
Nov 21, 2010 at 4:14am

oh shit, sorry i’ve only just noticed this! if you still need it (although it was 8 months ago you’ve probably moved on), i’ll do my best to help you.
looking at the error you got – is your version of java up-to-date? And about the empty source file, here it is:

import com.cycling74.max.*;
import com.cycling74.msp.*;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import javazoom.jl.decoder.Bitstream;
import javazoom.jl.decoder.Decoder;
import javazoom.jl.decoder.Header;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.decoder.SampleBuffer;

public class mp3play extends MSPPerformer {
Thread t;
String filename;
Header currFrame;

private Bitstream bitstream;
private Decoder decoder;
private RandomAccessFileInputStream in = null;

short[] sampsL = new short[44100];
short[] sampsR = new short[44100];

private float filePosMS = 0;
private int recPos = 0;
private int playPos = 0;
private int playing = 0;
private boolean looping = false;

private static final String[] INLET_ASSIST = new String[] { “messages in” };

private static final String[] OUTLET_ASSIST = new String[] { “(signal) Channel 1 Output”, “(signal) Channel 2 Output”, “File position (ms)”, “Info Outlet” };

public mp3play() {
declareInlets(new int[] { DataTypes.ALL });
declareOutlets(new int[] { SIGNAL, SIGNAL, DataTypes.FLOAT, DataTypes.ALL });

setInletAssist(INLET_ASSIST);
setOutletAssist(OUTLET_ASSIST);

createInfoOutlet(false);

t = new Thread() {
public void run() {
while (1 == 1) {
while (playing == 1) {
int diff = 0;
if (recPos < playPos)
diff = recPos – playPos + sampsL.length;
else
diff = recPos – playPos;

if (diff + decoder.getOutputBlockSize() < = sampsL.length / 2) {
try {
short[] frame = decodeFrame();

if (frame != null) {
{
for (int i = 0; i < frame.length / 2; i++) {
sampsL[recPos] = frame[i * 2];
sampsR[recPos] = frame[i * 2 + 1];

recPos++;
recPos %= sampsL.length;
}
filePosMS += currFrame.ms_per_frame();

}
} else {
if (looping) {
seek(0);
} else
playing = 0;
}

} catch (JavaLayerException e) {
}
}

outlet(2, filePosMS);

try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
}

try {
Thread.sleep(20);
} catch (InterruptedException e) {
}

}
}
};

t.start();
}

public void open(String name) {
in = null;
playing = 0;
try {
in = new RandomAccessFileInputStream(new File(name));

} catch (FileNotFoundException e) {
outlet(3, new Atom[] { Atom.newAtom(“error”), Atom.newAtom(“filenotfound”) });
}

if (in != null) {
filePosMS = 0;
recPos = 0;
playPos = 0;
filename = name;
File f = new File(filename);
decoder = new Decoder();
bitstream = new Bitstream(in);
} else
playing = 0;
}

public void inlet(int i) {
int inlet = getInlet();
if (inlet == 0) {
if (in != null) {
playing = i;
}
}
}

public void seek(float endPosMS) throws JavaLayerException {
playing = 0;
recPos = 0;
playPos = 0;
if (currFrame != null && in != null) {
int offset = (int) (endPosMS / currFrame.ms_per_frame()) * currFrame.calculate_framesize();
try {
in.seek((long) (offset));
filePosMS = currFrame.total_ms(offset);
} catch (IOException e) {
}
}

decoder = new Decoder();
bitstream = new Bitstream(in);
playing = 1;
}

public void perform(MSPSignal[] in, MSPSignal[] out) {
float[] L = out[0].vec;
float[] R = out[1].vec;

if (playing == 1) {
int diff = 0;
if (recPos < playPos)
diff = recPos – playPos + sampsL.length;
else
diff = recPos – playPos;

if (diff > 0) {
for (int i = 0; i < L.length; i++) {
L[i] = (float) sampsL[playPos] / (float) Short.MAX_VALUE;
R[i] = (float) sampsR[playPos] / (float) Short.MAX_VALUE;

playPos += 1;
if (playPos >= sampsL.length)
playPos = 0;
}
} else {
for (int i = 0; i < L.length; i++) {
L[i] = R[i] = 0;
}
}
} else {
for (int i = 0; i < L.length; i++) {
L[i] = R[i] = 0;
}
}
}

protected short[] decodeFrame() throws JavaLayerException {
try {
if (decoder == null)
return null;
if (bitstream == null)
return null;

Header h = bitstream.readFrame();
if (h == null) {
outlet(3, “done”);
return null;
} else
currFrame = h;

SampleBuffer output = (SampleBuffer) decoder.decodeFrame(currFrame, bitstream);
short[] samps = output.getBuffer();
bitstream.closeFrame();

return samps;
} catch (RuntimeException e) {
throw new JavaLayerException(“Exception decoding audio frame”, e);
}
}

public void info() {
if (in != null) {
File f = new File(filename);
float lengthMS = currFrame.total_ms((int) f.length());
int frequency = currFrame.frequency();
int bitRate = currFrame.bitrate() / 1000;
outlet(3, new Atom[] { Atom.newAtom(“filename”), Atom.newAtom(filename) });
outlet(3, new Atom[] { Atom.newAtom(“samplerate”), Atom.newAtom(frequency) });
outlet(3, new Atom[] { Atom.newAtom(“bitrate”), Atom.newAtom(bitRate + “Kbps”) });
outlet(3, new Atom[] { Atom.newAtom(“length”), Atom.newAtom(lengthMS) });
} else
outlet(3, new Atom[] { Atom.newAtom(“error”), Atom.newAtom(“nofileopen”) });
}

public void loop(int i) {
if (i == 1)
looping = true;
else
looping = false;
}

public void notifyDeleted() {
t.stop();
t = null;
}
}

#169256
Dec 1, 2010 at 3:57pm

Hi,
I still get that error.

java.lang.UnsupportedClassVersionError: Bad version number in .class file
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:676)
at com.cycling74.max.MXJClassLoaderImpl.doLoadClass(MXJClassLoaderImpl.java:119)
at com.cycling74.max.MXJClassLoader.loadClazz(MXJClassLoader.java:88)
Could not load class ‘mp3play’

I tried starting “fresh” and loaded the above source into an [mxj quickie mp3play] object, and tried to compile. Before starting max, I put the RandomAccessFileInputStream.class into the Max “class” directory. This compile failed:

/Applications/Max5/Cycling '74/java/classes/mp3play.java[ 25 ] cannot access RandomAccessFileInputStream
bad class file: /Applications/Max5/Cycling '74/java/classes/RandomAccessFileInputStream.class
class file has wrong version 50.0, should be 49.0
Please remove or make sure it appears in the correct subdirectory of the classpath.
private RandomAccessFileInputStream in = null;
        ^
1 error
[ Dec 1, 2010 7:39:44 AM ]
 compilation of /Applications/Max5/Cycling '74/java/classes/mp3play.java failed.

I think the problem is that the RandomAccessFileInputStream class is compiled with an old version of java. If the source for that is available, it could be recompiled, and maybe get this baby working!

Peter

#169257
Dec 1, 2010 at 9:40pm

ah ok, here it is:

import java.io.*;

public class RandomAccessFileInputStream extends InputStream {
private RandomAccessFile raf;

public RandomAccessFileInputStream(File file) throws FileNotFoundException {
raf = new RandomAccessFile(file, “r”);
}

/**
* Skip ahead in the file by the specified bytes.
*/
synchronized public void seek(long bytes) throws IOException {
raf.seek((int) bytes);
}

/**
* Skip ahead in the file by the specified bytes.
*/
synchronized public void skipForward(long bytes) throws IOException {
raf.skipBytes((int) bytes);
}

/**
* Skip backward in the file by the specified bytes.
*/
synchronized public void skipBackward(long bytes) throws IOException {
long pos = raf.getFilePointer() – bytes;

if (pos < 0)
pos = 0;

raf.seek(pos);
}

/**
* Returns the current position within the file.
*/
public long getPosition() throws IOException {
return raf.getFilePointer();
}

/**
* Returns the current position within the file as a percentage String.
*/
public String getPercentage() throws IOException {
int pos = (int) ((((float) raf.getFilePointer()) / ((float) raf
.length())) * 100);

if (pos < 10)
return “0″ + pos + “%”;
else
return pos + “%”;

}

/**
* Returns the length of the file in bytes.
*/
public long getLength() throws IOException {
return raf.length();
}

// —————————-
// InputStream methods:
synchronized public int read() throws IOException {
return raf.read();
}

synchronized public int read(byte[] b) throws IOException {
return raf.read(b);
}

synchronized public int read(byte[] b, int off, int len) throws IOException {
return raf.read(b, off, len);
}

synchronized public long skip(long n) throws IOException {
long left = raf.length() – raf.getFilePointer();

if (n > left)
n = left;

return raf.skipBytes((int) n);
}

public int available() throws IOException {
return 0;
}

public void close() throws IOException {
raf.close();
}

public void mark(int readlimit) {

}

public void reset() throws IOException {

}

public boolean markSupported() {
return false;
}

}

#169258
Dec 2, 2010 at 1:35am

cool, that works! I’ve attached a zip with classes and .java files, along with a patch that explains a couple other things.

Attachments:
  1. mp3playjava.zip
#169259
Dec 2, 2010 at 10:10am

Wicked, glad you got it to work. Did you have go at stream-lining it at all? I sometimes find that it breaks audio for a split second when you open a new file.

#169260
Dec 2, 2010 at 4:53pm

No, I haven’t gotten into tweaking it at all. I just wanted to confirm it worked! I’ll try building something simple around it in the next few months and see how well it performs. I have some other things ahead of this in the work queue.
Ultimately, the best solution for max might lie in using jlayer to load a buffer~, in hopes of it being faster than buffer~’s quicktime-based “import” command….

#169261
Jan 7, 2011 at 2:24am

Whatever i tried, files in the max preferences, with or without”/Volumes/”
i always that error message

print: error filenotfound

any idea?

#169262
Jan 30, 2011 at 2:45pm

Hey freeka, could you clarify the problem? Are you trying to get this external to work? What do you mean by “/Volumes/”?

Rob

#169263

You must be logged in to reply to this topic.