OSDN Git Service

・文字コード判定方法の改善
authorAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sun, 12 Jun 2016 16:59:17 +0000 (01:59 +0900)
committerAkiyoshi Kamide <kamide@yk.rim.or.jp>
Sun, 12 Jun 2016 16:59:17 +0000 (01:59 +0900)
  シーケンス名だけでなく、テキスト系メタイベント全て結合したバイト列で
  判定することにより、シーケンス名に日本語が全くないMIDIファイルでの
  判定精度を向上
・MIDIファイル保存時、変更フラグの表示がすぐに更新されない問題を改善

src/camidion/chordhelper/ChordHelperApplet.java
src/camidion/chordhelper/midieditor/MidiMessageForm.java
src/camidion/chordhelper/midieditor/MidiSequenceEditor.java
src/camidion/chordhelper/midieditor/PlaylistTableModel.java
src/camidion/chordhelper/midieditor/SequenceTrackListTableModel.java
src/camidion/chordhelper/midieditor/TrackEventListTableModel.java
src/camidion/chordhelper/music/MIDISpec.java

index 0b7c3b6..d27db2e 100644 (file)
@@ -285,7 +285,7 @@ public class ChordHelperApplet extends JApplet {
         */
        public static class VersionInfo {
                public static final String      NAME = "MIDI Chord Helper";
-               public static final String      VERSION = "Ver.20160605.1";
+               public static final String      VERSION = "Ver.20160612.1";
                public static final String      COPYRIGHT = "Copyright (C) 2004-2016";
                public static final String      AUTHER = "@きよし - Akiyoshi Kamide";
                public static final String      URL = "http://www.yk.rim.or.jp/~kamide/music/chordhelper/";
index bb567f0..4772b50 100644 (file)
@@ -416,7 +416,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                                        dataText.setVisible(false);
                                }
                                else {
-                                       dataText.setTitle(MIDISpec.hasMetaText(msgType)?"Text:":"Data:");
+                                       dataText.setTitle(MIDISpec.hasMetaMessageText(msgType)?"Text:":"Data:");
                                }
                        }
                        else {
@@ -440,7 +440,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                        int msgType = data1Text.getValue();
                        if( msgType < 0 ) return null;
                        byte msgData[];
-                       if( MIDISpec.hasMetaText(msgType) ) {
+                       if( MIDISpec.hasMetaMessageText(msgType) ) {
                                msgData = dataText.getString().getBytes(charset);
                        }
                        else if( msgType == 0x2F ) { // EOT
@@ -532,7 +532,7 @@ public class MidiMessageForm extends JPanel implements ActionListener {
                        case 0x59: keysigSelecter.setKey(new Key(data)); break;
                        default: break;
                        }
-                       if( MIDISpec.hasMetaText(msgType) ) {
+                       if( MIDISpec.hasMetaMessageText(msgType) ) {
                                dataText.setString(new String(data,charset));
                        }
                        else {
index 0515d93..58ac513 100644 (file)
@@ -488,7 +488,8 @@ public class MidiSequenceEditor extends JDialog {
                        ) {
                                @Override
                                public void actionPerformed(ActionEvent event) {
-                                       SequenceTrackListTableModel sequenceModel = getModel().getSelectedSequenceModel();
+                                       PlaylistTableModel playlistModel = getModel();
+                                       SequenceTrackListTableModel sequenceModel = playlistModel.getSelectedSequenceModel();
                                        String fn = sequenceModel.getFilename();
                                        if( fn != null && ! fn.isEmpty() ) setSelectedFile(new File(fn));
                                        if( showSaveDialog((Component)event.getSource()) != JFileChooser.APPROVE_OPTION ) return;
@@ -500,6 +501,7 @@ public class MidiSequenceEditor extends JDialog {
                                        try ( FileOutputStream out = new FileOutputStream(f) ) {
                                                out.write(sequenceModel.getMIDIdata());
                                                sequenceModel.setModified(false);
+                                               playlistModel.fireSequenceModified(sequenceModel, false);
                                        }
                                        catch( IOException ex ) {
                                                showError( ex.getMessage() );
@@ -894,7 +896,7 @@ public class MidiSequenceEditor extends JDialog {
                                        scrollToEventAt(tick);
                                        // ペーストで曲の長さが変わったことをプレイリストに通知
                                        SequenceTrackListTableModel seqModel = trackModel.getParent();
-                                       seqModel.getParent().fireSequenceModified(seqModel);
+                                       seqModel.getParent().fireSequenceModified(seqModel, true);
                                        eventDialog.setVisible(false);
                                        trackModel = null;
                                }
@@ -930,7 +932,7 @@ public class MidiSequenceEditor extends JDialog {
                                                scrollToEventAt(partnerTick > tick ? partnerTick : tick);
                                        }
                                }
-                               seqModel.getParent().fireSequenceModified(seqModel);
+                               seqModel.getParent().fireSequenceModified(seqModel, true);
                                eventDialog.setVisible(false);
                                return true;
                        }
index 48873cc..72824c4 100644 (file)
@@ -424,25 +424,26 @@ public class PlaylistTableModel extends AbstractTableModel {
                return sequenceList.get(selectedIndex);
        }
        /**
-        * æ\8c\87å®\9aã\81\95ã\82\8cã\81\9fã\82·ã\83¼ã\82±ã\83³ã\82¹ã\81\8c修正ã\81\95ã\82\8cã\81\9fã\81\93ã\81¨ã\82\92é\80\9aç\9f¥します。
+        * æ\8c\87å®\9aã\81\95ã\82\8cã\81\9fã\82·ã\83¼ã\82±ã\83³ã\82¹ã\81®æ\9b´æ\96°æ¸\88ã\81¿ã\83\95ã\83©ã\82°ã\82\92å¤\89æ\9b´ã\81\97ã\81¦å\85¨ã\81¦ã\81®å\88\97ã\82\92å\86\8d表示します。
         * @param sequenceTableModel MIDIシーケンスモデル
+        * @param isModified 更新済みフラグ
         */
-       public void fireSequenceModified(SequenceTrackListTableModel sequenceTableModel) {
+       public void fireSequenceModified(SequenceTrackListTableModel sequenceTableModel, boolean isModified) {
                int index = sequenceList.indexOf(sequenceTableModel);
                if( index < 0 ) return;
-               sequenceTableModel.setModified(true);
+               sequenceTableModel.setModified(isModified);
                fireTableRowsUpdated(index, index);
        }
        /**
-        * æ\8c\87å®\9aã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bé\81¸æ\8a\9eç¯\84å\9b²ã\81®ã\82·ã\83¼ã\82±ã\83³ã\82¹ã\81\8cå¤\89æ\9b´ã\81\95ã\82\8cã\81\9fã\81\93ã\81¨ã\82\92é\80\9aç\9f¥します。
-        * 更新済みフラグをセットし、選択されたシーケンスの全ての列を再表示します。
+        * æ\8c\87å®\9aã\81\95ã\82\8cã\81¦ã\81\84ã\82\8bé\81¸æ\8a\9eç¯\84å\9b²ã\81®ã\82·ã\83¼ã\82±ã\83³ã\82¹ã\81«ã\81¤ã\81\84ã\81¦ã\80\81æ\9b´æ\96°æ¸\88ã\81¿ã\83\95ã\83©ã\82°ã\82\92å¤\89æ\9b´ã\81\97ã\81¦å\85¨ã\81¦ã\81®å\88\97ã\82\92å\86\8d表示します。
+        * @param isModified 更新済みフラグ
         */
-       public void fireSelectedSequenceModified() {
+       public void fireSelectedSequenceModified(boolean isModified) {
                if( sequenceListSelectionModel.isSelectionEmpty() ) return;
                int minIndex = sequenceListSelectionModel.getMinSelectionIndex();
                int maxIndex = sequenceListSelectionModel.getMaxSelectionIndex();
                for( int index = minIndex; index <= maxIndex; index++ ) {
-                       sequenceList.get(index).setModified(true);
+                       sequenceList.get(index).setModified(isModified);
                }
                fireTableRowsUpdated(minIndex, maxIndex);
        }
index 22f35cf..c54c5c4 100644 (file)
@@ -2,12 +2,9 @@ package camidion.chordhelper.midieditor;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 import javax.sound.midi.MidiSystem;
 import javax.sound.midi.Sequence;
@@ -221,9 +218,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
         * シーケンスtickインデックスを返します。
         * @return シーケンスtickインデックス
         */
-       public SequenceTickIndex getSequenceTickIndex() {
-               return sequenceTickIndex;
-       }
+       public SequenceTickIndex getSequenceTickIndex() { return sequenceTickIndex; }
        /**
         * MIDIシーケンスを設定します。
         * @param sequence MIDIシーケンス(nullを指定するとトラックリストが空になる)
@@ -254,23 +249,9 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
                        trackModelList.add(new TrackEventListTableModel(this, track));
                }
                // 文字コードの判定
-               byte b[] = MIDISpec.getNameBytesOf(sequence);
-               if( b != null && b.length > 0 ) {
-                       try {
-                               String autoDetectedName = new String(b, "JISAutoDetect");
-                               Set<Map.Entry<String,Charset>> entrySet;
-                               entrySet = Charset.availableCharsets().entrySet();
-                               for( Map.Entry<String,Charset> entry : entrySet ) {
-                                       Charset cs = entry.getValue();
-                                       if( ! autoDetectedName.equals(new String(b, cs)) )
-                                               continue;
-                                       charset = cs;
-                                       break;
-                               }
-                       } catch (UnsupportedEncodingException e) {
-                               e.printStackTrace();
-                       }
-               }
+               Charset cs = MIDISpec.getCharsetOf(sequence);
+               charset = cs==null ? Charset.defaultCharset() : cs;
+               //
                // トラックが挿入されたことを通知
                fireTableRowsInserted(0, tracks.length-1);
        }
@@ -312,11 +293,8 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
         * @return 成功したらtrue
         */
        public boolean setName(String name) {
-               if( name.equals(toString()) )
-                       return false;
-               byte b[] = name.getBytes(charset);
-               if( ! MIDISpec.setNameBytesOf(sequence, b) )
-                       return false;
+               if( name.equals(toString()) ) return false;
+               if( ! MIDISpec.setNameBytesOf(sequence, name.getBytes(charset)) ) return false;
                setModified(true);
                fireTableDataChanged();
                return true;
@@ -345,7 +323,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
                int row = indexOf(track);
                if( row < 0 ) return;
                fireTableRowsUpdated(row, row);
-               sequenceListTableModel.fireSequenceModified(this);
+               sequenceListTableModel.fireSequenceModified(this, true);
        }
        /**
         * 選択されているトラックモデルを返します。
@@ -386,7 +364,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
                trackModelList.add(new TrackEventListTableModel(this, newTrack));
                int lastRow = getRowCount() - 1;
                fireTableRowsInserted(lastRow, lastRow);
-               sequenceListTableModel.fireSelectedSequenceModified();
+               sequenceListTableModel.fireSelectedSequenceModified(true);
                trackListSelectionModel.setSelectionInterval(lastRow, lastRow);
                return lastRow;
        }
@@ -406,7 +384,7 @@ public class SequenceTrackListTableModel extends AbstractTableModel {
                        trackModelList.remove(i);
                }
                fireTableRowsDeleted(minIndex, maxIndex);
-               sequenceListTableModel.fireSelectedSequenceModified();
+               sequenceListTableModel.fireSelectedSequenceModified(true);
        }
        /**
         * このシーケンスモデルのシーケンスをシーケンサーが操作しているか調べます。
index 5c591f7..14a1153 100644 (file)
@@ -220,7 +220,7 @@ public class TrackEventListTableModel extends AbstractTableModel {
                fireTableDataChanged();
                if( MIDISpec.isEOT(msg) ) {
                        // EOTの場所が変わると曲の長さが変わるので、親モデルへ通知する。
-                       sequenceTrackListTableModel.getParent().fireSequenceModified(sequenceTrackListTableModel);
+                       sequenceTrackListTableModel.getParent().fireSequenceModified(sequenceTrackListTableModel, true);
                }
        }
        /**
@@ -252,7 +252,7 @@ public class TrackEventListTableModel extends AbstractTableModel {
                if( ! MIDISpec.setNameBytesOf(track, b) )
                        return false;
                sequenceTrackListTableModel.setModified(true);
-               sequenceTrackListTableModel.getParent().fireSequenceModified(sequenceTrackListTableModel);
+               sequenceTrackListTableModel.getParent().fireSequenceModified(sequenceTrackListTableModel, true);
                fireTableDataChanged();
                return true;
        }
@@ -543,7 +543,7 @@ public class TrackEventListTableModel extends AbstractTableModel {
                int oldLastIndex = lastIndex + midiEvents.length;
                if(lastIndex < 0) lastIndex = 0;
                fireTableRowsDeleted(oldLastIndex, lastIndex);
-               sequenceTrackListTableModel.getParent().fireSelectedSequenceModified();
+               sequenceTrackListTableModel.getParent().fireSelectedSequenceModified(true);
        }
        /**
         * 引数の選択内容が示すMIDIイベントを除去します。
index 071dc69..e0d883f 100644 (file)
@@ -1,7 +1,9 @@
 package camidion.chordhelper.music;
+import java.io.UnsupportedEncodingException;
 import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import javax.sound.midi.InvalidMidiDataException;
 import javax.sound.midi.MetaMessage;
@@ -56,7 +58,7 @@ public class MIDISpec {
         * @param metaMessageType メタメッセージタイプ
         * @return テキストがつくときtrue
         */
-       public static boolean hasMetaText(int metaMessageType) {
+       public static boolean hasMetaMessageText(int metaMessageType) {
                return (metaMessageType > 0 && metaMessageType < 10);
        }
        /**
@@ -73,8 +75,7 @@ public class MIDISpec {
         * @return 拍子記号ならtrue
         */
        public static boolean isTimeSignature(MidiMessage midiMessage) {
-               if ( !(midiMessage instanceof MetaMessage) )
-                       return false;
+               if ( !(midiMessage instanceof MetaMessage) ) return false;
                return isTimeSignature( ((MetaMessage)midiMessage).getType() );
        }
        /**
@@ -82,17 +83,14 @@ public class MIDISpec {
         * @param metaMessageType メタメッセージタイプ
         * @return EOTならtrue
         */
-       public static boolean isEOT(int metaMessageType) {
-               return metaMessageType == 0x2F;
-       }
+       public static boolean isEOT(int metaMessageType) { return metaMessageType == 0x2F; }
        /**
         * MIDIメッセージが EOT (End Of Track) か調べます。
         * @param midiMessage MIDIメッセージ
         * @return EOTならtrue
         */
        public static boolean isEOT(MidiMessage midiMessage) {
-               if ( !(midiMessage instanceof MetaMessage) )
-                       return false;
+               if ( !(midiMessage instanceof MetaMessage) ) return false;
                return isEOT( ((MetaMessage)midiMessage).getType() );
        }
        /**
@@ -105,8 +103,7 @@ public class MIDISpec {
         * @return テンポ[QPM]
         */
        public static int byteArrayToQpmTempo(byte[] b) {
-               int tempoInUsPerQuarter
-                       = ((b[0] & 0xFF) << 16) | ((b[1] & 0xFF) << 8) | (b[2] & 0xFF);
+               int tempoInUsPerQuarter = ((b[0] & 0xFF) << 16) | ((b[1] & 0xFF) << 8) | (b[2] & 0xFF);
                return MICROSECOND_PER_MINUTE / tempoInUsPerQuarter;
        }
        /**
@@ -199,8 +196,7 @@ public class MIDISpec {
                //
                Track tracks[] = seq.getTracks();
                byte b[];
-               for( Track track : tracks )
-                       if( (b = getNameBytesOf(track)) != null ) return b;
+               for( Track track : tracks ) if( (b = getNameBytesOf(track)) != null ) return b;
                return null;
        }
        /**
@@ -215,10 +211,48 @@ public class MIDISpec {
         */
        public static boolean setNameBytesOf(Sequence seq, byte[] name) {
                Track tracks[] = seq.getTracks();
-               for( Track track : tracks )
-                       if( setNameBytesOf(track,name) ) return true;
+               for( Track track : tracks ) if( setNameBytesOf(track,name) ) return true;
                return false;
        }
+       /**
+        * シーケンスの名前や歌詞など、メタイベントのテキストをもとに文字コードを判定します。
+        * 判定できなかった場合はnullを返します。
+        * @param seq MIDIシーケンス
+        * @return 文字コード判定結果(またはnull)
+        */
+       public static Charset getCharsetOf(Sequence seq) {
+               Track tracks[] = seq.getTracks();
+               byte[] b = new byte[0];
+               for( Track track : tracks ) {
+                       MidiMessage message;
+                       MetaMessage metaMessage;
+                       for( int i=0; i<track.size(); i++ ) {
+                               message = track.get(i).getMessage();
+                               if( ! (message instanceof MetaMessage) ) continue;
+                               metaMessage = (MetaMessage)message;
+                               if( ! hasMetaMessageText(metaMessage.getType()) ) continue;
+                               byte[] additional = metaMessage.getData();
+                               byte[] concated = new byte[b.length + additional.length];
+                               System.arraycopy(b, 0, concated, 0, b.length);
+                               System.arraycopy(additional, 0, concated, b.length, additional.length);
+                               b = concated;
+                       }
+               }
+               if( b.length > 0 ) {
+                       try {
+                               String autoDetectedName = new String(b, "JISAutoDetect");
+                               Set<Map.Entry<String,Charset>> entrySet;
+                               entrySet = Charset.availableCharsets().entrySet();
+                               for( Map.Entry<String,Charset> entry : entrySet ) {
+                                       Charset cs = entry.getValue();
+                                       if( autoDetectedName.equals(new String(b, cs)) ) return cs;
+                               }
+                       } catch (UnsupportedEncodingException e) {
+                               e.printStackTrace();
+                       }
+               }
+               return null;
+       }
        ///////////////////////////////////////////////////////////////////
        //
        // Channel Message / System Message
@@ -756,7 +790,7 @@ public class MIDISpec {
                        str += meta_name;
                        //
                        // Add the text data
-                       if( hasMetaText(msgtype) ) {
+                       if( hasMetaMessageText(msgtype) ) {
                                str +=" ["+(new String(msgdata,charset))+"]";
                                return str;
                        }