
Dalam
artikel sebelumnya, saya menggambarkan garis penalaran saat mem-parsing format data biner yang tidak diketahui. Menggunakan Hex-editor Synalaze It !, saya menunjukkan bagaimana Anda dapat mengurai header file biner dan menyorot blok data utama. Karena dalam kasus format SNG blok-blok ini membentuk struktur hierarkis, saya berhasil menggunakan rekursi dalam tata bahasa untuk secara otomatis membangun tampilan pohon mereka dalam bentuk yang dapat dibaca manusia.
Pada artikel ini, saya akan menjelaskan pendekatan serupa yang saya gunakan untuk mengurai langsung data musik. Dengan menggunakan fitur built-in editor Hex, saya akan membuat prototipe konverter data ke dalam format Midi yang umum dan sederhana. Kita harus menghadapi sejumlah jebakan dan teka-teki tentang tugas yang tampaknya sederhana untuk mengkonversi sampel waktu. Akhirnya, saya akan menjelaskan bagaimana Anda dapat menggunakan hasil yang diperoleh dan tata bahasa file biner untuk menghasilkan bagian dari kode untuk konverter masa depan.
Parsing data musik
Jadi, saatnya mencari tahu bagaimana data musik disimpan dalam file .SNG. Sebagian, saya menyebutkan ini di artikel sebelumnya. Dokumentasi synthesizer menyatakan bahwa file SNG dapat berisi hingga 128 "lagu", yang masing-masing terdiri dari 16 trek dan satu trek master (untuk merekam acara global dan mengubah efek utama). Berbeda dengan format Midi, di mana acara musik hanya mengikuti satu sama lain dengan delta waktu tertentu, format SNG berisi ukuran musik.
Ukuran adalah semacam wadah untuk urutan catatan. Dimensi ukuran ditunjukkan dalam notasi musik. Misalnya, 4/4 - berarti ukurannya berisi 4 ketukan, yang masing-masing sama dalam durasi hingga seperempat not. Sederhananya, ukuran seperti itu akan berisi 4 not seperempat, atau 2 not setengah, atau 8 delapan not.
Begini tampilannya dalam notasi musik Langkah-langkah dalam file SNG digunakan untuk mengedit trek di sequencer synthesizer bawaan. Dengan menggunakan menu, Anda dapat menghapus, menambah, dan menduplikasi tindakan di mana saja di trek. Anda juga dapat mengulang siklus atau mengubah dimensi mereka. Akhirnya, Anda cukup mulai merekam trek dari ukuran apa pun.
Mari kita coba lihat bagaimana semua ini disimpan dalam file biner. Wadah umum untuk "lagu" adalah blok SGS1. Data untuk setiap lagu disimpan dalam blok SDT1:

Blok SPR1 dan BMT1 menyimpan pengaturan lagu umum (tempo, pengaturan metronom) dan pengaturan trek individual (tambalan, efek, pengaturan arpeggiator, dll.). Kami tertarik pada blok TRK1 - ini berisi acara musik. Tetapi Anda perlu turun beberapa tingkat hirarki lagi - untuk memblokir MTK1

Akhirnya, kami menemukan trek kami - ini adalah blok MTE1. Mari kita coba rekam jejak kosong berdurasi pendek pada synthesizer dan satu bit lagi - untuk memahami bagaimana informasi tentang tindakan dalam bentuk biner disimpan.

Tampaknya ukuran disimpan sebagai struktur delapan byte. Tambahkan beberapa catatan:

Jadi, kita dapat mengasumsikan bahwa semua peristiwa disimpan dalam bentuk yang sama. Awal blok MTE berisi informasi yang masih belum diketahui, kemudian urutan struktur delapan byte menuju akhir. Buka editor tata bahasa dan buat struktur
acara dengan ukuran 8 byte.
Tambahkan struktur
mte1Chunk yang mewarisi
childChunk dan letakkan tautan ke
acara di struktur
data . Kami menunjukkan bahwa
peristiwa dapat diulang berkali-kali tanpa batas. Selanjutnya, melalui eksperimen, kami mengetahui ukuran dan tujuan beberapa byte sebelum dimulainya aliran peristiwa trek. Saya mendapat yang berikut:

Di awal blok MTE1, jumlah acara trek, jumlahnya, dan, mungkin, dimensi acara disimpan. Setelah menerapkan tata bahasa, blok mulai terlihat seperti ini:

Mari kita beralih ke aliran peristiwa. Setelah menganalisis beberapa file dengan urutan catatan yang berbeda, gambar berikut muncul:
# | Jenis | Representasi biner |
---|
1 | Kalahkan 1 | 01 00 00 ... |
2 | Catatan | 09 00 3C ... |
3 | Catatan | 09 00 3C ... |
4 | Catatan | 09 00 3C ... |
5 | Beat2 | 01 C3 90 ... |
6 | Catatan | 09 00 3C ... |
7 | Akhir Track | 03 88 70 ... |
Sepertinya byte pertama mengkodekan jenis acara. Tambahkan bidang
jenis ke struktur
acara . Mari kita buat dua struktur yang mewarisi
acara :
ukur dan
catat . Kami menunjukkan Nilai Tetap yang sesuai untuk masing-masing. Dan akhirnya, tambahkan tautan ke struktur ini dalam
data blok
mte1Chunk .

Terapkan perubahan:

Kami telah membuat kemajuan yang baik. Masih memahami bagaimana tinggi dan kekuatan catatan dikodekan, serta perubahan waktu dari setiap peristiwa relatif terhadap yang lain. Mari kita coba lagi membandingkan file kita dengan hasil ekspor ke midi, dilakukan melalui menu synthesizer. Kali ini kami secara khusus tertarik pada acara mengklik catatan.

Peristiwa yang sama di file SNG Hebat! Tampaknya nada dan tekanan nada dikodekan dengan cara yang persis sama seperti dalam format midi hanya dengan beberapa byte. Tambahkan bidang yang sesuai ke tata bahasa.
Sayangnya, segala sesuatunya tidak begitu sederhana dengan pergeseran sementara.
Kami menangani durasi dan delta
Dalam format midi, acara NoteOn dan NoteOff terpisah. Durasi catatan ditentukan oleh waktu delta antara peristiwa-peristiwa ini. Dalam kasus format SNG, di mana tidak ada analog dari peristiwa NoteOff, durasi dan nilai delta waktu harus disimpan dalam satu struktur.
Untuk memahami bagaimana mereka disimpan, saya mencatat beberapa urutan catatan dari berbagai durasi pada synthesizer.

Jelas, data yang kita butuhkan adalah dalam 4 byte terakhir dari struktur acara. Keteraturan tidak terlihat dengan mata telanjang, jadi kami memilih byte yang menarik bagi kami di editor dan menggunakan alat Panel Data.
Rupanya, baik durasi catatan dan pergeseran waktu dikodekan oleh sepasang byte (UInt16). Dalam hal ini, urutan byte terbalik - Little Endian. Setelah membandingkan jumlah data yang cukup, saya menemukan bahwa waktu delta di sini tidak dihitung dari peristiwa sebelumnya seperti di midi, tetapi dari awal jam. Jika catatan berakhir pada ukuran berikutnya, maka pada ukuran saat ini panjangnya akan 0x7fff, dan di berikutnya akan diulang dengan delta 0x7fff yang sama dan durasi diukur dari awal ukuran baru. Sejalan dengan itu, jika nada terdengar beberapa langkah, maka pada masing-masing perantara satu durasi dan delta akan sama dengan 0x7fff.
Sirkuit kecil
Unit delta / durasi waktu dihitung dalam sel. Catatan 1 terdengar normal, dan Catatan 2 terus terdengar dalam langkah-langkah ke-2 dan ke-3. Menurut saya, semua ini terlihat agak kasar. Di sisi lain, dalam notasi musik, not terus menerus terdengar beberapa langkah ditunjukkan dengan cara yang sama oleh legato.
Di mana "burung kakaktua" memiliki durasi? Seperti midi, tics digunakan di sini. Dari dokumentasi diketahui bahwa durasi satu share adalah 480 ticks. Dengan tempo 100 ketukan per menit dan dimensi 4/4, durasi not seperempat adalah (60/100) = 0,6 detik. Dengan demikian, durasi satu tick adalah 0,6 / 480 = 0,00125 detik. Ketukan 4/4 standar akan bertahan 4 * 480 = 1920 ticks atau 2,4 detik pada kecepatan 100 bpm.
Semua ini akan bermanfaat bagi kita di masa depan. Sementara itu, tambahkan durasi dan delta ke struktur
catatan kami. Juga, perhatikan bahwa ada bidang dalam struktur kebijaksanaan yang menyimpan jumlah acara. Bidang lain berisi nomor seri ukuran - tambahkan mereka ke struktur
ukuran .

Prototipe konverter
Sekarang kami memiliki cukup informasi untuk mencoba mengonversi data. Editor Hex Synalaze It dalam versi pro memungkinkan Anda untuk menulis skrip dengan python atau lua. Saat membuat skrip, Anda perlu memutuskan apa yang ingin kami kerjakan: dengan tata bahasa itu sendiri, dengan masing-masing file pada disk atau entah bagaimana memproses data yang diurai. Sayangnya, masing-masing templat memiliki beberapa batasan. Program ini menyediakan sejumlah kelas dan metode untuk bekerja, tetapi tidak semuanya dapat diakses dari semua templat. Mungkin ini adalah cacat dalam dokumentasi, tetapi saya belum menemukan bagaimana Anda dapat memuat tata bahasa untuk daftar file, parsing dan gunakan struktur yang dihasilkan untuk mengekspor data.
Oleh karena itu, kami akan membuat skrip untuk bekerja dengan hasil penguraian file saat ini. Templat ini mengimplementasikan tiga metode: init, terminate, dan processResult. Yang terakhir disebut secara otomatis dan secara rekursif melewati semua struktur dan data yang diterima selama parsing.
Untuk menulis data yang dikonversi di midi, kami menggunakan toolkit Python MIDI (https://github.com/vishnubob/python-midi). Karena kami menerapkan Bukti Konsep, kami tidak akan melakukan konversi durasi catatan dan delta. Sebagai gantinya, kami menetapkan nilai tetap. Catatan dengan durasi 0x7fff atau dengan delta serupa hanya dibuang untuk saat ini.
Kemampuan editor skrip bawaan sangat terbatas, sehingga semua kode harus ditempatkan dalam satu file.
gist.github.com/bkotov/71d7dfafebfe775616c4bd17d6ddfe7bJadi, mari kita coba konversi file dan dengarkan apa yang kita dapatkan
Hmm ... Dan ternyata cukup menarik. Hal pertama yang terpikir oleh saya ketika saya mencoba untuk merumuskan seperti apa itu musik tanpa struktur. Saya akan mencoba memberikan definisi:
Musik tidak terstruktur - sepotong musik dengan struktur yang direduksi, dibangun di atas harmoni. Catatan durasi dan interval antara catatan dibatalkan atau dikurangi dengan nilai yang sama.Semacam suara harmonis. Biarlah mutiara (dengan analogi dengan putih, biru, merah, merah muda, dll), tampaknya tidak ada yang mengambil kombinasi ini.
Mungkin kita harus mencoba untuk melatih jaringan saraf pada data saya, mungkin hasilnya akan menarik.
Tugas untuk menghangatkan pikiran
Ini semua luar biasa, tetapi masalah utama masih belum terpecahkan. Kita perlu mengubah durasi note menjadi event NoteOff, dan waktu offset event relatif terhadap awal pengukuran menjadi delta waktu antara event yang berdekatan. Saya akan mencoba merumuskan kondisi masalah secara lebih formal.
Tantangan:
1
1
2
3
...
N
2
...
N
1
...
: 1
: 1920
: Int
: Int
: 9
: 0-127
: 0-127
: 0-1920 0xFF
: 0-1920 0xFF
, , 0xFF, =0xFF . , . = = 0xFF.
.
midi. :
:
: 9
: 0-127
: 0-127
: Int
:
: 8
: 0-127
: 0-127
: Int
Tugasnya sedikit disederhanakan. Dalam file SNG nyata, setiap ukuran dapat memiliki dimensi yang berbeda. Selain acara Note On / Off, acara lain juga akan terjadi di aliran, misalnya, menekan pedal penopang atau mengubah nada menggunakan pitchBend.
Saya akan memberikan solusi saya untuk masalah ini di artikel selanjutnya (jika ada).
Hasil saat ini
Karena solusi dengan skrip tidak mengurangi jumlah file yang berubah-ubah, saya memutuskan untuk menulis konverter konsol di Swift. Jika saya menulis konverter dua arah, maka struktur tata bahasa yang dibuat akan berguna bagi saya dalam kode. Anda dapat mengekspornya ke struktur C atau bahasa lain menggunakan fungsionalitas scripting yang sama yang dibangun ke Synalize It! File dengan contoh ekspor semacam itu dibuat secara otomatis ketika Anda memilih template Grammar.

Saat ini, konverter sudah 99% selesai (dalam bentuk yang sesuai dengan saya dalam hal fungsi). Saya berencana untuk meletakkan kode dan tata bahasa di github.
Contoh, untuk mana semuanya dimulai,
Anda dapat mendengarkan di sini .
Bagaimana bagian ini terdengar sudah jadi.