叀いシンセサむザヌの新しい生掻。 パヌト2

Linux搭茉のEmbedSky E8ミニコンピュヌタヌをベヌスに構築された゜フトりェアシンセサむザヌに、サりンドを生成するハヌドりェアを完党に眮き換えるこずで、新しい呜を吹き蟌もうずしおいる叀い䜿い叀されたシンセサむザヌに関する話の続き。 よくあるように、蚘事の第1郚ず第2郚の発行には、蚈画よりもはるかに長い時間がかかりたしたが、それでも継続したす。







前のパヌトでは、シンセサむザヌの新しい「頭脳」甚のハヌドりェアプラットフォヌムを遞択するプロセスに぀いお、゜リュヌションの技術的特城に぀いお説明し、必芁なラむブラリヌを組み立おるプロセスずプロセスで遭遇する問題に぀いお簡単に説明したした。 さお、鉄に぀いおは、シンセサむザヌのキヌボヌドマトリックスがどのように配眮されおいるかを確認し、゜フトりェア郚分に぀いおさらに詳しく説明したす。





キヌボヌドマトリックス


シンセサむザヌのキヌボヌドマトリックスは、マむクロコントロヌラヌの倚くのファンがおそらくArduinoに接続しおいる通垞のキヌボヌドマトリックスに非垞に䌌おいたす。 シンセサむザヌキヌごずに、1぀の最も安䟡なモデルのスむッチから2぀のモデルの倧郚分のスむッチを提䟛したす。 キヌが抌されたずきに䞀方が少し早く閉じる2぀の隣接するスむッチを䜿甚しお、マむクロコントロヌラヌは条件付きの力、たたはキヌが抌された速床を決定できるため、察応するボリュヌムの音が再生されたす。 次のようになりたす。





ボヌドの背面には、抌されたキヌの「誀った」読み取りを防ぐダむオヌドがありたすが、同時にいく぀かのキヌを抌しおいたす。 キヌボヌドマトリックスの回路図の䞀郚を次に瀺したす。これらの2぀のスむッチずそれらに接続されおいるダむオヌドが衚瀺されおいたす。





マトリックスをスキャンするために、マむクロコントロヌラヌは列Nのラベルが付いたピンを順番にプルし、行のレベルBのラベルが付いたピンを確認したす。 行のレベルが高い堎合、珟圚アクティブな「列ず行」の組み合わせに察応するキヌが抌されたす。 図はキヌボヌドの䞀郚のみを瀺しおいたす-合蚈76個のキヌがありたす13行ず6 x 2列。これにより、マトリックスのスキャンに合蚈156のオプションが、マむクロコントロヌラヌの25の䜿甚枈み出力が提䟛されたす。 キヌボヌド党䜓のスキャンは毎秒数十回実行され、実行者には芋えたせん。



私のシンセサむザヌでは、キヌボヌドのスキャンを担圓するマむクロコントロヌラヌはもずもず、8 MHzの呚波数で動䜜し、4 KBのROMず192バむトのRAMメモリを備えた8ビットのワンタむムプログラマブルHitachi HD63B05V0マむクロコントロヌラヌでした。 残念なこずに、このコントロヌラヌは、最初の蚘事の冒頭で説明した電力事故の埌、䜜動䞍胜であるこずが刀明したした。 しかし、幞いなこずに、それは私の既存のATmega162コントロヌラヌずほが互換性があり、ボヌド䞊の2぀のトラックのみを切断しお再はんだ付けするこずで眮き換えたした。その1぀はRESETピンで、間違った堎所にあるこずが刀明したしたHD63B05V0など。



このコントロヌラヌをオンにするず他のピンにもあるため組み蟌みのUARTを䜿甚できなかったため、抌されたキヌに関する情報を衚瀺するためにシリアルポヌトのこの䞀方向曞き蟌み専甚実装を䜿甚したした。 たた、シリアルポヌトの゜フトりェア実装も䜿甚するTinySafeBootブヌトロヌダヌは、将来のファヌムりェア曎新を可胜にするためにマむクロコントロヌラヌに泚がれたした。 すべおの高レベルシンセサむザヌ゜フトりェアの迅速な開発のための蚀語ずしおPython + Qt5を遞択したため、TinySafeBootのために、AVRマむクロコントロヌラヌのファヌムりェアを読み曞きできるPythonモゞュヌルも䜜成したした。 AVRマむクロコントロヌラヌ自䜓は、EmbedSky E8ボヌドのUART1シリアルポヌトに接続され、レベル倉換の必芁性を回避するために3.3Vで駆動されたす。



AVRのファヌムりェア゜ヌス
#include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <string.h> #include "dbg_putchar.h" #define MIDI_BASE 18 #define ZERO_BASE 28 #define KEYS_COUNT 76 #define hiz(port, dir) do { \ (dir) = 0; \ (port) = 0; \ } while(0) #define alow(port, dir) do { \ (dir) = 0xff; \ (port) = 0; \ } while(0) uint8_t keys[KEYS_COUNT]; /* Get state of a row by its index * starting from 1 to 13 */ uint8_t getRow(uint8_t idx) { if (idx <= 8) { return (PINC & (1 << (8 - idx))); } else if (idx >= 9 && idx <= 11) { return (PINE & (1 << (11 - idx))); } else if (idx == 12) { return (PINA & (1 << PIN6)); } else if (idx == 13) { return (PINA & (1 << PIN4)); } return 0; } inline void activateColumn1(uint8_t idx) { PORTD = 0x00 | (1 << (8 - idx)); PORTB = 0x00; } void activateColumn2(uint8_t idx) { if (idx <= 3) { PORTB = 0x00 | (1 << (idx + 4)); PORTD = 0x00; } else if (idx == 4) { PORTB = 0x00 | (1 << PIN4); PORTD = 0x00; } else if (idx == 5 || idx == 6) { PORTD = 0x00 | (1 << (idx - 5)); PORTB = 0x00; } } inline void deactivateColumns(void) { PORTD = 0x00; PORTB = 0x00; } inline void initPorts(void) { hiz(PORTA, DDRA); hiz(PORTC, DDRC); hiz(PORTE, DDRE); PORTB = 0x00; DDRB = 0xfe; DDRD = 0xff; } void resetRows(void) { /* output low */ alow(PORTC, DDRC); alow(PORTE, DDRE); /* don't touch PA7 & PA5 */ DDRA |= 0x5f; PORTA &= ~0x5f; _delay_us(10); /* back to floating input */ hiz(PORTC, DDRC); hiz(PORTE, DDRE); DDRA &= ~0x5f; } /* base MIDI note number is 25: C#0 */ int main(void) { uint8_t row, col, layer; uint8_t note, offset; initPorts(); memset(keys, 0, sizeof(keys)); dbg_tx_init(); dbg_putchar('O'); dbg_putchar('K'); while(1) { for (layer = 0; layer < 2; layer++) { for (col = 1; col <= 6; col++) { if (!layer) activateColumn1(col); else activateColumn2(col); for (row = 1; row <= 13; row++) { note = 6 * row + col + MIDI_BASE; offset = note - ZERO_BASE; if (getRow(row)) { if (!layer) { /* increase velocity counter */ if (keys[offset] < 254 && !(keys[offset] & 0x80)) keys[offset]++; } else { if (!(keys[offset] & 0x80)) { /* generate note-on event */ dbg_putchar(0x90); dbg_putchar(note); /*dbg_putchar(keys[offset]);*/ dbg_putchar(0x7f); /* stop counting */ keys[offset] |= 0x80; } } } else { if (layer) continue; if (keys[offset] & 0x80) { /* generate note off event */ dbg_putchar(0x90); dbg_putchar(note); dbg_putchar(0x00); /* reset key state */ keys[offset] = 0x00; } } } deactivateColumns(); resetRows(); } } } return 0; }
      
      







TinySafeBoot甚のPythonモゞュヌル
 import serial import binascii import struct import intelhex import sys class TSB(object): CONFIRM = '!' REQUEST = '?' def __init__(self, port): self.port = serial.Serial(port, baudrate=9600, timeout=1) self.flashsz = 0 def check(self): if not self.flashsz: raise Exception("Not activated") def activate(self): self.port.write("@@@") (self.tsb, self.version, self.status, self.sign, self.pagesz, self.flashsz, self.eepsz) = \ struct.unpack("<3sHB3sBHH", self.port.read(14)) self.port.read(2) self.pagesz *= 2 self.flashsz *= 2 self.eepsz += 1 assert(self.port.read() == self.CONFIRM) def rflash(self, progress=None, size=0): self.check() self.port.write("f") self.addr = 0 self.flash = "" size = self.flashsz if not size else size while self.addr < size: if progress is not None: progress("read", self.addr, size) self.port.write(self.CONFIRM) page = self.port.read(self.pagesz) if len(page) != self.pagesz: raise Exception("Received page too short: %d" % len(page)) self.addr += len(page) self.flash += page return self.flash.rstrip('\xff') def wflash(self, data, progress=None): if len(data) % self.pagesz != 0: data = data + "\xff" * (self.pagesz - (len(data) % self.pagesz)) assert(len(data) % self.pagesz == 0) self.check() self.port.write("F") self.addr = 0 assert(self.port.read() == self.REQUEST) while self.addr < len(data): if progress is not None: progress("write", self.addr, len(data)) self.port.write(self.CONFIRM) self.port.write(data[self.addr:self.addr + self.pagesz]) self.addr += self.pagesz assert(self.port.read() == self.REQUEST) self.port.write(self.REQUEST) return self.port.read() == self.CONFIRM def vflash(self, data, progress=None): fw = self.rflash(progress, len(data)) return fw == data def info(self): print "Tiny Safe Bootloader: %s" % self.tsb print "Page size: %d" % self.pagesz print "Flash size: %d" % self.flashsz print "EEPROM size: %d" % self.eepsz if __name__ == "__main__": import argparse def progress(op, addr, total): sys.stdout.write("\r%s address: $%0.4x/$%0.4x" % (op, addr, total)) sys.stdout.flush() parser = argparse.ArgumentParser() parser.add_argument("filename", help="firmware file in Intel HEX format") parser.add_argument("--device", help="Serial port to use for programming", default="/dev/ttyUSB0") args = parser.parse_args() tsb = TSB(args.device) tsb.activate() tsb.info() fw = intelhex.IntelHex(args.filename) assert(tsb.wflash(fw.tobinstr(), progress)) assert(tsb.vflash(fw.tobinstr(), progress)) print "\nOK\n"
      
      







AVRのプログラマヌずしお、私はたずLaunchpad MSP430をベヌスにしたプログラマヌを䜿甚したしたが、そのうちいく぀かがありたすが、この仮蚭の奇跡ちなみにうたくいきたすは、䞭囜から到着したTL866CS MiniProプログラマヌに取っお代わりたした。 新しいプログラマヌの気持ちは非垞にポゞティブです。



倖郚RAMチップを接続するためのAVRマむクロコントロヌラヌむンタヌフェヌスを介した非垞に独創的なスキャン方法を含む、シンセサむザヌのキヌボヌド蚭蚈ずスキャン方法に関する非垞に詳现な情報は、 OpenMusicLabsりェブサむトで説明されおいたす



Realtime Preemptionサポヌトを䜿甚したカヌネルのクッキング


スケゞュヌラをより现かく制埡し、サりンドを再生する際のレむテンシヌを枛らすためず、スポヌツの関心のために、私はカヌネルをPREEPMT RTパッチずずもに䜿甚するこずに決めたした。その䞻な機胜の1぀は割り蟌みも「プロセス」になりたす優先床に基づいおスケゞュヌラヌによっお暪取りされたす。 S5PV210プロセッサ甚にSamsungが提䟛する元のコアは、システムの構築に基づいお、明らかにAndroidのカヌネルバヌゞョン3.0.8に基づいおいたす。 このカヌネルバヌゞョン3.0.8のプロゞェクトサむトで利甚可胜なRT_PREEMPTパッチは、競合なしで゜ヌスに重ね合わせるこずを望みたせんでしたが、最終的にはすべおの競合を手動で解決し、バヌゞョン3.0.8-rt23にパッチを適甚するこずができたした。



スピンロックやミュヌテックスなどの基本構造もこの方法で倉曎されたカヌネルで倉曎されるこずが刀明したため、ビデオカメラ、静電容量匏タッチスクリヌンコントロヌラヌなどの䞀郚の呚蟺機噚の独自ドラむバヌは、最悪の堎合、コンパむルされたオブゞェクトファむルずしおリンクされなくなりたしたオヌディオコヌデック。 埌でそれらに戻り、それらをオフにしお、新しく組み立おられたリアルタむムカヌネルを䜿甚しおボヌドを初めお起動しようずするず、すぐにカヌネルパニックが発生したす。 kgdbデバッガヌが起動する前でも発生したため埌で刀明したように、起動しおも動䜜したせん、デバッグのために、 start_kernel



init/main.c



ファむル start_kernel



関数に挿入しお堎所を特定する必芁がありたしたすべおが厩れおいたす。 したがっお、カヌネルhrtimers_init()



最埌hrtimers_init()



やったこずは、 hrtimers_init()



関数を呌び出すこずであり、これは高解像床タむマヌずその割り蟌みを初期化するこずでした。 このコヌドはプラットフォヌム固有であり、この堎合はarch/arm/plat-s5p/hr-time-rtc.c



たす。 前述したように、PREEMPT RTパッチを䜿甚したカヌネルの䞻な機胜の1぀は、割り蟌みがスレッドになるこずです。 これは通垞のカヌネルで可胜ですが、デフォルトでPREEMPT RTを䜿甚するカヌネルは、そのようなほずんどすべおの割り蟌みを䜜成しようずしたす。 コヌドをさらに分析するず、kthreadd_taskタスクがこれらのスレッドの操䜜に䜿甚され、 start_kernel



関数の最埌で初期化されるこずが瀺されたした。タむマヌが初期化されるよりもずっず埌です。 この䜎䞋は、kthreadd_taskがただNULLであったのに、カヌネルがストリヌミングによっおタむマヌを䞭断しようずしたためです。 これは、どのような状況でもストリヌミングされるべきではない個々の割り蟌みを蚭定するこずで解決されたす。IRQF_NO_THREADフラグは、 hr-time-rtc.c



タむマヌ割り蟌みフラグに远加されたした。 やった カヌネルは起動したしたが、これはほんの始たりです...



前述したように、副䜜甚の1぀は、オヌディオ入力/出力を担圓するモゞュヌルが新しいカヌネルずのリンクを停止したこずです。 これは、PREEMPT RTを䜿甚するカヌネルがバヌゞョン3.0.8でSLABメモリ管理メカニズムのみをサポヌトし、最初はモゞュヌルが新しいカヌネルでサポヌトされおいないSLUBメカニズムを有効にしおコンパむルされたためです。 しかし、Kaspersky Labで働くこずができたのは幞運で、ARMのHex-Raysデコンパむラヌを䜿甚しおドラむバヌずコヌデックファむルを逆コンパむルするよう同僚に説埗し、その埌、゜ヌスコヌドをほが完党に再䜜成するこずができたした。 実際には、その結果、オヌディオむンタヌフェむスは「新しい」ドラむバで決定されたため、WM8960マむクロサヌキットレゞスタを初期化するための䜎レベルの手順の違いにより、サりンドはアヌティファクトで再生されたした。 しばらくの間、ドラむバヌを調敎しようずしたしたが、その埌、より簡単な方法を遞択したした-私は䞭囜の䌚瀟EmbedSky Techに送っお、そこでミニコンピュヌタヌずPREEMPT_RTのパッチを賌入し、オヌディオドラむバヌファむルのコンパむルず送信を䟝頌したした。 すぐに応答し、最終的にサりンドが期埅どおりに機胜するファむルを送っおくれたした。



ずころで、逆コンパむルしたドラむバヌで忙しかったのですが、kgdbデバッガヌが自分のカヌネルでも元のカヌネルでも動䜜しないこずがわかりたした。 刀明したように、シリアルポヌトの同期ポヌリングが必芁です。これは、Samsungシリアルポヌトドラむバヌ drivers/tty/serial/samsung.c



では利甚できたせんでした。 このパッチに基づいおドラむバヌに必芁なサポヌトを远加し、その埌デバッガヌが動䜜したした。



さらに掘りたす。 新しいコアの第2の副䜜甚は非垞に䜎く、倧きな「遅れ」、S5PV210チップ䞊のシステムの4぀のすべおの長いシリアルポヌトの速床であるこずが刀明したした。ポヌリングキヌボヌドシンセサむザヌ。 長い間、私はその理由を理解しようずしたしたが、端末に各文字を入力するず、数癟䞇のシリアルポヌト割り蟌みが生成されるこずに気づきたした-カヌネルはそれらを凊理するために急いでいないようでした。 最埌に、䞊蚘のフラグを䜿甚しおIRQF_NO_THREADすべおのシリアルポヌト割り蟌みを非スレッドにするこずで、この問題を解決したした。 この゜リュヌションserial_core.c



、Samsungドラむバヌに加えお、 serial_core.h



ずserial_core.h



を倉曎しなければならず、䞀般的にすべおのシリアルポヌトに圱響するため、あたり矎しくありたせんでした。 PREEMPT RTを䜿甚したカヌネルでは、NO_THREADのドラむバヌでspin_lock_tを䜿甚できないが、raw_spinlock_tを䜿甚する必芁があるため。



前述したように、512 MBのRAMからビデオカメラ、ハヌドりェアコヌデック、HDMIなどのさたざたな呚蟺機噚をサポヌトする元のカヌネルでは、玄390 MBしか䜿甚できず、残りは䞊蚘のデバむス甚に予玄されおいたした、垞にカヌネル構成プロセス䞭に無効にされた堎合でも。 特にシンセサむザヌがサンプルを保存するのに䜙分な120 MBのRAMが邪魔にならないこずを考えるず、非垞に無駄です。 メモリはファむルarch/arm/mach-s5pv210/mach-tq210.c



に予玄されおいたした。これは、特定のマシンこの堎合はボヌドの構成ずデバむスに関するすべおの情報を収集するための䞻芁なポむントです。 メモリの割り圓おs5p_reserve_bootmem



関数の呌び出しに぀いおコメントし、 s5p_reserve_bootmem



機胜するために120 MBの远加メモリを取埗したす。



カヌネルに加えられた最埌の倉曎は、オヌディオデヌタの最小バッファサむズに関するもので、元のメモリの1ペヌゞに盞圓し、44100 Hzのサンプリング呚波数で、16ビットの2チャネルがそれぞれ玄20ミリ秒-少し倚かった。 この倀は、ファむルsound/soc/samsung/dma.c



で128バむトに倉曎され、その埌、安定性ずパフォヌマンスを犠牲にするこずなく、最小バッファヌサむズが数ミリ秒に削枛されたした。



PREEMPT RTおよびGitHubのすべおの倉曎を含むカヌネル゜ヌスコヌド



AVRマむクロコントロヌラヌはどのようにLinuxSamplerず通信したすか


AVRはミニコンピュヌタヌボヌドのシリアルポヌトに接続され、既補のMIDIメッセヌゞを゜フトりェアUARTに出力したす。 ドラむバヌを蚘述する必芁をなくすために、すべおのオヌディオおよびMIDIデヌタのトランスポヌトずしおJACKサヌバヌを䜿甚するこずが決定されたした。 Cの小さなアプリケヌションがシリアルポヌトに接続し、JACKに自身をMIDI-OUTずしお登録し、受信したすべおのMIDIメッセヌゞのリダむレクトを開始したす。JACKはすでにそれらをLinuxSamplerに配信したす。 安くお陜気な。



シリアルポヌトずJACK間のブリッゞアプリケヌションの゜ヌスコヌド
 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/time.h> #include <unistd.h> #include <assert.h> #include <string.h> #include <sysexits.h> #include <errno.h> #include <signal.h> #include <fcntl.h> #include <termios.h> #include <jack/jack.h> #include <jack/midiport.h> #define UART_SPEED B9600 jack_port_t *output_port; jack_client_t *jack_client = NULL; int input_fd; void init_serial(int fd) { struct termios termios; int res; res = tcgetattr (fd, &termios); if (res < 0) { fprintf (stderr, "Termios get error: %s\n", strerror(errno)); exit (EXIT_FAILURE); } cfsetispeed (&termios, UART_SPEED); cfsetospeed (&termios, UART_SPEED); termios.c_iflag &= ~(IGNPAR | IXON | IXOFF); termios.c_iflag |= IGNPAR; termios.c_cflag &= ~(CSIZE | PARENB | CSTOPB | CREAD | CLOCAL); termios.c_cflag |= CS8; termios.c_cflag |= CREAD; termios.c_cflag |= CLOCAL; termios.c_lflag &= ~(ICANON | ECHO); termios.c_cc[VMIN] = 3; termios.c_cc[VTIME] = 0; res = tcsetattr (fd, TCSANOW, &termios); if (res < 0) { fprintf (stderr, "Termios set error: %s\n", strerror(errno)); exit (EXIT_FAILURE); } } double get_time(void) { double seconds; int ret; struct timeval tv; ret = gettimeofday(&tv, NULL); if (ret) { perror("gettimeofday"); exit(EX_OSERR); } seconds = tv.tv_sec + tv.tv_usec / 1000000.0; return seconds; } double get_delta_time(void) { static double previously = -1.0; double now; double delta; now = get_time(); if (previously == -1.0) { previously = now; return 0; } delta = now - previously; previously = now; assert(delta >= 0.0); return delta; } static double nframes_to_ms(jack_nframes_t nframes) { jack_nframes_t sr; sr = jack_get_sample_rate(jack_client); assert(sr > 0); return (nframes * 1000.0) / (double)sr; } static double nframes_to_seconds(jack_nframes_t nframes) { return nframes_to_ms(nframes) / 1000.0; } static jack_nframes_t ms_to_nframes(double ms) { jack_nframes_t sr; sr = jack_get_sample_rate(jack_client); assert(sr > 0); return ((double)sr * ms) / 1000.0; } static jack_nframes_t seconds_to_nframes(double seconds) { return ms_to_nframes(seconds * 1000.0); } static void process_midi_output(jack_nframes_t nframes) { int t, res; void *port_buffer; char midi_buffer[3]; jack_nframes_t last_frame_time; port_buffer = jack_port_get_buffer(output_port, nframes); if (port_buffer == NULL) { printf("jack_port_get_buffer failed, cannot send anything.\n"); return; } jack_midi_clear_buffer(port_buffer); last_frame_time = jack_last_frame_time(jack_client); t = seconds_to_nframes(get_delta_time()); res = read(input_fd, midi_buffer, sizeof(midi_buffer)); if (res < 0 && errno == EAGAIN) return; res = jack_midi_event_write(port_buffer, t, midi_buffer, 3); if (res != 0) { printf("jack_midi_event_write failed, NOTE LOST."); } } static int process_callback(jack_nframes_t nframes, void *notused) { if (nframes <= 0) { printf("Process callback called with nframes = 0; bug in JACK?"); return 0; } process_midi_output(nframes); return 0; } int connect_to_input_port(const char *port) { int ret; ret = jack_port_disconnect(jack_client, output_port); if (ret) { printf("Cannot disconnect MIDI port."); return -3; } ret = jack_connect(jack_client, jack_port_name(output_port), port); if (ret) { printf("Cannot connect to %s.", port); return -4; } printf("Connected to %s.", port); return 0; } static void init_jack(void) { int i, err; jack_client = jack_client_open("midibridge", JackNullOption, NULL); if (jack_client == NULL) { printf("Could not connect to the JACK server; run jackd first?"); exit(EXIT_FAILURE); } err = jack_set_process_callback(jack_client, process_callback, 0); if (err) { printf("Could not register JACK process callback."); exit(EXIT_FAILURE); } char port_name[32]; snprintf(port_name, sizeof(port_name), "midi_out"); output_port = jack_port_register(jack_client, port_name, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); if (output_port == NULL) { printf("Could not register JACK output port '%s'.", port_name); exit(EXIT_FAILURE); } if (jack_activate(jack_client)) { printf("Cannot activate JACK client."); exit(EXIT_FAILURE); } } static void usage(void) { fprintf(stderr, "usage: midibridge -a <input port>\n"); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { int ch; char *autoconnect_port_name = NULL; while ((ch = getopt(argc, argv, "a:")) != -1) { switch (ch) { case 'a': autoconnect_port_name = strdup(optarg); break; default: usage(); } } input_fd = open("/dev/ttySAC1", O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if (input_fd < 0) { fprintf(stderr, "Cannot open serial port %s\n", strerror(errno)); return EXIT_FAILURE; } init_serial (input_fd); init_jack(); if (autoconnect_port_name) { if (connect_to_input_port(autoconnect_port_name)) { printf("Couldn't connect to '%s', exiting.", autoconnect_port_name); exit(EXIT_FAILURE); } } getc(stdin); return 0; }
      
      









この゜リュヌションでは、JACKぞのオヌディオ出力をサポヌトするmplayerを介しおARMおよびWAV / MP3甚にコンパむルしたjack-smf-player



を䜿甚しお、JACKでMIDIファむルを再生するこずもできたす。



ボヌナス


以前の投皿に察するnefelim4agのコメントのおかげで、私はlibhybris-通垞のLinuxシステムでAndroidドラむバヌを䜿甚できるラむブラリヌの存圚に぀いお孊びたした。 タンバリンずのいく぀かのダンスの埌、残念ながら、私はシステムでlibhybrisを取埗し、OpenGL ES 2.0、EGLFS、およびQt Quick 2.0をサポヌトしおQt 5およびPyQt5を再構築できたした。 珟圚、私のナヌザヌむンタヌフェむスはQt Quickを䜿甚しおおり、 Android 4.0で刈り取られおいる最新のファッショントレンドに沿っおいたす。







最埌に


シンセサむザヌが半分に分類された状態にあるため、小さなデモはこれたでのずころオヌディオのみです。 ビデオは、䞭囜で泚文されたマザヌボヌドが到着し、シンセサむザヌのすべおの郚品を接続した埌、8月に生たれる可胜性が高い次の投皿にありたす。 さらに、次の投皿は、このような䜎レベルのカヌネル操䜜ではなく、PyQt5およびQtQuickの゜フトりェアのナヌザヌ郚分を念頭に眮いお、もちろん、結果を実蚌するプロセスに専念するでしょう。



誰かが興味がある堎合

ARM甚にクロスコンパむルされたすべおの゜フトりェアをリストする
  • alsa-lib-1.0.27.2
  • alsa-utils-1.0.27.2
  • libaudiofile-0.3.6
  • dbus-1.8.0
  • dropbear-2014.63
  • fftw-3.3.3
  • fluidsynth-1.1.6
  • fontconfig-2.11.0
  • freetype-2.5.3
  • glib-2.34.3
  • libicu-52.1
  • jack-audio-connection-kit-0.121.3
  • jack-smf-utils-1.0
  • libffi-3.0.13
  • libgig-3.3.0
  • libgig-svn
  • リブリブリス
  • libsamplerate-0.1.8
  • libsndfile-1.0.25
  • linuxsampler-1.0.0
  • linuxsampler-svn
  • mplayer SVN-r36900-4.4.6
  • openssl-1.0.0l
  • psutil-1.2.1
  • pajack-0.5.2
  • PyQt-gpl-5.2
  • pyserial-2.7
  • Python 2.7.6
  • strace-4.8
  • tslib-1.4.1




このリストから䜕かを収集する必芁があり、問題がある堎合は、喜んで私の経隓を共有したす。 さらに、ここで述べられおいるこずの倚くは、FriendlyARM Tiny210ず呌ばれる別の䞀般的なプラットフォヌムにも圓おはたりたす。これは、同じS5PV210プロセッサに基づいおおり、おそらく誰かがリアルタむムコアを䜿甚する必芁がありたす。



All Articles