Author Topic: TiMidity++ AE  (Read 23031 times)

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
TiMidity++ AE
« on: December 26, 2011, 04:32:36 PM »
If i can ever figure out how SDL works, i plan on making a simple non stock based midi player for android. I do however know that i have to use SDL_mixer as that is what pelya used in his port of OpenTTD. I'm going to look at the mupen64plus source to see where to start  :P

Offline Paul

  • Administrator
  • double
  • *****
  • Posts: 3473
  • Developer
    • View Profile
    • PaulsCode.Com
Re: TiMidity++ AE
« Reply #1 on: December 26, 2011, 05:15:42 PM »
It might be easier to start with the sample app that ships with SDL, just because I made a few "customizations" in the code specific to my app (mainly with the keyboard input sections and the SDLActivity and SDLSurface Java classes) which wouldn't really apply to most other projects (it's kind of a hybrid between Pelya's port and the official port with some emulation and GUI interfaces thrown in).  On the other hand, it might give you some ideas about things that can be customized.  Let me know if you run into any problems understanding the port (I've become pretty familiar with the code and where various components are located)
Device: Samsung Galaxy Nexus i515
CPU: TI OMAP4460, 1.2 GHz (dual core, ARM Cortex-A9)
GPU: PowerVR SGX540, 307 MHz
RAM: 1 GB
Resolution: 720 x 1280
Rom: omni-4.4.4-20141014-toro-FML KitKat 4.4.4, rooted

Device: Eee PC 1015PEM
CPU: Intel Atom N550, 1.5 GHz (dual core, x86)
GPU: Intel GMA 3150, 200 MHz (dual core)
RAM: 2GB
Resolution: 1024 x 600
Rom: android-x86-4.3-20130725 Jelly Bean 4.3, rooted

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #2 on: December 26, 2011, 06:23:56 PM »
I'm starting with the easy stuff first such as making the icon:
http://db.tt/LLT96qVh
I have re-sized it per android's directions for the 4 standard screen resolutions.

Offline Epic_bubble

  • long
  • ***
  • Posts: 235
    • View Profile
Re: TiMidity++ AE
« Reply #3 on: December 27, 2011, 08:05:15 AM »
Hey there xperia64, is this your first time making an android app? :)
Device: Xperia play
CPU: Qualcomm 1 GHz Scorpion (Snapdragon)
GPU: Adreno 205
RAM: 512 MB
Screen res: 854 ? 480
ROM: stock android 2.3.4 rooted

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #4 on: December 27, 2011, 04:42:01 PM »
The first one involving actual coding. I should probably start with something easier

Offline Paul

  • Administrator
  • double
  • *****
  • Posts: 3473
  • Developer
    • View Profile
    • PaulsCode.Com
Re: TiMidity++ AE
« Reply #5 on: December 27, 2011, 05:01:09 PM »
I started with some simple jPCT apps in pure Java/SDK, because I was familiar with the PC version of the library.  I then ported DOSBox to android using Pelya's SDL port (pretty much plug-and-play) as a way of getting my feet wet with the NDK and SDL on Android.  Something like that's really all the practice you'd need (the rest is not much different than any other project, since you clearly have some development experience to draw on).  The SDK is actually the hardest part to figure out IMO (very different than traditional swing)
Device: Samsung Galaxy Nexus i515
CPU: TI OMAP4460, 1.2 GHz (dual core, ARM Cortex-A9)
GPU: PowerVR SGX540, 307 MHz
RAM: 1 GB
Resolution: 720 x 1280
Rom: omni-4.4.4-20141014-toro-FML KitKat 4.4.4, rooted

Device: Eee PC 1015PEM
CPU: Intel Atom N550, 1.5 GHz (dual core, x86)
GPU: Intel GMA 3150, 200 MHz (dual core)
RAM: 2GB
Resolution: 1024 x 600
Rom: android-x86-4.3-20130725 Jelly Bean 4.3, rooted

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #6 on: January 21, 2012, 02:33:41 PM »
Ok so i have learned that I actually don't need sdl, just the compiled libTiMidity as specified in the readme :D
Code: [Select]
libTiMidity -- MIDI to WAVE converter library.

This library is based on the TiMidity decoder from SDL_sound library.
Purpose to create this library is to avoid unnecessary dependences.
SDL_sound requires SDL and some other libraries, that not needed to
process MIDI files. In addition libTiMidity provides more suitable
API to work with MIDI songs, it enables to specify full path to the
timidity configuration file, and have function to retrieve meta data
from MIDI song.

If you have propositions regarding development of this library please
mail to me <lostclus@ua.fm>
this should make things a lot easier

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #7 on: February 05, 2012, 05:18:18 PM »
Easy part done. Library is compiled. Now for the hard part of actually making the app

Offline Paul

  • Administrator
  • double
  • *****
  • Posts: 3473
  • Developer
    • View Profile
    • PaulsCode.Com
Re: TiMidity++ AE
« Reply #8 on: February 06, 2012, 03:59:54 PM »
Here are those functions, from the chat earlier:

Code: [Select]
void JNI_Init_Varriables( JNIEnv* env, jclass cls )
{
    mEnv = env;
    mActivityClass = cls;

    midGetSongName = (*mEnv)->GetStaticMethodID( mEnv, mActivityClass,
                                "getSongName","()Ljava/lang/String;" );
    midGetConfigFile = (*mEnv)->GetStaticMethodID( mEnv, mActivityClass,
                                "getConfigFile","()Ljava/lang/String;" );
}
Code: [Select]
static char strBuff[1024];
char* JNI_GetSongName()
{
    jstring javaS = (*mEnv)->CallStaticStringMethod( mEnv, mActivityClass, midGetSongName );
    const char *nativeS = (*mEnv)->GetStringUTFChars( mEnv, javaS, 0 );
    strcpy( strBuff, nativeS );
    (*mEnv)->ReleaseStringUTFChars( mEnv, javaS, nativeS );
    return strBuff;
}
Code: [Select]
char* JNI_GetConfigFile()
{
    jstring javaS = (*mEnv)->CallStaticStringMethod( mEnv, mActivityClass, midGetConfigFile );
    const char *nativeS = (*mEnv)->GetStringUTFChars( mEnv, javaS, 0 );
    strcpy( strBuff, nativeS );
    (*mEnv)->ReleaseStringUTFChars( mEnv, javaS, nativeS );
    return strBuff;
}

The basic idea for linking them to your Activity class (Java side) is to add the following definition:

Code: [Select]
public static native void JNI_Init_Varriables();
Call it in the onCreate method:

Code: [Select]
JNI_Init_Varriables();
And implement the following static methods:

Code: [Select]
public static String getSongName()
{
   // TODO: get the song filename somehow, and return it
}
public static String getConfigFile()
{
   // TODO: get the config filename somehow, and return it
}
Device: Samsung Galaxy Nexus i515
CPU: TI OMAP4460, 1.2 GHz (dual core, ARM Cortex-A9)
GPU: PowerVR SGX540, 307 MHz
RAM: 1 GB
Resolution: 720 x 1280
Rom: omni-4.4.4-20141014-toro-FML KitKat 4.4.4, rooted

Device: Eee PC 1015PEM
CPU: Intel Atom N550, 1.5 GHz (dual core, x86)
GPU: Intel GMA 3150, 200 MHz (dual core)
RAM: 2GB
Resolution: 1024 x 600
Rom: android-x86-4.3-20130725 Jelly Bean 4.3, rooted

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #9 on: February 06, 2012, 06:51:47 PM »
2/6/12 0.1: http://db.tt/V9atcm0T 
2/7/12 0.2: http://db.tt/l10gtvo8 Fixed scrambled folder lists. changed dp to 30
2/9/12 0.3: http://db.tt/kl91TwkN Added a filter which only displays .mid, .midi, or .smf files.
2/12/12 0.4: http://db.tt/yz08Ouxp Fixed rotation app restart, made back button go up a directory, changed filter to display 32 different music file types. Preparation to actually hook up the native code.
2/16/12 0.4.1: http://db.tt/Ni9eIJzw Minor fix, made it so when keypad slides out, it does not reset the app.
2/19/12 0.5: http://db.tt/mz3xsRGh Added command that causes app to exit while pressing back and the file browser is in the root of the sd card.
just a folder viewer, native timidity library is compiled but not implemented.
« Last Edit: February 19, 2012, 01:53:13 PM by xperia64 »

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #10 on: February 07, 2012, 07:50:29 PM »
fixed the file filter by filtering the objects as they were being transferred from the array to the arraylist.
and here is what should be the main file as far as i know.
« Last Edit: February 09, 2012, 05:51:57 PM by xperia64 »

Offline Paul

  • Administrator
  • double
  • *****
  • Posts: 3473
  • Developer
    • View Profile
    • PaulsCode.Com
Re: TiMidity++ AE
« Reply #11 on: February 09, 2012, 07:08:34 PM »
Ok, start by adding including jni.h at the top of one of your .c files (if you create a new .c file for this, which you should eventually, then be sure to also include timidity.h at the top as well).  Then add the following static globals and function:

Code: [Select]
static char cFilename[1024];  // increase the size if paths could be super-long
static MidSong *midiSong;  // TODO: figure out where you want this (assuming static global for now)
void JNI_Play_Song( JNIEnv* env, jclass cls, jstring jFilename )
{
    const char *nativeS = (*mEnv)->GetStringUTFChars( mEnv, jFilename, 0 );
    strcpy( cFilename, nativeS );
    (*mEnv)->ReleaseStringUTFChars( mEnv, jFilename, nativeS );

    // ok, the filename is now contained in 'cFilename'.

    MidIStream *midiStream;
    midiStream = mid_istream_open_file ( cFilename );
    MidSongOptions *midiOptions;
    // TODO: this could be a memory leak here, call free() somewhere:
    midiOptions = (MidSongOptions *) malloc( sizeof( MidSongOptions ) );
    // TODO: some kind of error checking, to avoid segfault if null pointers
   
    midiSong = mid_song_load( midiStream, midiOptions );  // TODO: error checking
    mid_song_start( midiSong );
}

Then, in your .java file (the file browser for now), add the following prototype:

Code: [Select]
public static native void JNI_Play_Song( String filename );
And finally, in the part of the code where the filename was chosen (you'll want the full path, BTW), place the following line:
Code: [Select]
JNI_Play_Song( filename );
Once you get it so it compiles and runs (and there are no simple errors showing up in the logcat), then you will be ready to move on to creating the Android audio context through JNI (I expect that it won't actually play any audio right now).  There might be some error about there not being an audio device or something, and it might segfault, or it might just be silent (the logcat output should give you an idea what it is complaining about).
Device: Samsung Galaxy Nexus i515
CPU: TI OMAP4460, 1.2 GHz (dual core, ARM Cortex-A9)
GPU: PowerVR SGX540, 307 MHz
RAM: 1 GB
Resolution: 720 x 1280
Rom: omni-4.4.4-20141014-toro-FML KitKat 4.4.4, rooted

Device: Eee PC 1015PEM
CPU: Intel Atom N550, 1.5 GHz (dual core, x86)
GPU: Intel GMA 3150, 200 MHz (dual core)
RAM: 2GB
Resolution: 1024 x 600
Rom: android-x86-4.3-20130725 Jelly Bean 4.3, rooted

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #12 on: February 09, 2012, 08:00:57 PM »
Code: [Select]
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        {
        System.loadLibrary("timidity"); // or whatever the name is (take of the "lib" and ".so")
        }
        catch(  UnsatisfiedLinkError, e )
        {
        Log.e( "Oops!", "Unable to load native library 'timidity'" );
        }
        myPath = (TextView) findViewById(R.id.path);

        getDir(rootsd);

    }

Offline Paul

  • Administrator
  • double
  • *****
  • Posts: 3473
  • Developer
    • View Profile
    • PaulsCode.Com
Re: TiMidity++ AE
« Reply #13 on: February 09, 2012, 08:05:21 PM »
You are missing the "try" and open-bracket.  Should look like this:

Code: [Select]
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
                try
                {
            System.loadLibrary("timidity"); // or whatever the name is (take of the "lib" and ".so")
        }
        catch(  UnsatisfiedLinkError, e )
        {
            Log.e( "Oops!", "Unable to load native library 'timidity'" );
        }
        myPath = (TextView) findViewById(R.id.path);

        getDir(rootsd);

    }

--EDIT--
And there was a stray bracket in there.  Fixed.
« Last Edit: February 09, 2012, 08:07:29 PM by Paul »
Device: Samsung Galaxy Nexus i515
CPU: TI OMAP4460, 1.2 GHz (dual core, ARM Cortex-A9)
GPU: PowerVR SGX540, 307 MHz
RAM: 1 GB
Resolution: 720 x 1280
Rom: omni-4.4.4-20141014-toro-FML KitKat 4.4.4, rooted

Device: Eee PC 1015PEM
CPU: Intel Atom N550, 1.5 GHz (dual core, x86)
GPU: Intel GMA 3150, 200 MHz (dual core)
RAM: 2GB
Resolution: 1024 x 600
Rom: android-x86-4.3-20130725 Jelly Bean 4.3, rooted

Offline xperia64

  • Developer
  • double
  • *****
  • Posts: 591
    • View Profile
    • My Apps
Re: TiMidity++ AE
« Reply #14 on: February 10, 2012, 01:39:32 PM »
i added the try and catch thing. it does not give the "unable to load" message so that is good, but still crashes when selecting a song. here is the logcat.
Code: [Select]
02-10 14:36:00.938: D/dalvikvm(2135): No JNI_OnLoad found in /data/data/com.xperia64.timidityae/lib/libtimidity.so 0x2afc8960, skipping init
02-10 14:36:15.548: E/AndroidRuntime(2135): FATAL EXCEPTION: main
02-10 14:36:15.548: E/AndroidRuntime(2135): java.lang.UnsatisfiedLinkError: JNI_Play_Song
02-10 14:36:15.548: E/AndroidRuntime(2135): at com.xperia64.timidityae.TimidityAEActivity.JNI_Play_Song(Native Method)
02-10 14:36:15.548: E/AndroidRuntime(2135): at com.xperia64.timidityae.TimidityAEActivity.onListItemClick(TimidityAEActivity.java:215)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.app.ListActivity$2.onItemClick(ListActivity.java:319)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.widget.AdapterView.performItemClick(AdapterView.java:284)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.widget.ListView.performItemClick(ListView.java:3518)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.widget.AbsListView$PerformClick.run(AbsListView.java:1902)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.os.Handler.handleCallback(Handler.java:587)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.os.Handler.dispatchMessage(Handler.java:92)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.os.Looper.loop(Looper.java:123)
02-10 14:36:15.548: E/AndroidRuntime(2135): at android.app.ActivityThread.main(ActivityThread.java:3701)
02-10 14:36:15.548: E/AndroidRuntime(2135): at java.lang.reflect.Method.invokeNative(Native Method)
02-10 14:36:15.548: E/AndroidRuntime(2135): at java.lang.reflect.Method.invoke(Method.java:507)
02-10 14:36:15.548: E/AndroidRuntime(2135): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:862)
02-10 14:36:15.548: E/AndroidRuntime(2135): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)
02-10 14:36:15.548: E/AndroidRuntime(2135): at dalvik.system.NativeStart.main(Native Method)