├── .classpath ├── .gitignore ├── .project ├── README.md ├── Screenshots ├── kAI-GUI.png ├── kAI-screener.png └── kaiDJ.png ├── demo ├── Katy Perry - Firework.mp3 └── Katy Perry - Firework.mp3.kai ├── dist └── karaok-AI.jar ├── karaok-AI.jardesc ├── lib ├── common │ ├── JID3.jar │ ├── WhisperTimeSync.jar │ ├── commons-logging-api.jar │ ├── hsqldb.jar │ ├── jakarta-regexp-1.5.jar │ ├── jid3lib-0.5.4.jar │ ├── jl1.0.1.jar │ ├── mp3spi1.9.4.jar │ ├── myid3.jar │ ├── tritonus_share.jar │ ├── ws-commons-util-1.0.2.jar │ ├── xmlrpc-client-3.1.3.jar │ └── xmlrpc-common-3.1.3.jar ├── swt-linux.jar ├── swt-mac.jar └── swt-win.jar └── src ├── com └── cubaix │ ├── kai │ ├── KaiClient.java │ ├── KaiEditor.java │ ├── KaiPlayer.java │ ├── KaiScreener.java │ ├── KaiSrt.java │ ├── KaiViewer.java │ ├── LogoPanel.java │ ├── img │ │ ├── Logo.png │ │ ├── LogoSmall.png │ │ ├── LogoSquare.png │ │ ├── LogoSquareL.png │ │ └── kAI.svg │ └── img2 │ │ ├── arrows-fullscreen.svg │ │ └── fullscreen.png │ └── kaiDJ │ ├── CategoryManager.java │ ├── DJPlayer.java │ ├── KaiDJ.java │ ├── LogoPanel.java │ ├── PlayList.java │ ├── PlayManager.java │ ├── SearchManager.java │ ├── db │ ├── Db.java │ ├── Id3Analyzer.java │ ├── SongDescr.java │ └── SongGroup.java │ ├── img │ ├── Icon.ico │ ├── Icon.png │ ├── LogoSmall.png │ ├── kaiDJ.svg │ ├── playerBck.png │ └── playerBck.xcf │ ├── img2 │ ├── addDbBut.png │ ├── addDbBut.xcf │ ├── addGroupBut.png │ ├── addGroupBut.xcf │ ├── allButtons.svg │ ├── bookmarks.svg │ ├── butBck.png │ ├── butBck.xcf │ ├── butBckDark.png │ ├── butBckDark.xcf │ ├── butBckMid.png │ ├── butBckMid.xcf │ ├── catBut.png │ ├── catBut.xcf │ ├── chat-square-text-fill.svg │ ├── chat-square-text.svg │ ├── database-add.svg │ ├── eraseDbBut.png │ ├── folder2-open.svg │ ├── globe.svg │ ├── kaiBut.png │ ├── kaiIcon.png │ ├── kaiIcon.svg │ ├── mixBut.png │ ├── mixBut.xcf │ ├── newPLBut.png │ ├── newPLBut.xcf │ ├── openCatBut.png │ ├── openPLBut.png │ ├── save2.svg │ ├── saveCatBut.png │ ├── savePLBut.png │ ├── search.svg │ ├── searchKaiBut.png │ ├── showProfBut.png │ ├── showProfBut.xcf │ ├── shuffleBut.png │ ├── shuffleBut.xcf │ ├── stars.svg │ ├── stopAftBut.png │ ├── stopAftBut.xcf │ ├── trash3.svg │ ├── webSiteBut.png │ └── webSiteBut.xcf │ ├── swt │ ├── KaiButton.java │ ├── KaiScrollBar.java │ ├── PlayListListener.java │ └── TimedCanvas.java │ ├── utils │ └── FileUtils.java │ ├── web │ └── BrowserControl.java │ └── xml │ ├── ConfigLoader.java │ ├── PlayListLoader.java │ ├── XLoader.java │ ├── XObject.java │ ├── XQualifier.java │ ├── XTag.java │ └── charEntities.tsv ├── javazoom └── jlgui │ └── basicplayer │ ├── BasicController.java │ ├── BasicPlayer.java │ ├── BasicPlayerEvent.java │ ├── BasicPlayerEventLauncher.java │ ├── BasicPlayerException.java │ └── BasicPlayerListener.java └── kj ├── audio └── KJAudioDataConsumer.java ├── dsp ├── KJDigitalSignalProcessingAudioDataConsumer.java ├── KJDigitalSignalProcessor.java ├── KJDigitalSignalProcessor1.java └── KJFFT.java └── ui └── dsp └── KJScopeAndSpectrumAnalyser.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /last.jdj 3 | /MP3_v3.hdb.backup 4 | /MP3_v3.hdb.data 5 | /MP3_v3.hdb.log 6 | /MP3_v3.hdb.properties 7 | /MP3_v3.hdb.script 8 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | karaok-AI 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # karaok-AI 2 | **karaok-AI** is a karaoke Player / Editor with automatic clip creation from any song file using vocals and lyrics extraction (Speech-to-Text). 3 | 4 | karaok-AI lyrics and timestamps **editor**: 5 | 6 | 7 | 8 | karaok-AI **screener** with synchronized lyrics: 9 | 10 | 11 | 12 | Lyrics **auto-extract** and **edit** example: 13 | 14 | [![Lyrics auto-extract and edit example](https://github.com/EtienneAb3d/karaok-AI/assets/25932245/7e688c83-ac3b-4eaf-b038-58df7161c09a)](https://karaok-ai.neurospell.com/karaok-AI-DemoLady.mp4) 15 | 16 | Auto-extracted Vocals/Drums/Bass/Other stem **remixing** example: 17 | 18 | [![Lyrics auto-extract and edit example](https://github.com/EtienneAb3d/karaok-AI/assets/25932245/7e688c83-ac3b-4eaf-b038-58df7161c09a)](https://karaok-ai.neurospell.com/karaok-AI-DemoKaty.mp4) 19 | 20 | karaok-AI is using WhisperHallu and WhisperTimeSync to extract vocals and lyrics:
21 | https://github.com/EtienneAb3d/WhisperHallu
22 | https://github.com/EtienneAb3d/WhisperTimeSync 23 | 24 | # Included: kaiDJ 25 | 26 | **kaiDJ** is a minimalist and easy to use, but yet powerful and versatile DJ Party Player. 27 | - multi-sound cards support. Two players with auto-mix between songs, one pre-listen player. 28 | - indexing of thousands of songs in a single efficient database (mp3, wav, etc). 29 | - direct search / selection over all songs in the database. Management of song categories. 30 | - playlist offering the possibility to manage songs by nested groups. 31 | - Open / save m3u and m3u8 playlists keeping groups definitions. 32 | 33 | Read the documentation for the basics. 34 | 35 | 36 | 37 |
38 | This tool is a demonstration of our know-how.
39 | If you are interested in a commercial/industrial AI linguistic project, contact us:
40 | https://cubaix.com 41 | -------------------------------------------------------------------------------- /Screenshots/kAI-GUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/Screenshots/kAI-GUI.png -------------------------------------------------------------------------------- /Screenshots/kAI-screener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/Screenshots/kAI-screener.png -------------------------------------------------------------------------------- /Screenshots/kaiDJ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/Screenshots/kaiDJ.png -------------------------------------------------------------------------------- /demo/Katy Perry - Firework.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/demo/Katy Perry - Firework.mp3 -------------------------------------------------------------------------------- /demo/Katy Perry - Firework.mp3.kai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/demo/Katy Perry - Firework.mp3.kai -------------------------------------------------------------------------------- /dist/karaok-AI.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/dist/karaok-AI.jar -------------------------------------------------------------------------------- /karaok-AI.jardesc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /lib/common/JID3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/JID3.jar -------------------------------------------------------------------------------- /lib/common/WhisperTimeSync.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/WhisperTimeSync.jar -------------------------------------------------------------------------------- /lib/common/commons-logging-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/commons-logging-api.jar -------------------------------------------------------------------------------- /lib/common/hsqldb.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/hsqldb.jar -------------------------------------------------------------------------------- /lib/common/jakarta-regexp-1.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/jakarta-regexp-1.5.jar -------------------------------------------------------------------------------- /lib/common/jid3lib-0.5.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/jid3lib-0.5.4.jar -------------------------------------------------------------------------------- /lib/common/jl1.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/jl1.0.1.jar -------------------------------------------------------------------------------- /lib/common/mp3spi1.9.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/mp3spi1.9.4.jar -------------------------------------------------------------------------------- /lib/common/myid3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/myid3.jar -------------------------------------------------------------------------------- /lib/common/tritonus_share.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/tritonus_share.jar -------------------------------------------------------------------------------- /lib/common/ws-commons-util-1.0.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/ws-commons-util-1.0.2.jar -------------------------------------------------------------------------------- /lib/common/xmlrpc-client-3.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/xmlrpc-client-3.1.3.jar -------------------------------------------------------------------------------- /lib/common/xmlrpc-common-3.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/common/xmlrpc-common-3.1.3.jar -------------------------------------------------------------------------------- /lib/swt-linux.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/swt-linux.jar -------------------------------------------------------------------------------- /lib/swt-mac.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/swt-mac.jar -------------------------------------------------------------------------------- /lib/swt-win.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/lib/swt-win.jar -------------------------------------------------------------------------------- /src/com/cubaix/kai/KaiClient.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kai; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.net.URL; 9 | import java.util.zip.ZipEntry; 10 | import java.util.zip.ZipOutputStream; 11 | 12 | import org.apache.xmlrpc.client.XmlRpcClient; 13 | import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; 14 | 15 | import com.cubaix.kaiDJ.KaiDJ; 16 | import com.cubaix.kaiDJ.utils.FileUtils; 17 | 18 | public class KaiClient { 19 | KaiDJ parentKDJ = null; 20 | String path = null; 21 | String taskId = null; 22 | 23 | public KaiClient(KaiDJ aParentKDJ) { 24 | parentKDJ = aParentKDJ; 25 | } 26 | 27 | XmlRpcClient getXmlRcpClient() throws Exception { 28 | XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); 29 | config.setServerURL(new URL("http://odyssee.neurospell.com:8991")); 30 | config.setEnabledForExtensions(false); 31 | config.setConnectionTimeout(60 * 1000);//1mn 32 | config.setReplyTimeout(10 * 60 * 60 * 1000);//10h 33 | XmlRpcClient client = new XmlRpcClient(); 34 | client.setConfig(config); 35 | return client; 36 | } 37 | 38 | public void getCode() throws Exception { 39 | XmlRpcClient client = getXmlRcpClient(); 40 | Object[] params = new Object[] {parentKDJ.userEMail}; 41 | System.out.println("GET KAI CODE..."); 42 | String aRep = (String)client.execute("Middleware.kaiCode",params); 43 | System.out.println("GetCode reply: "+aRep); 44 | } 45 | 46 | public String extract(String aPath,String aLng) throws Exception { 47 | path = aPath; 48 | XmlRpcClient client = getXmlRcpClient(); 49 | File aFile = new File(aPath); 50 | System.out.println("LOADING: "+aFile.getCanonicalPath()); 51 | FileInputStream fileInputStream; 52 | byte[] aBuf = null; 53 | try { 54 | fileInputStream = new FileInputStream(aFile); 55 | aBuf = new byte[(int) aFile.length()]; 56 | fileInputStream.read(aBuf); 57 | fileInputStream.close(); 58 | } catch (IOException e) { 59 | e.printStackTrace(System.err); 60 | } 61 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 62 | try(ZipOutputStream zos = new ZipOutputStream(baos)) { 63 | 64 | /* File is not on the disk, test.txt indicates 65 | only the file name to be put into the zip */ 66 | ZipEntry entry = new ZipEntry(aFile.getName()); 67 | zos.putNextEntry(entry); 68 | zos.write(aBuf); 69 | zos.closeEntry(); 70 | } 71 | catch(IOException ioe) { 72 | ioe.printStackTrace(); 73 | } 74 | Object[] params = new Object[] {parentKDJ.userEMail,parentKDJ.userCode,baos.toByteArray(),aLng,parentKDJ.userEMail.replaceAll("[@.]","_")}; 75 | System.out.println("UPLOADING..."); 76 | String aRes = (String)client.execute("Middleware.kai",params); 77 | System.out.println("Res: "+aRes); 78 | return aRes; 79 | } 80 | 81 | public String state() throws Exception { 82 | XmlRpcClient client = getXmlRcpClient(); 83 | System.out.println("STATE: "+taskId); 84 | Object[] params = new Object[] {parentKDJ.userEMail,parentKDJ.userCode,taskId,parentKDJ.userEMail.replaceAll("[@.]","_")}; 85 | String aRes = (String)client.execute("Middleware.kaiState",params); 86 | System.out.println("Res: "+aRes); 87 | return aRes; 88 | } 89 | 90 | public void get() throws Exception { 91 | XmlRpcClient client = getXmlRcpClient(); 92 | System.out.println("GET: "+taskId); 93 | Object[] params = new Object[] {parentKDJ.userEMail,parentKDJ.userCode,taskId,parentKDJ.userEMail.replaceAll("[@.]","_")}; 94 | byte[] aKai = (byte[])client.execute("Middleware.kaiGet",params); 95 | FileOutputStream aFOS = new FileOutputStream(path+".kai"); 96 | aFOS.write(aKai); 97 | aFOS.flush(); 98 | aFOS.close(); 99 | System.out.println("SAVED"); 100 | FileUtils.unzipDir(path+".kai", new File(path).getParentFile().getCanonicalPath(), true); 101 | System.out.println("UNZIPPED"); 102 | } 103 | 104 | public static void main(String[] args) { 105 | try { 106 | } catch (Exception e) { 107 | e.printStackTrace(System.err); 108 | } 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/KaiPlayer.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kai; 2 | 3 | import org.eclipse.swt.widgets.Composite; 4 | 5 | import com.cubaix.kaiDJ.KaiDJ; 6 | import com.cubaix.kaiDJ.db.SongDescr; 7 | import com.cubaix.kaiDJ.DJPlayer; 8 | 9 | public class KaiPlayer extends DJPlayer { 10 | SongDescr song = null; 11 | String stem = null; 12 | 13 | public KaiPlayer(KaiDJ aParentKDJ, Composite parent, int style, int aDest) { 14 | super(aParentKDJ, parent, style, aDest,false); 15 | } 16 | 17 | @Override 18 | protected void extractProperties() { 19 | super.extractProperties(); 20 | if(stem != null) { 21 | currentAuthor = stem; 22 | } 23 | if(song != null) { 24 | currentTitle = song.title+" / "+song.author; 25 | } 26 | } 27 | 28 | void load(SongDescr aSong,String aPath,String aStem) { 29 | song = aSong; 30 | stem = aStem; 31 | super.load(aPath); 32 | } 33 | 34 | @Override 35 | public void timeToNext() { 36 | //Do nothing 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/KaiScreener.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kai; 2 | 3 | import java.io.InputStream; 4 | 5 | import org.eclipse.swt.SWT; 6 | import org.eclipse.swt.events.KeyEvent; 7 | import org.eclipse.swt.events.KeyListener; 8 | import org.eclipse.swt.events.PaintEvent; 9 | import org.eclipse.swt.events.PaintListener; 10 | import org.eclipse.swt.graphics.GC; 11 | import org.eclipse.swt.graphics.Image; 12 | import org.eclipse.swt.graphics.Point; 13 | import org.eclipse.swt.graphics.Rectangle; 14 | import org.eclipse.swt.widgets.Composite; 15 | 16 | import com.cubaix.kaiDJ.KaiDJ; 17 | import com.cubaix.kaiDJ.db.SongDescr; 18 | import com.cubaix.kaiDJ.swt.TimedCanvas; 19 | 20 | public class KaiScreener extends TimedCanvas { 21 | KaiViewer parentKV = null; 22 | 23 | Rectangle panelBounds = null; 24 | Image dblBuf = null; 25 | Rectangle dblBounds = new Rectangle(0, 0, 1280, 720); 26 | GC dblBufGC; 27 | 28 | Image fullScreenBut = null; 29 | 30 | int currentKaiIdx = -1; 31 | int currentKaiIdxJustBefore = -1; 32 | 33 | public KaiScreener(KaiViewer aParentKV, Composite parent, int style) { 34 | super(aParentKV.parentKE.parentKDJ, parent, style); 35 | parentKV = aParentKV; 36 | 37 | InputStream aIS = getClass().getResourceAsStream("img2/fullscreen.png"); 38 | fullScreenBut = new Image(parentKDJ.display, aIS); 39 | 40 | final KaiScreener aThis = this; 41 | addPaintListener(new PaintListener() { 42 | public void paintControl(PaintEvent aPE) { 43 | panelBounds = getClientArea(); 44 | GC aPlGC = new GC(aThis); 45 | paintDbl(aPlGC); 46 | aPlGC.dispose(); 47 | needRedraw(); 48 | } 49 | }); 50 | addKeyListener(new KeyListener() { 51 | @Override 52 | public void keyReleased(KeyEvent arg0) { 53 | } 54 | 55 | @Override 56 | public void keyPressed(KeyEvent arg0) { 57 | } 58 | }); 59 | Thread aTrackTh = new Thread(new Runnable() { 60 | @Override 61 | public void run() { 62 | while(!aThis.isDisposed()) { 63 | try { 64 | SongDescr aSong = parentKV.parentKE.song; 65 | if(aSong != null && aSong.kaiSrt != null) { 66 | int aKaiIdx = aSong.kaiSrt.getChunkIdx(parentKV.parentKE.playerVocals.getPositionMs()); 67 | int aJustBef = aSong.kaiSrt.getChunkIdxJustBefore(parentKV.parentKE.playerVocals.getPositionMs()); 68 | if(aKaiIdx != currentKaiIdx || aJustBef != currentKaiIdxJustBefore) { 69 | currentKaiIdx = aKaiIdx; 70 | currentKaiIdxJustBefore = aJustBef; 71 | needRedraw(); 72 | parentKV.parentKE.logoPanel.needRedraw(); 73 | } 74 | } 75 | Thread.sleep(10); 76 | } catch (Exception e) { 77 | e.printStackTrace(System.err); 78 | } 79 | } 80 | } 81 | }); 82 | aTrackTh.start(); 83 | } 84 | 85 | @Override 86 | protected void paintTimed() { 87 | if(KaiDJ._DEBUG_PAINT) { 88 | System.out.println("SCREENER.paintTimed()"); 89 | } 90 | try { 91 | if (dblBuf == null) { 92 | dblBuf = new Image(parentKDJ.display,dblBounds.width,dblBounds.height); 93 | dblBufGC = new GC(dblBuf); 94 | } 95 | 96 | dblBufGC.setClipping(0, 0,dblBounds.width,dblBounds.height); 97 | dblBufGC.setBackground(parentKDJ.mainBckC); 98 | dblBufGC.fillRectangle(0, 0,dblBounds.width,dblBounds.height); 99 | 100 | SongDescr aSong = parentKV.parentKE.song; 101 | if(aSong != null && aSong.kaiSrt != null) { 102 | currentKaiIdx = aSong.kaiSrt.getChunkIdx(parentKV.parentKE.playerVocals.getPositionMs()); 103 | int aJustBef = aSong.kaiSrt.getChunkIdxJustBefore(parentKV.parentKE.playerVocals.getPositionMs()); 104 | 105 | dblBufGC.setFont(parentKDJ.viewerFont); 106 | int aPadding = 5; 107 | 108 | Point aC = dblBufGC.textExtent("M"); 109 | int aPosY = dblBounds.y+dblBounds.height/2; 110 | for(int i = currentKaiIdx;i >= 0 && i >= currentKaiIdx-5;i--) { 111 | if(i >= aSong.kaiSrt.chunkTexts.size()) { 112 | aPosY -= aC.y; 113 | continue; 114 | } 115 | String aKaiText = aSong.kaiSrt.chunkTexts.elementAt(i); 116 | if(i == currentKaiIdx) { 117 | Point aE = dblBufGC.textExtent(aKaiText); 118 | aPosY -= aE.y/2; 119 | continue; 120 | } 121 | 122 | for(String aT : aKaiText.split("\n")) { 123 | aPosY -= aC.y; 124 | } 125 | aPosY -= aC.y; 126 | } 127 | for(int i = currentKaiIdx-5;i < aSong.kaiSrt.chunkTexts.size();i++) { 128 | if(aPosY > dblBounds.height) { 129 | break; 130 | } 131 | if(i < 0) { 132 | continue; 133 | } 134 | // if(i == aJustBef) { 135 | // dblBufGC.setForeground(parentKDJ.logoLightC); 136 | // dblBufGC.drawLine(dblBounds.x, aPosY, dblBounds.x+dblBounds.width, aPosY); 137 | // } 138 | String aKaiText = aSong.kaiSrt.chunkTexts.elementAt(i); 139 | if(i == currentKaiIdx) { 140 | dblBufGC.setForeground(parentKDJ.logoLightC); 141 | } 142 | else { 143 | dblBufGC.setForeground(parentKDJ.logoDarkC); 144 | } 145 | for(String aT : aKaiText.split("\n")) { 146 | aT = aT.trim(); 147 | if(i == aJustBef) { 148 | aT = "⇢⇢⇢ "+aT+" ⇠⇠⇠"; 149 | } 150 | Point aE = dblBufGC.textExtent(aT); 151 | dblBufGC.drawText(aT,dblBounds.x + dblBounds.width/2 - aE.x/2, dblBounds.y + aPosY, true); 152 | aPosY += aC.y; 153 | } 154 | aPosY += aC.y; 155 | } 156 | 157 | } 158 | 159 | dblBufGC.drawImage(fullScreenBut, dblBounds.width-40, dblBounds.height-40); 160 | 161 | // Draw final image 162 | GC aPlGC = new GC(this); 163 | paintDbl(aPlGC); 164 | aPlGC.dispose(); 165 | } catch (Throwable t) { 166 | System.err.println("Can't paint screen : " + t); 167 | t.printStackTrace(System.err); 168 | } 169 | } 170 | 171 | void paintDbl(GC aPlGC) { 172 | if(dblBuf == null) { 173 | return; 174 | } 175 | aPlGC.setAntialias(SWT.ON); 176 | aPlGC.setInterpolation(SWT.HIGH); 177 | aPlGC.drawImage(dblBuf 178 | ,0, 0, dblBounds.width, dblBounds.height 179 | , 0, 0,panelBounds.width,panelBounds.height); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/KaiSrt.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kai; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.OutputStreamWriter; 10 | import java.util.Vector; 11 | 12 | import com.cubAIx.WhisperTimeSync.WhisperTimeSync; 13 | import com.cubaix.kaiDJ.utils.FileUtils; 14 | 15 | public class KaiSrt { 16 | static final boolean _DEBUG = false; 17 | String path = null; 18 | String text = null; 19 | String srt = null; 20 | String lng = "xx"; 21 | public Vector chunkTexts = new Vector(); 22 | public Vector chunkStarts = new Vector(); 23 | public Vector chunkStops = new Vector(); 24 | 25 | public KaiSrt(String aPath) { 26 | path = aPath; 27 | load(); 28 | } 29 | 30 | public int getChunkIdx(long aTimeMS) { 31 | if(chunkStarts.size() <= 0) { 32 | return -1; 33 | } 34 | if(aTimeMS < chunkStarts.elementAt(0)) { 35 | return -1; 36 | } 37 | for(int l = 0;l < chunkTexts.size();l++) { 38 | if(chunkStarts.elementAt(l) <= aTimeMS && chunkStops.elementAt(l) > aTimeMS) { 39 | return l; 40 | } 41 | } 42 | for(int l = 0;l < chunkTexts.size();l++) { 43 | if(chunkStops.elementAt(l) > aTimeMS) { 44 | return l-1; 45 | } 46 | } 47 | if(aTimeMS > chunkStops.elementAt(chunkStops.size()-1)) { 48 | return chunkStops.size(); 49 | } 50 | return -1; 51 | } 52 | 53 | public int getChunkIdxJustBefore(long aTimeMS) { 54 | for(int l = 0;l < chunkTexts.size();l++) { 55 | if(chunkStarts.elementAt(l) <= aTimeMS+1000 && chunkStarts.elementAt(l) > aTimeMS) { 56 | return l; 57 | } 58 | } 59 | return -1; 60 | } 61 | 62 | public String getChunkText(long aTimeMS) { 63 | int aIdx = getChunkIdx(aTimeMS); 64 | if(aIdx < 0) { 65 | return ""; 66 | } 67 | return chunkTexts.elementAt(aIdx); 68 | } 69 | 70 | public void load() { 71 | try { 72 | String aKsrtPath = path+".ksrt"; 73 | if(!new File(aKsrtPath).exists()) { 74 | FileUtils.unzipDir(path+".kai", new File(aKsrtPath).getParentFile().getCanonicalPath(), false); 75 | } 76 | if(new File(aKsrtPath+".edited").exists()) { 77 | aKsrtPath = aKsrtPath+".edited"; 78 | } 79 | BufferedReader aBR = new BufferedReader(new InputStreamReader(new FileInputStream(aKsrtPath), "utf-8")); 80 | String aLine; 81 | StringBuffer aSB = new StringBuffer(); 82 | while((aLine = aBR.readLine()) != null) { 83 | aLine = aLine.trim().replaceAll("\\\\n", "\n") 84 | .replaceAll("\r*\n", "\n"); 85 | if(aSB.length() > 0) { 86 | aSB.append("\n"); 87 | } 88 | aSB.append(aLine); 89 | } 90 | String aKsrt = aSB.toString(); 91 | if(_DEBUG) { 92 | System.out.println(aKsrt); 93 | } 94 | if(aKsrt.indexOf("\n1\n") >= 0) { 95 | text = aKsrt.substring(0, aKsrt.indexOf("\n1\n00:")); 96 | srt = ("\n\n"+aKsrt.substring(aKsrt.indexOf("\n1\n00:")+1)) 97 | .replaceAll("\n\n[0-9]+\n", "\n\n").substring(2); 98 | } 99 | else if(aKsrt.indexOf("\n00:") >= 0) { 100 | text = aKsrt.substring(0, aKsrt.indexOf("\n00:")); 101 | srt = ("\n\n"+aKsrt.substring(aKsrt.indexOf("\n00:")+1)) 102 | .replaceAll("\n\n[0-9]+\n", "\n\n").substring(2); 103 | } 104 | else if(aKsrt.indexOf("\n") >= 0){ 105 | text = aKsrt.substring(0, aKsrt.indexOf("\n")); 106 | srt = ("\n\n"+aKsrt.substring(aKsrt.indexOf("\n")+1)) 107 | .replaceAll("\n\n[0-9]+\n", "\n\n").substring(2); 108 | } 109 | aBR.close(); 110 | 111 | if(_DEBUG) { 112 | System.out.println("LOADED\n" 113 | + "----------\n" 114 | + "TEXT="+text+"\n" 115 | + "----------\n" 116 | + "SRT="+srt+"\n" 117 | ); 118 | } 119 | 120 | resyncText2Srt(); 121 | srt2Text(); 122 | } catch (Exception e) { 123 | e.printStackTrace(System.err); 124 | } 125 | } 126 | 127 | public void save(String aPath) { 128 | try { 129 | BufferedWriter aBW = new BufferedWriter( 130 | new OutputStreamWriter(new FileOutputStream(aPath) 131 | ,"UTF8")); 132 | aBW.write(text+"\n"+srt); 133 | aBW.flush(); 134 | aBW.close(); 135 | } catch (Exception e) { 136 | } 137 | } 138 | 139 | public void resyncText2Srt() throws Exception { 140 | WhisperTimeSync aWTS = new WhisperTimeSync(); 141 | srt = srt.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\r*\n", "\n"); 142 | text = text.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\r*\n", "\n"); 143 | String aSync = aWTS.processString(srt, text, lng); 144 | aSync = aSync.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\r*\n", "\n"); 145 | boolean aEmptyFound=true; 146 | StringBuffer aSB = new StringBuffer(); 147 | chunkTexts = new Vector(); 148 | chunkStarts = new Vector(); 149 | chunkStops = new Vector(); 150 | for(String aL : aSync.split("\n")) { 151 | aL = aL.trim(); 152 | if(aL.isEmpty()) { 153 | aSB.append("\n"); 154 | aEmptyFound = true; 155 | continue; 156 | } 157 | if(aEmptyFound && aL.matches("[0-9]+")) { 158 | //Ignore 159 | continue; 160 | } 161 | if(aL.matches("[0-9][0-9]:[0-9][0-9]:[0-9][0-9][.,][0-9][0-9][0-9] --> [0-9][0-9]:[0-9][0-9]:[0-9][0-9][.,][0-9][0-9][0-9]")) { 162 | aSB.append(aL); 163 | aSB.append("\n"); 164 | chunkTexts.add(""); 165 | Integer aStartH = Integer.parseInt(aL.substring(0, 2)); 166 | Integer aStartM = Integer.parseInt(aL.substring(3, 5)); 167 | Integer aStartS = Integer.parseInt(aL.substring(6, 8)); 168 | Integer aStartMS = Integer.parseInt(aL.substring(9, 12)); 169 | chunkStarts.add((long)(aStartH*60*60*1000+aStartM*60*1000+aStartS*1000+aStartMS)); 170 | Integer aStopH = Integer.parseInt(aL.substring(17, 19)); 171 | Integer aStopM = Integer.parseInt(aL.substring(20, 22)); 172 | Integer aStopS = Integer.parseInt(aL.substring(23, 25)); 173 | Integer aStopMS = Integer.parseInt(aL.substring(26, 29)); 174 | chunkStops.add((long)(aStopH*60*60*1000+aStopM*60*1000+aStopS*1000+aStopMS)); 175 | continue; 176 | } 177 | if(chunkTexts.size() <= 0) { 178 | //No chunk?? 179 | aSB.append(aL); 180 | aSB.append("\n"); 181 | continue; 182 | } 183 | String aCurrent = chunkTexts.elementAt(chunkTexts.size()-1); 184 | if(aCurrent.length() > 0) { 185 | aSB.append("\n"); 186 | aCurrent += "\n"; 187 | } 188 | aSB.append(aL); 189 | aCurrent += aL; 190 | chunkTexts.setElementAt(aCurrent,chunkTexts.size()-1); 191 | } 192 | srt = aSB.toString().trim(); 193 | } 194 | 195 | public void srt2Text() { 196 | boolean aInText = false; 197 | StringBuffer aSB = new StringBuffer(); 198 | srt = srt.replaceAll("<", "<").replaceAll(">", ">").replaceAll("\r*\n", "\n"); 199 | if(_DEBUG) { 200 | System.out.println("srt2Text() srt="+srt); 201 | } 202 | for(String aL : srt.split("\n")) { 203 | aL = aL.trim(); 204 | if(_DEBUG) { 205 | System.out.println("srt2Text() aL="+aL); 206 | } 207 | if(aL.isEmpty()) { 208 | aInText = false; 209 | if(_DEBUG) { 210 | System.out.println("srt2Text() INTEXT OFF"); 211 | } 212 | } 213 | if(aL.matches("[0-9][0-9]:[0-9][0-9]:[0-9][0-9][.,][0-9][0-9][0-9] --> [0-9][0-9]:[0-9][0-9]:[0-9][0-9][.,][0-9][0-9][0-9]")) { 214 | aInText = true; 215 | if(_DEBUG) { 216 | System.out.println("srt2Text() INTEXT ON"); 217 | } 218 | continue; 219 | } 220 | if(aInText) { 221 | aSB.append(aL); 222 | aSB.append("\n"); 223 | if(_DEBUG) { 224 | System.out.println("srt2Text() ADDED TXT="+aL); 225 | } 226 | } 227 | } 228 | text = aSB.toString(); 229 | if(_DEBUG) { 230 | System.out.println("srt2Text() text="+text); 231 | } 232 | } 233 | 234 | public static void main(String[] args) { 235 | try { 236 | KaiSrt aSrt = new KaiSrt("/home/cubaix/Musique/MP3/Soiree3eme/Best of 2011/Katy Perry - Firework.mp3"); 237 | for(int l = 0;l < aSrt.chunkTexts.size();l++) { 238 | System.out.println(aSrt.chunkStarts.elementAt(l)+" --> "+aSrt.chunkStops.elementAt(l)+" "+aSrt.chunkTexts.elementAt(l)); 239 | } 240 | } catch (Exception e) { 241 | e.printStackTrace(System.err); 242 | } 243 | } 244 | 245 | } 246 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/KaiViewer.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kai; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.events.MouseEvent; 5 | import org.eclipse.swt.events.MouseListener; 6 | import org.eclipse.swt.events.PaintEvent; 7 | import org.eclipse.swt.events.PaintListener; 8 | import org.eclipse.swt.graphics.GC; 9 | import org.eclipse.swt.graphics.Rectangle; 10 | import org.eclipse.swt.layout.GridData; 11 | import org.eclipse.swt.layout.GridLayout; 12 | import org.eclipse.swt.widgets.Display; 13 | import org.eclipse.swt.widgets.Shell; 14 | 15 | import com.cubaix.kaiDJ.KaiDJ; 16 | 17 | public class KaiViewer { 18 | protected KaiEditor parentKE = null; 19 | 20 | public Shell shell = null; 21 | public GC mainGC = null; 22 | 23 | KaiScreener screener = null; 24 | 25 | public KaiViewer(KaiEditor aParentKE) { 26 | parentKE = aParentKE; 27 | start(); 28 | } 29 | 30 | void createInterface() { 31 | // final jDJ aThis = this; 32 | shell = new Shell(parentKE.parentKDJ.display, SWT.SHELL_TRIM); 33 | shell.setText("karaok-AI " + parentKE.parentKDJ._VERSION); 34 | shell.open(); 35 | mainGC = new GC(shell); 36 | shell.addPaintListener(new PaintListener() { 37 | public void paintControl(PaintEvent arg0) { 38 | paint(); 39 | } 40 | }); 41 | shell.setImage(parentKE.parentKDJ.kaiIcon); 42 | GridLayout gridLayout = new GridLayout(); 43 | gridLayout.numColumns = 1; 44 | gridLayout.marginWidth = 0; 45 | gridLayout.marginHeight = 0; 46 | gridLayout.horizontalSpacing = 0; 47 | gridLayout.verticalSpacing = 0; 48 | shell.setLayout(gridLayout); 49 | 50 | screener = new KaiScreener(this, shell, SWT.FILL); 51 | GridData aGD = new GridData(GridData.FILL_BOTH); 52 | screener.setLayoutData(aGD); 53 | screener.setBackground(parentKE.parentKDJ.playerC); 54 | screener.setForeground(parentKE.parentKDJ.blackC); 55 | screener.addMouseListener(new MouseListener() { 56 | @Override 57 | public void mouseUp(MouseEvent arg0) { 58 | shell.setFullScreen(!shell.getFullScreen()); 59 | } 60 | 61 | @Override 62 | public void mouseDown(MouseEvent arg0) { 63 | } 64 | 65 | @Override 66 | public void mouseDoubleClick(MouseEvent arg0) { 67 | } 68 | }); 69 | 70 | shell.pack(); 71 | // Size 72 | Rectangle aR = parentKE.parentKDJ.display.getBounds(); 73 | if(aR.width > 1920) { 74 | aR.width = 1920; 75 | } 76 | if(aR.height > 1080) { 77 | aR.height = 1080; 78 | } 79 | aR.width /=2; 80 | aR.height /=2; 81 | aR.x += aR.width; 82 | aR.y += aR.height; 83 | aR.width -= 20; 84 | if(aR.y+aR.height > parentKE.parentKDJ.display.getBounds().height - 40) { 85 | aR.y = parentKE.parentKDJ.display.getBounds().height-aR.height - 40; 86 | } 87 | if(KaiDJ._SIZE_FOR_SCREENSHOTS) { 88 | aR.width = KaiDJ._SIZE_FOR_SCREENSHOTS_W; 89 | aR.height = KaiDJ._SIZE_FOR_SCREENSHOTS_H; 90 | } 91 | shell.setBounds(aR); 92 | } 93 | 94 | void paint() { 95 | if(KaiDJ._DEBUG_PAINT) { 96 | System.out.println("VIEWER.paint()"); 97 | } 98 | synchronized (mainGC) { 99 | Rectangle aRect = shell.getBounds(); 100 | mainGC = new GC(shell); 101 | mainGC.setClipping(0, 0, aRect.width, aRect.height); 102 | mainGC.setBackground(parentKE.parentKDJ.mainBckC); 103 | mainGC.fillRectangle(0, 0, aRect.width, aRect.height); 104 | mainGC.dispose(); 105 | screener.needRedrawSlow(); 106 | } 107 | } 108 | 109 | void start() { 110 | try { 111 | // Create interface 112 | createInterface(); 113 | } 114 | catch (Throwable t) { 115 | t.printStackTrace(System.err); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/LogoPanel.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kai; 2 | 3 | import java.io.InputStream; 4 | import java.util.StringTokenizer; 5 | 6 | import org.eclipse.swt.events.PaintEvent; 7 | import org.eclipse.swt.events.PaintListener; 8 | import org.eclipse.swt.graphics.GC; 9 | import org.eclipse.swt.graphics.Image; 10 | import org.eclipse.swt.graphics.Rectangle; 11 | import org.eclipse.swt.widgets.Composite; 12 | 13 | import com.cubaix.kaiDJ.DJPlayer; 14 | import com.cubaix.kaiDJ.KaiDJ; 15 | import com.cubaix.kaiDJ.swt.TimedCanvas; 16 | 17 | public class LogoPanel extends TimedCanvas { 18 | private KaiEditor parentKE; 19 | Image panelBck = null; 20 | // Image panelTransBck = null; 21 | public String help = null; 22 | final int lineHeight = 15; 23 | 24 | Rectangle panelBounds = null; 25 | Image dblBuf = null; 26 | GC dblBufGC; 27 | 28 | public LogoPanel(KaiEditor aParentKE, Composite parent, int style) { 29 | super(aParentKE.parentKDJ, parent, style); 30 | parentKE = aParentKE; 31 | final LogoPanel aThis = this; 32 | addPaintListener(new PaintListener() { 33 | public void paintControl(PaintEvent aPE) { 34 | panelBounds = getClientArea(); 35 | GC aPlGC = new GC(aThis); 36 | paintDbl(aPlGC); 37 | aPlGC.dispose(); 38 | needRedraw(); 39 | } 40 | }); 41 | } 42 | 43 | void loadImg() { 44 | if (parentKDJ == null || parentKDJ.display == null || parentKDJ.display.isDisposed()) { 45 | return; 46 | } 47 | InputStream aIS = getClass().getResourceAsStream("img/LogoSmall.png"); 48 | panelBck = new Image(parentKDJ.display, aIS); 49 | 50 | // panelTransBck = new Image(parentJDJ.display, aIS); 51 | // byte[] aAlpha = panelTransBck.getImageData().alphaData; 52 | // if(aAlpha != null){ 53 | // for(int i = 0;i < aAlpha.length;i++){ 54 | // aAlpha[i] = 127; 55 | // } 56 | // } 57 | } 58 | 59 | protected void paintTimed() { 60 | if(KaiDJ._DEBUG_PAINT) { 61 | System.out.println("LOGOPANEL.paintTimed()"); 62 | } 63 | if (panelBck == null) { 64 | loadImg(); 65 | } 66 | if(panelBck == null || panelBounds == null){ 67 | return; 68 | } 69 | try { 70 | Rectangle aRectDbl = null; 71 | if (dblBuf != null) { 72 | aRectDbl = dblBuf.getBounds(); 73 | } 74 | if (dblBuf == null || panelBounds.width != aRectDbl.width || panelBounds.height != aRectDbl.height) { 75 | if (dblBuf != null) { 76 | dblBuf.dispose(); 77 | dblBuf = null; 78 | dblBufGC.dispose(); 79 | } 80 | dblBuf = new Image(parentKDJ.display, panelBounds); 81 | dblBufGC = new GC(dblBuf); 82 | } 83 | 84 | Rectangle aImgR = panelBck.getBounds(); 85 | dblBufGC.setClipping(panelBounds.x, panelBounds.y, panelBounds.width, panelBounds.height); 86 | dblBufGC.setForeground(parentKDJ.blackC); 87 | dblBufGC.setBackground(parentKDJ.mainBckC); 88 | dblBufGC.fillRectangle(panelBounds); 89 | if (help == null) { 90 | dblBufGC.drawImage(panelBck, panelBounds.x /* + (panelBounds.width - aImgR.width) / 2 */, panelBounds.y); 91 | } else { 92 | // dblBufGC.drawImage(panelTransBck, panelBounds.x + (panelBounds.width - aImgR.width) / 2, panelBounds.y); 93 | dblBufGC.drawImage(panelBck, panelBounds.x, panelBounds.y); 94 | StringTokenizer aTok = new StringTokenizer(help, "\n"); 95 | int aPosY = 0; 96 | dblBufGC.setFont(parentKDJ.initialFont); 97 | dblBufGC.setForeground(parentKDJ.playerC); 98 | // dblBufGC.drawText("** HELP **", aImgR.width, aPosY, true); 99 | aPosY += lineHeight; 100 | while (aTok.hasMoreTokens()) { 101 | String aStr = aTok.nextToken(); 102 | dblBufGC.drawText(aStr, panelBounds.x + aImgR.width, panelBounds.y + aPosY, true); 103 | aPosY += lineHeight; 104 | } 105 | } 106 | 107 | dblBufGC.setForeground(parentKDJ.playerC); 108 | if(parentKE.song != null && parentKE.song.kaiSrt != null) { 109 | dblBufGC.setFont(parentKDJ.kaiFont); 110 | dblBufGC.setForeground(parentKDJ.playerC); 111 | int aPadding = 5; 112 | 113 | int aKaiIdx = parentKE.song.kaiSrt.getChunkIdx(parentKE.playerVocals.getPositionMs()); 114 | String aKaiText = (aKaiIdx < 0) ? "" : ((aKaiIdx >= parentKE.song.kaiSrt.chunkTexts.size()) ? "" :parentKE.song.kaiSrt.chunkTexts.elementAt(aKaiIdx)); 115 | aKaiText = aKaiText.replaceAll("\n", " ").trim(); 116 | 117 | for(int i = aKaiIdx+1;i < parentKE.song.kaiSrt.chunkTexts.size();i++) { 118 | String aKaiTextNext = parentKE.song.kaiSrt.chunkTexts.elementAt(i); 119 | aKaiText += (aKaiText.length() > 0 ? " — ":"")+aKaiTextNext.replaceAll("\n", " ").trim(); 120 | } 121 | 122 | dblBufGC.drawText(aKaiText,panelBounds.x + aPadding, panelBounds.y + panelBounds.height - aPadding - 18, true); 123 | } 124 | if(parentKDJ.player1.kaiSrt != null || parentKDJ.player2.kaiSrt != null) { 125 | needRedrawSlow(); 126 | } 127 | 128 | // Draw final image 129 | GC aPlGC = new GC(this); 130 | paintDbl(aPlGC); 131 | aPlGC.dispose(); 132 | } 133 | catch (Throwable t) { 134 | System.err.println("Can't paint logo : " + t); 135 | t.printStackTrace(System.err); 136 | } 137 | } 138 | 139 | void paintDbl(GC aPlGC) { 140 | if(dblBuf == null) { 141 | return; 142 | } 143 | aPlGC.drawImage(dblBuf, 0, 0); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/img/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kai/img/Logo.png -------------------------------------------------------------------------------- /src/com/cubaix/kai/img/LogoSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kai/img/LogoSmall.png -------------------------------------------------------------------------------- /src/com/cubaix/kai/img/LogoSquare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kai/img/LogoSquare.png -------------------------------------------------------------------------------- /src/com/cubaix/kai/img/LogoSquareL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kai/img/LogoSquareL.png -------------------------------------------------------------------------------- /src/com/cubaix/kai/img/kAI.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 41 | 46 | 53 | kAI 67 | 68 | 88 | 89 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/img2/arrows-fullscreen.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | 39 | 44 | 45 | -------------------------------------------------------------------------------- /src/com/cubaix/kai/img2/fullscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kai/img2/fullscreen.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/CategoryManager.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ; 2 | 3 | import java.util.Vector; 4 | 5 | import org.eclipse.swt.SWT; 6 | import org.eclipse.swt.events.KeyEvent; 7 | import org.eclipse.swt.events.KeyListener; 8 | import org.eclipse.swt.events.MouseEvent; 9 | import org.eclipse.swt.events.MouseListener; 10 | import org.eclipse.swt.events.SelectionEvent; 11 | import org.eclipse.swt.events.SelectionListener; 12 | import org.eclipse.swt.layout.GridData; 13 | import org.eclipse.swt.layout.GridLayout; 14 | import org.eclipse.swt.widgets.Combo; 15 | import org.eclipse.swt.widgets.Composite; 16 | import org.eclipse.swt.widgets.Label; 17 | 18 | import com.cubaix.kaiDJ.db.SongDescr; 19 | import com.cubaix.kaiDJ.swt.PlayListListener; 20 | 21 | public class CategoryManager extends Composite { 22 | KaiDJ parentJDJ; 23 | PlayList pl; 24 | PlayListListener playListListener; 25 | Combo categoriesC; 26 | // Text categoryT; 27 | String currentCategory = ""; 28 | public CategoryManager(KaiDJ aParentJDJ,Composite parent, int style) { 29 | super(parent, style); 30 | parentJDJ = aParentJDJ; 31 | 32 | String os = System.getProperty("os.name"); 33 | 34 | //Main panel 35 | GridLayout aGL = new GridLayout(); 36 | aGL.horizontalSpacing = 0; 37 | aGL.verticalSpacing = 0; 38 | aGL.marginHeight = 0; 39 | aGL.marginWidth = 0; 40 | aGL.numColumns = 1; 41 | this.setLayout(aGL); 42 | GridData aGD = new GridData(GridData.FILL_BOTH); 43 | this.setLayoutData(aGD); 44 | 45 | //Buttons 46 | Composite aButPanel = new Composite(this,SWT.NULL); 47 | aGL = new GridLayout(); 48 | aGL.horizontalSpacing = 0; 49 | aGL.verticalSpacing = 0; 50 | aGL.marginHeight = 0; 51 | aGL.marginWidth = 0; 52 | aGL.numColumns = 2; 53 | aButPanel.setLayout(aGL); 54 | aGD = new GridData(GridData.FILL_HORIZONTAL); 55 | aButPanel.setLayoutData(aGD); 56 | 57 | Label aLabel = new Label(aButPanel,SWT.NULL); 58 | aLabel.setText("Category name: "); 59 | if(!os.toLowerCase().startsWith("mac")){ 60 | //Mac seems to not support properly background colors here 61 | aLabel.setBackground(parentJDJ.mainBckC); 62 | aLabel.setForeground(parentJDJ.playerC); 63 | } 64 | aGD = new GridData(GridData.FILL_VERTICAL); 65 | aLabel.setLayoutData(aGD); 66 | 67 | categoriesC = new Combo(aButPanel,SWT.NULL); 68 | categoriesC.setToolTipText("Select/Enter a category"); 69 | if(!os.toLowerCase().startsWith("mac")){ 70 | //Mac seems to not support properly background colors here 71 | categoriesC.setBackground(parentJDJ.mainBckC); 72 | categoriesC.setForeground(parentJDJ.whiteC); 73 | } 74 | aGD = new GridData(GridData.FILL_BOTH); 75 | categoriesC.setLayoutData(aGD); 76 | categoriesC.addSelectionListener(new SelectionListener(){ 77 | public void widgetDefaultSelected(SelectionEvent arg0) { 78 | } 79 | public void widgetSelected(SelectionEvent evt) { 80 | currentCategory = categoriesC.getItem(categoriesC.getSelectionIndex()); 81 | doCategory(); 82 | } 83 | 84 | }); 85 | categoriesC.addKeyListener(new KeyListener() { 86 | public void keyPressed(KeyEvent arg0) {} 87 | public void keyReleased(KeyEvent arg0) { 88 | int aCharCode = arg0.character & 0xFF; 89 | if (aCharCode > 32 || arg0.keyCode == 8 || (arg0.keyCode >= 32 && arg0.keyCode < 65535)) { 90 | currentCategory = categoriesC.getText(); 91 | doCategory(); 92 | } 93 | } 94 | }); 95 | 96 | // categoryT = new Text(aButPanel, SWT.BORDER); 97 | // categoryT.setToolTipText("Enter a category"); 98 | // if(!os.toLowerCase().startsWith("mac")){ 99 | // //Mac seems to not support properly background colors here 100 | // categoryT.setBackground(parentJDJ.mainBckC); 101 | // categoryT.setForeground(parentJDJ.whiteC); 102 | // } 103 | // aGD = new GridData(GridData.FILL_BOTH); 104 | // categoryT.setLayoutData(aGD); 105 | // categoryT.addKeyListener(new KeyListener() { 106 | // public void keyPressed(KeyEvent arg0) {} 107 | // public void keyReleased(KeyEvent arg0) { 108 | // int aCharCode = arg0.character & 0xFF; 109 | // if (aCharCode > 32 || arg0.keyCode == 8 || (arg0.keyCode >= 32 && arg0.keyCode < 65535)) { 110 | // currentCategory = categoryT.getText(); 111 | // pl.getPl().clear(); 112 | // parentJDJ.db.getCat(pl.getPl(),currentCategory); 113 | // pl.needRedraw(); 114 | // } 115 | // } 116 | // }); 117 | 118 | //PL 119 | pl = new PlayList(aParentJDJ, this, SWT.NONE); 120 | pl.listTC.setToolTip("Edit category: \n"// 121 | + "- Click to load a song on the pre-listen player\n"// 122 | + "- Double-click to add a song at the end of the playlist\n"// 123 | + "- Ctrl+Click to add a song after the current selection or the current playing song\n"// 124 | + "- Suppr key to remove a song"); 125 | aGD = new GridData(GridData.FILL_BOTH); 126 | pl.setLayoutData(aGD); 127 | pl.addMouseListener(new MouseListener() { 128 | public void mouseDoubleClick(MouseEvent aEvt) { 129 | if (pl.isClickInTopBar(aEvt.x, aEvt.y)) { 130 | // Nothing to do 131 | } else { 132 | //Add song to playlist 133 | SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 134 | if (aDescr != null) { 135 | parentJDJ.managerPlay.addSong(aDescr); 136 | } 137 | } 138 | } 139 | 140 | public void mouseDown(MouseEvent aEvt) { 141 | if(aEvt.stateMask == SWT.CTRL){ 142 | //Add after 143 | if (pl.isClickInTopBar(aEvt.x, aEvt.y)) { 144 | // Nothing to do 145 | } else { 146 | SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 147 | if (aDescr != null) { 148 | //Add song to playlist 149 | parentJDJ.managerPlay.addSongAfter(aDescr); 150 | } 151 | } 152 | } 153 | } 154 | 155 | public void mouseUp(MouseEvent arg0) { 156 | } 157 | }); 158 | pl.addPlayListListener(playListListener = new PlayListListener(){ 159 | public void removed(SongDescr aDescr) { 160 | parentJDJ.db.delInCat(aDescr,currentCategory); 161 | updateCategoriesList(); 162 | } 163 | public void added(SongDescr aDescr) { 164 | parentJDJ.db.insertCat(aDescr,currentCategory); 165 | parentJDJ.db.commit(); 166 | updateCategoriesList(); 167 | } 168 | }); 169 | 170 | //Init values 171 | updateCategoriesList(); 172 | } 173 | 174 | 175 | 176 | /* (non-Javadoc) 177 | * @see org.eclipse.swt.widgets.Widget#dispose() 178 | */ 179 | public void dispose() { 180 | pl.removePlayListListener(playListListener); 181 | super.dispose(); 182 | } 183 | 184 | /** 185 | * @param aDefaultCat 186 | */ 187 | public void checkCategory(String aDefaultCat){ 188 | if(currentCategory == null || currentCategory.length() <= 0){ 189 | currentCategory = aDefaultCat; 190 | parentJDJ.display.syncExec(new Runnable(){ 191 | public void run() { 192 | categoriesC.setText(currentCategory); 193 | } 194 | 195 | }); 196 | } 197 | } 198 | 199 | /** 200 | * @param aDescr 201 | */ 202 | public void addSong(SongDescr aDescr){ 203 | checkCategory("Misc"); 204 | parentJDJ.db.insertCat(aDescr,currentCategory); 205 | parentJDJ.db.commit(); 206 | pl.getPl().add(aDescr); 207 | pl.listTC.needRedraw(); 208 | updateCategoriesList(); 209 | } 210 | 211 | /** 212 | * @param aPath 213 | * @param aClear 214 | */ 215 | public void load(String aPath, boolean aClear) { 216 | pl.load(aPath, aClear, 0); 217 | } 218 | 219 | /** 220 | * 221 | */ 222 | void updateCategoriesList(){ 223 | final Vector aRes = parentJDJ.db.getAllCat(); 224 | parentJDJ.display.syncExec(new Runnable(){ 225 | public void run() { 226 | categoriesC.removeAll(); 227 | for(int c = 0;c < aRes.size();c++){ 228 | categoriesC.add((String)aRes.elementAt(c)); 229 | } 230 | categoriesC.setText(currentCategory); 231 | } 232 | }); 233 | } 234 | 235 | /** 236 | * 237 | */ 238 | void doCategory(){ 239 | // Start main refresh thread 240 | Thread aThread = new Thread(new Runnable(){ 241 | public void run() { 242 | pl.getPl().clear(); 243 | parentJDJ.db.getCat(pl.getPl(),currentCategory); 244 | pl.listTC.needRedraw(); 245 | } 246 | }, "Category request"); 247 | aThread.setPriority(Thread.MIN_PRIORITY); 248 | aThread.start(); 249 | } 250 | 251 | } 252 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/LogoPanel.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ; 2 | 3 | import java.io.InputStream; 4 | import java.util.StringTokenizer; 5 | 6 | import org.eclipse.swt.events.PaintEvent; 7 | import org.eclipse.swt.events.PaintListener; 8 | import org.eclipse.swt.graphics.GC; 9 | import org.eclipse.swt.graphics.Image; 10 | import org.eclipse.swt.graphics.Rectangle; 11 | import org.eclipse.swt.widgets.Composite; 12 | 13 | import com.cubaix.kai.KaiSrt; 14 | import com.cubaix.kaiDJ.swt.TimedCanvas; 15 | 16 | public class LogoPanel extends TimedCanvas { 17 | private KaiDJ parentKDJ; 18 | Image panelBck = null; 19 | // Image panelTransBck = null; 20 | public String help = null; 21 | final int lineHeight = 15; 22 | 23 | Rectangle panelBounds = null; 24 | Image dblBuf = null; 25 | GC dblBufGC; 26 | 27 | static final int _SOUNDPROFILESIZE = 128; 28 | float[] soundProfile1 = new float[_SOUNDPROFILESIZE]; 29 | float[] soundProfile2 = new float[_SOUNDPROFILESIZE]; 30 | int soundProfilePos = 0; 31 | 32 | public LogoPanel(KaiDJ aParentKDJ, Composite parent, int style) { 33 | super(aParentKDJ, parent, style); 34 | parentKDJ = aParentKDJ; 35 | final LogoPanel aThis = this; 36 | addPaintListener(new PaintListener() { 37 | public void paintControl(PaintEvent aPE) { 38 | panelBounds = getClientArea(); 39 | GC aPlGC = new GC(aThis); 40 | paintDbl(aPlGC); 41 | aPlGC.dispose(); 42 | needRedraw(); 43 | } 44 | }); 45 | 46 | //EM 15/11/2008 47 | createSoundProfileThread(); 48 | } 49 | 50 | void loadImg() { 51 | if (parentKDJ == null || parentKDJ.display == null || parentKDJ.display.isDisposed()) { 52 | return; 53 | } 54 | InputStream aIS = getClass().getResourceAsStream("img/LogoSmall.png"); 55 | panelBck = new Image(parentKDJ.display, aIS); 56 | 57 | // panelTransBck = new Image(parentJDJ.display, aIS); 58 | // byte[] aAlpha = panelTransBck.getImageData().alphaData; 59 | // if(aAlpha != null){ 60 | // for(int i = 0;i < aAlpha.length;i++){ 61 | // aAlpha[i] = 127; 62 | // } 63 | // } 64 | } 65 | 66 | protected void paintTimed() { 67 | if(KaiDJ._DEBUG_PAINT) { 68 | System.out.println("LOGOPANEL.paintTimed()"); 69 | } 70 | if (panelBck == null) { 71 | loadImg(); 72 | } 73 | if(panelBck == null || panelBounds == null){ 74 | return; 75 | } 76 | try { 77 | Rectangle aRectDbl = null; 78 | if (dblBuf != null) { 79 | aRectDbl = dblBuf.getBounds(); 80 | } 81 | if (dblBuf == null || panelBounds.width != aRectDbl.width || panelBounds.height != aRectDbl.height) { 82 | if (dblBuf != null) { 83 | dblBuf.dispose(); 84 | dblBuf = null; 85 | dblBufGC.dispose(); 86 | } 87 | dblBuf = new Image(parentKDJ.display, panelBounds); 88 | dblBufGC = new GC(dblBuf); 89 | } 90 | 91 | Rectangle aImgR = panelBck.getBounds(); 92 | dblBufGC.setClipping(panelBounds.x, panelBounds.y, panelBounds.width, panelBounds.height); 93 | dblBufGC.setForeground(parentKDJ.blackC); 94 | dblBufGC.setBackground(parentKDJ.mainBckC); 95 | dblBufGC.fillRectangle(panelBounds); 96 | if (help == null) { 97 | dblBufGC.drawImage(panelBck, panelBounds.x /* + (panelBounds.width - aImgR.width) / 2 */, panelBounds.y); 98 | } else { 99 | // dblBufGC.drawImage(panelTransBck, panelBounds.x + (panelBounds.width - aImgR.width) / 2, panelBounds.y); 100 | dblBufGC.drawImage(panelBck, panelBounds.x, panelBounds.y); 101 | StringTokenizer aTok = new StringTokenizer(help, "\n"); 102 | int aPosY = 0; 103 | dblBufGC.setFont(parentKDJ.initialFont); 104 | dblBufGC.setForeground(parentKDJ.playerC); 105 | // dblBufGC.drawText("** HELP **", aImgR.width, aPosY, true); 106 | aPosY += lineHeight; 107 | while (aTok.hasMoreTokens()) { 108 | String aStr = aTok.nextToken(); 109 | dblBufGC.drawText(aStr, panelBounds.x + aImgR.width, panelBounds.y + aPosY, true); 110 | aPosY += lineHeight; 111 | } 112 | } 113 | 114 | dblBufGC.setForeground(parentKDJ.playerC); 115 | DJPlayer aPlayerSrt = null; 116 | if(parentKDJ.player1.currentGain > parentKDJ.player2.currentGain) { 117 | aPlayerSrt = parentKDJ.player1; 118 | } 119 | else { 120 | aPlayerSrt = parentKDJ.player2; 121 | } 122 | if(aPlayerSrt.kaiSrt != null) { 123 | dblBufGC.setFont(parentKDJ.kaiFont); 124 | dblBufGC.setForeground(parentKDJ.playerC); 125 | int aPadding = 5; 126 | 127 | int aKaiIdx = aPlayerSrt.kaiSrt.getChunkIdx(aPlayerSrt.getPositionMs()); 128 | String aKaiText = (aKaiIdx < 0) ? "" : aPlayerSrt.kaiSrt.chunkTexts.elementAt(aKaiIdx); 129 | aKaiText = aKaiText.replaceAll("\n", " ").trim(); 130 | 131 | for(int i = aKaiIdx+1;i < aPlayerSrt.kaiSrt.chunkTexts.size();i++) { 132 | String aKaiTextNext = aPlayerSrt.kaiSrt.chunkTexts.elementAt(i); 133 | aKaiText += (aKaiText.length() > 0 ? " — ":"")+aKaiTextNext.replaceAll("\n", " ").trim(); 134 | } 135 | 136 | dblBufGC.drawText(aKaiText,panelBounds.x + aPadding, panelBounds.y + panelBounds.height - aPadding - 18, true); 137 | } 138 | if(parentKDJ.player1.kaiSrt != null || parentKDJ.player2.kaiSrt != null) { 139 | needRedrawSlow(); 140 | } 141 | 142 | // Draw final image 143 | GC aPlGC = new GC(this); 144 | paintDbl(aPlGC); 145 | aPlGC.dispose(); 146 | } 147 | catch (Throwable t) { 148 | System.err.println("Can't paint logo : " + t); 149 | t.printStackTrace(System.err); 150 | } 151 | } 152 | 153 | void paintDbl(GC aPlGC) { 154 | if(dblBuf == null) { 155 | return; 156 | } 157 | aPlGC.drawImage(dblBuf, 0, 0); 158 | } 159 | 160 | //EM 15/11/2008 161 | void createSoundProfileThread(){ 162 | Thread aTh = new Thread(new Runnable(){ 163 | public void run() { 164 | while(true){ 165 | try{ 166 | Thread.sleep(40); 167 | //Read values 168 | soundProfile1[soundProfilePos] = (float)parentKDJ.player1.currentGain * (parentKDJ.player1.vuMeterRight + parentKDJ.player1.vuMeterLeft) / 2; 169 | soundProfile2[soundProfilePos] = (float)parentKDJ.player2.currentGain * (parentKDJ.player2.vuMeterRight + parentKDJ.player2.vuMeterLeft) / 2; 170 | soundProfilePos++; 171 | soundProfile1[soundProfilePos] = (float)parentKDJ.player1.currentGain * (parentKDJ.player1.vuMeterRightB + parentKDJ.player1.vuMeterLeftB) / 2; 172 | soundProfile2[soundProfilePos] = (float)parentKDJ.player2.currentGain * (parentKDJ.player2.vuMeterRightB + parentKDJ.player2.vuMeterLeftB) / 2; 173 | soundProfilePos++; 174 | soundProfilePos = soundProfilePos % _SOUNDPROFILESIZE; 175 | 176 | //EM 28/04/2009 : only if activated 177 | if(parentKDJ.showSoundProfile){ 178 | parentKDJ.display.asyncExec(new Runnable() { 179 | public void run() { 180 | try { 181 | paintSoundProfile(); 182 | } catch (Throwable t) { 183 | } 184 | } 185 | }); 186 | } 187 | 188 | } 189 | catch(Throwable t){ 190 | //?? 191 | } 192 | } 193 | } 194 | }); 195 | aTh.start(); 196 | } 197 | 198 | static final int _SOUNDPROFILEHEIGHT = 20; 199 | void paintSoundProfile(){ 200 | if(KaiDJ._DEBUG_PAINT) { 201 | System.out.println("LOGOPANEL.paintSoundProfile()"); 202 | } 203 | if(panelBck == null || panelBounds == null){ 204 | return; 205 | } 206 | try { 207 | GC panelGC = new GC(this); 208 | Rectangle aImgR = panelBck.getBounds(); 209 | //panelGC.setClipping(panelBounds.x, panelBounds.y, panelBounds.width, panelBounds.height); 210 | 211 | for(int i = 0; i < _SOUNDPROFILESIZE;){ 212 | panelGC.setForeground(parentKDJ.mainBckC); 213 | panelGC.drawLine(panelBounds.x + i, panelBounds.y + aImgR.height + 28, panelBounds.x + i, panelBounds.y + aImgR.height + 10 - _SOUNDPROFILEHEIGHT); 214 | panelGC.drawLine(panelBounds.x + i + 1, panelBounds.y + aImgR.height + 28, panelBounds.x + i + 1, panelBounds.y + aImgR.height + 10 - _SOUNDPROFILEHEIGHT); 215 | panelGC.setForeground(parentKDJ.redC); 216 | panelGC.drawLine(panelBounds.x + i, panelBounds.y + aImgR.height + 10, panelBounds.x + i, panelBounds.y + aImgR.height + 10 - (int)(_SOUNDPROFILEHEIGHT*soundProfile1[(soundProfilePos + i)%_SOUNDPROFILESIZE])); 217 | //EM 28/04/2009 : bottom to top 218 | panelGC.drawLine(panelBounds.x + i, panelBounds.y + aImgR.height + 28, panelBounds.x + i, panelBounds.y + aImgR.height + 28 - (int)(_SOUNDPROFILEHEIGHT*soundProfile2[(soundProfilePos + i)%_SOUNDPROFILESIZE])); 219 | i++; 220 | panelGC.setForeground(parentKDJ.yellowC); 221 | panelGC.drawLine(panelBounds.x + i, panelBounds.y + aImgR.height + 10, panelBounds.x + i, panelBounds.y + aImgR.height + 10 - (int)(_SOUNDPROFILEHEIGHT*soundProfile1[(soundProfilePos + i)%_SOUNDPROFILESIZE])); 222 | //EM 28/04/2009 : bottom to top 223 | panelGC.drawLine(panelBounds.x + i, panelBounds.y + aImgR.height + 28, panelBounds.x + i, panelBounds.y + aImgR.height + 28 - (int)(_SOUNDPROFILEHEIGHT*soundProfile2[(soundProfilePos + i)%_SOUNDPROFILESIZE])); 224 | i++; 225 | } 226 | panelGC.dispose(); 227 | } catch (Throwable t) { 228 | System.err.println("Can't paint logo : " + t); 229 | t.printStackTrace(System.err); 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/PlayManager.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.events.KeyEvent; 5 | import org.eclipse.swt.events.KeyListener; 6 | import org.eclipse.swt.events.MouseEvent; 7 | import org.eclipse.swt.events.MouseListener; 8 | import org.eclipse.swt.events.SelectionEvent; 9 | import org.eclipse.swt.events.SelectionListener; 10 | import org.eclipse.swt.layout.GridData; 11 | import org.eclipse.swt.layout.GridLayout; 12 | import org.eclipse.swt.widgets.Composite; 13 | import org.eclipse.swt.widgets.Text; 14 | 15 | import com.cubaix.kaiDJ.db.SongDescr; 16 | import com.cubaix.kaiDJ.swt.KaiButton; 17 | 18 | public class PlayManager extends Composite { 19 | KaiDJ parentJDJ; 20 | KaiButton addFolderB; 21 | Text folderText; 22 | PlayList pl; 23 | public PlayManager(KaiDJ aParentJDJ,Composite parent, int style) { 24 | super(parent, style); 25 | parentJDJ = aParentJDJ; 26 | 27 | //Main panel 28 | GridLayout aGL = new GridLayout(); 29 | aGL.horizontalSpacing = 0; 30 | //aGL.verticalSpacing = 4; 31 | aGL.marginHeight = 0; 32 | aGL.marginWidth = 0; 33 | aGL.numColumns = 1; 34 | this.setLayout(aGL); 35 | GridData aGD = new GridData(GridData.FILL_BOTH); 36 | this.setLayoutData(aGD); 37 | setBackground(parentJDJ.mainBckC); 38 | 39 | //Buttons 40 | Composite aButPanel = new Composite(this,SWT.NULL); 41 | aButPanel.setBackground(parentJDJ.mainBckC); 42 | aGL = new GridLayout(); 43 | //aGL.horizontalSpacing = 4; 44 | aGL.verticalSpacing = 0; 45 | aGL.marginHeight = 0; 46 | aGL.marginWidth = 0; 47 | aGL.numColumns = 2; 48 | aButPanel.setLayout(aGL); 49 | aGD = new GridData(GridData.FILL_HORIZONTAL); 50 | aButPanel.setLayoutData(aGD); 51 | 52 | addFolderB = new KaiButton(parentJDJ,aButPanel, SWT.NULL); 53 | addFolderB.setBackground(parentJDJ.mainBckC); 54 | addFolderB.setToolTipText("Add named group"); 55 | addFolderB.setImagePath("img2/addGroupBut.png"); 56 | aGD = new GridData();// GridData.FILL_HORIZONTAL); 57 | aGD.heightHint = KaiButton._HEIGHT; 58 | aGD.widthHint = KaiButton._WIDTH; 59 | addFolderB.setLayoutData(aGD); 60 | addFolderB.addSelectionListener(new SelectionListener() { 61 | public void widgetDefaultSelected(SelectionEvent arg0) { 62 | } 63 | 64 | public void widgetSelected(SelectionEvent arg0) { 65 | pl.addGroup(folderText.getText()); 66 | } 67 | }); 68 | // Group name Text 69 | String os = System.getProperty("os.name"); 70 | folderText = new Text(aButPanel, SWT.BORDER); 71 | folderText.setToolTipText("Edit group name"); 72 | if(!os.toLowerCase().startsWith("mac")){ 73 | //Mac seems to not support properly background colors here 74 | folderText.setBackground(parentJDJ.mainBckC); 75 | folderText.setForeground(parentJDJ.whiteC); 76 | } 77 | aGD = new GridData(GridData.FILL_BOTH); 78 | // aGD.heightHint = 20; 79 | folderText.setLayoutData(aGD); 80 | folderText.addKeyListener(new KeyListener() { 81 | public void keyPressed(KeyEvent arg0) { 82 | } 83 | 84 | public void keyReleased(KeyEvent arg0) { 85 | int aCharCode = arg0.character & 0xFF; 86 | if (aCharCode > 32 || arg0.keyCode == 8 || (arg0.keyCode >= 32 && arg0.keyCode < 65535)) { 87 | pl.setGroupLabel(folderText.getText()); 88 | } 89 | } 90 | }); 91 | 92 | //PL 93 | pl = new PlayList(aParentJDJ, this, SWT.NONE); 94 | pl.listTC.setToolTip("Edit playlist: \n"// 95 | + "- Click to load a song on the pre-listen player\n"// 96 | + "- Double-click to play and mix a song\n"// 97 | + "- Click&Drag to move a song or a group, or resize a group\n"// 98 | + "- Ctrl+Click to move a song or a group after the current selection or the current playing song\n"// 99 | + "- Suppr key to remove a song or a group"); 100 | aGD = new GridData(GridData.FILL_BOTH); 101 | pl.setLayoutData(aGD); 102 | 103 | //Listeners 104 | pl.listTC.addMouseListener(new MouseListener() { 105 | public void mouseDoubleClick(MouseEvent aEvt) { 106 | if (pl.isClickInTopBar(aEvt.x, aEvt.y)) { 107 | // Nothing to do 108 | } else { 109 | final SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 110 | //No need to use SWT thread from here. Thread should end fastly, but player load may block (?) 111 | Thread aTh = new Thread(new Runnable(){ 112 | public void run() { 113 | SongDescr aNewDescr; 114 | if (aDescr == null || (aNewDescr = pl.getFirstPlayable(aDescr.getPlID())) == null) { 115 | // Nothing detected, try to get something new 116 | parentJDJ.timeToNext(null); 117 | return; 118 | } 119 | pl.select(aNewDescr); 120 | if (parentJDJ.player1.playState <= 0 && parentJDJ.player2.playState <= 0) { 121 | // First play 122 | pl.setSelectedPlaying(); 123 | parentJDJ.player1.currentGain = 0.8; 124 | parentJDJ.player1.load(aNewDescr.path); 125 | parentJDJ.player1.play(); 126 | parentJDJ.player2.currentGain = 0; 127 | parentJDJ.player2.fadeOut(); 128 | } else if (parentJDJ.player1.playState <= 0 || parentJDJ.player1.playState == 2) { 129 | // Cross fade 130 | pl.setSelectedPlaying(); 131 | parentJDJ.player1.load(aNewDescr.path); 132 | parentJDJ.player1.play(); 133 | parentJDJ.player1.fadeIn(); 134 | parentJDJ.player2.fadeOut(); 135 | } else if (parentJDJ.player2.playState <= 0 || parentJDJ.player2.playState == 2) { 136 | // Cross fade 137 | pl.setSelectedPlaying(); 138 | parentJDJ.player2.load(aNewDescr.path); 139 | parentJDJ.player2.play(); 140 | parentJDJ.player2.fadeIn(); 141 | parentJDJ.player1.fadeOut(); 142 | } 143 | } 144 | },"TMP (MANAGER PLAYER DBL-CLICK)"); 145 | aTh.start(); 146 | } 147 | } 148 | 149 | public void mouseDown(MouseEvent aEvt) { 150 | if(aEvt.stateMask == SWT.CTRL){ 151 | //Add after 152 | if (pl.isClickInTopBar(aEvt.x, aEvt.y)) { 153 | // Nothing to do 154 | } else { 155 | Integer aSelPlId = pl.getLastSelectedPlId(); 156 | SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 157 | if (aDescr != null) { 158 | pl.clickedPlId = aDescr.getPlID(); 159 | //Move song/group to playlist 160 | SongDescr aLastDescr = pl.moveAt(pl.getIndex(aSelPlId) + 1); 161 | if(aLastDescr != null){ 162 | pl.select(aLastDescr); 163 | } 164 | } 165 | } 166 | } 167 | } 168 | 169 | public void mouseUp(MouseEvent arg0) { 170 | } 171 | }); 172 | } 173 | 174 | /** 175 | * @param aDescr 176 | */ 177 | public void addSong(SongDescr aDescr){ 178 | pl.addSong(aDescr); 179 | } 180 | 181 | /** 182 | * @param aDescr 183 | */ 184 | public void addSongAfter(SongDescr aDescr){ 185 | pl.addSongAfter(aDescr); 186 | } 187 | 188 | 189 | /** 190 | * @param aPath 191 | * @param aClear 192 | */ 193 | public void load(String aPath, boolean aClear) { 194 | pl.load(aPath, aClear, 1); 195 | } 196 | 197 | } 198 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/SearchManager.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ; 2 | 3 | import java.util.TreeSet; 4 | import java.util.Vector; 5 | 6 | import org.eclipse.swt.SWT; 7 | import org.eclipse.swt.events.KeyEvent; 8 | import org.eclipse.swt.events.KeyListener; 9 | import org.eclipse.swt.events.ModifyEvent; 10 | import org.eclipse.swt.events.ModifyListener; 11 | import org.eclipse.swt.events.MouseEvent; 12 | import org.eclipse.swt.events.MouseListener; 13 | import org.eclipse.swt.events.SelectionEvent; 14 | import org.eclipse.swt.events.SelectionListener; 15 | import org.eclipse.swt.layout.GridData; 16 | import org.eclipse.swt.layout.GridLayout; 17 | import org.eclipse.swt.widgets.Composite; 18 | import org.eclipse.swt.widgets.Text; 19 | 20 | import com.cubaix.kaiDJ.db.SongDescr; 21 | import com.cubaix.kaiDJ.swt.KaiButton; 22 | 23 | public class SearchManager extends Composite { 24 | KaiDJ parentKDJ; 25 | KaiButton shuffleAllB; 26 | boolean randomAllFlag = false; 27 | Text searchText; 28 | boolean mustSearch = false; 29 | String mustSearchText = null; 30 | public PlayList pl; 31 | 32 | public SearchManager(KaiDJ aParentKDJ,Composite parent, int style) { 33 | super(parent, style); 34 | parentKDJ = aParentKDJ; 35 | 36 | //Main panel 37 | GridLayout aGL = new GridLayout(); 38 | aGL.horizontalSpacing = 0; 39 | //aGL.verticalSpacing = 4; 40 | aGL.marginHeight = 0; 41 | aGL.marginWidth = 0; 42 | aGL.numColumns = 1; 43 | this.setLayout(aGL); 44 | GridData aGD = new GridData(GridData.FILL_BOTH); 45 | this.setLayoutData(aGD); 46 | setBackground(parentKDJ.mainBckC); 47 | 48 | //Buttons 49 | Composite aButPanel = new Composite(this,SWT.NULL); 50 | aButPanel.setBackground(parentKDJ.mainBckC); 51 | aGL = new GridLayout(); 52 | //aGL.horizontalSpacing = 4; 53 | aGL.verticalSpacing = 0; 54 | aGL.marginHeight = 0; 55 | aGL.marginWidth = 0; 56 | aGL.numColumns = 2; 57 | aButPanel.setLayout(aGL); 58 | aGD = new GridData(GridData.FILL_HORIZONTAL); 59 | aButPanel.setLayoutData(aGD); 60 | 61 | shuffleAllB = new KaiButton(parentKDJ,aButPanel, SWT.TOGGLE); 62 | shuffleAllB.setBackground(parentKDJ.mainBckC); 63 | shuffleAllB.setToolTipText("Shuffle selection"); 64 | shuffleAllB.setImagePath("img2/shuffleBut.png"); 65 | shuffleAllB.setText("Shuffle"); 66 | aGD = new GridData();// GridData.FILL_HORIZONTAL); 67 | aGD.heightHint = KaiButton._HEIGHT; 68 | aGD.widthHint = KaiButton._WIDTH; 69 | shuffleAllB.setLayoutData(aGD); 70 | shuffleAllB.addSelectionListener(new SelectionListener() { 71 | public void widgetDefaultSelected(SelectionEvent arg0) { 72 | } 73 | 74 | public void widgetSelected(SelectionEvent arg0) { 75 | randomAllFlag = shuffleAllB.getSelection(); 76 | } 77 | }); 78 | // Search Text 79 | searchText = new Text(aButPanel, SWT.BORDER); 80 | searchText.setToolTipText("Enter keywords"); 81 | String os = System.getProperty("os.name"); 82 | if(!os.toLowerCase().startsWith("mac")){ 83 | //Mac seems to not support properly background colors here 84 | searchText.setBackground(parentKDJ.mainBckC); 85 | searchText.setForeground(parentKDJ.whiteC); 86 | } 87 | aGD = new GridData(GridData.FILL_BOTH); 88 | searchText.setLayoutData(aGD); 89 | searchText.addModifyListener(new ModifyListener() { 90 | @Override 91 | public void modifyText(ModifyEvent arg0) { 92 | mustSearch = true; 93 | parentKDJ.db.breakSearch = true; 94 | doSearch(); 95 | } 96 | }); 97 | // searchText.addKeyListener(new KeyListener() { 98 | // public void keyPressed(KeyEvent arg0) { 99 | // } 100 | // 101 | // public void keyReleased(KeyEvent arg0) { 102 | // int aCharCode = arg0.character & 0xFF; 103 | // if (aCharCode > 32 || arg0.keyCode == 8 || (arg0.keyCode >= 32 && arg0.keyCode < 65535)) { 104 | // mustSearch = true; 105 | // parentKDJ.db.breakSearch = true; 106 | // doSearch(); 107 | // } 108 | // } 109 | // }); 110 | 111 | //PL 112 | pl = new PlayList(parentKDJ, this, SWT.NONE); 113 | pl.listTC.setToolTip("Browse songs: \n"// 114 | + "- Click to load a song on the pre-listen player\n"// 115 | + "- Double-click to add a song at the end of the playlist or the current category\n"// 116 | + "- Ctrl+Click to add a song after the current selection or the current playing song\n"// 117 | + "- Shift+Click to add a range of songs after the current selection or the current playing song"); 118 | aGD = new GridData(GridData.FILL_BOTH); 119 | pl.setLayoutData(aGD); 120 | 121 | //Listeners 122 | pl.listTC.addMouseListener(new MouseListener() { 123 | public void mouseDoubleClick(MouseEvent aEvt) { 124 | if (pl.isClickInTopBar(aEvt.x, aEvt.y)) { 125 | // Nothing to do 126 | } else { 127 | SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 128 | if (aDescr != null) { 129 | if(parentKDJ.managerCategories != null){ 130 | //Add song to category 131 | parentKDJ.managerCategories.addSong(aDescr); 132 | } 133 | else{ 134 | //Add song to playlist 135 | parentKDJ.managerPlay.addSong(aDescr); 136 | } 137 | } 138 | } 139 | } 140 | 141 | public void mouseDown(MouseEvent aEvt) { 142 | if (pl.isClickInTopBar(aEvt.x, aEvt.y)) { 143 | // Nothing to do 144 | } else { 145 | if(aEvt.stateMask == SWT.CTRL){ 146 | //Add after 147 | SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 148 | if (aDescr != null) { 149 | pl.selectedPlIds = new TreeSet(); 150 | pl.selectedPlIds.add(aDescr.getPlID()); 151 | parentKDJ.managerPlay.addSongAfter(aDescr); 152 | pl.listTC.needRedraw(); 153 | } 154 | } 155 | else if(aEvt.stateMask == SWT.SHIFT){ 156 | //Add after 157 | Integer aBefPlId = pl.getLastSelectedPlId(); 158 | SongDescr aDescr = pl.getMp3Descr(aEvt.x, aEvt.y); 159 | if (aDescr != null) { 160 | int aBefIndex = pl.getIndex(aBefPlId); 161 | int aIndex = pl.getIndex(aDescr.getPlID()); 162 | if(aBefIndex >= 0 && aIndex >= 0 && aBefIndex <= aIndex){ 163 | pl.selectedPlIds = new TreeSet(); 164 | for(int i = aBefIndex;i <= aIndex;i++){ 165 | aDescr = (SongDescr)pl.pl.elementAt(i); 166 | pl.selectedPlIds.add(aDescr.getPlID()); 167 | //Add song to playlist 168 | parentKDJ.managerPlay.addSongAfter(aDescr); 169 | } 170 | pl.listTC.needRedraw(); 171 | } 172 | } 173 | } 174 | } 175 | } 176 | 177 | public void mouseUp(MouseEvent arg0) { 178 | } 179 | }); 180 | } 181 | 182 | /** 183 | * 184 | */ 185 | public void doSearch(){ 186 | // Start main refresh thread 187 | Thread aThread = new Thread(new Runnable(){ 188 | public void run() { 189 | try { 190 | /*while (true)*/ { 191 | if (mustSearch) { 192 | parentKDJ.shell.getDisplay().syncExec(new Runnable() { 193 | public void run() { 194 | mustSearchText = searchText.getText(); 195 | } 196 | }); 197 | mustSearch = false; 198 | Vector aRes = new Vector(); 199 | pl.setPl(aRes); 200 | parentKDJ.db.search(aRes, mustSearchText); 201 | pl.listTC.needRedraw(); 202 | } 203 | //Thread.sleep(100); 204 | } 205 | } catch (Throwable t) { 206 | System.err.println("Main loop error : " + t); 207 | t.printStackTrace(System.err); 208 | } 209 | } 210 | 211 | }, "Search request"); 212 | aThread.setPriority(Thread.MIN_PRIORITY); 213 | aThread.start(); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/db/Id3Analyzer.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.db; 2 | 3 | import java.io.File; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Vector; 8 | 9 | import javax.sound.sampled.AudioFileFormat; 10 | import javax.sound.sampled.AudioFormat; 11 | import javax.sound.sampled.AudioSystem; 12 | 13 | import javazoom.jlgui.basicplayer.BasicController; 14 | import javazoom.jlgui.basicplayer.BasicPlayer; 15 | import javazoom.jlgui.basicplayer.BasicPlayerEvent; 16 | import javazoom.jlgui.basicplayer.BasicPlayerListener; 17 | 18 | import org.tritonus.share.sampled.TAudioFormat; 19 | import org.tritonus.share.sampled.file.TAudioFileFormat; 20 | 21 | import com.cubaix.kaiDJ.KaiDJ; 22 | 23 | public class Id3Analyzer implements BasicPlayerListener { 24 | KaiDJ parentJDJ; 25 | BasicPlayer player; 26 | SongDescr currentDescr = null; 27 | Db db; 28 | public boolean stopScan = false; 29 | 30 | public Id3Analyzer(KaiDJ aParentJDJ,final Db aDao) { 31 | super(); 32 | parentJDJ = aParentJDJ; 33 | db = aDao; 34 | scan(); 35 | } 36 | 37 | public synchronized void scan(){ 38 | Thread aTh = new Thread(new Runnable(){ 39 | public void run() { 40 | try{ 41 | scan(db); 42 | } 43 | catch(Throwable t){ 44 | t.printStackTrace(System.err); 45 | } 46 | } 47 | },"ID3 Analyzer"); 48 | aTh.setPriority(Thread.MIN_PRIORITY); 49 | aTh.start(); 50 | } 51 | /** 52 | * @param aDao 53 | */ 54 | synchronized void scan(Db aDao) { 55 | Vector aV = null; 56 | aV = aDao.getToAnalyze(); 57 | stopScan = false; 58 | //EM 02/11/2008 : faster with an array 59 | Object[] aVs = aV.toArray(); 60 | for (int m = 0; !stopScan && m < aVs.length; m++) { 61 | SongDescr aDescr = (SongDescr) aVs[m];//aV.elementAt(m); 62 | analyze(aDao, aDescr); 63 | //Display and commit only evry N 64 | if((m % 50) == 0){ 65 | parentJDJ.setMsg("Analyzing ID3 .. " + m + " / " + aV.size() + " .. " + aDescr.path); 66 | aDao.commit(); 67 | } 68 | // Let a bit CPU for other threads 69 | // try { 70 | // Thread.sleep(100); 71 | // } catch (Throwable t) { 72 | // } 73 | } 74 | if (aV.size() > 0) { 75 | aDao.commit(); 76 | } 77 | parentJDJ.setMsg(""); 78 | } 79 | 80 | public void analyze(Db aDao,SongDescr aDescr){ 81 | if (player == null) { 82 | // Instantiate BasicPlayer. 83 | //EM 29/04/2009 : parentJDJ 84 | player = new BasicPlayer(parentJDJ,false); 85 | player.addBasicPlayerListener(this); 86 | } 87 | try{ 88 | currentDescr = aDescr; 89 | try{ 90 | //player.open(new File(aDescr.path)); 91 | File file = new File(aDescr.path); 92 | AudioFileFormat m_audioFileFormat; 93 | m_audioFileFormat = AudioSystem.getAudioFileFormat(file); 94 | Map properties = null; 95 | if (m_audioFileFormat instanceof TAudioFileFormat) 96 | { 97 | // Tritonus SPI compliant audio file format. 98 | properties = ((TAudioFileFormat) m_audioFileFormat).properties(); 99 | // Clone the Map because it is not mutable. 100 | HashMap map = new HashMap(); 101 | if (properties != null) 102 | { 103 | Iterator it = properties.keySet().iterator(); 104 | while (it.hasNext()) 105 | { 106 | Object key = it.next(); 107 | Object value = properties.get(key); 108 | map.put(key, value); 109 | } 110 | } 111 | properties = map; 112 | } 113 | else properties = new HashMap(); 114 | // Add JavaSound properties. 115 | if (m_audioFileFormat.getByteLength() > 0) properties.put("audio.length.bytes", new Integer(m_audioFileFormat.getByteLength())); 116 | if (m_audioFileFormat.getFrameLength() > 0) properties.put("audio.length.frames", new Integer(m_audioFileFormat.getFrameLength())); 117 | if (m_audioFileFormat.getType() != null) properties.put("audio.type", (m_audioFileFormat.getType().toString())); 118 | // Audio format. 119 | AudioFormat audioFormat = m_audioFileFormat.getFormat(); 120 | if (audioFormat.getFrameRate() > 0) properties.put("audio.framerate.fps", new Float(audioFormat.getFrameRate())); 121 | if (audioFormat.getFrameSize() > 0) properties.put("audio.framesize.bytes", new Integer(audioFormat.getFrameSize())); 122 | if (audioFormat.getSampleRate() > 0) properties.put("audio.samplerate.hz", new Float(audioFormat.getSampleRate())); 123 | if (audioFormat.getSampleSizeInBits() > 0) properties.put("audio.samplesize.bits", new Integer(audioFormat.getSampleSizeInBits())); 124 | if (audioFormat.getChannels() > 0) properties.put("audio.channels", new Integer(audioFormat.getChannels())); 125 | if (audioFormat instanceof TAudioFormat) 126 | { 127 | // Tritonus SPI compliant audio format. 128 | Map addproperties = ((TAudioFormat) audioFormat).properties(); 129 | properties.putAll(addproperties); 130 | } 131 | // Add SourceDataLine 132 | //properties.put("basicplayer.sourcedataline", m_line); 133 | 134 | opened(null,properties); 135 | } 136 | catch(Throwable t){ 137 | //Invalide ?? 138 | currentDescr.author = "[INVALIDE]"; 139 | currentDescr.title = "[INVALIDE]"; 140 | currentDescr.album = "[INVALIDE]"; 141 | currentDescr.duration = -1; 142 | } 143 | aDao.update(currentDescr); 144 | currentDescr = null; 145 | } 146 | catch(Throwable t){ 147 | t.printStackTrace(System.err); 148 | } 149 | } 150 | 151 | public void opened(Object stream, Map properties) { 152 | //Get all props 153 | //Iterator aIt = properties.entrySet().iterator(); 154 | /* 155 | while(aIt.hasNext()){ 156 | Object aKey = aIt.next(); 157 | System.out.println("Prop : " + aKey); 158 | } 159 | */ 160 | // System.out.println("MP3 ID=" + currentDescr.id); 161 | // System.out.println("GET : author = " + properties.get("author")); 162 | // System.out.println("GET : title = " + properties.get("title")); 163 | // System.out.println("GET : album = " + properties.get("album")); 164 | // System.out.println("GET : duration = " + properties.get("duration")); 165 | currentDescr.set((String)properties.get("author"),(String)properties.get("title"),(String)properties.get("album"),((Long)properties.get("duration")).longValue()); 166 | } 167 | 168 | public void progress(int bytesread, long microseconds, byte[] pcmdata, 169 | Map properties) { 170 | // TODO Auto-generated method stub 171 | 172 | } 173 | 174 | public void stateUpdated(BasicPlayerEvent event) { 175 | // TODO Auto-generated method stub 176 | 177 | } 178 | 179 | public void setController(BasicController controller) { 180 | // TODO Auto-generated method stub 181 | 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/db/SongDescr.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.db; 2 | 3 | import java.io.File; 4 | import java.text.NumberFormat; 5 | 6 | import com.cubaix.kai.KaiSrt; 7 | 8 | public class SongDescr { 9 | static NumberFormat ddNF; 10 | static { 11 | ddNF = NumberFormat.getInstance(); 12 | ddNF.setMaximumIntegerDigits(2); 13 | ddNF.setMinimumIntegerDigits(2); 14 | } 15 | 16 | public Integer id = null; 17 | public String path = null; 18 | public String author = "[UNKNOWN]"; 19 | public String title = "[UNKNOWN]"; 20 | public String album = "[UNKNOWN]"; 21 | 22 | public long duration = -1; 23 | String durationDisplay = ""; 24 | public int hash = -1; 25 | int enablePlay = 0;//0 : undefined (not in play list), 1 : play, -1 : don't play 26 | 27 | Integer plID = new Integer((int)(Math.random() * Integer.MAX_VALUE)); 28 | 29 | public KaiSrt kaiSrt = null; 30 | 31 | /** 32 | * @param aId 33 | * @param aPath 34 | */ 35 | public SongDescr(Integer aId, String aPath) { 36 | id = aId; 37 | path = aPath; 38 | hash = path.toLowerCase().hashCode(); 39 | if(new File(path+".kai").exists()) { 40 | kaiSrt = new KaiSrt(path); 41 | } 42 | } 43 | 44 | /** 45 | * @param aId 46 | * @param aPath 47 | * @param aAuthor 48 | * @param aTitle 49 | * @param aAlbum 50 | * @param aDuration 51 | */ 52 | public SongDescr(Integer aId, String aPath, String aAuthor, String aTitle, 53 | String aAlbum, long aDuration) { 54 | id = aId; 55 | path = aPath; 56 | hash = path.toLowerCase().hashCode(); 57 | set(aAuthor, aTitle, aAlbum, aDuration); 58 | if(new File(path+".kai").exists()) { 59 | kaiSrt = new KaiSrt(path); 60 | } 61 | } 62 | 63 | /** 64 | * @param aId 65 | * @param aPath 66 | * @param aAuthor 67 | * @param aTitle 68 | * @param aAlbum 69 | * @param aDuration 70 | * @param aHash 71 | */ 72 | public SongDescr(Integer aId, String aPath, String aAuthor, String aTitle, 73 | String aAlbum, long aDuration, int aHash) { 74 | this(aId, aPath, aAuthor, aTitle, aAlbum, aDuration); 75 | if (aHash != 0) { 76 | hash = aHash; 77 | } 78 | } 79 | 80 | //Use this to build a copy with a new plID 81 | public SongDescr(SongDescr aDescr){ 82 | this(aDescr.id,aDescr.path,aDescr.author,aDescr.title,aDescr.album,aDescr.duration,aDescr.hash); 83 | } 84 | 85 | /** 86 | * @param aAuthor 87 | * @param aTitle 88 | * @param aAlbum 89 | * @param aDuration 90 | */ 91 | public void set(String aAuthor, String aTitle, String aAlbum, long aDuration) { 92 | author = aAuthor; 93 | title = aTitle; 94 | album = aAlbum; 95 | duration = aDuration; 96 | 97 | durationDisplay = durationToDisplay(duration); 98 | } 99 | 100 | /** 101 | * @param aTime 102 | * @return 103 | */ 104 | static public String durationToDisplay(long aTime){ 105 | long aSecAll = aTime / 1000000; 106 | long aDays = aSecAll / (3600 * 24); 107 | long aHours = (aSecAll / 3600)%24; 108 | long aMin = (aSecAll / 60)%60; 109 | long aSec = aSecAll % 60; 110 | //long aMs = (aTime % 1000) / 10; 111 | if(aDays > 0){ 112 | return aDays + ":" + aHours + ":" + ddNF.format(aMin) + ":" + ddNF.format(aSec); 113 | } 114 | if(aHours > 0){ 115 | return aHours + ":" + ddNF.format(aMin) + ":" + ddNF.format(aSec); 116 | } 117 | return ddNF.format(aMin) + ":" + ddNF.format(aSec); 118 | } 119 | 120 | public String getAlbum() { 121 | if (album == null) { 122 | return "[ERROR]"; 123 | } 124 | return album; 125 | } 126 | 127 | public void setAlbum(String album) { 128 | this.album = album; 129 | } 130 | 131 | public String getAuthor() { 132 | if (author == null) { 133 | return "[ERROR]"; 134 | } 135 | return author; 136 | } 137 | 138 | public void setAuthor(String author) { 139 | this.author = author; 140 | } 141 | 142 | public long getDuration() { 143 | return duration; 144 | } 145 | 146 | public void setDuration(long duration) { 147 | this.duration = duration; 148 | } 149 | 150 | public String getDurationDisplay() { 151 | if (durationDisplay == null) { 152 | return "[ERROR]"; 153 | } 154 | return durationDisplay; 155 | } 156 | 157 | public void setDurationDisplay(String durationDisplay) { 158 | this.durationDisplay = durationDisplay; 159 | } 160 | 161 | public Integer getId() { 162 | if (id == null) { 163 | return new Integer(-1); 164 | } 165 | return id; 166 | } 167 | 168 | public void setId(Integer id) { 169 | this.id = id; 170 | } 171 | 172 | public String getPath() { 173 | if (path == null) { 174 | return "[ERROR]"; 175 | } 176 | return path; 177 | } 178 | 179 | public void setPath(String path) { 180 | this.path = path; 181 | } 182 | 183 | //EM 28/04/2009 184 | public boolean isAccesible(){ 185 | return new File(this.path).exists(); 186 | } 187 | 188 | public String getTitle() { 189 | if (title == null) { 190 | return "[ERROR]"; 191 | } 192 | return title; 193 | } 194 | 195 | public void setTitle(String title) { 196 | this.title = title; 197 | } 198 | 199 | public int getHash() { 200 | return hash; 201 | } 202 | 203 | public void setHash(int hash) { 204 | this.hash = hash; 205 | } 206 | 207 | public int getEnablePlay() { 208 | return enablePlay; 209 | } 210 | 211 | public void setEnablePlay(int enablePlay) { 212 | this.enablePlay = enablePlay; 213 | } 214 | 215 | public Integer getPlID() { 216 | return plID; 217 | } 218 | 219 | public void setPlID(Integer plID) { 220 | this.plID = plID; 221 | } 222 | // protected void finalize() throws Throwable { 223 | // System.out.println("SONGDESCR Finalizing.."); 224 | // } 225 | } 226 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/db/SongGroup.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.db; 2 | 3 | 4 | public class SongGroup extends SongDescr { 5 | public static final int _KIND_OPEN = 0; 6 | public static final int _KIND_CLOSE = 1; 7 | 8 | public int kind = _KIND_OPEN; 9 | 10 | public SongGroup(int aKing,String aLabel) { 11 | super(new Integer(-1), aLabel); 12 | kind = aKing; 13 | } 14 | 15 | // @Override 16 | // protected void finalize() throws Throwable { 17 | // System.out.println("SONGGROUP Finalizing.."); 18 | // } 19 | } 20 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img/Icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img/Icon.ico -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img/Icon.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img/LogoSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img/LogoSmall.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img/kaiDJ.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 41 | 46 | 53 | kaiDJ 67 | 68 | 88 | 89 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img/playerBck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img/playerBck.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img/playerBck.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img/playerBck.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/addDbBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/addDbBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/addDbBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/addDbBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/addGroupBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/addGroupBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/addGroupBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/addGroupBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/bookmarks.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/butBck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/butBck.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/butBck.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/butBck.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/butBckDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/butBckDark.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/butBckDark.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/butBckDark.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/butBckMid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/butBckMid.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/butBckMid.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/butBckMid.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/catBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/catBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/catBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/catBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/chat-square-text-fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/chat-square-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/database-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/eraseDbBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/eraseDbBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/folder2-open.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/globe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/kaiBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/kaiBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/kaiIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/kaiIcon.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/kaiIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | 39 | 43 | 44 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/mixBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/mixBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/mixBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/mixBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/newPLBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/newPLBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/newPLBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/newPLBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/openCatBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/openCatBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/openPLBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/openPLBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/save2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/saveCatBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/saveCatBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/savePLBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/savePLBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/searchKaiBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/searchKaiBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/showProfBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/showProfBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/showProfBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/showProfBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/shuffleBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/shuffleBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/shuffleBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/shuffleBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/stars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/stopAftBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/stopAftBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/stopAftBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/stopAftBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/trash3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/webSiteBut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/webSiteBut.png -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/img2/webSiteBut.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/img2/webSiteBut.xcf -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/swt/KaiButton.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.swt; 2 | 3 | import java.io.InputStream; 4 | import java.util.Vector; 5 | import org.eclipse.swt.SWT; 6 | import org.eclipse.swt.events.MouseEvent; 7 | import org.eclipse.swt.events.MouseListener; 8 | import org.eclipse.swt.events.MouseTrackListener; 9 | import org.eclipse.swt.events.PaintEvent; 10 | import org.eclipse.swt.events.PaintListener; 11 | import org.eclipse.swt.events.SelectionListener; 12 | import org.eclipse.swt.graphics.GC; 13 | import org.eclipse.swt.graphics.Image; 14 | import org.eclipse.swt.graphics.Rectangle; 15 | import org.eclipse.swt.widgets.Canvas; 16 | import org.eclipse.swt.widgets.Composite; 17 | 18 | import com.cubaix.kaiDJ.KaiDJ; 19 | 20 | public class KaiButton extends Canvas { 21 | public static final int _WIDTH = 60; 22 | public static final int _HEIGHT = 25; 23 | 24 | KaiDJ parentJDJ; 25 | 26 | static Image butBck = null; 27 | static Image butBckMid = null; 28 | static Image butBckDark = null; 29 | String imgPath = null; 30 | Image img = null; 31 | 32 | String text; 33 | 34 | boolean isToggle = false; 35 | boolean selection = false; 36 | Vector selectionListeners = new Vector(); 37 | int state = 0;//0 current selection state, 1 over 38 | 39 | String toolTip = null; 40 | 41 | Rectangle buttonBounds = null; 42 | 43 | public KaiButton(KaiDJ aParentJDJ,Composite aParent, int aStyle) { 44 | super(aParent, aStyle); 45 | parentJDJ = aParentJDJ; 46 | isToggle = (aStyle & SWT.TOGGLE) != 0; 47 | this.addPaintListener(new PaintListener(){ 48 | public void paintControl(PaintEvent aPE) { 49 | buttonBounds = getClientArea(); 50 | paint(); 51 | } 52 | }); 53 | this.addMouseTrackListener(new MouseTrackListener(){ 54 | public void mouseEnter(MouseEvent arg0) { 55 | parentJDJ.logoPanel.help = toolTip; 56 | parentJDJ.logoPanel.needRedraw(); 57 | state = 1; 58 | needRedraw(); 59 | } 60 | public void mouseExit(MouseEvent arg0) { 61 | parentJDJ.logoPanel.help = null; 62 | parentJDJ.logoPanel.needRedraw(); 63 | state = 0; 64 | if(!isToggle){ 65 | //Always deselected 66 | selection = false; 67 | } 68 | needRedraw(); 69 | } 70 | public void mouseHover(MouseEvent arg0) { 71 | } 72 | }); 73 | this.addMouseListener(new MouseListener(){ 74 | public void mouseDoubleClick(MouseEvent aEvt) { 75 | } 76 | public void mouseDown(MouseEvent aEvt) { 77 | // state = 0; 78 | if(isToggle){ 79 | selection = !selection; 80 | } 81 | else{ 82 | selection = true; 83 | } 84 | needRedraw(); 85 | notifySelection(); 86 | } 87 | public void mouseUp(MouseEvent aEvt) { 88 | // state = 0; 89 | if(!isToggle){ 90 | //Always deselected 91 | selection = false; 92 | } 93 | needRedraw(); 94 | // notifySelection(); 95 | } 96 | 97 | }); 98 | } 99 | 100 | void notifySelection(){ 101 | for(int i = 0;i < selectionListeners.size();i++){ 102 | ((SelectionListener)selectionListeners.elementAt(i)).widgetSelected(null); 103 | } 104 | } 105 | 106 | public void setSelection(boolean aSel){ 107 | selection = aSel; 108 | } 109 | public boolean getSelection(){ 110 | return selection; 111 | } 112 | 113 | public void setImagePath(String aPath){ 114 | imgPath = aPath; 115 | } 116 | 117 | public void setText(String aText){ 118 | text = aText; 119 | } 120 | 121 | public void setToolTipText(String aText){ 122 | toolTip = aText; 123 | } 124 | 125 | public void addSelectionListener(SelectionListener aListener){ 126 | selectionListeners.add(aListener); 127 | } 128 | 129 | void needRedraw() { 130 | if (parentJDJ.display == null || parentJDJ.display.isDisposed()) { 131 | // Wait until it is available 132 | return; 133 | } 134 | // Use SWT async 135 | final KaiButton aThis = this; 136 | parentJDJ.display.asyncExec(new Runnable() { 137 | public void run() { 138 | try { 139 | buttonBounds = aThis.getClientArea(); 140 | paint(); 141 | } catch (Throwable t) { 142 | } 143 | } 144 | }); 145 | } 146 | 147 | /** 148 | * 149 | */ 150 | void loadBckImg() { 151 | if (parentJDJ == null || parentJDJ.display == null || parentJDJ.display.isDisposed()) { 152 | return; 153 | } 154 | InputStream aIS = KaiDJ.class.getResourceAsStream("img2/butBck.png"); 155 | butBck = new Image(parentJDJ.display, aIS); 156 | aIS = KaiDJ.class.getResourceAsStream("img2/butBckMid.png"); 157 | butBckMid = new Image(parentJDJ.display, aIS); 158 | aIS = KaiDJ.class.getResourceAsStream("img2/butBckDark.png"); 159 | butBckDark = new Image(parentJDJ.display, aIS); 160 | } 161 | 162 | void loadImg() { 163 | if (parentJDJ == null || parentJDJ.display == null || parentJDJ.display.isDisposed()) { 164 | return; 165 | } 166 | if(imgPath == null){ 167 | return; 168 | } 169 | InputStream aIS = KaiDJ.class.getResourceAsStream(imgPath); 170 | img = new Image(parentJDJ.display, aIS); 171 | } 172 | 173 | void paint() { 174 | if (butBck == null) { 175 | loadBckImg(); 176 | } 177 | if (img == null) { 178 | loadImg(); 179 | } 180 | if(butBck == null || img == null || buttonBounds == null){ 181 | return; 182 | } 183 | try{ 184 | GC aGC = new GC(this); 185 | // aPlayerGC.setClipping(playerBounds.x, playerBounds.y, 186 | // playerBounds.width, playerBounds.height); 187 | 188 | aGC.setClipping(buttonBounds.x, buttonBounds.y, buttonBounds.width, buttonBounds.height); 189 | aGC.setForeground(parentJDJ.blackC); 190 | aGC.setBackground(parentJDJ.mainBckC); 191 | aGC.fillRectangle(buttonBounds); 192 | 193 | Image aImgBck; 194 | if(state == 1){ 195 | //Over 196 | aImgBck = butBck; 197 | } 198 | else{ 199 | //Current selection 200 | if(selection){ 201 | aImgBck = butBckMid; 202 | } 203 | else{ 204 | aImgBck = butBckDark; 205 | } 206 | } 207 | 208 | aGC.drawImage(aImgBck, buttonBounds.x, buttonBounds.y); 209 | aGC.drawImage(img, buttonBounds.x + 8, buttonBounds.y + 5); 210 | // aGC.setFont(parentJDJ.initialFont); 211 | // aGC.drawText(text,32 - (int)(3.7 * (text.length()/2)),0,true); 212 | 213 | if (isToggle) { 214 | if (selection) { 215 | aGC.setBackground(parentJDJ.playerC); 216 | } else { 217 | //EM 06/07/2008 : background color for off state 218 | aGC.setBackground(parentJDJ.mainBckC/*.redC*/); 219 | } 220 | aGC.setForeground(parentJDJ.playerBarC); 221 | aGC.fillOval(buttonBounds.x + 40, buttonBounds.y + 8, 8, 8); 222 | aGC.drawOval(buttonBounds.x + 40, buttonBounds.y + 8, 8, 8); 223 | } 224 | 225 | if(state == 1){ 226 | //Over 227 | aGC.setForeground(parentJDJ.playerC); 228 | } 229 | else{ 230 | aGC.setForeground(parentJDJ.playerBarC); 231 | } 232 | aGC.setLineWidth(1); 233 | aGC.drawRectangle(buttonBounds.x,buttonBounds.y + 1,_WIDTH - 1,_HEIGHT - 2); 234 | 235 | aGC.dispose(); 236 | } catch (Throwable t) { 237 | System.err.println("Can't paint button : " + t); 238 | t.printStackTrace(System.err); 239 | } 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/swt/KaiScrollBar.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.swt; 2 | 3 | import java.util.Vector; 4 | 5 | import org.eclipse.swt.SWT; 6 | import org.eclipse.swt.events.MouseEvent; 7 | import org.eclipse.swt.events.MouseListener; 8 | import org.eclipse.swt.events.MouseMoveListener; 9 | import org.eclipse.swt.events.MouseWheelListener; 10 | import org.eclipse.swt.events.PaintEvent; 11 | import org.eclipse.swt.events.PaintListener; 12 | import org.eclipse.swt.events.SelectionListener; 13 | import org.eclipse.swt.graphics.Color; 14 | import org.eclipse.swt.graphics.GC; 15 | import org.eclipse.swt.graphics.Point; 16 | import org.eclipse.swt.graphics.Rectangle; 17 | import org.eclipse.swt.widgets.Canvas; 18 | import org.eclipse.swt.widgets.Composite; 19 | 20 | import com.cubaix.kaiDJ.KaiDJ; 21 | 22 | public class KaiScrollBar extends Canvas implements MouseWheelListener { 23 | KaiDJ parentKDJ = null; 24 | int style = SWT.VERTICAL; 25 | Composite parent = null; 26 | 27 | Vector selectionListener = new Vector(); 28 | int selection = 0; 29 | int maximum = 100; 30 | int thumb = 10; 31 | int increment = 1; 32 | int pageIncrement = 10; 33 | 34 | Point mouseLastPos = null; 35 | Point mouseLastDrag = null; 36 | 37 | Color thumbC = null; 38 | Color incrementC = null; 39 | Color pageIncrementC = null; 40 | Color borderC = null; 41 | 42 | public KaiScrollBar(KaiDJ aParentKDJ,Composite aParent, int aStyle) { 43 | super(aParent, SWT.None); 44 | parentKDJ = aParentKDJ; 45 | style = aStyle; 46 | parent = aParent; 47 | 48 | thumbC = parentKDJ.logoDarkC; 49 | incrementC = parentKDJ.logoDarkC; 50 | pageIncrementC = parentKDJ.mainBckC; 51 | borderC = parentKDJ.logoLightC; 52 | addPaintListener(new PaintListener() { 53 | @Override 54 | public void paintControl(PaintEvent aE) { 55 | paint(aE.gc); 56 | } 57 | }); 58 | final KaiScrollBar aMe = this; 59 | addMouseWheelListener(new MouseWheelListener() { 60 | @Override 61 | public void mouseScrolled(MouseEvent aE) { 62 | aMe.mouseScrolled(aE); 63 | } 64 | }); 65 | addMouseListener(new MouseListener() { 66 | @Override 67 | public void mouseUp(MouseEvent aME) { 68 | mouseLastDrag = null; 69 | if(mouseLastPos == null) { 70 | return; 71 | } 72 | if(mouseLastPos.x == aME.x && mouseLastPos.y == aME.y) { 73 | Rectangle aRect = getBounds(); 74 | if((style & SWT.VERTICAL) > 0) { 75 | double aScreenRange = aRect.height*(maximum-thumb)/(double)maximum; 76 | selection = (int)(maximum * (aME.y - aRect.y) / aScreenRange); 77 | if(selection < 0) { 78 | selection = 0; 79 | } 80 | if(selection > maximum) { 81 | selection = maximum; 82 | } 83 | for(SelectionListener aL : selectionListener) { 84 | aL.widgetSelected(null); 85 | } 86 | } 87 | else { 88 | double aScreenRange = aRect.width*(maximum-thumb)/(double)maximum; 89 | selection = (int)(maximum * (aME.x - aRect.x) / aScreenRange); 90 | if(selection < 0) { 91 | selection = 0; 92 | } 93 | if(selection > maximum) { 94 | selection = maximum; 95 | } 96 | for(SelectionListener aL : selectionListener) { 97 | aL.widgetSelected(null); 98 | } 99 | } 100 | redraw(); 101 | } 102 | mouseLastPos = null; 103 | } 104 | @Override 105 | public void mouseDown(MouseEvent aME) { 106 | mouseLastPos = new Point(aME.x, aME.y); 107 | } 108 | @Override 109 | public void mouseDoubleClick(MouseEvent arg0) { 110 | } 111 | }); 112 | addMouseMoveListener(new MouseMoveListener() { 113 | @Override 114 | public void mouseMove(MouseEvent aME) { 115 | if(mouseLastPos != null) { 116 | mouseLastDrag = mouseLastPos; 117 | mouseLastPos = null; 118 | } 119 | if(mouseLastDrag == null) { 120 | return; 121 | } 122 | 123 | Rectangle aRect = getBounds(); 124 | if((style & SWT.VERTICAL) > 0) { 125 | double aScreenRange = aRect.height*(maximum-thumb)/(double)maximum; 126 | int aDelta = (int)(maximum * (aME.y - mouseLastDrag.y) / aScreenRange); 127 | if(Math.abs(aDelta) <= 2) { 128 | //Do nothing on too small move 129 | return; 130 | } 131 | selection += aDelta; 132 | if(selection < 0) { 133 | selection = 0; 134 | } 135 | if(selection > maximum) { 136 | selection = maximum; 137 | } 138 | for(SelectionListener aL : selectionListener) { 139 | aL.widgetSelected(null); 140 | } 141 | } 142 | else { 143 | double aScreenRange = aRect.width*(maximum-thumb)/(double)maximum; 144 | int aDelta = (int)(maximum * (aME.x - mouseLastDrag.x) / aScreenRange); 145 | if(Math.abs(aDelta) <= 2) { 146 | //Do nothing on too small move 147 | return; 148 | } 149 | selection += aDelta; 150 | if(selection < 0) { 151 | selection = 0; 152 | } 153 | if(selection > maximum) { 154 | selection = maximum; 155 | } 156 | for(SelectionListener aL : selectionListener) { 157 | aL.widgetSelected(null); 158 | } 159 | } 160 | redraw(); 161 | mouseLastDrag.x = aME.x; 162 | mouseLastDrag.y = aME.y; 163 | } 164 | }); 165 | } 166 | 167 | void paint(GC aGC) { 168 | if(KaiDJ._DEBUG_PAINT) { 169 | System.out.println("KaiScrollBar.paint()"); 170 | } 171 | Rectangle aRect = getBounds(); 172 | aGC.setBackground(pageIncrementC); 173 | aGC.fillRectangle(0,0,aRect.width,aRect.height); 174 | aGC.setForeground(borderC); 175 | 176 | aGC.setBackground(thumbC); 177 | int aFreeRange = maximum-thumb; 178 | 179 | if((style & SWT.VERTICAL) > 0) { 180 | aGC.fillRectangle(aRect.width/2,0,1,aRect.height); 181 | if(aFreeRange <= 0) { 182 | aGC.fillRectangle(2,0,aRect.width - 3,aRect.height); 183 | } 184 | else { 185 | int aPos = (int)(aRect.height * (selection / (double)maximum) * (aFreeRange / (double)maximum)); 186 | int aThumb = (aRect.height * thumb) / maximum; 187 | if(aThumb <= 0) { 188 | aThumb = 2; 189 | } 190 | aGC.fillRectangle(2,aPos, aRect.width - 3, aThumb); 191 | } 192 | } 193 | else { 194 | aGC.fillRectangle(0,aRect.height/2,aRect.width,1); 195 | if(aFreeRange <= 0) { 196 | aGC.fillRectangle(0,2,aRect.width,aRect.height-2); 197 | } 198 | else { 199 | int aPos = (int)(aRect.width * (selection / (double)maximum) * (aFreeRange / (double)maximum)); 200 | int aThumb = (aRect.width * thumb) / maximum; 201 | if(aThumb <= 0) { 202 | aThumb = 2; 203 | } 204 | aGC.fillRectangle(aPos,2,aThumb,aRect.height - 3); 205 | } 206 | } 207 | } 208 | 209 | public void setThumbColor(Color aC) { 210 | thumbC = aC; 211 | } 212 | public void setIncrementColor(Color aC) { 213 | pageIncrementC = aC; 214 | } 215 | public void setPageIncrementColor(Color aC) { 216 | pageIncrementC = aC; 217 | } 218 | 219 | public void addSelectionListener(SelectionListener aSelectionListener) { 220 | selectionListener.add(aSelectionListener); 221 | } 222 | 223 | public int getSelection() { 224 | return selection; 225 | } 226 | public void setSelection(int aS) { 227 | selection = aS; 228 | } 229 | public int getMaximum() { 230 | return maximum; 231 | } 232 | public void setMaximum(int aM) { 233 | maximum = aM; 234 | } 235 | public int getThumb() { 236 | return thumb; 237 | } 238 | public void setThumb(int aT) { 239 | thumb = aT; 240 | } 241 | public int getIncrement() { 242 | return increment; 243 | } 244 | public void setIncrement(int aI) { 245 | increment = aI; 246 | } 247 | public int getPageIncrement() { 248 | return pageIncrement; 249 | } 250 | public void setPageIncrement(int aI) { 251 | pageIncrement = aI; 252 | } 253 | 254 | @Override 255 | public void mouseScrolled(MouseEvent aME) { 256 | selection -= (thumb * aME.count)/8; 257 | if(selection < 0) { 258 | selection = 0; 259 | } 260 | if(selection > maximum) { 261 | selection = maximum; 262 | } 263 | for(SelectionListener aL : selectionListener) { 264 | aL.widgetSelected(null); 265 | } 266 | redraw(); 267 | } 268 | 269 | } 270 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/swt/PlayListListener.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.swt; 2 | 3 | import com.cubaix.kaiDJ.db.SongDescr; 4 | 5 | public interface PlayListListener { 6 | public void removed(SongDescr aDescr); 7 | public void added(SongDescr aDescr); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/swt/TimedCanvas.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.swt; 2 | 3 | import org.eclipse.swt.SWT; 4 | import org.eclipse.swt.events.MouseEvent; 5 | import org.eclipse.swt.events.MouseTrackListener; 6 | import org.eclipse.swt.graphics.GC; 7 | import org.eclipse.swt.widgets.Canvas; 8 | import org.eclipse.swt.widgets.Composite; 9 | 10 | import com.cubaix.kaiDJ.KaiDJ; 11 | 12 | public class TimedCanvas extends Canvas { 13 | protected KaiDJ parentKDJ; 14 | private Thread paintThread = null; 15 | private boolean needRedraw = true; 16 | //EM 02/11/2008 17 | private boolean needRedrawSlow = true; 18 | 19 | private String toolTip = null; 20 | 21 | //EM 12/11/2008 22 | protected int refreshRate = 100; 23 | 24 | public TimedCanvas(KaiDJ aParentKDJ, Composite parent, int style) { 25 | super(parent, style); 26 | parentKDJ = aParentKDJ; 27 | this.addMouseTrackListener(new MouseTrackListener() { 28 | public void mouseEnter(MouseEvent arg0) { 29 | parentKDJ.logoPanel.help = toolTip; 30 | parentKDJ.logoPanel.needRedraw(); 31 | } 32 | 33 | public void mouseExit(MouseEvent arg0) { 34 | parentKDJ.logoPanel.help = null; 35 | parentKDJ.logoPanel.needRedraw(); 36 | } 37 | 38 | public void mouseHover(MouseEvent arg0) { 39 | } 40 | }); 41 | } 42 | 43 | /** 44 | * 45 | */ 46 | public void needRedraw() { 47 | needRedraw = true; 48 | checkRedrawThread(); 49 | } 50 | 51 | //EM 02/11/2008 52 | public void needRedrawSlow() { 53 | needRedrawSlow = true; 54 | checkRedrawThread(); 55 | } 56 | 57 | //EM 02/11/2008 : needRedrawSlow 58 | public void checkRedrawThread(){ 59 | if (paintThread == null || !paintThread.isAlive()) { 60 | // Create a new paint thread 61 | final TimedCanvas aThis = this; 62 | paintThread = new Thread(new Runnable() { 63 | public void run() { 64 | //EM 02/11/2008 : needRedrawSlow 65 | long aCount = 0; 66 | 67 | while (true) { 68 | try { 69 | // Be time respectuous 70 | Thread.sleep(refreshRate); 71 | aCount++; 72 | // Search for a possible change in interface 73 | if (aThis.paintThread != Thread.currentThread() || aThis.isDisposed()) { 74 | // Something has changed ?? 75 | break; 76 | } 77 | // Is there a request to draw ? 78 | if (needRedraw // 79 | //EM 02/11/2008 : needRedrawSlow 80 | || (needRedrawSlow && (aCount%10) == 0)) { 81 | // Immediatly take request into account 82 | needRedraw = false; 83 | needRedrawSlow = false; 84 | aCount = 0; 85 | 86 | if (parentKDJ.display == null || parentKDJ.display.isDisposed()) { 87 | // Wait until it is available 88 | continue; 89 | } 90 | // Use SWT async 91 | parentKDJ.display.asyncExec(new Runnable() { 92 | public void run() { 93 | try { 94 | paintTimed(); 95 | } 96 | catch (Throwable t) { 97 | t.printStackTrace(System.err); 98 | } 99 | } 100 | }); 101 | } 102 | } catch (Throwable t) { 103 | System.err.println("Display thread error (shutdown ?) : " + t); 104 | } 105 | } 106 | } 107 | }, "Display daemon {" + this.getClass().getName() + "}"); 108 | paintThread.setPriority(Thread.MIN_PRIORITY); 109 | paintThread.start(); 110 | } 111 | } 112 | 113 | @Override 114 | public void drawBackground(GC gc, int x, int y, int width, int height, int offsetX, int offsetY) { 115 | } 116 | 117 | /** 118 | * 119 | */ 120 | protected void paintTimed() { 121 | } 122 | 123 | public String getToolTip() { 124 | return toolTip; 125 | } 126 | 127 | public void setToolTip(String toolTip) { 128 | this.toolTip = toolTip; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.OutputStream; 7 | import java.nio.charset.Charset; 8 | import java.util.Vector; 9 | import java.util.zip.ZipEntry; 10 | import java.util.zip.ZipInputStream; 11 | 12 | public class FileUtils { 13 | 14 | final static public Vector unzipDir(String aZipPath,String aDestPath) throws Exception { 15 | return unzipDir(aZipPath,aDestPath,true); 16 | } 17 | final static public Vector unzipDir(String aZipPath,String aDestPath,boolean aOverWrite) throws Exception { 18 | String aCharEncoding = "utf-8"; 19 | ZipInputStream in = null; 20 | try{ 21 | in = new ZipInputStream(new FileInputStream(aZipPath),Charset.forName(aCharEncoding)); 22 | while (true) { 23 | //Will throw an Exception if not UTF-8 24 | ZipEntry entry = in.getNextEntry(); 25 | if (entry == null) { 26 | // End of zip 27 | break; 28 | } 29 | } 30 | } 31 | catch(Throwable t){ 32 | aCharEncoding = "Cp437"; 33 | } 34 | finally{ 35 | in.close(); 36 | } 37 | 38 | System.out.println("Using char encoding '"+aCharEncoding+"' for file names in zip file : "+ aZipPath); 39 | 40 | Vector aPathList = new Vector(); 41 | // Open the ZIP file 42 | in = new ZipInputStream(new FileInputStream(aZipPath),Charset.forName(aCharEncoding)); 43 | String aMainPath = aDestPath; 44 | 45 | if(!new File(aDestPath).exists()){ 46 | new File(aDestPath).mkdir(); 47 | } 48 | 49 | // Get the first entry 50 | while (true) { 51 | ZipEntry entry = in.getNextEntry(); 52 | if (entry == null) { 53 | // End of zip 54 | break; 55 | } 56 | String outFilename = aMainPath + File.separator + entry.getName(); 57 | System.out.println("Unzipping : "+ outFilename); 58 | if (entry.isDirectory()) { 59 | new File(outFilename).mkdir(); 60 | continue; 61 | } 62 | if(!new File(outFilename).getParentFile().exists()){ 63 | new File(outFilename).getParentFile().mkdir(); 64 | } 65 | 66 | aPathList.add(outFilename); 67 | 68 | //EM 15/01/2008 : need an overwrite option 69 | OutputStream out = (aOverWrite || !new File(outFilename).exists())? new FileOutputStream(outFilename) : null; 70 | 71 | // Transfer bytes from the ZIP file to the 72 | // output file 73 | byte[] buf = new byte[1024]; 74 | int len; 75 | while ((len = in.read(buf)) > 0) { 76 | //EM 15/01/2008 : need a overwrite option 77 | if(out != null){ 78 | out.write(buf, 0, len); 79 | } 80 | } 81 | 82 | // Close the streams 83 | //EM 15/01/2008 : need a overwrite option 84 | if(out != null){ 85 | out.flush(); 86 | out.close(); 87 | } 88 | } 89 | in.close(); 90 | return aPathList; 91 | } 92 | 93 | public static void main(String[] args) { 94 | try{ 95 | 96 | } 97 | catch(Throwable t){ 98 | t.printStackTrace(); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/web/BrowserControl.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.web; 2 | 3 | 4 | public class BrowserControl { 5 | /** 6 | * Display a file in the system browser. If you want to display a file, you must include the absolute path name. 7 | * 8 | * @param url 9 | * the file's url (the url must start with either "http://" or "file://"). 10 | */ 11 | // Used to identify the windows platform. 12 | private static final String WIN_ID = "Windows"; 13 | // The default system browser under windows. 14 | //private static final String WIN_PATH = "rundll32"; 15 | // The flag to display a url. 16 | //private static final String WIN_FLAG = "url.dll,FileProtocolHandler"; 17 | // The default browser under unix. 18 | //private static final String UNIX_PATH = "netscape"; 19 | // The flag to display a url. 20 | //private static final String UNIX_FLAG = "-remote openURL"; 21 | 22 | public static void displayURL(String url) { 23 | String osName = System.getProperty("os.name"); 24 | try { 25 | if (osName.startsWith("Mac OS")) { 26 | Runtime.getRuntime().exec("open " + url); 27 | } else if (osName.startsWith("Windows")) 28 | Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); 29 | else { // assume Unix or Linux 30 | String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; 31 | String browser = null; 32 | for (int count = 0; count < browsers.length && browser == null; count++) 33 | if (Runtime.getRuntime().exec(new String[] { "which", browsers[count] }).waitFor() == 0) 34 | browser = browsers[count]; 35 | if (browser == null) 36 | throw new Exception("Could not find web browser"); 37 | else 38 | Runtime.getRuntime().exec(new String[] { browser, url }); 39 | } 40 | } catch (Exception t) { 41 | t.printStackTrace(System.err); 42 | } 43 | } 44 | // boolean windows = isWindowsPlatform(); 45 | // String cmd = null; 46 | // try { 47 | // if (windows) { 48 | // // cmd = 'rundll32 url.dll,FileProtocolHandler http://...' 49 | // cmd = WIN_PATH + " " + WIN_FLAG + " " + url; 50 | // Process p = Runtime.getRuntime().exec(cmd); 51 | // } else { 52 | // // Under Unix, Netscape has to be running for the "-remote" 53 | // // command to work. So, we try sending the command and 54 | // // check for an exit value. If the exit command is 0, 55 | // // it worked, otherwise we need to start the browser. 56 | // // cmd = 'netscape -remote openURL(http://www.javaworld.com)' 57 | // cmd = UNIX_PATH + " " + UNIX_FLAG + "(" + url + ")"; 58 | // Process p = Runtime.getRuntime().exec(cmd); 59 | // try { 60 | // // wait for exit code -- if it's 0, command worked, 61 | // // otherwise we need to start the browser up. 62 | // int exitCode = p.waitFor(); 63 | // if (exitCode != 0) { 64 | // // Command failed, start up the browser 65 | // // cmd = 'netscape http://www.javaworld.com' 66 | // cmd = UNIX_PATH + " " + url; 67 | // p = Runtime.getRuntime().exec(cmd); 68 | // } 69 | // } catch (InterruptedException x) { 70 | // System.err.println("Error bringing up browser, cmd='" + cmd + "'"); 71 | // System.err.println("Caught: " + x); 72 | // } 73 | // } 74 | // } catch (IOException x) { 75 | // // couldn't exec browser 76 | // System.err.println("Could not invoke browser, command=" + cmd); 77 | // System.err.println("Caught: " + x); 78 | // } 79 | // } 80 | 81 | /** 82 | * Try to determine whether this application is running under Windows or some other platform by examing the "os.name" property. 83 | * 84 | * @return true if this application is running under a Windows OS 85 | */ 86 | public static boolean isWindowsPlatform() { 87 | String os = System.getProperty("os.name"); 88 | if (os != null && os.startsWith(WIN_ID)) 89 | return true; 90 | else 91 | return false; 92 | } 93 | 94 | /** 95 | * Simple example. 96 | */ 97 | public static void main(String[] args) { 98 | displayURL("http://www.javaworld.com"); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/xml/ConfigLoader.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.xml; 2 | 3 | import java.util.Vector; 4 | 5 | import com.cubaix.kaiDJ.KaiDJ; 6 | 7 | public class ConfigLoader { 8 | public ConfigLoader() { 9 | super(); 10 | // TODO Auto-generated constructor stub 11 | } 12 | 13 | /** 14 | * @param parentJDJ 15 | * @param aPathIn 16 | */ 17 | public static void save(KaiDJ parentJDJ, String aPathIn){ 18 | 19 | String aPath; 20 | if (aPathIn.toLowerCase().endsWith(".xml")) { 21 | aPath = aPathIn; 22 | } else { 23 | aPath = aPathIn + ".xml"; 24 | } 25 | try { 26 | // Create X structure 27 | Vector aXOs = new Vector(); 28 | aXOs.add(new XTag("")); 29 | aXOs.add(new XObject("\n", XObject.PUNCT)); 30 | aXOs.add(new XTag("")); 31 | aXOs.add(new XObject("\n", XObject.PUNCT)); 32 | //String aDecal = "\t"; 33 | 34 | aXOs.add(new XTag("")); 35 | aXOs.add(new XObject("\n", XObject.PUNCT)); 36 | 37 | aXOs.add(new XTag("")); 38 | aXOs.add(new XObject("\n", XObject.PUNCT)); 39 | 40 | aXOs.add(new XTag("")); 41 | aXOs.add(new XObject("\n", XObject.PUNCT)); 42 | 43 | aXOs.add(new XTag("")); 44 | aXOs.add(new XObject("\n", XObject.PUNCT)); 45 | 46 | new XLoader("UTF-8").save(aPath, aXOs); 47 | } catch (Throwable t) { 48 | t.printStackTrace(System.err); 49 | } 50 | } 51 | 52 | /** 53 | * @param parentJDJ 54 | * @param aPath 55 | * @return 56 | */ 57 | public static Vector load(KaiDJ parentJDJ, String aPath) { 58 | Vector pl = new Vector(); 59 | Vector aXOs = new XLoader("UTF-8").load(aPath); 60 | //Vector aGroups = new Vector(); 61 | for (int o = 0; o < aXOs.size(); o++) { 62 | XObject aXO = (XObject) aXOs.elementAt(o); 63 | if (aXO.kind == XObject.TAG) { 64 | XTag aXTag = (XTag) aXO; 65 | if (aXTag.tagName.equalsIgnoreCase("user")) { 66 | parentJDJ.userEMail = aXTag.getValue("email"); 67 | parentJDJ.userCode = aXTag.getValue("code"); 68 | if(aXTag.getValue("welcomed") != null) { 69 | parentJDJ.welcomed = true; 70 | } 71 | } 72 | else if (aXTag.tagName.equalsIgnoreCase("soundcard1")) { 73 | parentJDJ.soundCard1 = Integer.parseInt(aXTag.getValue("id")); 74 | } 75 | else if (aXTag.tagName.equalsIgnoreCase("soundcard2")) { 76 | parentJDJ.soundCard2 = Integer.parseInt(aXTag.getValue("id")); 77 | } 78 | else if (aXTag.tagName.equalsIgnoreCase("soundcardPre")) { 79 | parentJDJ.soundCardPre = Integer.parseInt(aXTag.getValue("id")); 80 | } 81 | } 82 | } 83 | return pl; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/xml/PlayListLoader.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.xml; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.OutputStreamWriter; 10 | import java.util.TreeMap; 11 | import java.util.Vector; 12 | 13 | import com.cubaix.kaiDJ.KaiDJ; 14 | import com.cubaix.kaiDJ.db.SongDescr; 15 | import com.cubaix.kaiDJ.db.SongGroup; 16 | 17 | public class PlayListLoader { 18 | 19 | public PlayListLoader() { 20 | } 21 | 22 | /** 23 | * @param parentJDJ 24 | * @param pl 25 | * @param aPathIn 26 | */ 27 | public static void save(KaiDJ parentJDJ, Vector pl, String aPath) { 28 | if (aPath.toLowerCase().endsWith(".m3u")) { 29 | saveM3U(parentJDJ, pl, aPath,"ISO-8859-1"); 30 | return; 31 | } 32 | if (aPath.toLowerCase().endsWith(".m3u8")) { 33 | saveM3U(parentJDJ, pl, aPath,"UTF-8"); 34 | return; 35 | } 36 | saveJDJ(parentJDJ, pl, aPath); 37 | } 38 | 39 | /** 40 | * @param parentJDJ 41 | * @param pl 42 | * @param aPath 43 | */ 44 | public static void saveM3U(KaiDJ parentJDJ, Vector pl, String aPath,String currentCharset) { 45 | try { 46 | BufferedWriter aOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(aPath), currentCharset)); 47 | aOut.write("#JDJ version soft=\"" + KaiDJ._VERSION + "\" pl=\"" + "1.0" + "\"\n"); 48 | for (int s = 0; s < pl.size(); s++) { 49 | SongDescr aDescr = (SongDescr) pl.elementAt(s); 50 | if (aDescr instanceof SongGroup) { 51 | if (((SongGroup) aDescr).kind == SongGroup._KIND_OPEN) { 52 | aOut.write("#JDJ group name=\"" + aDescr.getPath() + "\"\n"); 53 | } else { 54 | aOut.write("#JDJ /group\n"); 55 | } 56 | } else { 57 | aOut.write(aDescr.getPath() + "\n"); 58 | } 59 | } 60 | aOut.flush(); 61 | aOut.close(); 62 | } catch (Throwable t) { 63 | t.printStackTrace(System.err); 64 | } 65 | } 66 | 67 | /** 68 | * @param parentJDJ 69 | * @param pl 70 | * @param aPathIn 71 | */ 72 | public static void saveJDJ(KaiDJ parentJDJ, Vector pl, String aPathIn) { 73 | String aPath; 74 | if (aPathIn.toLowerCase().endsWith(".jdj")) { 75 | aPath = aPathIn; 76 | } else { 77 | aPath = aPathIn + ".jdj"; 78 | } 79 | try { 80 | // Create X structure 81 | Vector aXOs = new Vector(); 82 | aXOs.add(new XTag("")); 83 | aXOs.add(new XObject("\n", XObject.PUNCT)); 84 | aXOs.add(new XTag("")); 85 | aXOs.add(new XObject("\n", XObject.PUNCT)); 86 | String aDecal = "\t"; 87 | for (int s = 0; s < pl.size(); s++) { 88 | SongDescr aDescr = (SongDescr) pl.elementAt(s); 89 | if (aDescr instanceof SongGroup) { 90 | if (((SongGroup) aDescr).kind == SongGroup._KIND_OPEN) { 91 | aXOs.add(new XObject(aDecal, XObject.PUNCT)); 92 | aDecal += "\t"; 93 | aXOs.add(new XTag("")); 94 | } else { 95 | aDecal = aDecal.substring(1); 96 | aXOs.add(new XObject(aDecal, XObject.PUNCT)); 97 | aXOs.add(new XTag("")); 98 | } 99 | } else { 100 | aXOs.add(new XObject(aDecal, XObject.PUNCT)); 101 | aXOs.add(new XTag("")); 102 | } 103 | aXOs.add(new XObject("\n", XObject.PUNCT)); 104 | } 105 | new XLoader("UTF-8").save(aPath, aXOs); 106 | } catch (Throwable t) { 107 | t.printStackTrace(System.err); 108 | } 109 | } 110 | 111 | /** 112 | * @param parentJDJ 113 | * @param aPath 114 | * @return 115 | */ 116 | public static Vector load(KaiDJ parentJDJ, String aPath) { 117 | if (aPath.toLowerCase().endsWith(".m3u")) { 118 | return loadM3U(parentJDJ, aPath,"ISO-8859-1"); 119 | } 120 | if (aPath.toLowerCase().endsWith(".m3u8")) { 121 | return loadM3U(parentJDJ, aPath,"UTF-8"); 122 | } 123 | return loadJDJ(parentJDJ, aPath); 124 | } 125 | 126 | /** 127 | * @param parentJDJ 128 | * @param aPath 129 | * @return 130 | */ 131 | public static Vector loadM3U(KaiDJ parentJDJ, String aPath,String currentCharset) { 132 | Vector pl = new Vector(); 133 | try { 134 | BufferedReader aIn = new BufferedReader(new InputStreamReader(new FileInputStream(aPath), currentCharset)); 135 | String aLine; 136 | Vector aGroups = new Vector(); 137 | String aDir = new File(aPath).getParentFile().getCanonicalPath(); 138 | //EM 13/09/2008 : faster with all in a TreeMap 139 | TreeMap aAll = parentJDJ.db.getAllByPaths(); 140 | while ((aLine = aIn.readLine()) != null) { 141 | if (aLine.toLowerCase().startsWith("#jdj group ")) { 142 | XTag aXTag = new XTag("<" + aLine + ">"); 143 | pl.add(new SongGroup(SongGroup._KIND_OPEN, aXTag.getValue("name"))); 144 | aGroups.add(pl.elementAt(pl.size() - 1)); 145 | } else if (aLine.toLowerCase().startsWith("#jdj /group")) { 146 | //XTag aXTag = new XTag("<" + aLine + ">"); 147 | pl.add(new SongGroup(SongGroup._KIND_CLOSE, ((SongGroup) aGroups.elementAt(aGroups.size() - 1)).getPath())); 148 | aGroups.remove(aGroups.size() - 1); 149 | } else if (!aLine.toLowerCase().startsWith("#")) { 150 | String aNewPath = aLine.trim(); 151 | if(!aNewPath.matches("[a-zA-Z]:.*")){ 152 | //Build a full path 153 | aNewPath = new File(aDir,aNewPath).getCanonicalPath(); 154 | } 155 | //EM 13/09/2008 : faster with all in a TreeMap 156 | SongDescr aDescr = (SongDescr)aAll.get(aNewPath);//parentJDJ.db.searchPath(aNewPath); 157 | if (aDescr == null) {//Direct search 158 | aDescr = parentJDJ.db.searchPath(aNewPath); 159 | } 160 | if (aDescr == null) { 161 | aDescr = new SongDescr(new Integer(-1), aNewPath); 162 | } 163 | pl.add(aDescr); 164 | } 165 | } 166 | } catch (Throwable t) { 167 | t.printStackTrace(System.err); 168 | } 169 | return pl; 170 | } 171 | 172 | /** 173 | * @param parentJDJ 174 | * @param aPath 175 | * @return 176 | */ 177 | public static Vector loadJDJ(KaiDJ parentJDJ, String aPath) { 178 | Vector pl = new Vector(); 179 | Vector aXOs = new XLoader("UTF-8").load(aPath); 180 | Vector aGroups = new Vector(); 181 | //EM 13/09/2008 : faster with all in a TreeMap 182 | TreeMap aAll = parentJDJ.db.getAllByPaths(); 183 | for (int o = 0; o < aXOs.size(); o++) { 184 | XObject aXO = (XObject) aXOs.elementAt(o); 185 | if (aXO.kind == XObject.TAG) { 186 | XTag aXTag = (XTag) aXO; 187 | if (aXTag.tagName.equalsIgnoreCase("group")) { 188 | pl.add(new SongGroup(SongGroup._KIND_OPEN, aXTag.getValue("name"))); 189 | aGroups.add(pl.elementAt(pl.size() - 1)); 190 | } else if (aXTag.tagName.equalsIgnoreCase("/group")) { 191 | pl.add(new SongGroup(SongGroup._KIND_CLOSE, ((SongGroup) aGroups.elementAt(aGroups.size() - 1)).getPath())); 192 | aGroups.remove(aGroups.size() - 1); 193 | } else if (aXTag.tagName.equalsIgnoreCase("song")) { 194 | String aNewPath = aXTag.getValue("path").replaceAll("“", "\""); 195 | //EM 13/09/2008 : faster with all in a TreeMap 196 | SongDescr aDescr = (SongDescr)aAll.get(aNewPath);//parentJDJ.db.searchPath(aNewPath); 197 | if (aDescr == null) {//Direct search 198 | aDescr = parentJDJ.db.searchPath(aNewPath); 199 | } 200 | if (aDescr == null) { 201 | aDescr = new SongDescr(new Integer(-1), aNewPath); 202 | } 203 | pl.add(aDescr); 204 | } 205 | } 206 | } 207 | return pl; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/xml/XObject.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.xml; 2 | 3 | public class XObject 4 | { 5 | public static final int UNKNOWN = -1; 6 | public static final int WORD = 0; 7 | public static final int PUNCT = 1; 8 | public static final int TAG = 2; 9 | public static final int COMMENT = 3; 10 | public static final int SCRIPT = 3; 11 | 12 | public String text; 13 | public int kind = UNKNOWN; 14 | 15 | /** 16 | * 17 | */ 18 | public XObject() 19 | { 20 | } 21 | 22 | /** 23 | * @param aStr 24 | * @param aKind 25 | */ 26 | public XObject(String aStr,int aKind) 27 | { 28 | text = aStr; 29 | kind = aKind; 30 | // System.err.println("ABSgO " + aKind + " = " + text); 31 | } 32 | 33 | /** 34 | * @return 35 | */ 36 | public XObject getClone(){ 37 | return new XObject(text,kind); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/xml/XQualifier.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.xml; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.util.Hashtable; 6 | import java.util.Properties; 7 | import java.util.StringTokenizer; 8 | 9 | public class XQualifier { 10 | //Default values 11 | static public char nbsp = (char)160; 12 | static public String nbspStr = ""+nbsp; 13 | static public String PUNCTS = " ,;:.!?()[]{}\"\'*/+-=|\\�\n\r\t" 14 | + nbsp; 15 | static public String NL_AFTER_CHAR_RE = "[\n\r]"; 16 | static public String NL_AFTER_TAG_RE = "(/(p|tr|h[0-9]|il|title|head)|br)"; 17 | static public String INLINE_TAG_RE = "/?(b|i|u|a|img|font|span)"; 18 | static public String SPECIAL_EMPTY_RE = "(br|hr)"; 19 | static public boolean USE_ALPHA_ENTITIES = false; 20 | static public String EDITABLE_TAG_RE = "(b|i|u|a|img|font|span)"; 21 | static public String HIDDEN_FIELD_RE = "script"; 22 | 23 | static Properties properties = null; 24 | 25 | //EM 06/06/2006 : char entities is now here 26 | // Create and load charEntities table 27 | static public Hashtable alphaentitiesToNum = new Hashtable(); 28 | static public Hashtable numToAlphaentities = new Hashtable(); 29 | 30 | final static String charEntityRessource = "charEntities.tsv"; 31 | 32 | //IMPORTANT 33 | //Always init the settings 34 | static boolean initOk = init(); 35 | 36 | /** 37 | * 38 | */ 39 | static boolean init(){ 40 | properties = new Properties(); 41 | try{ 42 | // InputStream aIS = new FileInputStream(ServerLocationProperties.getInstance().getRootDir() + "/xml.properties");//XQualifier.class.getResourceAsStream("xml.properties"); 43 | // if(aIS == null){ 44 | // //Not found, keep default 45 | // log.debug("Can't find XML properties, will use default values"); 46 | // return false; 47 | // } 48 | // properties.load(aIS); 49 | // String aStr; 50 | // if((aStr = properties.getProperty("nbsp")) != null){ 51 | // nbsp = (char)Integer.parseInt(aStr); 52 | // } 53 | // if((aStr = properties.getProperty("poncts")) != null){ 54 | // PONCTS = aStr + nbsp; 55 | // } 56 | // if((aStr = properties.getProperty("nl.after.char.re")) != null){ 57 | // NL_AFTER_CHAR_RE = aStr; 58 | // } 59 | // if((aStr = properties.getProperty("nl.after.tag.re")) != null){ 60 | // NL_AFTER_TAG_RE = aStr; 61 | // } 62 | // if((aStr = properties.getProperty("inline.tag.re")) != null){ 63 | // INLINE_TAG_RE = aStr; 64 | // } 65 | // if((aStr = properties.getProperty("editable.tag.re")) != null){ 66 | // EDITABLE_TAG_RE = aStr; 67 | // } 68 | // if((aStr = properties.getProperty("hidden.field.re")) != null){ 69 | // HIDDEN_FIELD_RE = aStr; 70 | // } 71 | // if((aStr = properties.getProperty("special.empty.re")) != null){ 72 | // SPECIAL_EMPTY_RE = aStr; 73 | // } 74 | // if((aStr = properties.getProperty("use.alpha.entities")) != null){ 75 | // USE_ALPHA_ENTITIES = (Integer.parseInt(aStr) > 0); 76 | // } 77 | } 78 | catch(Throwable t){ 79 | System.err.println("Can't load XML properties, will use default values" + t); 80 | return false; 81 | } 82 | 83 | //EM 06/06/2006 84 | try{ 85 | loadCharEntities(); 86 | } 87 | catch(Throwable t){ 88 | System.err.println("Can't load char entities"+t); 89 | return false; 90 | } 91 | 92 | return true; 93 | } 94 | 95 | //EM 06/06/2006 : char entities are now here 96 | /** 97 | * 98 | */ 99 | static void loadCharEntities() { 100 | if (!alphaentitiesToNum.isEmpty()) { 101 | // Already loaded ? 102 | return; 103 | } 104 | try { 105 | // Load charEntities ressource 106 | BufferedReader aBR = new BufferedReader(new InputStreamReader(XLoader.class.getResourceAsStream(charEntityRessource))); 107 | String aLine; 108 | while ((aLine = aBR.readLine()) != null) { 109 | StringTokenizer aST = new StringTokenizer(aLine, "\t", false); 110 | String aEntAlpha = aST.nextToken(); 111 | /*String aEntNum =*/ aST.nextToken(); 112 | String aExa = aST.nextToken(); 113 | Integer aNum = Integer.decode(aExa); 114 | alphaentitiesToNum.put(aEntAlpha, aNum); 115 | numToAlphaentities.put(aNum,aEntAlpha); 116 | } 117 | } catch (Throwable t) { 118 | System.err.println("Can't load entity char table !"+ t); 119 | System.exit(-1); 120 | } 121 | } 122 | 123 | /** 124 | * @param aEntity 125 | * @return 126 | */ 127 | static public String transcodeFromEntity(String aEntity) { 128 | Integer aValue = null; 129 | if ((aValue = (Integer) XQualifier.alphaentitiesToNum.get(aEntity)) != null) { 130 | // Found in table 131 | char aChar = (char) (aValue.intValue() & 0xFFFF); 132 | return "" + aChar; 133 | } 134 | if (aEntity.matches("&#[0-9]+;")) { 135 | // Decode num 136 | char aChar = (char) (Integer.parseInt(aEntity.substring(2, aEntity.length() - 1)) & 0xFFFF); 137 | return "" + aChar; 138 | } 139 | if (aEntity.matches("&#[xX][0-9A-Fa-f]+;")) { 140 | // Decode hexa 141 | String aHexa = "0x" + aEntity.substring(3, aEntity.length() - 1); 142 | char aChar = (char) (Integer.decode(aHexa).intValue() & 0xFFFF); 143 | return "" + aChar; 144 | } 145 | System.err.println("Unknown entity '" + aEntity + "', will be kept like this"); 146 | // Not found 147 | return null; 148 | } 149 | 150 | //EM 06/06/2006 : char entities moved here 151 | /** 152 | * @param aStrIn 153 | * @return 154 | */ 155 | static public String transcodeToEntities(String aStrIn,boolean aUseLowCharTable) { 156 | StringBuffer aSB = new StringBuffer(); 157 | char aChar; 158 | int aInt; 159 | String aEntity; 160 | int aEntLen; 161 | for (int i = 0; i < aStrIn.length(); i++) { 162 | aChar = aStrIn.charAt(i); 163 | aInt = aChar & 0xFFFFFFFF; 164 | //First check for a & < > conversions 165 | if(aChar == '&'){ 166 | if((aEntLen = XQualifier.entityLen(aStrIn,i)) > 0){ 167 | //Ok it's an entity 168 | aSB.append(aStrIn.substring(i,i + aEntLen)); 169 | i += aEntLen - 1; 170 | continue; 171 | } 172 | //Not en entity, need to be transcoded 173 | aSB.append("&"); 174 | continue; 175 | } 176 | else if(aChar == '<'){ 177 | //Must be transcoded 178 | aSB.append("<"); 179 | continue; 180 | } 181 | else if(aChar == '>'){ 182 | //Must be transcoded 183 | aSB.append(">"); 184 | continue; 185 | } 186 | //Check for std conversions 187 | //EM 06/06/2006 188 | //if(charsetChecked && aInt <= 255) { 189 | if(aUseLowCharTable && aInt <= 255) { 190 | //For known charset, use low char table 191 | aSB.append(aChar); 192 | } 193 | else{ 194 | //Search for a conversion 195 | if(XQualifier.USE_ALPHA_ENTITIES && (aEntity = (String)XQualifier.numToAlphaentities.get(new Integer(aInt))) != null){ 196 | //Ok, alpha entity found 197 | aSB.append(aEntity); 198 | } 199 | else if(aInt <= 255){ 200 | //Style use low char table 201 | aSB.append(aChar); 202 | } 203 | else{ 204 | //Use decimal entity 205 | aSB.append("&#" + (aChar & 0xFFFF) + ";"); 206 | } 207 | } 208 | } 209 | return aSB.toString(); 210 | } 211 | 212 | /** 213 | * @param aChar 214 | * @return 215 | */ 216 | static public boolean useAlphaEntities(){ 217 | return USE_ALPHA_ENTITIES; 218 | } 219 | 220 | /** 221 | * @param aChar 222 | * @return 223 | */ 224 | static public boolean isPonctChar(char aChar){ 225 | return PUNCTS.indexOf(aChar) >= 0; 226 | } 227 | 228 | /** 229 | * @param aStr 230 | * @param aStartPos 231 | * @return 232 | */ 233 | static public int entityLen(String aStr,int aStartPos){ 234 | if(aStr.charAt(aStartPos) != '&'){ 235 | //Not possible 236 | return -1; 237 | } 238 | int aPos = aStartPos; 239 | String aChar; 240 | while(aPos < aStr.length()){ 241 | aChar = aStr.substring(aPos,aPos+1); 242 | if(aChar.equals(";")){ 243 | //Could be the end of entity 244 | if(aStr.substring(aStartPos,aPos + 1).matches("&([a-zA-Z]+|#[0-9]+|#0[xX][0-9a-fA-F]+);")){ 245 | //Ok entity 246 | return aPos + 1 - aStartPos; 247 | } 248 | //Not a good entity 249 | return -1; 250 | } 251 | if(!aChar.matches("[�-9a-zA-Z;]")){ 252 | //Impossible 253 | return -1; 254 | } 255 | aPos++; 256 | } 257 | return -1; 258 | } 259 | 260 | /** 261 | * @param aXLT 262 | * @return 263 | */ 264 | // static public boolean nlAfter(XLineToken aXLT) { 265 | // switch(aXLT.kind){ 266 | // case XLineToken.COLLAPSE: 267 | // for(int o = 0;o < ((XLineTokenCollapse)aXLT).chain.size();o++){ 268 | // if(nlAfter((XObject)((XLineTokenCollapse)aXLT).chain.elementAt(o))){ 269 | // return true; 270 | // } 271 | // } 272 | // return false; 273 | // default: 274 | // return nlAfter(aXLT.xO); 275 | // } 276 | // //return false; 277 | // } 278 | 279 | /** 280 | * @param aXO 281 | * @return 282 | */ 283 | static public boolean nlAfter(XObject aXO) { 284 | if(aXO.text.matches(NL_AFTER_CHAR_RE)){ 285 | return true; 286 | } 287 | if (aXO.kind != XObject.TAG) { 288 | return false; 289 | } 290 | if (((XTag) aXO).tagName.toLowerCase().matches(NL_AFTER_TAG_RE)) { 291 | return true; 292 | } 293 | return false; 294 | } 295 | 296 | /** 297 | * @param aT 298 | * @return 299 | */ 300 | static public boolean isInline(XTag aT){ 301 | return aT.tagName.toLowerCase().matches(INLINE_TAG_RE); 302 | } 303 | 304 | /** 305 | * @param aT 306 | * @return 307 | */ 308 | static public boolean isEditableTag(XTag aT){ 309 | return aT.tagName.toLowerCase().matches(EDITABLE_TAG_RE); 310 | } 311 | 312 | /** 313 | * @param aT 314 | * @return 315 | */ 316 | static public boolean isHiddenField(XTag aT){ 317 | return aT.tagName.toLowerCase().matches(HIDDEN_FIELD_RE); 318 | } 319 | 320 | /** 321 | * @return 322 | */ 323 | static public boolean isSpecialEmpty(XTag aT){ 324 | return aT.tagName.toLowerCase().matches(SPECIAL_EMPTY_RE); 325 | } 326 | 327 | /** 328 | * @return 329 | */ 330 | static public boolean isOpen(XTag aT){ 331 | if(isSpecialEmpty(aT)){ 332 | return false; 333 | } 334 | if(aT.text.matches("<( */.*|.*/ *)>")){ 335 | return false; 336 | } 337 | return true; 338 | } 339 | 340 | /** 341 | * @return 342 | */ 343 | static public boolean isClose(XTag aT){ 344 | return aT.text.matches("< */.*>"); 345 | } 346 | 347 | /** 348 | * @return 349 | */ 350 | static public boolean isEmpty(XTag aT){ 351 | if(isSpecialEmpty(aT)){ 352 | return true; 353 | } 354 | return aT.text.matches("<.*/ *>"); 355 | } 356 | 357 | } 358 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/xml/XTag.java: -------------------------------------------------------------------------------- 1 | package com.cubaix.kaiDJ.xml; 2 | 3 | import java.util.*; 4 | 5 | public class XTag extends XObject { 6 | 7 | public String tagName; 8 | Vector names, values; 9 | 10 | public boolean parseOk = true; 11 | 12 | /** 13 | * @param aStr 14 | */ 15 | public XTag(String aStr) { 16 | text = aStr; 17 | kind = TAG; 18 | 19 | names = new Vector(); 20 | values = new Vector(); 21 | 22 | parse(); 23 | 24 | // System.err.println("XTag name=" + tagName + " Names = " + names + 25 | // " Values = " + values); 26 | } 27 | 28 | public XObject getClone(){ 29 | return new XTag(text); 30 | } 31 | 32 | /** 33 | * 34 | */ 35 | void parse() { 36 | parseOk = true; 37 | StringTokenizer aTokenizer = new StringTokenizer(text, " \t\n\r<>=\"\'", true); 38 | int aState = -1; 39 | String aTok = null, aTmpName = null, aName = null, aValue = null; 40 | 41 | while (aState >= -1 && aTokenizer.hasMoreTokens()) { 42 | switch (aState) { 43 | case 2: // Attribute = '' 44 | aTok = aTokenizer.nextToken(); 45 | if ("\'".equals(aTok)) { 46 | // End 47 | names.add(aName); 48 | values.add(aValue); 49 | aName = null; 50 | aValue = null; 51 | aState = 0; 52 | continue; 53 | } 54 | aValue += aTok; 55 | break; 56 | case 1: // Attribute = "" 57 | aTok = aTokenizer.nextToken(); 58 | if ("\"".equals(aTok)) { 59 | // End 60 | names.add(aName); 61 | values.add(aValue); 62 | aName = null; 63 | aValue = null; 64 | aState = 0; 65 | continue; 66 | } 67 | aValue += aTok; 68 | break; 69 | case 0: 70 | default: 71 | aTok = aTokenizer.nextToken(); 72 | if (">".equals(aTok)) { 73 | aState = -2; 74 | if(aTokenizer.hasMoreElements()){ 75 | // Error 76 | System.err.println("Warning, bad tag attribute : " + text); 77 | parseOk = false; 78 | } 79 | continue; 80 | } 81 | if ("<".equals(aTok)) { 82 | if(aState != -1){ 83 | // Error 84 | System.err.println("Warning, bad tag attribute : " + text); 85 | parseOk = false; 86 | } 87 | //Begin of tag 88 | aState = 0; 89 | continue; 90 | } 91 | if (" ".equals(aTok) || "\t".equals(aTok) || "\r".equals(aTok) || "\n".equals(aTok)) { 92 | //No interest 93 | continue; 94 | } 95 | if ("=".equals(aTok)) { 96 | if(aTmpName == null){ 97 | // Error 98 | System.err.println("Warning, bad tag attribute : " + text); 99 | parseOk = false; 100 | } 101 | aName = aTmpName; 102 | aValue = ""; 103 | aTmpName = null; 104 | continue; 105 | } 106 | if ("\"".equals(aTok)) { 107 | if (aName == null) { 108 | // Error 109 | System.err.println("Warning, bad tag attribute : " + text); 110 | parseOk = false; 111 | } 112 | aState = 1; 113 | continue; 114 | } 115 | if ("\'".equals(aTok)) { 116 | if (aName == null) { 117 | // Error 118 | parseOk = false; 119 | System.err.println("Error, bad tag attribute : " + text); 120 | } 121 | aState = 2; 122 | continue; 123 | } 124 | if (aName != null && aName.length() > 0) { 125 | names.add(aName); 126 | values.add(aTok); 127 | aName = null; 128 | aValue = null; 129 | continue; 130 | } 131 | if (tagName == null) { 132 | tagName = aTok; 133 | if (tagName.startsWith("!")) { 134 | // Not a parsable tag ! 135 | parseOk = false; 136 | return; 137 | } 138 | continue; 139 | } 140 | if(aTmpName != null){ 141 | // Error 142 | System.err.println("Warning, bad tag attribute : " + text); 143 | parseOk = false; 144 | } 145 | aTmpName = aTok; 146 | break; 147 | } 148 | } 149 | //EM 29/05/2006 150 | // also take aAttrName into account : a possible attribute without a value 151 | if(aState >= 0 || aName != null || aValue != null || aTmpName != null){ 152 | parseOk = false; 153 | } 154 | } 155 | 156 | /** 157 | * @param aName 158 | * @return 159 | */ 160 | public String getValue(String aName) { 161 | for (int i = 0; i < names.size(); i++) { 162 | if (aName.equalsIgnoreCase((String) names.elementAt(i))) { 163 | if (i > values.size()) { 164 | return null; 165 | } 166 | return (String) values.elementAt(i); 167 | } 168 | } 169 | return null; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/com/cubaix/kaiDJ/xml/charEntities.tsv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EtienneAb3d/karaok-AI/2eaaf4fba6234ad6206e112c59a0d6143540aace/src/com/cubaix/kaiDJ/xml/charEntities.tsv -------------------------------------------------------------------------------- /src/javazoom/jlgui/basicplayer/BasicController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BasicController. 3 | * 4 | * JavaZOOM : jlgui@javazoom.net 5 | * http://www.javazoom.net 6 | * 7 | *----------------------------------------------------------------------- 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Library General Public License as published 10 | * by the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Library General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Library General Public 19 | * License along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | *---------------------------------------------------------------------- 22 | */ 23 | package javazoom.jlgui.basicplayer; 24 | 25 | import java.io.File; 26 | import java.io.InputStream; 27 | import java.net.URL; 28 | 29 | /** 30 | * This interface defines player controls available. 31 | */ 32 | public interface BasicController 33 | { 34 | /** 35 | * Open inputstream to play. 36 | * @param in 37 | * @throws BasicPlayerException 38 | */ 39 | public void open(InputStream in) throws BasicPlayerException; 40 | 41 | /** 42 | * Open file to play. 43 | * @param file 44 | * @throws BasicPlayerException 45 | */ 46 | public void open(File file) throws BasicPlayerException; 47 | 48 | /** 49 | * Open URL to play. 50 | * @param url 51 | * @throws BasicPlayerException 52 | */ 53 | public void open(URL url) throws BasicPlayerException; 54 | 55 | /** 56 | * Skip bytes. 57 | * @param bytes 58 | * @return bytes skipped according to audio frames constraint. 59 | * @throws BasicPlayerException 60 | */ 61 | public long seek(long bytes) throws BasicPlayerException; 62 | 63 | /** 64 | * Start playback. 65 | * @throws BasicPlayerException 66 | */ 67 | public void play() throws BasicPlayerException; 68 | 69 | /** 70 | * Stop playback. 71 | * @throws BasicPlayerException 72 | */ 73 | public void stop() throws BasicPlayerException; 74 | 75 | /** 76 | * Pause playback. 77 | * @throws BasicPlayerException 78 | */ 79 | public void pause() throws BasicPlayerException; 80 | 81 | /** 82 | * Resume playback. 83 | * @throws BasicPlayerException 84 | */ 85 | public void resume() throws BasicPlayerException; 86 | 87 | /** 88 | * Sets Pan (Balance) value. 89 | * Linear scale : -1.0 <--> +1.0 90 | * @param pan value from -1.0 to +1.0 91 | * @throws BasicPlayerException 92 | */ 93 | public void setPan(double pan) throws BasicPlayerException; 94 | 95 | /** 96 | * Sets Gain value. 97 | * Linear scale 0.0 <--> 1.0 98 | * @param gain value from 0.0 to 1.0 99 | * @throws BasicPlayerException 100 | */ 101 | public void setGain(double gain) throws BasicPlayerException; 102 | } 103 | -------------------------------------------------------------------------------- /src/javazoom/jlgui/basicplayer/BasicPlayerEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BasicPlayerEvent. 3 | * 4 | * JavaZOOM : jlgui@javazoom.net 5 | * http://www.javazoom.net 6 | * 7 | *----------------------------------------------------------------------- 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Library General Public License as published 10 | * by the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Library General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Library General Public 19 | * License along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | *---------------------------------------------------------------------- 22 | */ 23 | package javazoom.jlgui.basicplayer; 24 | 25 | /** 26 | * This class implements player events. 27 | */ 28 | public class BasicPlayerEvent 29 | { 30 | public static final int UNKNOWN = -1; 31 | public static final int OPENING = 0; 32 | public static final int OPENED = 1; 33 | public static final int PLAYING = 2; 34 | public static final int STOPPED = 3; 35 | public static final int PAUSED = 4; 36 | public static final int RESUMED = 5; 37 | public static final int SEEKING = 6; 38 | public static final int SEEKED = 7; 39 | public static final int EOM = 8; 40 | public static final int PAN = 9; 41 | public static final int GAIN = 10; 42 | private int code = UNKNOWN; 43 | private int position = -1; 44 | private double value = -1.0; 45 | private Object source = null; 46 | private Object description = null; 47 | 48 | /** 49 | * Constructor 50 | * @param source of the event 51 | * @param code of the envent 52 | * @param position optional stream position 53 | * @param value opitional control value 54 | * @param desc optional description 55 | */ 56 | public BasicPlayerEvent(Object source, int code, int position, double value, Object desc) 57 | { 58 | this.value = value; 59 | this.position = position; 60 | this.source = source; 61 | this.code = code; 62 | this.description = desc; 63 | } 64 | 65 | /** 66 | * Return code of the event triggered. 67 | * @return 68 | */ 69 | public int getCode() 70 | { 71 | return code; 72 | } 73 | 74 | /** 75 | * Return position in the stream when event occured. 76 | * @return 77 | */ 78 | public int getPosition() 79 | { 80 | return position; 81 | } 82 | 83 | /** 84 | * Return value related to event triggered. 85 | * @return 86 | */ 87 | public double getValue() 88 | { 89 | return value; 90 | } 91 | 92 | /** 93 | * Return description. 94 | * @return 95 | */ 96 | public Object getDescription() 97 | { 98 | return description; 99 | } 100 | 101 | public Object getSource() 102 | { 103 | return source; 104 | } 105 | 106 | public String toString() 107 | { 108 | if (code == OPENED) return "OPENED:" + position; 109 | else if (code == OPENING) return "OPENING:" + position + ":" + description; 110 | else if (code == PLAYING) return "PLAYING:" + position; 111 | else if (code == STOPPED) return "STOPPED:" + position; 112 | else if (code == PAUSED) return "PAUSED:" + position; 113 | else if (code == RESUMED) return "RESUMED:" + position; 114 | else if (code == SEEKING) return "SEEKING:" + position; 115 | else if (code == SEEKED) return "SEEKED:" + position; 116 | else if (code == EOM) return "EOM:" + position; 117 | else if (code == PAN) return "PAN:" + value; 118 | else if (code == GAIN) return "GAIN:" + value; 119 | else return "UNKNOWN:" + position; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/javazoom/jlgui/basicplayer/BasicPlayerEventLauncher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BasicPlayerEventLauncher. 3 | * 4 | * JavaZOOM : jlgui@javazoom.net 5 | * http://www.javazoom.net 6 | * 7 | *----------------------------------------------------------------------- 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Library General Public License as published 10 | * by the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Library General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Library General Public 19 | * License along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | *---------------------------------------------------------------------- 22 | */ 23 | package javazoom.jlgui.basicplayer; 24 | 25 | import java.util.Collection; 26 | import java.util.Iterator; 27 | 28 | /** 29 | * This class implements a threaded events launcher. 30 | */ 31 | public class BasicPlayerEventLauncher extends Thread 32 | { 33 | private int code = -1; 34 | private int position = -1; 35 | private double value = 0.0; 36 | private Object description = null; 37 | private Collection listeners = null; 38 | private Object source = null; 39 | 40 | /** 41 | * Contructor. 42 | * @param code 43 | * @param position 44 | * @param value 45 | * @param description 46 | * @param listeners 47 | * @param source 48 | */ 49 | public BasicPlayerEventLauncher(int code, int position, double value, Object description, Collection listeners, Object source) 50 | { 51 | super(); 52 | this.code = code; 53 | this.position = position; 54 | this.value = value; 55 | this.description = description; 56 | this.listeners = listeners; 57 | this.source = source; 58 | } 59 | 60 | public void run() 61 | { 62 | if (listeners != null) 63 | { 64 | Iterator it = listeners.iterator(); 65 | while (it.hasNext()) 66 | { 67 | BasicPlayerListener bpl = (BasicPlayerListener) it.next(); 68 | BasicPlayerEvent event = new BasicPlayerEvent(source, code, position, value, description); 69 | bpl.stateUpdated(event); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/javazoom/jlgui/basicplayer/BasicPlayerException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BasicPlayerException. 3 | * 4 | * JavaZOOM : jlgui@javazoom.net 5 | * http://www.javazoom.net 6 | * 7 | *----------------------------------------------------------------------- 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Library General Public License as published 10 | * by the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Library General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Library General Public 19 | * License along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | *---------------------------------------------------------------------- 22 | */ 23 | package javazoom.jlgui.basicplayer; 24 | 25 | import java.io.PrintStream; 26 | import java.io.PrintWriter; 27 | 28 | /** 29 | * This class implements custom exception for basicplayer. 30 | */ 31 | public class BasicPlayerException extends Exception 32 | { 33 | public static final String GAINCONTROLNOTSUPPORTED = "Gain control not supported"; 34 | public static final String PANCONTROLNOTSUPPORTED = "Pan control not supported"; 35 | public static final String WAITERROR = "Wait error"; 36 | public static final String CANNOTINITLINE = "Cannot init line"; 37 | public static final String SKIPNOTSUPPORTED = "Skip not supported"; 38 | private Throwable cause = null; 39 | 40 | public BasicPlayerException() 41 | { 42 | super(); 43 | } 44 | 45 | public BasicPlayerException(String msg) 46 | { 47 | super(msg); 48 | } 49 | 50 | public BasicPlayerException(Throwable cause) 51 | { 52 | super(); 53 | this.cause = cause; 54 | } 55 | 56 | public BasicPlayerException(String msg, Throwable cause) 57 | { 58 | super(msg); 59 | this.cause = cause; 60 | } 61 | 62 | public Throwable getCause() 63 | { 64 | return cause; 65 | } 66 | 67 | /** 68 | * Returns the detail message string of this throwable. If it was 69 | * created with a null message, returns the following: 70 | * (cause==null ? null : cause.toString()). 71 | */ 72 | public String getMessage() 73 | { 74 | if (super.getMessage() != null) 75 | { 76 | return super.getMessage(); 77 | } 78 | else if (cause != null) 79 | { 80 | return cause.toString(); 81 | } 82 | else 83 | { 84 | return null; 85 | } 86 | } 87 | 88 | public void printStackTrace() 89 | { 90 | printStackTrace(System.err); 91 | } 92 | 93 | public void printStackTrace(PrintStream out) 94 | { 95 | synchronized (out) 96 | { 97 | PrintWriter pw = new PrintWriter(out, false); 98 | printStackTrace(pw); 99 | pw.flush(); 100 | } 101 | } 102 | 103 | public void printStackTrace(PrintWriter out) 104 | { 105 | if (cause != null) cause.printStackTrace(out); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/javazoom/jlgui/basicplayer/BasicPlayerListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BasicPlayerListener. 3 | * 4 | * JavaZOOM : jlgui@javazoom.net 5 | * http://www.javazoom.net 6 | * 7 | *----------------------------------------------------------------------- 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU Library General Public License as published 10 | * by the Free Software Foundation; either version 2 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Library General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Library General Public 19 | * License along with this program; if not, write to the Free Software 20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | *---------------------------------------------------------------------- 22 | */ 23 | package javazoom.jlgui.basicplayer; 24 | 25 | import java.util.Map; 26 | 27 | /** 28 | * This interface defines callbacks methods that will be notified 29 | * for all registered BasicPlayerListener of BasicPlayer. 30 | */ 31 | public interface BasicPlayerListener 32 | { 33 | /** 34 | * Open callback, stream is ready to play. 35 | * 36 | * properties map includes audio format dependant features such as 37 | * bitrate, duration, frequency, channels, number of frames, vbr flag, 38 | * id3v2/id3v1 (for MP3 only), comments (for Ogg Vorbis), ... 39 | * 40 | * @param stream could be File, URL or InputStream 41 | * @param properties audio stream properties. 42 | */ 43 | public void opened(Object stream, Map properties); 44 | 45 | /** 46 | * Progress callback while playing. 47 | * 48 | * This method is called severals time per seconds while playing. 49 | * properties map includes audio format features such as 50 | * instant bitrate, microseconds position, current frame number, ... 51 | * 52 | * @param bytesread from encoded stream. 53 | * @param microseconds elapsed (reseted after a seek !). 54 | * @param pcmdata PCM samples. 55 | * @param properties audio stream parameters. 56 | */ 57 | public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties); 58 | 59 | /** 60 | * Notification callback for basicplayer events such as opened, eom ... 61 | * 62 | * @param event 63 | */ 64 | public void stateUpdated(BasicPlayerEvent event); 65 | 66 | /** 67 | * A handle to the BasicPlayer, plugins may control the player through 68 | * the controller (play, stop, ...) 69 | * @param controller : a handle to the player 70 | */ 71 | public void setController(BasicController controller); 72 | } 73 | -------------------------------------------------------------------------------- /src/kj/audio/KJAudioDataConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created on Jul 10, 2004 3 | * 4 | * TODO To change the template for this generated file go to 5 | * Window - Preferences - Java - Code Generation - Code and Comments 6 | */ 7 | package kj.audio; 8 | 9 | /** 10 | * @author Kris 11 | * 12 | * TODO To change the template for this generated type comment go to 13 | * Window - Preferences - Java - Code Generation - Code and Comments 14 | */ 15 | public interface KJAudioDataConsumer { 16 | 17 | void writeAudioData( byte[] pAudioData ); 18 | void writeAudioData( byte[] pAudioData, int pOffset, int pLength ); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/kj/dsp/KJDigitalSignalProcessingAudioDataConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created on Nov 30, 2004 3 | * 4 | * TODO To change the template for this generated file go to 5 | * Window - Preferences - Java - Code Generation - Code and Comments 6 | */ 7 | package kj.dsp; 8 | 9 | import java.util.ArrayList; 10 | 11 | import javax.sound.sampled.SourceDataLine; 12 | 13 | import com.cubaix.kaiDJ.KaiDJ; 14 | 15 | import kj.audio.KJAudioDataConsumer; 16 | //import kj.ui.KJJukeBox; 17 | 18 | /** 19 | * @author Kris 20 | * 21 | * TODO To change the template for this generated type comment go to 22 | * Window - Preferences - Java - Code Generation - Code and Comments 23 | */ 24 | public final class KJDigitalSignalProcessingAudioDataConsumer implements KJAudioDataConsumer { 25 | //EM 29/04/2009 : parentJDJ 26 | protected KaiDJ parentJDJ; 27 | 28 | private static final int DEFAULT_SAMPLE_SIZE = 2048; 29 | private static final int DEFAULT_FPS = 70; 30 | 31 | public static final int SAMPLE_TYPE_EIGHT_BIT = 1; 32 | public static final int SAMPLE_TYPE_SIXTEEN_BIT = 2; 33 | public static final int CHANNEL_MODE_MONO = 1; 34 | public static final int CHANNEL_MODE_STEREO = 2; 35 | 36 | //EM 14/11/2008 : public 37 | public Object readWriteLock = new Object(); 38 | 39 | //EM 14/11/2008 : public 40 | public SourceDataLine sourceDataLine; 41 | 42 | //EM 14/11/2008 : public 43 | public int sampleSize; 44 | 45 | //EM 14/11/2008 : public 46 | public long fpsAsNS; 47 | public long desiredFpsAsNS; 48 | 49 | //EM 14/11/2008 : public 50 | public byte[] audioDataBuffer; 51 | 52 | //EM 14/11/2008 : public 53 | public float[] left; 54 | public float[] right; 55 | 56 | private int position; 57 | //EM 14/11/2008 : public 58 | public long offset; 59 | 60 | //EM 14/11/2008 : externalization of inner class for more efficiency 61 | //(possibly not a big gain, but much more fluent in JOP profiler) 62 | //private SignalProcessor signalProcessor; 63 | private KJDigitalSignalProcessor1 signalProcessor; 64 | 65 | //EM 14/11/2008 : public 66 | public ArrayList dsps = new ArrayList(); 67 | 68 | //EM 14/11/2008 : public 69 | public int sampleType; 70 | //EM 14/11/2008 : public 71 | public int channelMode; 72 | 73 | /** 74 | * Default constructor creates a DSPAC with DEFAULT_SAMPLE_SIZE and DEFAULT_FPS as 75 | * parameters. 76 | */ 77 | //EM 29/04/2009 : parentJDJ 78 | public KJDigitalSignalProcessingAudioDataConsumer(KaiDJ aParentJDJ) { 79 | this( DEFAULT_SAMPLE_SIZE, DEFAULT_FPS ); 80 | 81 | //EM 29/04/2009 82 | parentJDJ = aParentJDJ; 83 | } 84 | 85 | /** 86 | * @param pSampleSize The sample size to extract from audio data sent to the SourceDataLine. 87 | * @param pFramePerSecond The desired refresh rate per second of registered DSP's. 88 | */ 89 | public KJDigitalSignalProcessingAudioDataConsumer( int pSampleSize, int pFramesPerSecond ) { 90 | this( pSampleSize, pFramesPerSecond, SAMPLE_TYPE_SIXTEEN_BIT, CHANNEL_MODE_STEREO ); 91 | } 92 | 93 | /** 94 | * @param pSampleSize The sample size to extract from audio data sent to the SourceDataLine. 95 | * @param pFramePerSecond The desired refresh rate per second of registered DSP's. 96 | * @param pSampleType The sample type SAMPLE_TYPE_EIGHT_BIT or SAMPLE_TYPE_SIXTEEN_BIT. 97 | * @param pFramePerSecond The channel mode CHANNEL_MODE_MONO or CHANNEL_MODE_STEREO. 98 | */ 99 | public KJDigitalSignalProcessingAudioDataConsumer( int pSampleSize, int pFramesPerSecond, int pSampleType, int pChannelMode ) { 100 | 101 | sampleSize = pSampleSize; 102 | desiredFpsAsNS = 1000000000L / (long)pFramesPerSecond; 103 | fpsAsNS = desiredFpsAsNS; 104 | 105 | setSampleType( pSampleType ); 106 | setChannelMode( pChannelMode ); 107 | } 108 | 109 | /** 110 | * Adds a DSP to the DSPAC and forwards any audio data to it at the specific 111 | * frame rate. 112 | * 113 | * @param A class implementing the KJDigitalSignalProcessor interface. 114 | */ 115 | public void add( KJDigitalSignalProcessor pSignalProcessor ) { 116 | dsps.add( pSignalProcessor ); 117 | } 118 | 119 | /** 120 | * Removes the specified DSP from this DSPAC if it exists. 121 | * 122 | * @param A class implementing the KJDigitalSignalProcessor interface. 123 | */ 124 | public void remove( KJDigitalSignalProcessor pSignalProcessor ) { 125 | dsps.remove( pSignalProcessor ); 126 | } 127 | 128 | public void setChannelMode( int pChannelMode ) { 129 | channelMode = pChannelMode; 130 | } 131 | 132 | public void setSampleType( int pSampleType ) { 133 | sampleType = pSampleType; 134 | } 135 | 136 | /** 137 | * Start monitoring the specified SourceDataLine. 138 | * 139 | * @param pSdl A SourceDataLine. 140 | */ 141 | public synchronized void start( SourceDataLine pSdl ) { 142 | 143 | // -- Stop processing previous source data line. 144 | if ( signalProcessor != null ) { 145 | stop(); 146 | } 147 | 148 | if ( signalProcessor == null ) { 149 | 150 | // System.out.println( "ADBS: " + pSdl.getBufferSize() ); 151 | 152 | sourceDataLine = pSdl; 153 | 154 | // -- Allocate double the memory than the SDL to prevent 155 | // buffer overlapping. 156 | audioDataBuffer = new byte[ pSdl.getBufferSize() << 1 ]; 157 | 158 | left = new float[ sampleSize ]; 159 | right = new float[ sampleSize ]; 160 | 161 | position = 0; 162 | offset = 0; 163 | 164 | //EM 14/11/2008 : externalization of inner class for more efficiency 165 | signalProcessor = new /*SignalProcessor();/*/KJDigitalSignalProcessor1(this); 166 | 167 | Thread aTh = new Thread( signalProcessor ,"DSP SignalProcessor"); 168 | aTh.start(); 169 | } 170 | 171 | } 172 | 173 | /** 174 | * Stop monitoring the currect SourceDataLine. 175 | */ 176 | public synchronized void stop() { 177 | 178 | if ( signalProcessor != null ) { 179 | 180 | signalProcessor.stop(); 181 | signalProcessor = null; 182 | 183 | audioDataBuffer = null; 184 | sourceDataLine = null; 185 | 186 | } 187 | 188 | } 189 | 190 | private void storeAudioData( byte[] pAudioData, int pOffset, int pLength ) { 191 | 192 | synchronized( readWriteLock ) { 193 | 194 | if ( audioDataBuffer == null ) { 195 | return; 196 | } 197 | 198 | int wOverrun = 0; 199 | 200 | if ( position + pLength > audioDataBuffer.length - 1 ) { 201 | 202 | wOverrun = ( position + pLength ) - audioDataBuffer.length; 203 | pLength = audioDataBuffer.length - position; 204 | 205 | } 206 | 207 | System.arraycopy( pAudioData, pOffset, audioDataBuffer, position, pLength ); 208 | 209 | if ( wOverrun > 0 ) { 210 | 211 | System.arraycopy( pAudioData, pOffset + pLength, audioDataBuffer, 0, wOverrun ); 212 | position = wOverrun; 213 | 214 | } else { 215 | position += pLength; 216 | } 217 | 218 | // KJJukeBox.getDSPDialog().setDSPBufferInfo( 219 | // position, 220 | // pOffset, 221 | // pLength, 222 | // audioDataBuffer.length ); 223 | 224 | } 225 | 226 | } 227 | 228 | /* (non-Javadoc) 229 | * @see kj.audio.KJAudioDataConsumer#writeAudioData(byte[]) 230 | */ 231 | public void writeAudioData( byte[] pAudioData ) { 232 | storeAudioData( pAudioData, 0, pAudioData.length ); 233 | } 234 | 235 | /* (non-Javadoc) 236 | * @see kj.audio.KJAudioDataConsumer#writeAudioData(byte[], int, int) 237 | */ 238 | public void writeAudioData( byte[] pAudioData, int pOffset, int pLength ) { 239 | storeAudioData( pAudioData, pOffset, pLength ); 240 | } 241 | 242 | private class SignalProcessor implements Runnable { 243 | 244 | boolean process = true; 245 | 246 | long lfp = 0; 247 | 248 | int frameSize; 249 | 250 | public SignalProcessor() { 251 | frameSize = sourceDataLine.getFormat().getFrameSize(); 252 | } 253 | 254 | private int calculateSamplePosition() { 255 | 256 | synchronized( readWriteLock ) { 257 | 258 | long wFp = sourceDataLine.getLongFramePosition(); 259 | long wNfp = lfp; 260 | 261 | lfp = wFp; 262 | 263 | int wSdp = (int)( (long)( wNfp * frameSize ) - (long)( audioDataBuffer.length * offset ) ); 264 | 265 | // KJJukeBox.getDSPDialog().setOutputPositionInfo( 266 | // wFp, 267 | // wFp - wNfp, 268 | // wSdp ); 269 | 270 | return wSdp; 271 | 272 | } 273 | 274 | } 275 | 276 | private void processSamples( int pPosition ) { 277 | 278 | int c = pPosition; 279 | 280 | if ( channelMode == CHANNEL_MODE_MONO && sampleType == SAMPLE_TYPE_EIGHT_BIT ) { 281 | 282 | for( int a = 0; a < sampleSize; a++, c++ ) { 283 | 284 | if ( c >= audioDataBuffer.length ) { 285 | offset++; 286 | c = ( c - audioDataBuffer.length ); 287 | } 288 | 289 | left[ a ] = (float)( (int)audioDataBuffer[ c ] / 128.0f ); 290 | right[ a ] = left[ a ]; 291 | 292 | } 293 | 294 | } else if ( channelMode == CHANNEL_MODE_STEREO && sampleType == SAMPLE_TYPE_EIGHT_BIT ) { 295 | 296 | for( int a = 0; a < sampleSize; a++, c += 2 ) { 297 | 298 | if ( c >= audioDataBuffer.length ) { 299 | offset++; 300 | c = ( c - audioDataBuffer.length ); 301 | } 302 | 303 | left[ a ] = (float)( (int)audioDataBuffer[ c ] / 128.0f ); 304 | right[ a ] = (float)( (int)audioDataBuffer[ c + 1 ] / 128.0f ); 305 | 306 | } 307 | 308 | } else if ( channelMode == CHANNEL_MODE_MONO && sampleType == SAMPLE_TYPE_SIXTEEN_BIT ) { 309 | 310 | for( int a = 0; a < sampleSize; a++, c += 2 ) { 311 | 312 | if ( c >= audioDataBuffer.length ) { 313 | offset++; 314 | c = ( c - audioDataBuffer.length ); 315 | } 316 | 317 | left[ a ] = (float)( ( (int)audioDataBuffer[ c + 1 ] << 8 ) + audioDataBuffer[ c ] ) / 32767.0f;; 318 | right[ a ] = left[ a ]; 319 | 320 | } 321 | 322 | } else if ( channelMode == CHANNEL_MODE_STEREO && sampleType == SAMPLE_TYPE_SIXTEEN_BIT ) { 323 | 324 | for( int a = 0; a < sampleSize; a++, c += 4 ) { 325 | 326 | if ( c >= audioDataBuffer.length ) { 327 | offset++; 328 | c = ( c - audioDataBuffer.length ); 329 | } 330 | 331 | left[ a ] = (float)( ( (int)audioDataBuffer[ c + 1 ] << 8 ) + audioDataBuffer[ c ] ) / 32767.0f; 332 | right[ a ] = (float)( ( (int)audioDataBuffer[ c + 3 ] << 8 ) + audioDataBuffer[ c + 2 ] ) / 32767.0f; 333 | 334 | } 335 | 336 | } 337 | 338 | } 339 | 340 | public void run() { 341 | 342 | while( process ) { 343 | 344 | try { 345 | 346 | long wStn = System.nanoTime(); 347 | 348 | int wSdp = calculateSamplePosition(); 349 | 350 | if ( wSdp > 0 ) { 351 | processSamples( wSdp ); 352 | } 353 | 354 | // -- Dispatch sample data to digtal signal processors. 355 | for( int a = 0; a < dsps.size(); a++ ) { 356 | 357 | // -- Calculate the frame rate ratio hint. This value can be used by 358 | // animated DSP's to fast forward animation frames to make up for 359 | // inconsistencies with the frame rate. 360 | float wFrr = (float)fpsAsNS / (float)desiredFpsAsNS; 361 | 362 | try { 363 | ( (KJDigitalSignalProcessor)dsps.get( a ) ).process( left, right, wFrr ); 364 | } catch( Exception pEx ) { 365 | System.err.println( "-- DSP Exception: " ); 366 | pEx.printStackTrace(); 367 | } 368 | } 369 | 370 | // KJJukeBox.getDSPDialog().setDSPInformation( 371 | // String.valueOf( 1000.0f / ( (float)( wEtn - wStn ) / 1000000.0f ) ) ); 372 | 373 | // System.out.println( 1000.0f / ( (float)( wEtn - wStn ) / 1000000.0f ) ); 374 | 375 | long wDelay = fpsAsNS - ( System.nanoTime() - wStn ); 376 | 377 | // -- No DSP registered? Put the the DSP thread to sleep. 378 | if ( dsps.isEmpty() ) { 379 | wDelay = 1000000000; // -- 1 second. 380 | } 381 | 382 | if ( wDelay > 0 ) { 383 | 384 | try { 385 | Thread.sleep( wDelay / 1000000, (int)wDelay % 1000000 ); 386 | } catch ( Exception pEx ) { 387 | // TODO Auto-generated catch block 388 | } 389 | 390 | // -- Adjust FPS until we meet the "desired FPS". 391 | if ( fpsAsNS > desiredFpsAsNS ) { 392 | fpsAsNS -= wDelay; 393 | } else { 394 | fpsAsNS = desiredFpsAsNS; 395 | } 396 | 397 | } else { 398 | 399 | // -- Reduce FPS because we cannot keep up with the "desired FPS". 400 | fpsAsNS += -wDelay; 401 | 402 | // -- Keep thread from hogging CPU. 403 | try { 404 | Thread.sleep( 10 ); 405 | } catch ( InterruptedException pEx ) { 406 | // TODO Auto-generated catch block 407 | } 408 | 409 | } 410 | 411 | } catch( Exception pEx ) { 412 | System.err.println( "- DSP Exception: " ); 413 | pEx.printStackTrace(); 414 | } 415 | 416 | } 417 | 418 | } 419 | 420 | public void stop() { 421 | process = false; 422 | } 423 | 424 | } 425 | 426 | } 427 | -------------------------------------------------------------------------------- /src/kj/dsp/KJDigitalSignalProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Created on Nov 30, 2004 3 | * 4 | * TODO To change the template for this generated file go to 5 | * Window - Preferences - Java - Code Generation - Code and Comments 6 | */ 7 | package kj.dsp; 8 | 9 | /** 10 | * @author Kris Fudalewski 11 | * 12 | * Classes must implement this interface in order to be registered with the 13 | * KJDigitalSignalProcessingAudioDataConsumer class. 14 | * 15 | */ 16 | public interface KJDigitalSignalProcessor { 17 | 18 | /** 19 | * Called by the KJDigitalSignalProcessingAudioDataConsumer. 20 | * 21 | * @param pLeftChannel Audio data for the left channel. 22 | * @param pRightChannel Audio data for the right channel. 23 | * @param pFrameRateRatioHint A float value representing the ratio of the current 24 | * frame rate to the desired frame rate. It is used to 25 | * keep DSP animation consistent if the frame rate drop 26 | * below the desired frame rate. 27 | */ 28 | void process( float[] pLeftChannel, float[] pRightChannel, float pFrameRateRatioHint ); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/kj/dsp/KJDigitalSignalProcessor1.java: -------------------------------------------------------------------------------- 1 | package kj.dsp; 2 | 3 | //EM 14/11/2008 : externalization of inner class for more efficiency 4 | //(possibly not a big gain, but much more fluent in JOP profiler) 5 | public final class KJDigitalSignalProcessor1 implements Runnable { 6 | 7 | KJDigitalSignalProcessingAudioDataConsumer dspadc; 8 | 9 | boolean process = true; 10 | 11 | long lfp = 0; 12 | 13 | int frameSize; 14 | 15 | KJDigitalSignalProcessor1(KJDigitalSignalProcessingAudioDataConsumer aDspadc){ 16 | dspadc = aDspadc; 17 | frameSize = dspadc.sourceDataLine.getFormat().getFrameSize(); 18 | } 19 | 20 | private int calculateSamplePosition() { 21 | 22 | synchronized( dspadc.readWriteLock ) { 23 | 24 | long wFp = dspadc.sourceDataLine.getLongFramePosition(); 25 | long wNfp = lfp; 26 | 27 | lfp = wFp; 28 | 29 | int wSdp = (int)( (long)( wNfp * frameSize ) - (long)( dspadc.audioDataBuffer.length * dspadc.offset ) ); 30 | 31 | // KJJukeBox.getDSPDialog().setOutputPositionInfo( 32 | // wFp, 33 | // wFp - wNfp, 34 | // wSdp ); 35 | 36 | return wSdp; 37 | 38 | } 39 | 40 | } 41 | 42 | private void processSamples( int pPosition ) { 43 | 44 | int c = pPosition; 45 | 46 | if ( dspadc.channelMode == dspadc.CHANNEL_MODE_MONO && dspadc.sampleType == dspadc.SAMPLE_TYPE_EIGHT_BIT ) { 47 | 48 | for( int a = 0; a < dspadc.sampleSize; a++, c++ ) { 49 | 50 | if ( c >= dspadc.audioDataBuffer.length ) { 51 | dspadc.offset++; 52 | c = ( c - dspadc.audioDataBuffer.length ); 53 | } 54 | 55 | dspadc.left[ a ] = (float)( (int)dspadc.audioDataBuffer[ c ] / 128.0f ); 56 | dspadc.right[ a ] = dspadc.left[ a ]; 57 | 58 | } 59 | 60 | } else if ( dspadc.channelMode == dspadc.CHANNEL_MODE_STEREO && dspadc.sampleType == dspadc.SAMPLE_TYPE_EIGHT_BIT ) { 61 | 62 | for( int a = 0; a < dspadc.sampleSize; a++, c += 2 ) { 63 | 64 | if ( c >= dspadc.audioDataBuffer.length ) { 65 | dspadc.offset++; 66 | c = ( c - dspadc.audioDataBuffer.length ); 67 | } 68 | 69 | dspadc.left[ a ] = (float)( (int)dspadc.audioDataBuffer[ c ] / 128.0f ); 70 | dspadc.right[ a ] = (float)( (int)dspadc.audioDataBuffer[ c + 1 ] / 128.0f ); 71 | 72 | } 73 | 74 | } else if ( dspadc.channelMode == dspadc.CHANNEL_MODE_MONO && dspadc.sampleType == dspadc.SAMPLE_TYPE_SIXTEEN_BIT ) { 75 | 76 | for( int a = 0; a < dspadc.sampleSize; a++, c += 2 ) { 77 | 78 | if ( c >= dspadc.audioDataBuffer.length ) { 79 | dspadc.offset++; 80 | c = ( c - dspadc.audioDataBuffer.length ); 81 | } 82 | 83 | dspadc.left[ a ] = (float)( ( (int)dspadc.audioDataBuffer[ c + 1 ] << 8 ) + dspadc.audioDataBuffer[ c ] ) / 32767.0f;; 84 | dspadc.right[ a ] = dspadc.left[ a ]; 85 | 86 | } 87 | 88 | } else if ( dspadc.channelMode == dspadc.CHANNEL_MODE_STEREO && dspadc.sampleType == dspadc.SAMPLE_TYPE_SIXTEEN_BIT ) { 89 | 90 | for( int a = 0; a < dspadc.sampleSize; a++, c += 4 ) { 91 | 92 | if ( c >= dspadc.audioDataBuffer.length ) { 93 | dspadc.offset++; 94 | c = ( c - dspadc.audioDataBuffer.length ); 95 | } 96 | 97 | dspadc.left[ a ] = (float)( ( (int)dspadc.audioDataBuffer[ c + 1 ] << 8 ) + dspadc.audioDataBuffer[ c ] ) / 32767.0f; 98 | dspadc.right[ a ] = (float)( ( (int)dspadc.audioDataBuffer[ c + 3 ] << 8 ) + dspadc.audioDataBuffer[ c + 2 ] ) / 32767.0f; 99 | 100 | } 101 | 102 | } 103 | 104 | } 105 | 106 | public void run() { 107 | while( process ) { 108 | 109 | try { 110 | 111 | long wStn = System.nanoTime(); 112 | 113 | int wSdp = calculateSamplePosition(); 114 | 115 | if ( wSdp > 0 ) { 116 | processSamples( wSdp ); 117 | } 118 | 119 | // -- Dispatch sample data to digtal signal processors. 120 | for( int a = 0; a < dspadc.dsps.size(); a++ ) { 121 | 122 | // -- Calculate the frame rate ratio hint. This value can be used by 123 | // animated DSP's to fast forward animation frames to make up for 124 | // inconsistencies with the frame rate. 125 | float wFrr = (float)dspadc.fpsAsNS / (float)dspadc.desiredFpsAsNS; 126 | 127 | try { 128 | ( (KJDigitalSignalProcessor)dspadc.dsps.get( a ) ).process( dspadc.left, dspadc.right, wFrr ); 129 | } catch( Exception pEx ) { 130 | System.err.println( "-- DSP Exception: " ); 131 | pEx.printStackTrace(); 132 | } 133 | } 134 | 135 | // KJJukeBox.getDSPDialog().setDSPInformation( 136 | // String.valueOf( 1000.0f / ( (float)( wEtn - wStn ) / 1000000.0f ) ) ); 137 | 138 | // System.out.println( 1000.0f / ( (float)( wEtn - wStn ) / 1000000.0f ) ); 139 | 140 | long wDelay = dspadc.fpsAsNS - ( System.nanoTime() - wStn ); 141 | 142 | // -- No DSP registered? Put the the DSP thread to sleep. 143 | if ( dspadc.dsps.isEmpty() ) { 144 | wDelay = 1000000000; // -- 1 second. 145 | } 146 | 147 | if ( wDelay > 0 ) { 148 | 149 | try { 150 | Thread.sleep( wDelay / 1000000, (int)wDelay % 1000000 ); 151 | } catch ( Exception pEx ) { 152 | // TODO Auto-generated catch block 153 | } 154 | 155 | // -- Adjust FPS until we meet the "desired FPS". 156 | if ( dspadc.fpsAsNS > dspadc.desiredFpsAsNS ) { 157 | dspadc.fpsAsNS -= wDelay; 158 | } else { 159 | dspadc.fpsAsNS = dspadc.desiredFpsAsNS; 160 | } 161 | 162 | } else { 163 | 164 | // -- Reduce FPS because we cannot keep up with the "desired FPS". 165 | dspadc.fpsAsNS += -wDelay; 166 | 167 | // -- Keep thread from hogging CPU. 168 | try { 169 | Thread.sleep( 10 ); 170 | } catch ( InterruptedException pEx ) { 171 | // TODO Auto-generated catch block 172 | } 173 | 174 | } 175 | 176 | } catch( Exception pEx ) { 177 | System.err.println( "- DSP Exception: " ); 178 | pEx.printStackTrace(); 179 | } 180 | 181 | } 182 | 183 | } 184 | 185 | public void stop() { 186 | process = false; 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /src/kj/dsp/KJFFT.java: -------------------------------------------------------------------------------- 1 | package kj.dsp; 2 | 3 | /** 4 | * @author Kris 5 | * 6 | * TODO To change the template for this generated type comment go to 7 | * Window - Preferences - Java - Code Generation - Code and Comments 8 | */ 9 | public class KJFFT { 10 | 11 | private float[] xre; 12 | private float[] xim; 13 | private float[] mag; 14 | 15 | private float[] fftSin; 16 | private float[] fftCos; 17 | private int[] fftBr; 18 | 19 | private int ss, ss2, nu, nu1; 20 | 21 | /** 22 | * @param The amount of the sample provided to the "calculate" method to use during 23 | * FFT calculations. 24 | */ 25 | public KJFFT( int pSampleSize ) { 26 | 27 | ss = pSampleSize; 28 | ss2 = ss >> 1; 29 | 30 | xre = new float[ ss ]; 31 | xim = new float[ ss ]; 32 | mag = new float[ ss2 ]; 33 | 34 | nu = (int)( Math.log( ss ) / Math.log( 2 ) ); 35 | nu1 = nu - 1; 36 | 37 | prepareFFTTables(); 38 | 39 | } 40 | 41 | private int bitrev( int j, int nu ) { 42 | 43 | int j1 = j; 44 | int j2; 45 | int k = 0; 46 | 47 | for( int i = 1; i <= nu; i++ ) { 48 | j2 = j1 >> 1; 49 | k = ( k << 1 ) + j1 - ( j2 << 1 ); 50 | j1 = j2; 51 | } 52 | 53 | return k; 54 | 55 | } 56 | 57 | 58 | /** 59 | * @param pSample The sample to compute FFT values on. 60 | * @return The results of the calculation, normalized between 0.0 and 1.0. 61 | */ 62 | public float[] calculate( float[] pSample ) { 63 | 64 | int n2 = ss2; 65 | int nu1 = nu - 1; 66 | 67 | int wAps = pSample.length / ss; 68 | 69 | // -- FIXME: This affects the calculation accuracy, because 70 | // is compresses the digital signal. Looks nice on 71 | // the spectrum analyser, as it chops off most of 72 | // sound we cannot hear anyway. 73 | for ( int a = 0, b = 0; a < pSample.length; a += wAps, b++ ) { 74 | xre[ b ] = pSample[ a ]; 75 | xim[ b ] = 0.0f; 76 | } 77 | 78 | float tr, ti, c, s; 79 | int k, kn2, x = 0; 80 | 81 | for ( int l = 1; l <= nu; l++ ) { 82 | 83 | k = 0; 84 | 85 | while ( k < ss ) { 86 | 87 | for ( int i = 1; i <= n2; i++ ) { 88 | 89 | // -- Tabled sin/cos 90 | c = fftCos[ x ]; 91 | s = fftSin[ x ]; 92 | 93 | kn2 = k + n2; 94 | 95 | tr = xre[ kn2 ] * c + xim[ kn2 ] * s; 96 | ti = xim[ kn2 ] * c - xre[ kn2 ] * s; 97 | 98 | xre[ kn2 ] = xre[ k ] - tr; 99 | xim[ kn2 ] = xim[ k ] - ti; 100 | xre[ k ] += tr; 101 | xim[ k ] += ti; 102 | 103 | k++; x++; 104 | 105 | } 106 | 107 | k += n2; 108 | 109 | } 110 | 111 | nu1--; 112 | n2 >>= 1; 113 | 114 | } 115 | 116 | int r; 117 | 118 | // -- Reorder output. 119 | for( k = 0; k < ss; k++ ) { 120 | 121 | // -- Use tabled BR values. 122 | r = fftBr[ k ]; 123 | 124 | if ( r > k ) { 125 | 126 | tr = xre[ k ]; 127 | ti = xim[ k ]; 128 | 129 | xre[ k ] = xre[ r ]; 130 | xim[ k ] = xim[ r ]; 131 | xre[ r ] = tr; 132 | xim[ r ] = ti; 133 | 134 | } 135 | 136 | } 137 | 138 | // -- Calculate magnitude. 139 | mag[ 0 ] = (float)( Math.sqrt( xre[ 0 ] * xre[ 0 ] + xim[ 0 ] * xim[ 0 ] ) ) / ss; 140 | 141 | for ( int i = 1; i < ss2; i++ ) { 142 | mag[ i ]= 2 * (float)( Math.sqrt( xre[ i ] * xre[ i ] + xim[ i ] * xim[ i ] ) ) / ss; 143 | } 144 | 145 | return mag; 146 | 147 | } 148 | 149 | private void prepareFFTTables() { 150 | 151 | int n2 = ss2; 152 | int nu1 = nu - 1; 153 | 154 | // -- Allocate FFT SIN/COS tables. 155 | fftSin = new float[ nu * n2 ]; 156 | fftCos = new float[ nu * n2 ]; 157 | 158 | float tr, ti, p, arg; 159 | int k = 0, x = 0; 160 | 161 | // -- Prepare SIN/COS tables. 162 | for ( int l = 1; l <= nu; l++ ) { 163 | 164 | while ( k < ss ) { 165 | 166 | for ( int i = 1; i <= n2; i++ ) { 167 | 168 | p = bitrev( k >> nu1, nu ); 169 | 170 | arg = 2 * (float)Math.PI * p / ss; 171 | 172 | fftSin[ x ] = (float)Math.sin( arg ); 173 | fftCos[ x ] = (float)Math.cos( arg ); 174 | 175 | k++; 176 | x++; 177 | 178 | } 179 | 180 | k += n2; 181 | 182 | } 183 | 184 | k = 0; 185 | 186 | nu1--; 187 | n2 >>= 1; 188 | 189 | } 190 | 191 | // -- Prepare bitrev table. 192 | fftBr = new int[ ss ]; 193 | 194 | for( k = 0; k < ss; k++ ) { 195 | fftBr[ k ] = bitrev( k, nu ); 196 | } 197 | 198 | } 199 | 200 | } 201 | --------------------------------------------------------------------------------