Link to home
Start Free TrialLog in
Avatar of Mike Eghtebas
Mike EghtebasFlag for United States of America

asked on

how to read clip property in a directory

Please rename cartcar.pdf (attached) as cartcar.wav to test it with the attached code. This audio clip is about 3.5 seconds. When it plays it to the end, using following lines, it disable Stop button.

    private class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            if (t<=0) stop();
        }
    }

The value t in millisecond is set at:

    public void start() {
        t =3650; //<----*********
        timer.start();
        audioClip.play();
        play.setEnabled(false);
        stop.setEnabled(true);
        loop.setEnabled(true);          
    }

Above, I have entered t =3650 manually. But it will be good if I could read this property and enter it using some code (see the attached image).

Question: How can I read the length of video in seconds from the property of the clip using code?

Thank you.  
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;

public class Exercise18_20 extends JApplet { 

    private JButton play = new JButton("Play");
    private JButton loop = new JButton("Loop");
    private JButton stop = new JButton("Stop");
    private AudioClip audioClip;
    private int t =0;
    private Timer timer = new Timer(0, new TimerListener());
    
    public Exercise18_20() {

        audioClip = Applet.newAudioClip(getClass().getResource("cartcar.wav"));
        JPanel pane = new JPanel(new FlowLayout());

        JPanel panel = new JPanel();
        panel.add(play);
        panel.add(loop);
        panel.add(stop);
        stop.setEnabled(false);
        add(panel, BorderLayout.CENTER);
        
        play.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    start();
                }
        });
        loop.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    loop();
                }
        });
        stop.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    stop();
                }
        });

        timer.start();
        
    }

    private class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
System.out.println(t--);
            if (t<=0) stop();
        }
    }    
  
    public void start() {
        t =3650;
        timer.start();
        audioClip.play();
        play.setEnabled(false);
        stop.setEnabled(true);
        loop.setEnabled(true);          
    }
    
    public void loop() {
        stop();
        audioClip.loop();
        loop.setEnabled(false);
        play.setEnabled(true); 
        stop.setEnabled(true);        
    }    
    
    public void stop() {
        timer.stop();
        audioClip.stop();
        stop.setEnabled(false);
        loop.setEnabled(true);
        play.setEnabled(true);       
    }    

    public static void main(String[] args) {

        Exercise18_20 player = new Exercise18_20();
        
         JFrame frame = new JFrame("Exercise18_20");
        Exercise18_20 applet = new Exercise18_20();
        applet.init();
        
        frame.getContentPane().add(applet, BorderLayout.CENTER);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.setSize(250,75);
        frame.setVisible(true);       
    }
}

Open in new window

cartcar.zip
property.png
Avatar of for_yan
for_yan
Flag of United States of America image


These are in general windows specific properties.
In this trail

http://www.cplusplus.com/forum/windows/24603/

there is a suggestion how to do it through JNI call to native
C++ fuction and the function itself

This would not be easy though

Thanks everyone.

Provided solution worked perfectly. I modified it a little bit like this:

	

const char * _filename = "E:\\test\\folder_µ_1\\Backup-0008.txt";
const TCHAR * file = _T(_filename);
WIN32_FILE_ATTRIBUTE_DATA fileAttrs;
BOOL result = GetFileAttributesEx(file, GetFileExInfoStandard, &fileAttrs);



I tested it in a simple C++ application and it worked perfectly. It worked for both ascii filepath and Unicode filepath. I also tried to get file size from fileAttrs structure and it was correct.

Now let me explain the situation in more details. I created a function using the code above in a C++ dll like this:


JNIEXPORT jlong JNICALL Java_FileAttrs_getAttrib(JNIEnv *env, jobject obj, jstring filename) 
{
   const char * _filename = env->GetStringUTFChars(filename, 0);
   const TCHAR * file = _T(_filename);
   printf("\n>>>_filename: "); printf(_filename);
   printf("\n>>>     file: "); printf(file);
   WIN32_FILE_ATTRIBUTE_DATA fileAttrs;
   BOOL result = GetFileAttributesEx(file, GetFileExInfoStandard, &fileAttrs);
   if (!result) {
      return -1;
   }
   return fileAttrs.dwFileAttributes;
}



This dll function is called from a Java application using jni (for Java, I’m using Eclipse). This java app sends filepath as a parameter to this dll function. Java has no problem with ascii and Unicode file paths. Now if the filepath has only ascii characters in it, C++ function works correctly and returns file attributes but if the filepath contains Unicode characters C++ function fails and return -1. I hard-coded the value of _filename variable for testing purpose and then called the function from Java using Eclipse and it worked perfectly.

1
2
	

//const char * _filename = env->GetStringUTFChars(filename, 0);
const char * _filename = "E:\\test\\folder_µ_1\\Backup-0008.txt";



So I suppose that env->GetStringUTFChars(filename, 0) function is creating problem.

The printf() statements in the code produced following output (captured from Eclipse output window):

When using env->GetStringUTFChars(filename, 0):
const char * _filename = env->GetStringUTFChars(filename, 0);
>>>_filename: E:\test\folder_µ_1\Backup-0008.txt
>>> file: E:\test\folder_µ_1\Backup-0008.txt

When using hard-coded value:
const char * _filename = "E:\\test\\folder_µ_1\\Backup-0008.txt";
>>>_filename: E:\test\folder_µ_1\Backup-0008.txt
>>> file: E:\test\folder_µ_1\Backup-0008.txt

You can see that printf() displayed correct filepath when hard-coded.

Maybe I need to convert utf chars to Unicode/ascii chars somehow.

Sorry if it is not related to the forum anymore.

Open in new window


the instance of this class:
http://docs.oracle.com/javase/6/docs/api/javax/sound/sampled/AudioFileFormat.html

can be obtained frfom file:

public static AudioFileFormat getAudioFileFormat(File file)

then getProperty("duration") should give the length in microseconds

Now Ill try but I don't have much hope frabnkly


AudioFileFormat aff = AudioSystem.getAudioFileFormat(File file)
System.out.println(aff.getProperty("duration"));

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of for_yan
for_yan
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Unfortunately it does not support either .mid or .mp3 file - writes error - usnsupported  file type

perhpas we can make it recognize MP3 if download MP3 plugin of the JMF:

http://www.oracle.com/technetwork/java/javase/download-137625.html

This is printout from your cartcar.wav

m: {}
WAVE (.wav) file, byte length: 71619, data format: PCM_UNSIGNED 22050.0 Hz, 8 bit, mono, 1 bytes/frame, , frame length: 71575
duration: null

Open in new window


so I guess duration would be 71575/22050 = 3.24 sec
so at least for .wav files we can do it
Avatar of Mike Eghtebas

ASKER

I just back. Thank you for all the work. I am using wav if it supports it. I am basically limited to mid or wav (the two I know java supports).

Although you started with c++ (which I know nothing about); but it seems in the last part your solutions are in java.

I am going through your post now.
yes, c++ is tough way, although it should give more properties and for any kind of windows files

The Java is much more limited for now only to wav's and allows limited properties but at least works for two wav's that i tried
and looks like allows to find the duration

and with my file tada.wav less than 2 sec seems also reasonable though I could not see it in windows properties
Now I am trying to copy your code piece to incorporate with what I have at:

     public void start() {
        t =3650; //<----*********
        timer.start();
        audioClip.play();
        play.setEnabled(false);
        stop.setEnabled(true);
        loop.setEnabled(true);          
    }
I guess I need to import some additional package. I am having problem with:

AudioFileFormat aff = AudioSystem.getAudioFileFormat(new File("cartcar.wav"));
            Map<String, Object> m = aff.properties();

in:

    public void start() {
       
        try{
            AudioFileFormat aff = AudioSystem.getAudioFileFormat(new File("cartcar.wav"));
            Map<String, Object> m = aff.properties();
            System.out.println("m: " + m);

            System.out.println(aff.toString());

            System.out.println("duration: " + aff.getProperty("duration"));
        }catch(Exception ex){
            ex.printStackTrace();
        }  
       
        t =3650;
        timer.start();
        audioClip.play();
        play.setEnabled(false);
        stop.setEnabled(true);
        loop.setEnabled(true);          
    }

Also, in the to, I have file name entered. It will be nice somehow to use that, see:

    public Exercise18_20() {

        audioClip = Applet.newAudioClip(getClass().getResource("cartcar.wav"));
        JPanel pane = new JPanel(new FlowLayout());


import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioSystem;

but it is part of standard java - my IDE recognized them automatically
Thanks, that was good.

Now it is asking for File and Map classes used in
                                                                                       v--******
AudioFileFormat aff = AudioSystem.getAudioFileFormat(new File("cartcar.wav"));
            Map<String, Object> m = aff.properties();
              ^---*****
it looks like:

AudioFileFormat aff = AudioSystem.getAudioFileFormat(getClass().getResource("cartcar.wav"));

working for File, in place of

                                                                                       v--******
AudioFileFormat aff = AudioSystem.getAudioFileFormat(new File("cartcar.wav"));
You don't need anything actually about map - just
AudioFileFormat aff = AudioSystem.getAudioFileFormat(new File("cartcar.wav"));
and then to parse
aff.toString()
into two numbers and then divide one by anorther to get the seconds

Map contains noithing and is not useful in this case
Now, method:  public void start()  works nicely except that I have to enter file name "cartcar.wav" two times. Once at:

    public Exercise18_20() {
        audioClip = Applet.newAudioClip(getClass().getResource("cartcar.wav"));

and once again at:

    public void start() {
        try{
//          AudioFileFormat aff = AudioSystem.getAudioFileFormat(audioClip)
            AudioFileFormat aff = AudioSystem.getAudioFileFormat(getClass().getResource("cartcar.wav"));


public void start() {
        
        try{
//          AudioFileFormat aff = AudioSystem.getAudioFileFormat(audioClip)
            AudioFileFormat aff = AudioSystem.getAudioFileFormat(getClass().getResource("cartcar.wav"));
            String[] temp = aff.toString().split(" ");
            t=(Integer.parseInt(temp[temp.length - 1])/22050)*1000;
            timer.start();
            audioClip.play();
            play.setEnabled(false);
            stop.setEnabled(true);
            loop.setEnabled(true);

        }catch(Exception ex){
            ex.printStackTrace();
        }  
        
          
    }

Open in new window

You can introduce variable clipURL = getClass().getResource("cartcar.wav");
 and use it both times.
It does not actually matter