
1. 項(xiàng)目概述當(dāng)樹莓派遇見特雷門琴如果你對(duì)電子音樂制作或者復(fù)古合成器有點(diǎn)興趣大概率聽說過“特雷門琴”這個(gè)名字。它可能是世界上最酷、也最“玄學(xué)”的樂器之一——演奏者不需要觸碰任何實(shí)體僅僅通過雙手在空中的位置變化就能控制音高和音量發(fā)出那種極具未來感和科幻感的“嗡嗡”聲。我第一次在電影原聲里聽到它的聲音時(shí)就被迷住了但一臺(tái)專業(yè)的特雷門琴價(jià)格不菲而且學(xué)習(xí)曲線陡峭。后來我接觸到了樹莓派這個(gè)萬能的小電腦。一個(gè)想法冒了出來能不能用樹莓派來復(fù)刻特雷門琴的核心交互邏輯并且把它變成一個(gè)標(biāo)準(zhǔn)的MIDI控制器呢這樣我就能用這種獨(dú)特的“隔空”演奏方式去控制我電腦里任何一款軟音源從古典弦樂到賽博朋克合成音色玩法一下子就打開了。這就是“Raspberry Pi Theremin Midi Project”的由來。它本質(zhì)上是一個(gè)基于距離感應(yīng)的MIDI控制器項(xiàng)目核心是用樹莓派讀取傳感器數(shù)據(jù)將其映射為MIDI信號(hào)讓任何有基礎(chǔ)電子和編程知識(shí)的朋友都能親手打造一臺(tái)屬于自己的、可無限擴(kuò)展的“數(shù)字特雷門琴”。這個(gè)項(xiàng)目非常適合音樂技術(shù)愛好者、硬件創(chuàng)客以及想給音樂制作增添一些物理交互樂趣的玩家。你不需要是特雷門琴大師甚至不需要精通樂理只要跟著步驟一步步來就能搭建出一個(gè)能真正用于音樂創(chuàng)作的酷炫工具。整個(gè)項(xiàng)目的成本可以控制在很低的范圍主要就是一塊樹莓派、兩個(gè)傳感器和一些基礎(chǔ)元件。2. 核心思路與方案選型傳統(tǒng)的特雷門琴原理是利用兩個(gè)振蕩器通過手部靠近天線改變電容從而引發(fā)頻率差來產(chǎn)生音頻信號(hào)。我們的數(shù)字版本則走了另一條更直觀、更易實(shí)現(xiàn)的路徑用非接觸式距離傳感器來模擬手部位置用樹莓派作為大腦進(jìn)行數(shù)據(jù)處理和協(xié)議轉(zhuǎn)換。2.1 為什么選擇“傳感器MIDI”方案最初我也考慮過直接用樹莓派生成音頻比如用它的PWM引腳或音頻接口輸出模擬信號(hào)。但很快我就放棄了這個(gè)想法。原因有三第一樹莓派作為通用計(jì)算設(shè)備其音頻生成的實(shí)時(shí)性和穩(wěn)定性在復(fù)雜環(huán)境下可能不如專用芯片第二直接生成音頻限制了音色你得到的可能只是一個(gè)單調(diào)的方波或正弦波第三也是最關(guān)鍵的可擴(kuò)展性太差。而MIDI方案完美解決了這些問題。MIDI不是聲音信號(hào)而是一套控制指令比如“按下C4鍵”、“松開踏板”、“調(diào)制輪轉(zhuǎn)到127”。我們的樹莓派特雷門琴只需要專注于做好一件事精準(zhǔn)地把手部距離轉(zhuǎn)換成這些控制指令。至于發(fā)出什么聲音交給專業(yè)的合成器、采樣器軟件或硬件音源。這意味著你今天可以用它控制一個(gè)模擬弦樂音色明天就能無縫切換成一個(gè)狂暴的電子Lead可玩性呈指數(shù)級(jí)增長(zhǎng)。2.2 傳感器選型VL53L0X vs. HC-SR04這是項(xiàng)目的第一個(gè)關(guān)鍵決策點(diǎn)。我們需要兩個(gè)傳感器分別對(duì)應(yīng)音高Pitch和音量Volume。HC-SR04超聲波傳感器這是很多入門項(xiàng)目的首選。便宜、易得。它通過發(fā)送和接收超聲波來測(cè)距。但在我們這個(gè)項(xiàng)目里它有致命缺點(diǎn)響應(yīng)速度慢、波束角大、易受干擾。手部細(xì)微快速的移動(dòng)這正是演奏所需它可能捕捉不到而且周圍環(huán)境的反射容易導(dǎo)致讀數(shù)跳動(dòng)不穩(wěn)這對(duì)于需要平滑連續(xù)變化的音高控制來說是災(zāi)難。VL53L0X激光測(cè)距傳感器我最終選擇的方案。它采用飛行時(shí)間ToF原理發(fā)射不可見的激光并測(cè)量反射時(shí)間。它的優(yōu)勢(shì)非常突出高精度與高速度毫米級(jí)精度測(cè)量頻率可達(dá)50Hz以上能完美跟蹤手部快速移動(dòng)。小測(cè)量點(diǎn)激光束非常集中只測(cè)量你手部特定點(diǎn)的距離不受周圍環(huán)境干擾讀數(shù)極其穩(wěn)定。體積小巧易于安裝和隱藏。雖然VL53L0X比HC-SR04貴一些但對(duì)于音樂控制這種對(duì)實(shí)時(shí)性和穩(wěn)定性要求極高的場(chǎng)景這筆投資絕對(duì)值。一個(gè)穩(wěn)定的傳感器是流暢演奏體驗(yàn)的基礎(chǔ)。2.3 軟件棧選擇Python python-rtmidi樹莓派上常見的編程語言都能用我選擇Python因?yàn)樗鲜挚?、庫豐富、社區(qū)支持好非常適合快速原型開發(fā)。核心的MIDI庫我推薦python-rtmidi。它是一個(gè)基于C RtMidi庫的Python綁定跨平臺(tái)、高效、且功能完整。相比一些更簡(jiǎn)單的MIDI庫python-rtmidi能更好地處理MIDI消息的實(shí)時(shí)發(fā)送延遲低并且可以方便地枚舉系統(tǒng)中的MIDI輸入輸出端口這對(duì)于后續(xù)連接DAW數(shù)字音頻工作站至關(guān)重要。另一個(gè)備選是mido它更抽象、接口更友好但在極端實(shí)時(shí)性上稍遜一籌。對(duì)于我們的項(xiàng)目python-rtmidi是更專業(yè)的選擇。注意網(wǎng)絡(luò)上有些教程使用過時(shí)的庫或方法比如直接操作ALSA原始端口那會(huì)非常復(fù)雜且容易出錯(cuò)。python-rtmidi封裝了底層細(xì)節(jié)讓我們能專注于業(yè)務(wù)邏輯。3. 硬件搭建與電路連接這一部分我們動(dòng)手把各個(gè)部件連接起來。你需要準(zhǔn)備以下材料樹莓派3B/3B/4B/Zero 2W等型號(hào)均可推薦4B性能更充裕及配套電源、SD卡。VL53L0X激光測(cè)距傳感器x2。面包板、杜邦線母對(duì)母若干??蛇x電阻如果傳感器模塊沒有內(nèi)置電平轉(zhuǎn)換可能需要3.3V-5V的邏輯電平轉(zhuǎn)換器但大多數(shù)針對(duì)樹莓派的VL53L0X模塊都已適配3.3V。VL53L0X通常通過I2C接口與樹莓派通信。幸運(yùn)的是一個(gè)I2C總線可以掛載多個(gè)設(shè)備只要它們的I2C地址不同。默認(rèn)情況下VL53L0X的地址是0x29所以我們需要先修改其中一個(gè)傳感器的地址。3.1 硬件連接步驟第一步連接第一個(gè)傳感器例如用于控制音高將第一個(gè)VL53L0X模塊的VCC引腳連接到樹莓派的3.3V引腳物理引腳1或17。將GND引腳連接到樹莓派的GND例如物理引腳6或9。將SCL時(shí)鐘線連接到樹莓派的GPIO3 (SCL1)物理引腳5。將SDA數(shù)據(jù)線連接到樹莓派的GPIO2 (SDA1)物理引腳3。第二步修改第二個(gè)傳感器的I2C地址在連接第二個(gè)傳感器用于控制音量之前我們需要先寫一段簡(jiǎn)單的Python腳本臨時(shí)修改它的地址。暫時(shí)只連接第一個(gè)傳感器音高傳感器確保接線正確。在樹莓派上啟用I2C接口sudo raspi-config-Interface Options-I2C-Yes。安裝必要的庫sudo apt update sudo apt install python3-pip pip3 install smbus2創(chuàng)建一個(gè)Python腳本change_address.pyimport smbus2 import time bus smbus2.SMBus(1) # 樹莓派使用I2C總線1 # VL53L0X的默認(rèn)地址 DEFAULT_ADDRESS 0x29 # 我們?yōu)榈诙€(gè)傳感器選擇的新地址確保在有效范圍內(nèi)0x08-0x77且不沖突 NEW_ADDRESS 0x30 # 修改地址的寄存器操作具體操作需參考VL53L0X數(shù)據(jù)手冊(cè)或使用專用庫簡(jiǎn)化 # 這里是一個(gè)概念性步驟實(shí)際操作建議使用vl53l0x-python庫中的函數(shù) def change_sensor_address(): # 通常需要先解除傳感器的寫保護(hù)然后寫入新地址 # 示例非直接可用代碼 # bus.write_byte_data(DEFAULT_ADDRESS, 0xXX, 0xXX) # 解鎖 # bus.write_byte_data(DEFAULT_ADDRESS, 0xXX, NEW_ADDRESS) # 寫新地址 print(地址修改功能需結(jié)合具體傳感器驅(qū)動(dòng)庫實(shí)現(xiàn)。) if __name__ __main__: change_sensor_address() print(f嘗試將傳感器地址從{DEFAULT_ADDRESS:#x}修改為{NEW_ADDRESS:#x}。) print(請(qǐng)斷開此傳感器連接第二個(gè)傳感器然后運(yùn)行i2cdetect驗(yàn)證。)實(shí)際上更簡(jiǎn)單的方法是使用現(xiàn)成的庫如adafruit-circuitpython-vl53l0x來初始化傳感器并設(shè)置地址。我們會(huì)在下一章的軟件部分詳細(xì)實(shí)現(xiàn)。運(yùn)行i2cdetect -y 1命令你應(yīng)該能看到地址0x29被列出。運(yùn)行修改地址的腳本或使用庫方法后斷開這個(gè)傳感器。第三步連接第二個(gè)傳感器音量傳感器將第二個(gè)VL53L0X模塊的VCC和GND同樣連接到樹莓派的3.3V和GND。將第二個(gè)傳感器的SCL和SDA引腳并聯(lián)到第一個(gè)傳感器對(duì)應(yīng)的樹莓派引腳上即都接到GPIO3和GPIO2。這是I2C總線的標(biāo)準(zhǔn)接法。現(xiàn)在第二個(gè)傳感器應(yīng)該已經(jīng)被我們預(yù)先設(shè)置成了新地址例如0x30。重新連接第一個(gè)傳感器地址仍為默認(rèn)的0x29。再次運(yùn)行i2cdetect -y 1你現(xiàn)在應(yīng)該能看到兩個(gè)地址0x29和0x30。這表明兩個(gè)傳感器都已正確掛載且樹莓派可以分別與它們通信。實(shí)操心得焊接 vs. 面包板。初期原型階段用面包板快速搭建和調(diào)試非常方便。但如果你希望項(xiàng)目更穩(wěn)固、可用于演出或長(zhǎng)期擺放強(qiáng)烈建議將杜邦線焊接在傳感器和排針上或者直接使用焊接好的模塊。面包板連接在移動(dòng)中容易松動(dòng)導(dǎo)致傳感器失靈在演奏中途出問題會(huì)很掃興。4. 軟件環(huán)境配置與核心代碼解析硬件就緒后我們來讓樹莓派“思考”和“發(fā)聲”。軟件部分分為三層驅(qū)動(dòng)傳感器、處理數(shù)據(jù)、發(fā)送MIDI。4.1 系統(tǒng)與依賴安裝首先確保你的樹莓派系統(tǒng)是最新的并安裝必要的庫。# 更新系統(tǒng) sudo apt update sudo apt upgrade -y # 安裝Python3開發(fā)工具和pip如果尚未安裝 sudo apt install python3-dev python3-pip -y # 安裝I2C工具用于調(diào)試 sudo apt install i2c-tools -y # 安裝核心Python庫 pip3 install adafruit-circuitpython-vl53l0x # VL53L0X傳感器驅(qū)動(dòng) pip3 install python-rtmidi # MIDI庫 pip3 install numpy # 用于數(shù)據(jù)平滑處理可選但推薦4.2 傳感器驅(qū)動(dòng)與數(shù)據(jù)讀取我們使用Adafruit的庫來操作VL53L0X它封裝了復(fù)雜的底層寄存器操作非常簡(jiǎn)單易用。創(chuàng)建一個(gè)名為theremin_midi.py的主程序文件import time import board import busio import adafruit_vl53l0x import rtmidi import numpy as np # 初始化I2C總線 i2c busio.I2C(board.SCL, board.SDA) # 初始化第一個(gè)傳感器音高傳感器- 使用默認(rèn)地址 pitch_sensor adafruit_vl53l0x.VL53L0X(i2c) # 注意第二個(gè)傳感器需要先修改地址。通常庫支持在初始化時(shí)指定地址。 # 但Adafruit庫默認(rèn)會(huì)掃描并初始化所有地址為0x29的設(shè)備。 # 因此更可靠的方法是先只連接一個(gè)傳感器初始化并修改其地址再連接第二個(gè)。 # 下面演示一個(gè)更手動(dòng)的流程假設(shè)第二個(gè)傳感器地址已設(shè)為0x30 # 步驟1: 創(chuàng)建第二個(gè)傳感器對(duì)象并手動(dòng)指定地址 # 我們需要先停止第一個(gè)傳感器的測(cè)距以避免干擾 pitch_sensor.measurement_timing_budget 0 # 重新初始化I2C嘗試與0x30地址通信這里需要一點(diǎn)底層操作 # 實(shí)際上Adafruit庫對(duì)此支持不直接我們可以使用另一個(gè)庫或自行實(shí)現(xiàn)。 # 為了簡(jiǎn)化這里采用一個(gè)實(shí)用方案使用兩個(gè)不同的I2C總線如果樹莓派支持或使用一個(gè)多路復(fù)用器。 # 但對(duì)于大多數(shù)項(xiàng)目一個(gè)更簡(jiǎn)單的替代方案是使用超聲波傳感器HC-SR04控制音量因?yàn)樗褂肎PIO而非I2C不存在地址沖突。 # 鑒于復(fù)雜度本例將采用簡(jiǎn)化版**只使用一個(gè)VL53L0X控制音高用另一個(gè)模擬傳感器如紅外距離或電位器控制音量**。 # 以下是使用一個(gè)VL53L0X音高和一個(gè)模擬電位器音量的代碼框架。 print(傳感器初始化完成單音高傳感器模式。)由于I2C地址沖突和庫的支持問題在實(shí)際操作中使用兩個(gè)完全相同的VL53L0X傳感器并讓Adafruit庫直接驅(qū)動(dòng)會(huì)有些棘手。這里分享一個(gè)關(guān)鍵技巧如果你堅(jiān)持要使用兩個(gè)VL53L0X可以考慮使用I2C多路復(fù)用器如TCA9548A它可以讓多個(gè)同地址設(shè)備共享一條I2C總線。但對(duì)于初次嘗試我強(qiáng)烈建議采用混合方案音高控制VL53L0X激光傳感器追求高精度和速度。音量控制一個(gè)模擬旋轉(zhuǎn)電位器連接到樹莓派的ADC引腳需外接ADC芯片如ADS1115因?yàn)闃漭蓻]有模擬輸入引腳。電位器提供了物理觸感和穩(wěn)定的控制其實(shí)比在空中控制音量更容易操作和校準(zhǔn)。4.3 MIDI映射邏輯與數(shù)據(jù)平滑這是項(xiàng)目的核心算法部分。我們需要將傳感器讀取的原始距離值單位毫米映射到有音樂意義的MIDI值上。1. 音高映射MIDI音符編號(hào)從0C-1到127G9。我們通常只使用其中一部分例如MIDI編號(hào)48C3到84C6這是一個(gè)適合旋律演奏的音域。# 參數(shù)配置 PITCH_MIN_MM 50 # 手最近距離毫米對(duì)應(yīng)最高音 PITCH_MAX_MM 500 # 手最遠(yuǎn)距離毫米對(duì)應(yīng)最低音 MIDI_NOTE_MIN 48 # 最低MIDI音符編號(hào)C3 MIDI_NOTE_MAX 84 # 最高M(jìn)IDI音符編號(hào)C6 def map_distance_to_midi_note(distance): 將距離映射到MIDI音符編號(hào) # 將距離限制在最小最大值之間 clamped_dist max(PITCH_MIN_MM, min(PITCH_MAX_MM, distance)) # 線性映射 # 距離越近音越高所以用MAX_MM - distance note MIDI_NOTE_MIN ( (PITCH_MAX_MM - clamped_dist) / (PITCH_MAX_MM - PITCH_MIN_MM) ) * (MIDI_NOTE_MAX - MIDI_NOTE_MIN) return int(round(note))2. 數(shù)據(jù)平滑防抖動(dòng)傳感器讀數(shù)會(huì)有微小跳動(dòng)直接映射會(huì)導(dǎo)致音符“顫抖”。我們需要進(jìn)行平滑濾波。class SmoothingFilter: 一個(gè)簡(jiǎn)單的移動(dòng)平均濾波器 def __init__(self, window_size5): self.window_size window_size self.values [] def update(self, new_value): self.values.append(new_value) if len(self.values) self.window_size: self.values.pop(0) # 移除最舊的值 return sum(self.values) / len(self.values) # 初始化濾波器 pitch_filter SmoothingFilter(window_size5) # volume_filter SmoothingFilter(window_size3) # 音量變化可以更靈敏些3. 音量映射如果使用電位器假設(shè)我們使用ADS1115 ADC讀取電位器值0-3.3V對(duì)應(yīng)0-32767的讀數(shù)映射到MIDI控制器值0-127。VOLUME_ADC_MIN 0 VOLUME_ADC_MAX 25000 # 根據(jù)實(shí)際ADC讀數(shù)調(diào)整 MIDI_CC_VALUE_MIN 0 MIDI_CC_VALUE_MAX 127 def map_adc_to_midi_cc(adc_value): 將ADC值映射到MIDI控制器值用于音量CC7或其他 clamped_adc max(VOLUME_ADC_MIN, min(VOLUME_ADC_MAX, adc_value)) cc_value (clamped_adc - VOLUME_ADC_MIN) / (VOLUME_ADC_MAX - VOLUME_ADC_MIN) * (MIDI_CC_VALUE_MAX - MIDI_CC_VALUE_MIN) return int(round(cc_value))4.4 MIDI消息發(fā)送與主循環(huán)我們使用python-rtmidi來發(fā)送MIDI消息。需要發(fā)送兩種消息音符開Note On和音符關(guān)Note Off當(dāng)音高變化到新的音符時(shí)需要關(guān)閉前一個(gè)音符開啟新音符??刂聘淖僀ontrol Change連續(xù)發(fā)送音量變化信息CC編號(hào)7通常對(duì)應(yīng)主音量。# 初始化MIDI輸出 midiout rtmidi.MidiOut() available_ports midiout.get_ports() print(可用MIDI端口:, available_ports) if available_ports: # 通常選擇第一個(gè)虛擬端口例如“Midi Through”或你創(chuàng)建的虛擬端口 midiout.open_port(0) print(f已打開端口: {available_ports[0]}) else: # 如果沒有可用端口可以創(chuàng)建虛擬端口需要系統(tǒng)支持如使用sudo modprobe snd-virmidi創(chuàng)建 midiout.open_virtual_port(Raspberry Pi Theremin) print(已創(chuàng)建虛擬端口: Raspberry Pi Theremin) current_note None # 記錄當(dāng)前正在播放的音符 try: while True: # 1. 讀取音高傳感器距離 pitch_distance pitch_sensor.range smoothed_pitch pitch_filter.update(pitch_distance) new_note map_distance_to_midi_note(smoothed_pitch) # 2. 如果音高變化超過了半個(gè)音防止微抖動(dòng)則切換音符 if current_note is None or abs(new_note - current_note) 1: # 發(fā)送前一個(gè)音符的 Note Off 消息力度為0 if current_note is not None: note_off [0x80, current_note, 0] # 0x80: Note Off 通道1 midiout.send_message(note_off) # 發(fā)送新音符的 Note On 消息 note_on [0x90, new_note, 100] # 0x90: Note On 通道1, 力度100 midiout.send_message(note_on) current_note new_note print(fNote: {new_note} (Distance: {smoothed_pitch:.0f}mm)) # 3. 讀取并發(fā)送音量控制信息假設(shè)使用電位器 # volume_raw read_volume_from_adc() # 需要實(shí)現(xiàn)ADC讀取函數(shù) # smoothed_volume volume_filter.update(volume_raw) # volume_cc map_adc_to_midi_cc(smoothed_volume) # cc_message [0xB0, 7, volume_cc] # 0xB0: Control Change 通道1, CC#7, 值 # midiout.send_message(cc_message) # print(fVolume CC: {volume_cc}) time.sleep(0.01) # 控制循環(huán)速度約100Hz except KeyboardInterrupt: print(程序終止。) finally: # 發(fā)送所有音符關(guān)閉消息 if current_note is not None: midiout.send_message([0x80, current_note, 0]) del midiout print(MIDI端口已關(guān)閉。)這段代碼構(gòu)成了項(xiàng)目的核心邏輯。它不斷讀取傳感器平滑數(shù)據(jù)映射到MIDI值并在音高變化足夠大時(shí)發(fā)送新的音符指令。5. 系統(tǒng)集成與DAW連接調(diào)試代碼能在樹莓派上運(yùn)行并發(fā)送MIDI消息了但如何讓電腦里的音樂軟件接收到呢這里有幾個(gè)方案。5.1 方案一USB-MIDI直連推薦這是最穩(wěn)定、延遲最低的方案。樹莓派可以被配置成一個(gè)USB-MIDI設(shè)備。安裝必要軟件sudo apt install fluidsynth一個(gè)軟件合成器可用于測(cè)試和sudo apt install connectome一個(gè)強(qiáng)大的MIDI路由工具或使用更簡(jiǎn)單的ttymidi。使用ttymidi簡(jiǎn)單# 下載并編譯 ttymidi git clone https://github.com/ElBartoME/ttymidi.git cd ttymidi make sudo ./ttymidi -s /dev/ttyAMA0 這會(huì)在樹莓派上創(chuàng)建一個(gè)虛擬的ALSA MIDI端口。然后你需要修改上面的Python代碼連接到這個(gè)端口aconnect -l查看端口名。更優(yōu)方案使用usb-gadget模式樹莓派Zero/3/4這需要編譯內(nèi)核模塊將樹莓派模擬成一個(gè)標(biāo)準(zhǔn)的USB-MIDI設(shè)備。插上USB線電腦就會(huì)識(shí)別出一個(gè)新的MIDI輸入設(shè)備。這是最專業(yè)的方案但設(shè)置稍復(fù)雜。5.2 方案二網(wǎng)絡(luò)MIDIWi-Fi/以太網(wǎng)通過局域網(wǎng)發(fā)送MIDI信號(hào)適合樹莓派和電腦不便直連的情況。安裝rtpMIDI或使用python-rtmidi的網(wǎng)絡(luò)功能。在電腦上同樣安裝一個(gè)網(wǎng)絡(luò)MIDI服務(wù)如macOS的“音頻MIDI設(shè)置”可以創(chuàng)建網(wǎng)絡(luò)MIDI會(huì)話Windows可用rtpMIDI。配置樹莓派和電腦在同一個(gè)網(wǎng)絡(luò)并連接到同一個(gè)MIDI會(huì)話。這種方式延遲比USB稍高但足夠用于非專業(yè)演出。5.3 在DAW中配置以Ableton Live為例確保樹莓派的MIDI信號(hào)已成功發(fā)送到電腦在macOS的“音頻MIDI設(shè)置”或Windows的“MIDI-OX”等工具中能看到輸入活動(dòng)。打開Ableton Live進(jìn)入Options-Preferences-Link/MIDI。在MIDI Ports部分找到樹莓派對(duì)應(yīng)的輸入端口打開Track和Remote開關(guān)。創(chuàng)建一個(gè)MIDI軌道在MIDI From下拉菜單中選擇該端口。在該軌道上加載任意樂器如Simpler,Wavetable或第三方VST?,F(xiàn)在揮動(dòng)你的手就應(yīng)該能聽到聲音了調(diào)試技巧如果DAW里沒聲音按以下步驟排查先看樹莓派運(yùn)行Python腳本時(shí)觀察打印出的音符編號(hào)是否隨你手動(dòng)變化如果不變化檢查傳感器連接和代碼映射范圍。再看系統(tǒng)MIDI在電腦上打開一個(gè)MIDI監(jiān)視軟件如macOS的Midi MonitorWindows的MIDI-OX檢查是否能收到來自樹莓派的Note On/Off消息。收不到則檢查USB或網(wǎng)絡(luò)連接。最后看DAW確認(rèn)DAW的MIDI軌道輸入選擇正確軌道監(jiān)聽按鈕小喇叭已打開樂器有輸出且主音量正常。6. 演奏優(yōu)化與進(jìn)階玩法基礎(chǔ)功能實(shí)現(xiàn)后我們可以讓它變得更好玩、更實(shí)用。6.1 校準(zhǔn)與個(gè)性化設(shè)置每個(gè)人的手臂長(zhǎng)度和演奏習(xí)慣不同固定的距離-音高映射可能不合適。我們可以在代碼開始時(shí)加入一個(gè)簡(jiǎn)單的校準(zhǔn)例程。def calibration_routine(sensor, axis_namePitch): print(f請(qǐng)將手放在{axis_name}傳感器最近演奏位置按回車鍵...) input() min_val sensor.range print(f最近點(diǎn)記錄: {min_val}mm) print(f請(qǐng)將手放在{axis_name}傳感器最遠(yuǎn)演奏位置按回車鍵...) input() max_val sensor.range print(f最遠(yuǎn)點(diǎn)記錄: {max_val}mm) return min_val, max_val # 程序啟動(dòng)時(shí)運(yùn)行校準(zhǔn) pitch_min, pitch_max calibration_routine(pitch_sensor, Pitch) # 更新映射參數(shù) PITCH_MIN_MM pitch_min PITCH_MAX_MM pitch_max6.2 增加更多控制維度兩個(gè)傳感器音高音量只是開始。你可以輕松擴(kuò)展第三個(gè)傳感器控制彎音Pitch Bend。將手部左右移動(dòng)映射到彎音輪信息上MIDI Pitch Bend消息實(shí)現(xiàn)更富表現(xiàn)力的滑音。按鈕或電容觸摸添加幾個(gè)GPIO按鈕映射到MIDI CC上用于切換音色庫CC32、觸發(fā)效果器開關(guān)CC控制效果器On/Off等。光敏電阻用光線強(qiáng)弱控制調(diào)制輪Modulation為聲音添加自動(dòng)顫音。6.3 音階與量化對(duì)于不熟悉無品樂器的人來說自由音高很難演奏出準(zhǔn)確的旋律??梢约尤胍綦A量化功能。def quantize_to_scale(note, scale_intervals[0, 2, 4, 5, 7, 9, 11]): 將輸入音符量化到指定的音階例如C大調(diào) # scale_intervals 是音階中各音級(jí)相對(duì)于根音的半音數(shù) base_note 48 # C3作為根音 relative_note note - base_note octave relative_note // 12 degree relative_note % 12 # 找到最接近的音階級(jí)別 closest_interval min(scale_intervals, keylambda x: abs(x - degree)) quantized_note base_note octave * 12 closest_interval return quantized_note在發(fā)送MIDI消息前對(duì)new_note調(diào)用這個(gè)函數(shù)你的演奏就會(huì)被“吸附”到C大調(diào)的音符上立刻變得悅耳動(dòng)聽。你可以通過按鈕切換不同的音階大調(diào)、小調(diào)、五聲音階等。6.4 外殼設(shè)計(jì)與用戶體驗(yàn)一個(gè)裸露的面包板肯定不夠酷。你可以使用3D打印、激光切割亞克力甚至舊木盒來制作一個(gè)美觀的外殼。設(shè)計(jì)時(shí)考慮傳感器位置音高和音量傳感器應(yīng)垂直或呈一定角度放置避免相互干擾并符合人體工學(xué)。指示燈加入LED指示燈用不同顏色顯示當(dāng)前模式如自由音高模式、量化模式、不同音階。電源管理使用大容量充電寶供電讓你的樹莓派特雷門琴真正成為無線便攜樂器。這個(gè)項(xiàng)目從硬件連接到軟件編程再到音樂制作集成完成了一個(gè)完整的創(chuàng)意循環(huán)。它不僅僅是一個(gè)簡(jiǎn)單的模仿而是一個(gè)可深度定制和擴(kuò)展的音樂交互平臺(tái)。我自己的設(shè)備現(xiàn)在已經(jīng)增加了彎音控制和三個(gè)模式切換按鈕用它來演奏一些簡(jiǎn)單的科幻電影主題曲或?yàn)殡娮訕诽砑蛹磁d段落總能帶來很多樂趣。最重要的是整個(gè)搭建和調(diào)試過程本身就是一次對(duì)物理計(jì)算、信號(hào)處理和音樂技術(shù)融合的深刻學(xué)習(xí)。