/* * MidiFile.cs * Copyright (c) 2009 kbinani * * This file is part of Boare.Lib.Vsq. * * Boare.Lib.Vsq is free software; you can redistribute it and/or * modify it under the terms of the BSD License. * * Boare.Lib.Vsq is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #if JAVA package org.kbinani.vsq; import java.io.*; import java.util.*; import org.kbinani.*; #else using System; using bocoree; using bocoree.java.util; using bocoree.java.io; namespace Boare.Lib.Vsq { using boolean = System.Boolean; using Long = System.Int64; #endif public class MidiFile { private Vector> m_events; private int m_format; private int m_time_format; public MidiFile( String path ) #if JAVA throws FileNotFoundException #endif { RandomAccessFile stream = new RandomAccessFile( path, "r" ); try { // ヘッダ byte[] byte4 = new byte[4]; stream.read( byte4, 0, 4 ); if ( PortUtil.make_uint32_be( byte4 ) != 0x4d546864 ) { throw new Exception( "header error: MThd" ); } // データ長 stream.read( byte4, 0, 4 ); long length = PortUtil.make_uint32_be( byte4 ); // フォーマット stream.read( byte4, 0, 2 ); m_format = PortUtil.make_uint16_be( byte4 ); // トラック数 int tracks = 0; stream.read( byte4, 0, 2 ); tracks = (int)PortUtil.make_uint16_be( byte4 ); // 時間分解能 stream.read( byte4, 0, 2 ); m_time_format = PortUtil.make_uint16_be( byte4 ); // 各トラックを読込み m_events = new Vector>(); for ( int track = 0; track < tracks; track++ ) { Vector track_events = new Vector(); // ヘッダー stream.read( byte4, 0, 4 ); if ( PortUtil.make_uint32_be( byte4 ) != 0x4d54726b ) { throw new Exception( "header error; MTrk" ); } // チャンクサイズ stream.read( byte4, 0, 4 ); long size = (long)PortUtil.make_uint32_be( byte4 ); long startpos = stream.getFilePointer(); // チャンクの終わりまで読込み ByRef clock = new ByRef( (long)0 ); ByRef last_status_byte = new ByRef( (byte)0x00 ); while ( stream.getFilePointer() < startpos + size ) { MidiEvent mi = MidiEvent.read( stream, clock, last_status_byte ); track_events.add( mi ); } if ( m_time_format != 480 ) { int count = track_events.size(); for ( int i = 0; i < count; i++ ) { MidiEvent mi = track_events.get( i ); mi.clock = mi.clock * 480 / m_time_format; track_events.set( i, mi ); } } m_events.add( track_events ); } m_time_format = 480; #if DEBUG && MIDI_PRINT_TO_FILE String dbg = PortUtil.combinePath( PortUtil.getDirectoryName( path ), PortUtil.getFileNameWithoutExtension( path ) + ".txt" ); BufferedWriter sw = null; try { sw = new BufferedWriter( new FileWriter( dbg ) ); const String format = " {0,8} 0x{1:X4} {2,-35} 0x{3:X2} 0x{4:X2}"; const String format0 = " {0,8} 0x{1:X4} {2,-35} 0x{3:X2}"; for ( int track = 1; track < m_events.size(); track++ ) { sw.write( "MidiFile..ctor; track=" + track ); sw.newLine(); byte msb, lsb, data_msb, data_lsb; msb = lsb = data_msb = data_lsb = 0x0; for ( int i = 0; i < m_events.get( track ).size(); i++ ) { if ( m_events.get( track ).get( i ).firstByte == 0xb0 ) { switch ( m_events.get( track ).get( i ).data[0] ) { case 0x63: msb = m_events.get( track ).get( i ).data[1]; lsb = 0x0; break; case 0x62: lsb = m_events.get( track ).get( i ).data[1]; break; case 0x06: data_msb = m_events.get( track ).get( i ).data[1]; ushort nrpn = (ushort)(msb << 8 | lsb); String name = NRPN.getName( nrpn ); if ( name.Equals( "" ) ) { name = "* * UNKNOWN * *"; sw.write( String.Format( format0, m_events.get( track ).get( i ).clock, nrpn, name, data_msb ) ); sw.newLine(); } else { //if ( !NRPN.is_require_data_lsb( nrpn ) ) { sw.write( String.Format( format0, m_events.get( track ).get( i ).clock, nrpn, name, data_msb ) ); sw.newLine(); //} } break; case 0x26: data_lsb = m_events.get( track ).get( i ).data[1]; ushort nrpn2 = (ushort)(msb << 8 | lsb); String name2 = NRPN.getName( nrpn2 ); if ( name2.Equals( "" ) ) { name2 = "* * UNKNOWN * *"; } sw.write( String.Format( format, m_events.get( track ).get( i ).clock, nrpn2, name2, data_msb, data_lsb ) ); sw.newLine(); break; } } } } } catch ( Exception ex ) { } finally { if ( sw != null ) { try { sw.close(); } catch ( Exception ex2 ) { } } } #endif } catch ( Exception ex ) { } finally { if ( stream != null ) { try { stream.close(); } catch ( Exception ex2 ) { } } } } public Vector getMidiEventList( int track ) { if ( m_events == null ) { return new Vector(); } else if ( 0 <= track && track < m_events.size() ) { return m_events.get( track ); } else { return new Vector(); } } public int getTrackCount() { if ( m_events == null ) { return 0; } else { return m_events.size(); } } public void close() { if ( m_events != null ) { int c = m_events.size(); for ( int i = 0; i < c; i++ ) { m_events.get( i ).clear(); } m_events.clear(); } } } #if !JAVA } #endif