Mục lục:

Bộ trống MIDI trên Python và Arduino: 5 bước (có hình ảnh)
Bộ trống MIDI trên Python và Arduino: 5 bước (có hình ảnh)

Video: Bộ trống MIDI trên Python và Arduino: 5 bước (có hình ảnh)

Video: Bộ trống MIDI trên Python và Arduino: 5 bước (có hình ảnh)
Video: Biến hình khi văn phòng Schannel có khách đến 2024, Tháng mười một
Anonim
Image
Image
Bộ trống MIDI trên Python và Arduino
Bộ trống MIDI trên Python và Arduino
Bộ trống MIDI trên Python và Arduino
Bộ trống MIDI trên Python và Arduino

Tôi luôn muốn mua một bộ trống kể từ khi tôi còn là một đứa trẻ. Hồi đó, tất cả các thiết bị âm nhạc không có tất cả các ứng dụng kỹ thuật số như chúng ta có rất nhiều ngày nay, do đó giá cả cùng với kỳ vọng là quá cao. Gần đây, tôi đã quyết định mua một bộ trống rẻ nhất từ eBay, với ưu tiên duy nhất: Khả năng xé nó ra và gắn phần cứng và phần mềm của riêng tôi vào thiết bị.

Việc mua sắm không gây thất vọng chút nào: Bộ trống cuộn di động với 9 miếng đệm âm thanh khác nhau, hai bàn đạp chuyển đổi chân cho trống kick và hi-hat và ổ cắm điện micro-USB. Điều thực sự kích thích, đó là âm thanh đầu ra (Sử dụng thực tế cho bộ này là kết nối loa ngoài và thưởng thức nó). Vì vậy, tôi đã quyết định chuyển đổi nó sang lập trình của riêng tôi qua USB, bộ trống MIDI dựa trên Arduino và Giao diện người dùng dựa trên Python, để sử dụng tiện dụng và dễ dàng sửa đổi như lựa chọn âm lượng, ghi chú và kênh.

Các tính năng của thiết bị:

  • Giá thấp
  • Tạo bộ trống từ bất kỳ đầu vào kỹ thuật số nào - thậm chí cả dãy nút nhấn
  • Chỉ hỗ trợ giao tiếp và cấp nguồn qua giao diện USB - Tích hợp bộ chuyển đổi USB sang UART và thiết bị Arduino
  • Các bộ phận tối thiểu để hoạt động đúng
  • Giao diện người dùng dựa trên Python dễ sử dụng
  • Hỗ trợ MIDI hoàn chỉnh với các chân điều chỉnh tốc độ, ghi chú và Arduino
  • Lưu & Tải cấu hình trống tùy chỉnh được lưu trữ trong bộ nhớ của thiết bị

Hãy tiếp tục dự án…

Bước 1: Lý thuyết về hoạt động

Nguyên lý hoạt động
Nguyên lý hoạt động
Nguyên lý hoạt động
Nguyên lý hoạt động
Nguyên lý hoạt động
Nguyên lý hoạt động

Sơ đồ khối

Trước hết, hãy tập trung vào cấu trúc dự án và chia nó thành các khối riêng biệt:

Bộ trống cuộn

Đơn vị chính của dự án. Nó bao gồm 9 miếng đệm trống riêng biệt, trong đó mỗi miếng đệm là một loạt các nút thay đổi trạng thái logic của chúng khi được đánh. Do cấu trúc của nó, có thể cấu tạo bộ trống cụ thể này từ bất kỳ nút nhấn nào. Mỗi đệm trống được kết nối với điện trở kéo lên trên bảng điện tử chính, do đó trong khi đệm trống được đánh liên tục, một công tắc cụ thể được gắn với mặt đất của mạch và LOW hợp lý xuất hiện trên đường dây đệm trống. Khi không có áp suất nào được áp dụng, công tắc đệm trống sẽ mở và do điện trở kéo lên với đường dây điện, CAO hợp lý xuất hiện trên đường đệm trống. Vì mục đích của dự án là tạo ra một thiết bị MIDI kỹ thuật số hoàn chỉnh, nên tất cả các bộ phận tương tự trên PCB chính có thể bị bỏ qua. Điều quan trọng cần lưu ý là bộ trống đó có hai bàn đạp cho trống kick và hi-hat, chúng cũng được gắn với các điện trở kéo lên và chia sẻ cùng một logic hoạt động như tất cả các miếng trống (Chúng ta sẽ thảo luận về nó một chút sau).

Arduino Pro-Micro

Bộ não của bộ trống. Mục đích của nó là phát hiện xem có tín hiệu phát ra từ đệm trống hay không và cung cấp đầu ra MIDI thích hợp với tất cả các thông số cần thiết: Lưu ý, vận tốc và thời lượng của tín hiệu. Do tính chất kỹ thuật số của miếng đệm trống, chúng có thể được gắn đơn giản với đầu vào kỹ thuật số arduino (tổng cộng 10 chân). Để lưu trữ tất cả các cài đặt mong muốn và thông tin MIDI, chúng tôi sẽ sử dụng bộ nhớ của nó - EEPROM, do đó mỗi khi chúng tôi bật nguồn thiết bị, thông tin MIDI sẽ được tải từ EEPROM, giúp nó có thể lập trình lại và cấu hình lại. Ngoài ra, Arduino Pro-Micro có sẵn trong một gói rất nhỏ và có thể được phân bổ dễ dàng trong hộp bên trong bộ trống.

FTDI USB to Serial Converter

Để lập trình và xác định các tính năng thiết bị của chúng tôi với sự trợ giúp của ứng dụng PC, cần phải chuyển đổi giao diện USB sang nối tiếp, vì Arduino Pro-Micro không có USB. Vì giao tiếp giữa các thiết bị dựa trên UART, thiết bị FTDI được sử dụng trong dự án này, do tính đơn giản của việc sử dụng bất kể các thuộc tính bổ sung của nó.

Ứng dụng PC - Python

Khi nói đến phát triển giao diện người dùng và các dự án xây dựng nhanh, Python là một giải pháp tuyệt vời. Mục đích của ứng dụng UI là giúp xác định lại các thuộc tính MIDI cho bộ trống của chúng tôi thuận tiện hơn nhiều, lưu trữ thông tin, thiết bị chương trình và thực hiện giao tiếp giữa các hệ thống mà không cần phải biên dịch mã lặp đi lặp lại. Bởi vì chúng tôi đang sử dụng giao diện nối tiếp để giao tiếp với bộ trống, có rất nhiều mô-đun miễn phí trên internet, hỗ trợ bất kỳ loại giao tiếp nối tiếp nào. Ngoài ra, như nó sẽ được thảo luận ở phần sau, giao diện UART bao gồm tổng cộng ba chân: RXD, TXD và DTR. DTR được sử dụng để thực hiện thiết lập lại trên mô-đun Arduino, do đó khi chúng ta quan tâm đến việc chạy ứng dụng MIDI hoặc kết nối giao diện người dùng với thiết bị chương trình, hoàn toàn không cần phải gắn lại cáp USB hoặc bất kỳ thứ gì.

Bước 2: Các bộ phận và dụng cụ

Các bộ phận

  • Bộ trống cuộn
  • 2 x Bàn đạp duy trì (Thông thường, bao gồm trong gói DK).
  • FTDI - Bộ chuyển đổi USB sang nối tiếp
  • Arduino Pro Micro
  • Cáp Micro-USB

Dụng cụ

  • Sắt hàn / Trạm
  • Hàn thiếc
  • Dây lõi đơn có đường kính mỏng
  • Cái nhíp
  • Máy cắt
  • Kìm
  • Dao
  • Cái vặn vít
  • Máy in 3D (Tùy chọn - cho các nền tảng bàn đạp tùy chỉnh)

Phần mềm

  • Arduino IDE
  • Python 3 trở lên
  • JetBrains Pycharm
  • Giao diện MIDI không có lông
  • loopMIDI

Bước 3: Hàn và lắp ráp

Hàn và lắp ráp
Hàn và lắp ráp
Hàn và lắp ráp
Hàn và lắp ráp
Hàn và lắp ráp
Hàn và lắp ráp

Vì có ba mô-đun phải được kết hợp nên quá trình hàn và lắp ráp rất ngắn và đơn giản:

  • Đính kèm Arduino Pro-Micro với thiết bị FTDI, đảm bảo rằng các kết nối tuân thủ I / O được xác định trên mỗi thiết bị:

    • VBUS-VBUS
    • GND-GND
    • DTR-DTR
    • RXD-TXD
    • TXD-RXD
  • Tháo tất cả các vít khỏi vỏ nhựa trống, đảm bảo bạn có thể tập trung vào cáp pad-to-board và các điện trở kéo lên của nó
  • Hàn các dây mỏng cho mô-đun Arduino-FTDI mà chúng tôi đã xây dựng trước đây:

    • Đầu vào kỹ thuật số: D [2:11]
    • VBUS
    • D +
    • NS-
    • GND
  • Chèn mô-đun vào bên trong hộp pin để các dây dẫn nổi ở cùng một phía với các điện trở kéo của miếng đệm
  • Hàn tất cả các đầu vào kỹ thuật số vào các đầu cuối của đệm trống như thể hiện trong hình cuối cùng.
  • Hàn bus micro-USB (VBUS, D +, D-, GND) với thiết bị FTDI, đảm bảo rằng không có sai sót khi truy tìm các dây này.
  • Gắn mô-đun Arduino-FTDI bằng keo nóng vào hộp pin
  • Lắp ráp thiết bị với phần đính kèm vít thích hợp

Chúng tôi đã làm xong, thiết bị đã được lắp ráp. Hãy tiếp tục mã…

Bước 4: Lập trình A: Arduino

Lập trình A: Arduino
Lập trình A: Arduino

Cho phép Mô tả từng bước bản phác thảo của chúng tôi:

Trước hết, cần phải bao gồm hai thư viện cần thiết cho hoạt động thích hợp. EEPROM đã được cài đặt sẵn trong Arduino IDE, nhưng mô-đun gỡ lỗi cho trống đá phải được cài đặt riêng

#include #include

Các công tắc này được sử dụng chủ yếu trong trình tự gỡ lỗi. Nếu bạn muốn thử kết nối thiết bị đầu cuối Arduino với đệm trống và xác định tất cả các đầu vào kỹ thuật số, thì các công tắc này phải được xác định

/ * Công tắc dành cho nhà phát triển: Bỏ ghi chú chế độ mong muốn để gỡ lỗi hoặc khởi tạo * /// # xác định LOAD_DEFAULT_VALUES // Tải các giá trị không đổi thay vì EEPROM // # xác định PRINT_PADS_PIN_NUMBERS // In số pin được kết nối với bảng được đánh qua cổng nối tiếp

Các trường không đổi đại diện cho tất cả các giá trị mặc định, bao gồm cả liệt kê đệm trống. Để chạy thiết bị lần đầu tiên, cần phải biết kết nối chính xác của bàn đạp Hi-Hat và Kick

/ * Kiểu liệt kê trống * /

enum DRUM_POSITION {KICK = 0, SNARE, HIHAT, RIDE, CYMBAL1, CYMBAL2, TOM_HIGH, TOM_MID, TOM_LO, HIHAT_PEDAL};

/ * Giá trị mặc định * /

const uint8_t DRUM_NOTES [10] = {36, 40, 42, 51, 49, 55, 47, 45, 43, 48}; const uint8_t DRUM_VELOCITIES [10] = {110, 100, 100, 110, 110, 110, 110, 110, 110, 110}; const uint8_t DRUM_PINS [10] = {8, 6, 4, 3, 11, 9, 5, 10, 2, 7};

/ * Kick trống thời gian xóa * /

const uint8_t KICK_DB_DURATION = 30;

EEPROM được sử dụng để lưu trữ / tải tất cả dữ liệu đến từ ứng dụng PC. Các địa chỉ trải dài được mô tả ở trên, hiển thị vị trí chính xác cho thông tin MIDI cho mỗi đệm trống

/ * Ánh xạ địa chỉ EEPROM

Ghi chú: | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 |

Các chân: | 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 | Tốc độ | 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23 | * / const uint8_t NOTES_ADDR = 0x00; const uint8_t VELOCITIES_ADDR = 0x14; const uint8_t PINS_ADDR = 0x0A;

Các biến toàn cục được sử dụng để xác định trạng thái của từng pad và thực hiện giao tiếp MIDI cho phù hợp

/ * Biến toàn cục * /

uint8_t drumNotes [10], drumVelocities [10], drumPins [10]; // Biến MIDI

uint8_t uartBuffer [64]; // Bộ đệm UART để thu thập và lưu trữ kick Debouncer dữ liệu MIDI (DRUM_PINS [KICK], KICK_DB_DURATION); // Đối tượng Debouncer cho kick drum dễ bay hơi bool beforeState [9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // Các trạng thái logic trước đó của Drum pad trạng thái bool dễ bay hơi currentState [9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; // Trạng thái logic hiện tại của Drum pad

Chức năng EEPROM

/ * Lưu cài đặt trong EEPROM * /

void storeEEPROM () {

memcpy (drumNotes, uartBuffer, 10); memcpy (drumPins, uartBuffer + 10, 10); memcpy (drumVelocities, uartBuffer + 20, 10); for (uint8_t i = 0; i <10; i ++) EEPROM.write (NOTES_ADDR + i, drumNotes ); for (uint8_t i = 0; i <10; i ++) EEPROM.write (PINS_ADDR + i, drumPins ); for (uint8_t i = 0; i <10; i ++) EEPROM.write (VELOCITIES_ADDR + i, drumVelocities ); }

/ * Tải cài đặt từ EEPROM * /

void loadEEPROM () {for (uint8_t i = 0; i <10; i ++) drumNotes = EEPROM.read (NOTES_ADDR + i); for (uint8_t i = 0; i <10; i ++) drumPins = EEPROM.read (PINS_ADDR + i); for (uint8_t i = 0; i <10; i ++) drumVelocities = EEPROM.read (VELOCITIES_ADDR + i); }

Khởi tạo các biến và chế độ lập trình, trong trường hợp bàn đạp và khởi động Arduino được kích hoạt đồng thời

void enterProgrammingMode () {

bool confirmBreak = false; uint8_t lineCnt = 0; uint8_t charCnt = 0; char readChar = 0; while (! confirmBreak) {if (Serial.available ()) {uartBuffer [charCnt] = Serial.read (); if (charCnt> = 29) confirmBreak = true; khác charCnt ++; }} Serial.println ("Được"); storeEEPROM (); }

void initValues () {

#ifdef LOAD_DEFAULT_VALUES bản ghi nhớ (drumNotes, DRUM_NOTES, 10); memcpy (drumVelocities, DRUM_VELOCITIES, 10); memcpy (drumPins, DRUM_PINS, 10); #else loadEEPROM (); #endif}

Bộ xử lý Giao tiếp MIDI với độ trễ thời gian giữ nốt 1ms

/ * Phát chức năng nốt MIDI * /

void midiOut (enum DRUM_POSITION drumIn) {

if (drumIn == HIHAT) {// Nếu HI-HAT bị nhấn, cần phải thực hiện kiểm tra xem bàn đạp có được nhấn hay không nếu (! digitalRead (drumPins [HIHAT_PEDAL])) {noteOn (0x90, drumNotes [HIHAT_PEDAL], drumVelocities) [HIHAT_PEDAL]); trì hoãn (1); noteOn (0x90, drumNotes [HIHAT_PEDAL], 0); } else {noteOn (0x90, drumNotes [HIHAT], drumVelocities [HIHAT]); trì hoãn (1); noteOn (0x90, drumNotes [HIHAT], 0); }} else {// Lưu ý truyền MIDI trống thông thườngOn (0x90, drumNotes [drumIn], drumVelocities [drumIn]); trì hoãn (1); noteOn (0x90, drumNotes [drumIn], 0); }}

void noteOn (int cmd, int pitch, int speed) {Serial.write (cmd); Serial.write (cao độ); Serial.write (vận tốc); }

các hàm setup () và loop () với vòng lặp thao tác thiết bị vô hạn:

void setup () {

Serial.begin (115200);

for (uint8_t i = 0; i <10; i ++) {pinMode (i + 2, INPUT); } #ifdef PRINT_PADS_PIN_NUMBERS while (true) {// Vòng lặp gỡ lỗi vô hạn for (uint8_t i = 0; i <10; i ++) {if (! digitalRead (i + 2)) {Serial.print ("Pin No: D"); Serial.print (i + '0'); // Chuyển số thành ký tự ASCII}}} #else initValues (); / * Chế độ lập trình: Nếu nhấn hai bàn đạp trong khi khởi động - chế độ được kích hoạt * / if (! DigitalRead (drumPins [KICK]) &&! DigitalRead (drumPins [HIHAT_PEDAL])) enterProgrammingMode (); #endif}

void loop () {for (uint8_t i = 1; i <9; i = i + 1) {currentState = digitalRead (drumPins ); if (! currentState && beforeState ) midiOut (i); // So sánh các trạng thái và phát hiện cạnh rơi xuống beforeState = currentState ; } kick.update (); // Kick drum sử dụng thuật toán gỡ lỗi tùy chỉnh if (kick.edge ()) if (kick.falling ()) midiOut (KICK); }

Bước 5: Lập trình B: Python & Giao diện người dùng

Lập trình B: Python & Giao diện Người dùng
Lập trình B: Python & Giao diện Người dùng
Lập trình B: Python & Giao diện Người dùng
Lập trình B: Python & Giao diện Người dùng
Lập trình B: Python & Giao diện Người dùng
Lập trình B: Python & Giao diện Người dùng

Giao diện người dùng Python hơi phức tạp để hiểu ngay từ cái nhìn đầu tiên, do đó chúng tôi sẽ cố gắng giải thích những điều cơ bản của nó, cách sử dụng, mỗi nút có chức năng gì và cách lập trình thiết bị Arduino đúng cách.

Giao diện người dùng - Ứng dụng

Giao diện người dùng là một đại diện đồ họa cho người lập trình bộ trống của chúng tôi, làm cho nó thực sự dễ sử dụng và thuận tiện để lập trình thiết bị Arduino bất cứ lúc nào. Giao diện người dùng bao gồm một số mô-đun đồ họa được gắn với hoạt động được đề xuất của chúng. chúng ta hãy xem xét từng cái một:

  1. Hình ảnh bộ trống: Giao diện người dùng Python sử dụng tọa độ hình ảnh X-Y để xác định loại trống nào đã được chọn. Nếu vùng trống hợp lệ được chọn, thông báo IO thứ cấp sẽ hiển thị, với các trường ghi chú, vận tốc và thiết bị đầu cuối Arduino cho đệm trống chuyên dụng. Sau khi các thông số này được người dùng xác nhận và phê duyệt, các giá trị này có thể được truyền trực tiếp đến thiết bị Arduino.
  2. Hình ảnh bộ điều khiển bên ngoài: Để có thể sử dụng bộ trống MIDI với môi trường tạo VST / Nhạc, cần phải chạy trình thông dịch Serial-To-MIDI. Tôi đã sử dụng Hairless, có sẵn miễn phí và có thể chạy trực tiếp từ giao diện người dùng của chúng tôi, chỉ bằng cách nhấn vào hình ảnh của nó.
  3. Danh sách cổng COM: Để giao tiếp với Arduino, cần phải chỉ định cổng COM kèm theo của nó. Danh sách đang được làm mới bằng cách nhấn nút Làm mới.
  4. Cấu hình Tải / Lưu: Có các giá trị MIDI mặc định được xác định trong mã, người dùng có thể sửa đổi các giá trị này thông qua tương tác với giao diện người dùng. Cấu hình được xác định trong tệp config.txt ở một định dạng cụ thể, người dùng có thể lưu hoặc tải tệp này.
  5. Nút thiết bị chương trình: Để lưu trữ tất cả các giá trị MIDI đã sửa đổi trong Arduino EEPROM, bạn cần nhấn hai bàn đạp chân (Kick drum và Hi-hat pedal) sau đó, đợi quá trình truyền dữ liệu hoàn tất. Nếu có bất kỳ sự cố giao tiếp nào, cửa sổ bật lên thích hợp sẽ được hiển thị. Nếu quá trình truyền thành công, giao diện người dùng sẽ hiển thị thông báo thành công.
  6. Nút thoát: Chỉ thoát ứng dụng với sự cho phép của người dùng.

Điểm nổi bật về mã Python

Có rất nhiều thứ đang diễn ra trong mã, vì vậy chúng tôi sẽ mở rộng trên các hàm được viết hơn là trên toàn bộ mã.

Trước hết, để sử dụng UI, cần phải tải xuống một số mô-đun để mã hoạt động:

nhập phân luồng osimport nhập tkinter dưới dạng tk từ hộp tin nhập tkinter từ nhập tkinter * từ PIL nhập ImageTk, Nhập ảnh numpy dưới dạng np nhập nối tiếp nhập giọt

Một số mô-đun được bao gồm trong gói Python mặc định. Một số mô-đun nên được cài đặt thông qua công cụ PIP:

pip cài đặt Pillow

pip cài đặt numpy pip cài đặt ScreenInfo

Bạn nên chạy ứng dụng qua PyCharm. Trong các bản phát hành trong tương lai, tôi đang có kế hoạch xuất tệp thực thi cho dự án.

Giải thích mã ngắn gọn

Sẽ dễ hiểu hơn nhiều về mã nếu chúng ta nhìn vào các dòng của nó từ quan điểm của các hàm và lớp:

1. Chức năng chính - mã bắt đầu ở đây

if _name_ == '_main_': drumkit_gui ()

2. Hằng số Bộ trống, tọa độ và thông tin MIDI mặc định

class Drums: DRUM_TYPES = ["Kick", "Hihat", "Snare", "Crash 1", "Crash 2", "Tom High", "Tom Mid", "Tom Low", "Ride", "Hihat Pedal "," Bộ điều khiển "]

COORDINATES_X = [323, 117, 205, 173, 565, 271, 386, 488, 487, 135, 79]

COORDINATES_Y = [268, 115, 192, 40, 29, 107, 104, 190, 71, 408, 208] DIMS_WIDTH = [60, 145, 130, 120, 120, 70, 70, 130, 120, 70, 145] DIMS_LENGTH = [60, 60, 80, 35, 35, 40, 40, 70, 35, 100, 50]

DRUM_ENUM = ["Kick", "Snare", "Hihat", "Ride", "Crash 1", "Crash 2", "Tom High", "Tom Mid", "Tom Low", "Hihat Pedal"]

DRUM_NOTES = [36, 40, 42, 51, 49, 55, 47, 45, 43, 48] DRUM_VELOCITIES = [110, 100, 100, 110, 110, 110, 110, 110, 110, 110] DRUM_PINS = [8, 6, 4, 3, 11, 9, 5, 10, 2, 7]

3. Chức năng UI - Xử lý giao diện người dùng và các đối tượng đồ họa

def set_active (ui)

def thứ cấp_ui (kiểu_ trống)

class SelectionUi (tk. Frame)

Ứng dụng lớp (tk. Frame)

def drumkit_gui ()

def event_ui_clicked (event)

def getorigin (bản thân, sự kiện)

4. Giao tiếp nối tiếp

def get_serial_ports ()

def Communication_with_arduino (port)

5. Làm việc với tệp: Lưu trữ / Tải cài đặt từ tệp txt

def save_config ()

def load_config ()

6. Chạy ứng dụng bên ngoài hairless.exe từ mã bằng khả năng phân luồng Python

class ExternalExecutableThread (threading. Thread)

def run_hairless_executable ()

Để chạy mã, có một danh sách các tệp phải được đính kèm vào thư mục dự án:

  • config.txt: Tệp cài đặt
  • hairless.exe: Công cụ chuyển đổi MIDI không có lông
  • drumkit.png: Hình ảnh xác định tất cả các miếng trống có thể nhấp trên giao diện người dùng của chúng tôi (Phải tải xuống từ bộ hình ảnh của bước này)
  • drumgui.py: Mã dự án

Đó là mọi thứ chúng ta cần nhấn mạnh để làm cho nó hoạt động. Điều rất quan trọng là phải thêm các tệp vào dự án: hình ảnh bộ trống, tệp thực thi hairless.exe và tệp cài đặt config.txt.

Và.. Đây là chúng tôi đã hoàn thành!:)

Hy vọng bạn sẽ thấy hướng dẫn này hữu ích.

Cảm ơn vì đã đọc!:)

Đề xuất: