android midi 编辑6,Android6.0MIDI设备相关应用程序开发
最近開發了一款基于Android6.0系統的鋼琴學習系統,本文將主要介紹MIDI協議的常識、Android MIDI 相關API的使用,以及MIDI應用程序開發需要借鑒的開源項目,最后分析本項目的架構。
本文的主要結構如下圖所示:
本文項目架構
1.MIDI概述
1.1樂器數字接口
(Musical Instrument Digital Interface,簡稱MIDI)是一個工業標準的電子通信協議.為電子樂器等演奏設備(如合成器)定義各種音符或彈奏碼,容許電子樂器、電腦、手機或其它的舞臺演出配備彼此連接,調整和同步,得以即時交換演奏數據。MIDI不發送聲音,只發送像是音調和音樂強度的數據,音量,顫音和相位[1]等參數的控制信號,還有設置節奏的時鐘信號。在不同的電腦上,輸出的聲音也因音源器不同而有差異。
1.2 MIDI的優點
1.共通語言及語法:
鍵盤樂器,電子鼓,電腦,編曲機及其他為MIDI設計出來的特殊功能電子樂器之間可以輕易的相互鏈接
2.簡化的鏈接:
減少了音樂設備之間導線、信號線鏈接的復雜性(如音量控制)
3.更少的演出者:
1980年代初期,音樂演出者可以僅靠一至兩人進行現場演出,同時操作數臺MIDI設備,制造出像交響樂團般的演出效果
4.更低的獲取門檻:
用戶可以以更少的花費創作、編輯、制作高質量的數字音樂。專業的音樂家可以在家里自己錄音,宅錄,不用花錢租錄音室,也不用請一堆樂手來幫忙錄音。同時更讓沒音樂基礎的愛好者可以利用MIDI音樂軟件高度擴充性進行高質量錄音
5.方便可攜的電子音樂器材:
大量減少了樂手巡回演出時所需攜帶的樂器、器材與線材的數量,在搬運、裝載、架設器材也簡易了許多,卻仍可以制造出相當的音色與效果.
1.3 MIDI的運作過程
當MIDI播放器演奏了一個音符的時候,它隨之將音符轉換成MIDI信息。一個典型的由鍵盤獲取的音符的MIDI信息的過程包括:
1.用戶以特定速率(又譯,力度-velocity)演奏中央C音符。
2.用戶改變按壓鍵盤按鍵的力度-這個技術稱為鍵后觸感(aftertouch)。
3.用戶釋放并停止演奏中央C音符。
2.Android Midi相關API
2.1用到的主要類在android.media.midi中,除此之外還要用到音頻播放相關的API:AudioTrack,AudioRecord等相關API.
2.2接口 MidiManager.OnDeviceOpenedListener
/**? ? * Listener class used for receiving the results of {@link #openDevice} and? ? * {@link #openBluetoothDevice}? ? */? ? public interface OnDeviceOpenedListener {? ? ? ? /**? ? ? ? * Called to respond to a {@link #openDevice} request? ? ? ? *? ? ? ? * @param device a {@link MidiDevice} for opened device, or null if opening failed? ? ? ? */? ? ? ? abstract public void onDeviceOpened(MidiDevice device);? ? } 在調用Midimanger.openDevice(MidiDeviceInfo, MidiManager.OnDeviceOpenedListener, Handler)方法時需要傳入這樣一個接口,再回調函數里能夠得到打開的設備MidiDevice
2.3相關類
2.3.1 MidiDevice該類屬于Midi設備,該類的創建比較特殊,需要通過 openDevice(MidiDeviceInfo, MidiManager.OnDeviceOpenedListener, Handler)進行創建,在MidiManager.OnDeviceOpenedListener的回調中會得到該類1 MidiDeviceInfo getInfo ()2 MidiInputPort openInputPort (int portNumber)3 MidiOutputPort openOutputPort (int portNumber)這三個方法相對比較容易理解,主要用來得到設備的信息,通過端口號來打開一個輸入端口和輸出端口4 MidiDevice.MidiConnection connectPorts (MidiInputPort inputPort,? ? ? ? ? ? ? ? int outputPortNumber)這個方法相對比較特殊,主要用來將兩個設備連接起來,第一個參數為需要連接的設備的輸入端口,第二個參數為輸出設備的輸出端口號
2.3.2 MidiDevice.MidiConnection兩個設備連接在一起的connection當需要斷開連接時需要關閉對應的connection ,釋放流和相應的系統資源,防止內存泄漏等
2.3.3 MidiDeviceInfoMidiDeviceInfo 包含了設備的所有物理信息的詳細描述,而真正在不通設備之間建立連接的是MidiDevice.MidiDeviceInfo包含豐富的物理信息:PROPERTY_BLUETOOTH_DEVICEPROPERTY_MANUFACTURERPROPERTY_NAMEPROPERTY_PRODUCTPROPERTY_SERIAL_NUMBERPROPERTY_USB_DEVICEPROPERTY_VERSIONTYPE_BLUETOOTHTYPE_USBTYPE_VIRTUAL可以通過下面的方法傳入不同的常量來獲得對應的信息info.getProperties()? ? ? ? ? ? ? ? ? ? .getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);int getId ():返回設備的id號int getInputPortCount ():得到設備的輸入端口的個數int getOutputPortCount ()得到設備輸出端口的個數PortInfo[] getPorts ():返回設備的端口? ,返回的變量是一個數組,可能包含設備的輸入端口和輸出端口,PortInfo是MidiDeviceInfo的內部類,包含端口的信息,輸入輸出類型等Bundle getProperties ():返回一個bundle對象,可以用其或得設備的物理信息int getType ():得到設備的類型boolean isPrivate ():判斷設備是否屬于私有設備
2.3.4 MidiDeviceInfo.PortInfoString getName ()int getPortNumber ()int getType ()幾個方法很容易理解分別返回端口的名字 端口號 以及輸入輸出類型
2.3.5 MidiDeviceServiceMidiDeviceService? 繼承于Service ,用于創建一個虛擬的Midi設備一般情況下,我們通過繼承這個類去構建一個虛擬的Midi設備,繼承這個類必須重寫兩個方法,分別用來接收其他Midi設備發出的信息,或者向其他設備發送信息? MidiReceiver[] onGetInputPortReceivers (),向service設備提供MidiReceiver 去接收信息? MidiReceiver[] getOutputPortReceivers () ,用來提供發送信息的MidiReceiver并且繼承這個類必須在Manifest文件中進行注冊我們可以定義該虛擬設備的制造商,產品? 以及輸入輸出類型等信息MidiDeviceInfo getDeviceInfo ()得到該設備的信息void onDeviceStatusChanged (MidiDeviceStatus status)在設備的狀態被改變時進行回調
2.3.6 MidiDeviceStatus1.MidiDeviceInfo getDeviceInfo ()能夠通過狀態改變的回調,得到設備的信息2.int getOutputPortOpenCount (int portNumber)假如該設備是一個輸出設備,能夠得到所有與該輸出設備某端口(portNumbe)連接的設備的數量,一個輸出設備能夠同時被多個設備連接。3.boolean isInputPortOpen (int portNumber)假如該設備是一個輸入設備,能夠得到該輸入設備的某個端口是否打開,一個輸入設備,只能被一個設備連接
2.3.7 MidiInputPort
2.3.8 MidiManagerMidiManger 是MIDI設備的管理者 ,類似于PackgerManger MediaManger 等系統某一類的管理者,其得到的方式與其他Manger的得到方式類似:MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);幾個常用的公用方法:1 MidiDeviceInfo[] getDevices ()? 該方法能夠返回 系統所連結的所有MIDI設備,系統能夠識別多個不同的MIDI設備,甚至包括輸入輸出設備,并將這些設備的相關信息以數組的形式返回2 void openBluetoothDevice (BluetoothDevice bluetoothDevice,? ? ? ? ? ? ? ? MidiManager.OnDeviceOpenedListener listener,? ? ? ? ? ? ? ? Handler handler)? 該方法表明系統可以連接通過藍牙連接MIDI設備,假設該Midi設備支持藍牙,因開發過程中沒有此設備,沒有做過測試,但藍牙Midi設備的可擴展性、便攜性無疑更強3 void openDevice (MidiDeviceInfo deviceInfo,? ? ? ? ? ? ? ? MidiManager.OnDeviceOpenedListener listener,? ? ? ? ? ? ? ? Handler handler) 該方法用來打開一個設備,需要傳入被打開設備的信息 打開設備的回調接口 以及Handler4 void registerDeviceCallback (MidiManager.DeviceCallback callback,? ? ? ? ? ? ? ? Handler handler) 注冊一個回調接口,用來檢測設備的插入與連接,當設備被連接時,如果該設備有打開的端口, onDeviceStatusChanged(MidiDeviceStatus)方法會立刻被調用.5 void unregisterDeviceCallback (MidiManager.DeviceCallback callback) 注銷回調接口
2.3.9 MidiManager.DeviceCallback當設備被連接時的回調:void onDeviceAdded (MidiDeviceInfo device)void onDeviceRemoved (MidiDeviceInfo device)void onDeviceStatusChanged (MidiDeviceStatus status)? 分別對應設備插入 移除 狀態改變的 notifaction 通知
2.3.10 MidiOutputPort
2.3.11 MidiReceiverMidiReceiver 用來接收來自Midi設備的信息或者向Midi設備發送信息1.int getMaxMessageSize () 返回MidiReceiver可以接受的信息的最大容量2 void onSend (byte[] msg,? ? ? ? ? ? ? ? int offset,? ? ? ? ? ? ? ? int count,? ? ? ? ? ? ? ? long timestamp)當信息被傳遞的時候被調用3 void send (byte[] msg,? ? ? ? ? ? ? ? int offset,? ? ? ? ? ? ? ? int count)用來發送信息(不包含發送時間)4 void send (byte[] msg,? ? ? ? ? ? ? ? int offset,? ? ? ? ? ? ? ? int count,? ? ? ? ? ? ? ? long timestamp)用來發送信息(包含時間戳)
2.3.12MidiSenderMidiSender 用來綁定Midi設備的MidiReceiver1 void connect (MidiReceiver receiver)用來連接某個MidiReceiver
2.2.4相關開源項目
https://github.com/googlesamples/android-MidiScope.git(只發送信息,不發聲音)https://github.com/googlesamples/android-MidiSynth.git(能夠檢測設備,連接設備并發聲)
3.項目架構項目架構及詳細分析見項目源碼
https://github.com/duanjiefei/MidiPaino.git
總結
以上是生活随笔為你收集整理的android midi 编辑6,Android6.0MIDI设备相关应用程序开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017云栖大会 资料
- 下一篇: php怎么读取上传文件的md5,利用PH