【微實驗】使用MATLAB制作一張賽博古琴?

當一個理工音樂人沒錢去買古琴,我直接用代碼畫一個古琴!

目錄

零、總腳本:

一、核心功能:交互模塊拆解

二、核心價值

一、初始化腳本:參數配置與啟動界面

①廢話不說,直接上代碼

②代碼模塊拆解與詳細解讀

(一)基礎參數定義模塊:搭建古琴音準與演奏邏輯框架

1. 音高基礎參數:定調與空弦音初始化

2. 演奏技法參數:定義左右手動作邏輯

3. 徽位參數:還原古琴 13 徽的物理特性

(二)可視化界面繪制模塊:1:1 還原古琴視覺結構

1. 窗口初始化:適配屏幕尺寸的比例設計

2. 琴弦繪制:還原 7 根弦的位置與粗細差異

3. 徽位繪制:13 徽的位置與尺寸精準還原

4. 輔助設置:關閉坐標軸,專注視覺體驗

(三)預留功能模塊:為后續交互與音頻合成鋪路

二、演奏音符函數

①廢話不說,先上代碼

②核心輸入參數與作用

核心邏輯:從參數到頻率的計算

音頻生成與播放流程

核心功能總結

三、撥弦發聲函數

核心功能與輸入輸出

工作原理:從諧波疊加到真實音色

關鍵設計:貼近真實弦樂器的特性

三、其他函數


零、總腳本:

%%
run('ini.m');%初始化
%guqin_gui();
function guqin_gui()% 初始化狀態:按音狀態為 1,泛音狀態為 0playing_mode = 1; mode_text = uicontrol('Style','text','String','按音','Position',[10,window_height-50,100,30],'FontSize',12,'ForegroundColor','white');arrow_left = uicontrol('Style','pushbutton','String','<','Position',[10,window_height-100,30,30],'Callback',@arrow_left_callback);arrow_right = uicontrol('Style','pushbutton','String','>','Position',[50,window_height-100,30,30],'Callback',@arrow_right_callback);pressed_mic = zeros(7,1); % 存儲每根弦的按音徽位for i = 1:7pressed_mic(i) = 0; % 初始化為散音end% 為小鍵盤按鍵添加回調函數set(f, 'KeyPressFcn', @key_press_callback);function key_press_callback(hObject, event)% 獲取按鍵的字符key = event.Keyswitch keycase '1'play_note(1);case '2'play_note(2);case '3'play_note(3);case '4'play_note(4);case '5'play_note(5);case '6'play_note(6);case '7'play_note(7);case '0'% 散音for i = 1:7pressed_mic(i) = 0;endupdate_display();case 'numpad1'pressed_mic(1) = 1;update_display();case 'numpad2'pressed_mic(2) = 2;update_display();case 'numpad3'pressed_mic(3) = 3;update_display();case 'numpad4'pressed_mic(4) = 4;update_display();case 'numpad5'pressed_mic(5) = 5;update_display();case 'numpad6'pressed_mic(6) = 6;update_display();case 'numpad7'pressed_mic(7) = 7;update_display();case 'numpad8'pressed_mic(1) = 8;update_display();case 'numpad9'pressed_mic(2) = 9;update_display();case 'add'pressed_mic(3) = 10;update_display();case 'divide'pressed_mic(4) = 11;update_display();case 'multiply'pressed_mic(5) = 12;update_display();case 'subtract'pressed_mic(6) = 13;update_display();% 'numlock'    'add'return'  'decimal'  'numpad0'case ' 'if playing_mode == 1playing_mode = 0;set(mode_text,'String','泛音');elseplaying_mode = 1;set(mode_text,'String','按音');endendendfunction arrow_left_callback(hObject, event)% 向左移動按音位置for i = 1:7if pressed_mic(i) > 0pressed_mic(i) = max(pressed_mic(i)-1,0);endendupdate_display();endfunction arrow_right_callback(hObject, event)% 向右移動按音位置for i = 1:7if playing_mode == 1 && pressed_mic(i) < 13pressed_mic(i) = min(pressed_mic(i)+1,13);endendupdate_display();endfunction update_display()for i = 1:7if playing_mode == 1if pressed_mic(i) == 0text(0.7, y_right_pos(i), '散音', 'FontSize', 10, 'Color', 'white');elsetext(0.7, y_right_pos(i), num2str(pressed_mic(i)), 'FontSize', 10, 'Color', 'white');endelsetext(0.7, y_right_pos(i), '泛音', 'FontSize', 10, 'Color', 'white');endendend% 音高與頻率的變換函數
% freq=fr_of(note,octave)
% [note_str, octave,cent_offset] = nt_of(freq)end

這是古琴模擬系統的交互控制中樞,負責搭建可視化操作界面、綁定鍵盤 / 按鈕事件,實現 “演奏模式切換、徽位選擇、音位顯示” 的完整交互邏輯,連接虛擬界面與發聲功能。

核心功能:交互模塊拆解

  1. 初始化交互狀態

    • 默認playing_mode=1(按音模式),界面顯示 “按音” 文本;
    • pressed_mic數組存儲 7 根弦的當前按音徽位(初始 0,即散音)。
  2. 界面控件與事件綁定

    • 模式切換:空格鍵切換 “按音 / 泛音”,同步更新界面文本;
    • 徽位調整:左右箭頭按鈕整體增減所有弦的徽位(限制 1-13);
    • 鍵盤控制
      • 主鍵盤 1-7:觸發對應弦發聲;
      • 小鍵盤 1-9/+-*/:設置對應弦的徽位(1-13);
      • 0 鍵:重置所有弦為散音。
  3. 狀態顯示更新
    update_display函數實時在界面標注每根弦的狀態:按音時顯示 “散音” 或徽位數字,泛音時顯示 “泛音”,確保用戶直觀掌握當前演奏參數。

作為 “用戶操作” 與 “play_note發聲函數” 的中間層,它將鍵盤 / 按鈕輸入轉化為具體的 “弦號、演奏模式、徽位” 參數,實現 “所見即所控、所控即所發” 的虛擬演奏體驗。

一、初始化腳本:參數配置與啟動界面

①廢話不說,直接上代碼

以下算作初始化代碼,創建腳本文件,命名為“ini.m”并存儲。

%演奏方式:泛音、按音對應0和1
%徽位:1-13,0為不按
% 初始化音名和八度    %弦號:從低音到高音分別是1234567
%正宮調定弦
notes = {'C', 'D', 'F', 'G', 'A', 'C', 'D'};
octaves = [3, 3, 3, 3, 3, 4, 4];
% 徽位與琴弦右側長度倍數關系的數據表
mic_positions = [1/8; 1/6; 1/5; 1/4; 1/3; 2/5; 1/2; 3/5; 2/3; 3/4; 4/5; 5/6; 7/8];
%徽位標準的大小
mic_size = [1/8 1/6  1/5  1/4  1/3  1/5  1/2  1/5  1/3  1/4 1/5 1/6 1/8];
% 七條琴弦粗細
line_widths = [3.2 3 2.6 2.3 2 1.6 1.3]; 
%指:(左手:取音法,右手:撥弦法
boxian=['挑','勾','抹','托','剔','劈','打','帶','艸如一','撮','歷','','','','','',''];
quyin=['大','食','中','名','跪','艸'];%散音,指左手不取音,默認空弦音
%另,上下進退復屬于位置變更,
type=['按','泛'];%按音,泛音。延音?
marker_num=['一','二','三','四','五','六','七','八','九','十','十一','十二','十三'];
marker_tenth=['一','二','三','四','五','六','七','八','九','十'];
%初始七根弦的空弦音頻率數組
base_freq=[0 0 0 0 0 0 0];
for i=1:7base_freq(i)=fr_of(notes{i},octaves(i));%計算填充
end% num_harmonics: 諧波數量% harmonic_amps: 諧波振幅比例,長度為 num_harmonics 的向量% harmonic_phases: 諧波相位,長度為 num_harmonics 的向量% decay_factor: 衰減系數,范圍在 0 到 1 之間% duration: 聲音持續時間% 生成時間向量       % 生成面板琴弦和徽位% 獲取屏幕的大小screen_size = get(0,'ScreenSize');screen_width = screen_size(3); % 屏幕的寬度screen_height = screen_size(4); % 屏幕的高度% 計算窗口的高度,根據 125:22 的長寬比aspect_ratio = 125 / 22; window_height = screen_width / aspect_ratio;% 確保窗口的高度不超過屏幕的高度,如果超過,則根據屏幕高度計算窗口寬度if window_height > screen_heightwindow_height = screen_height;window_width = window_height * aspect_ratio;elsewindow_width = screen_width;end% 創建圖形窗口,使其寬度充滿屏幕或高度達到屏幕高度(取決于哪個先滿足條件)f = figure('Position', [0, 0, window_width, window_height]);%寬:長=125:22% 設置窗口背景顏色為棕黑色set(f, 'Color', [0.2 0.1 0]); % 關閉菜單和工具欄set(f, 'MenuBar', 'none', 'ToolBar', 'none');% 繪制七條琴弦y_pos = linspace(0.9, 0.1, 7); % 七條琴弦的 y 位置x_start = 0.1;x_end = 0.9;width = 0.8; % 琴弦橫向填充整個窗口height = width / aspect_ratio; y_pos = 0.5 + (y_pos - mean(y_pos)) * height / (max(y_pos) - min(y_pos));y_left_pos = 0.5 + (y_pos - 0.5) * 0.6;y_right_pos = 0.5 +(y_pos - 0.5) * 1.0;% 存儲琴弦的線條句柄line_handles = zeros(1, 7);for i = 1:7line_handles(i) = plot([x_start, x_end], [y_left_pos(i), y_right_pos(i)], 'LineWidth', line_widths(i), 'Color', [1 1 0.8]); % 亮黃白色的琴弦text(0.9, y_right_pos(i), num2str(i), 'FontSize', 12, 'Color', 'white'); % 弦號白色hold on;end    % 繪制徽位for j = 1:13x_mic = x_start + (x_end - x_start) * mic_positions(j);size=round(20.*mic_size(j));plot(x_mic, (y_right_pos(1)-y_left_pos(1))/(x_end-x_start)*(x_mic-y_left_pos(1))+y_pos(1)-0.5*(y_pos(2)-y_pos(1)), 'wo', 'MarkerSize',size, 'MarkerFaceColor', [240, 180, 50]./256);hold on;end %每根弦上,任意位置點的繪制%l代表有效長度,即該點到琴弦右側的距離占總琴弦長度的比例    
%     for i = 1:7
%         k=(y_left_pos(i)- y_right_pos(i))/(x_start-x_end);%琴弦的斜率
%         for j = 1:13
%             x_mic = x_start + (x_end - x_start) * mic_positions(j);
%             l=mic_positions(14-j);            
%             y=-k*l*(x_end - x_start)+y_right_pos(i);
%             plot(x_mic, y, 'ro', 'MarkerSize',line_widths(i)+2, 'MarkerFaceColor', 'r');
%             hold on;
%         end 
%     endaxis off; % 關閉坐標軸顯示

這段 MATLAB 代碼是一套古琴數字化模擬系統的基礎模塊,主要實現兩大核心功能:一是通過計算初始化古琴 7 根琴弦的空弦音頻率,定義泛音、按音等演奏參數;二是構建可視化的古琴虛擬界面,精準還原古琴的琴弦、徽位等物理結構,為后續的交互演奏(如點擊徽位發聲、模擬按弦動作)提供視覺載體。整體代碼邏輯從 “音頻參數定義” 到 “視覺界面繪制” 層層遞進,是古琴數字化仿真項目的核心奠基代碼。

②代碼模塊拆解與詳細解讀

(一)基礎參數定義模塊:搭建古琴音準與演奏邏輯框架

這部分代碼是整個系統的 “數據字典”,從音高、演奏技法、徽位尺寸等維度,為古琴模擬建立標準化參數體系,具體分為 6 類核心參數:

1. 音高基礎參數:定調與空弦音初始化
% 正宮調定弦(古琴經典調式,對應現代音高)
notes = {'C', 'D', 'F', 'G', 'A', 'C', 'D'};  % 7根弦的音名(從低音弦1到高音弦7)
octaves = [3, 3, 3, 3, 3, 4, 4];              % 對應八度(弦1-5為小字三組,弦6-7為小字四組)
% 初始化空弦音頻率數組(調用fr_of函數計算音名對應的頻率,如C3約130.81Hz)
base_freq=[0 0 0 0 0 0 0];
for i=1:7base_freq(i)=fr_of(notes{i},octaves(i));% 循環填充7根弦的空弦頻率
end
  • 關鍵作用:確定古琴的 “基準音高”,base_freq數組最終存儲的是每根空弦音的具體頻率(如弦 1 為 C3,頻率約 130.81Hz),是后續計算泛音、按音頻率的基礎。
  • 依賴函數fr_of是自定義的 “音名轉頻率” 函數,核心是根據十二平均律,將 “音名 + 八度” 轉化為具體的赫茲值(Hz)。
2. 演奏技法參數:定義左右手動作邏輯
% 右手撥弦法(共12種經典技法,空值為預留擴展位)
boxian=['挑','勾','抹','托','剔','劈','打','帶','艸如一','撮','歷','','','','','',''];
% 左手取音法(含散音邏輯:左手不取音時默認空弦音)
quyin=['大','食','中','名','跪','艸'];% “大/食/中/名/跪”對應不同手指按弦,“艸”為散音標識
% 演奏類型(核心兩類:按音、泛音;延音為預留功能)
type=['按','泛'];
  • 設計邏輯:為后續 “交互演奏” 預留接口 —— 比如用戶點擊界面時,系統可根據選擇的 “右手技法(如挑)” 和 “左手取音法(如食指按弦)”,調用不同的音頻合成邏輯(如按音有按壓阻尼感,泛音更清亮)。
3. 徽位參數:還原古琴 13 徽的物理特性
% 徽位與琴弦右側長度倍數關系(核心物理參數)
mic_positions = [1/8; 1/6; 1/5; 1/4; 1/3; 2/5; 1/2; 3/5; 2/3; 3/4; 4/5; 5/6; 7/8];
% 徽位視覺大小(13徽尺寸隨位置變化,符合真實古琴徽位比例)
mic_size = [1/8 1/6  1/5  1/4  1/3  1/5  1/2  1/5  1/3  1/4 1/5 1/6 1/8];
% 徽位標識文字(1-10用“一-十”,11-13用“十一-十三”)
marker_num=['一','二','三','四','五','六','七','八','九','十','十一','十二','十三'];
marker_tenth=['一','二','三','四','五','六','七','八','九','十'];
  • 核心原理mic_positions是關鍵 —— 古琴 13 徽的位置并非均勻分布,而是根據 “弦長比例” 確定(如 7 徽在弦長 1/2 處,是泛音的核心位置),該數組存儲的是 “徽位到琴弦右側的距離占總弦長的比例”,后續繪制徽位和計算泛音頻率都依賴此參數。

(二)可視化界面繪制模塊:1:1 還原古琴視覺結構

這部分代碼是 “虛擬古琴” 的視覺載體,通過計算屏幕尺寸、琴弦位置、徽位坐標,在 MATLAB 圖形窗口中精準繪制古琴外觀,具體分為 4 個核心步驟:

1. 窗口初始化:適配屏幕尺寸的比例設計
% 獲取屏幕分辨率,計算窗口大小(遵循古琴長寬比125:22)
screen_size = get(0,'ScreenSize');  % 獲取屏幕尺寸:[左,下,寬,高]
screen_width = screen_size(3);      % 屏幕寬度
screen_height = screen_size(4);     % 屏幕高度
aspect_ratio = 125 / 22;            % 古琴標準長寬比(長:寬=125:22)
% 計算窗口高度(優先寬充滿屏幕,若高度超屏幕則按高度適配)
window_height = screen_width / aspect_ratio;
if window_height > screen_heightwindow_height = screen_height;window_width = window_height * aspect_ratio;
elsewindow_width = screen_width;
end
% 創建圖形窗口(無菜單/工具欄,背景為棕黑色,模擬古琴木胎顏色)
f = figure('Position', [0, 0, window_width, window_height]);
set(f, 'Color', [0.2 0.1 0]);       % 背景色:棕黑色(RGB值)
set(f, 'MenuBar', 'none', 'ToolBar', 'none');  % 關閉菜單和工具欄,專注視覺
  • 設計細節:嚴格遵循古琴的真實長寬比(125:22),同時適配不同屏幕分辨率,避免界面拉伸變形;棕黑色背景模擬古琴的木胎質感,提升視覺沉浸感。
2. 琴弦繪制:還原 7 根弦的位置與粗細差異
% 計算7根弦的Y軸位置(從高音弦到低音弦,縱向均勻分布)
y_pos = linspace(0.9, 0.1, 7);  % 初始縱向比例(0.9為高音弦,0.1為低音弦)
x_start = 0.1;  % 琴弦左端起點(相對窗口寬度的比例,0.1即10%處)
x_end = 0.9;    % 琴弦右端終點(90%處)
width = 0.8;    % 琴弦橫向長度(占窗口寬度80%)
height = width / aspect_ratio;  % 琴弦縱向適配高度
% 調整琴弦Y軸位置,確保居中且適配窗口高度
y_pos = 0.5 + (y_pos - mean(y_pos)) * height / (max(y_pos) - min(y_pos));
y_left_pos = 0.5 + (y_pos - 0.5) * 0.6;  % 琴弦左端Y坐標(略微內收,模擬琴首)
y_right_pos = 0.5 +(y_pos - 0.5) * 1.0;  % 琴弦右端Y坐標(模擬琴尾)% 循環繪制7根弦(存儲句柄,便于后續交互)
line_handles = zeros(1, 7);
for i = 1:7% 繪制琴弦:亮黃白色(模擬蠶絲弦顏色),粗細隨弦號變化(低音弦粗,高音弦細)line_handles(i) = plot([x_start, x_end], [y_left_pos(i), y_right_pos(i)], ...'LineWidth', line_widths(i), 'Color', [1 1 0.8]);% 在琴弦右端標注弦號(白色文字,1為低音弦,7為高音弦)text(0.9, y_right_pos(i), num2str(i), 'FontSize', 12, 'Color', 'white');hold on;  % 保持繪圖窗口,繼續繪制后續元素
end    
  • 關鍵細節
    • 琴弦粗細:line_widths = [3.2 3 2.6 2.3 2 1.6 1.3],嚴格遵循真實古琴 “低音弦粗、高音弦細” 的規律(弦 1 最粗 3.2pt,弦 7 最細 1.3pt);
    • 位置設計:琴弦左端(琴首)略微內收(y_left_pos乘以 0.6),模擬真實古琴 “琴首窄、琴尾寬” 的形態,視覺更逼真。
3. 徽位繪制:13 徽的位置與尺寸精準還原
% 循環繪制13個徽位(從1徽到13徽)
for j = 1:13% 計算徽位X坐標(根據mic_positions的弦長比例,映射到窗口寬度)x_mic = x_start + (x_end - x_start) * mic_positions(j);% 計算徽位視覺大小(按mic_size比例縮放,默認基礎20pt)size=round(20.*mic_size(j));% 繪制徽位:白色外圈+米黃色填充(模擬螺鈿徽位,真實古琴常用材質)plot(x_mic, (y_right_pos(1)-y_left_pos(1))/(x_end-x_start)*(x_mic-y_left_pos(1))+y_pos(1)-0.5*(y_pos(2)-y_pos(1)), ...'wo', 'MarkerSize',size, 'MarkerFaceColor', [240, 180, 50]./256);hold on;
end 
  • 核心邏輯
    • 徽位位置:通過x_mic = x_start + (x_end - x_start) * mic_positions(j),將 “弦長比例” 轉化為窗口中的實際 X 坐標,確保 13 徽的位置與真實古琴完全一致(如 7 徽在 X 軸中間,對應弦長 1/2 處);
    • 徽位外觀:白色外圈('wo'即白色圓圈)+ 米黃色填充(RGB [240,180,50]/256),模擬真實古琴的 “螺鈿徽位” 質感,同時尺寸隨mic_size變化(如 7 徽最大,1、13 徽最小),符合真實古琴的徽位大小規律。
4. 輔助設置:關閉坐標軸,專注視覺體驗
axis off; % 關閉坐標軸顯示,避免網格、刻度干擾古琴視覺效果
  • 作用:隱藏 MATLAB 默認的坐標軸、刻度和網格,讓虛擬古琴界面更簡潔,視覺上更接近真實樂器。

(三)預留功能模塊:為后續交互與音頻合成鋪路

代碼中注釋掉的部分(如下)和未完善的音頻參數(如諧波、衰減系數),是為后續功能擴展預留的接口。

  • 擴展方向
    • 交互功能:解開注釋后,可實現 “點擊徽位顯示紅色按點”,模擬左手按弦動作;
    • 音頻合成:結合base_freq和徽位比例(如泛音頻率 = 空弦頻率 ×(1 / 徽位比例)),可計算出任意徽位的音高,再通過諧波參數合成對應的古琴音色。

二、演奏音符函數

①廢話不說,先上代碼

function note=play_note(string_num, play_style, fret_num)% string_num:弦號,從低音到高音分別是 1234567,弦號(string_num)為索引,調用 base_freq(string_num)即獲取對應弦的基音頻率% play_style:演奏方式,泛音、按音對應 1 和 2,如果是 1,則音色空靈,隨機生成 num_harmonics: 諧波數量為 2-4;如果是 2 為按音,生成諧波數量 5-7% fret_num:徽位,1-13,假設按 fret_num 徽,% ①泛音模式下,弦的等分段發音,發音頻率為發音弦基頻的為 mic_size(string_num)^(-1)倍,% ②按音模式下,有效弦長發音,即發音弦基頻的為 mic_positions(string_num)^(-1)倍,% 0為不按,發音為基頻,以此獲得 out_freq  base_freq=[87.30705785825, 97.99885899543, 109.99943633644, 130.8127826503, 146.8323839587, 164.8137784564, 195.9977179909];%base_freq=[130.812782650299,146.832383958704,174.614115716502,195.997717990875,220,261.625565300599,293.664767917407]./2;% 徽位與琴弦右側長度倍數關系的數據表mic_positions = [1/8; 1/6; 1/5; 1/4; 1/3; 2/5; 1/2; 3/5; 2/3; 3/4; 4/5; 5/6; 7/8];%徽位標準的大小mic_size = [1/8 1/6  1/5  1/4  1/3  1/5  1/2  1/5  1/3  1/4 1/5 1/6 1/8 ];% 初始化 fundamental_freqfundamental_freq = base_freq(string_num);    % 根據演奏方式和徽位計算實際基頻%有效弦長fl=floor(fret_num);if fl==0l=(fret_num-fl)/8;elseif fl==13l=7/8+(fret_num-fl)/8;elsel=mic_positions(fl)+(fret_num-fl)*(mic_positions(fl+1)-mic_positions(fl));endif play_style == 2%按音      fundamental_freq = fundamental_freq / l;num_harmonics = randi([2, 4]);elsefundamental_freq = fundamental_freq / l;num_harmonics = randi([5, 7]);end    draw_point(string_num,l);note=nt_of(fundamental_freq);harmonic_amps = 1./(1:num_harmonics); % 諧波振幅比例,例如 1/nharmonic_phases = 2*pi*rand(1, num_harmonics); % 諧波相位,隨機生成decay_factor = -1.5.*sqrt((1:num_harmonics)); % 衰減系數duration = 5; % 持續時間,單位為秒Fs = 44100; % 采樣頻率    % 調用 string_pluck 函數生成弦樂撥弦的聲音[y, ~] = string_pluck(fundamental_freq, num_harmonics, harmonic_amps, harmonic_phases, decay_factor, duration, Fs);% 播放生成的聲音player = audioplayer(y, Fs);% 播放音頻play(player);% 等待 2 秒后停止pause(1);stop(player);  
end% % 繪制生成的音頻信號的時域波形
% figure;
% plot(t, y);
% title('弦樂撥弦的時域波形');
% xlabel('時間 (s)');
% ylabel('幅度');
% grid on;

該函數是古琴數字化模擬系統的 “發聲控制核心”,作用是根據用戶輸入的 “弦號、演奏方式、徽位”,計算對應音高并生成、播放古琴音色,本質是 “參數映射→頻率計算→音頻合成→播放輸出” 的完整流程。

②核心輸入參數與作用

函數接收 3 個關鍵參數,直接決定發聲的 “弦、法、位”,對應真實古琴演奏的核心要素:

  • string_num(弦號):1-7(1 為低音弦,7 為高音弦),用于調用預設的base_freq數組,獲取對應弦的空弦基頻(如弦 1 基頻約 87.31Hz);
  • play_style(演奏方式):1 = 泛音、2 = 按音,決定音色特點(泛音空靈、按音厚重)與諧波數量(泛音 2-4 個諧波,按音 5-7 個諧波);
  • fret_num(徽位):0(空弦)或 1-13(具體徽位),用于計算 “有效弦長比例”,最終確定實際發聲頻率。

核心邏輯:從參數到頻率的計算

函數最關鍵的步驟是 “根據徽位和演奏方式,把空弦基頻轉化為實際發聲頻率”,核心是 “有效弦長比例” 的計算:

  1. 徽位插值計算(l 值)
    fret_num不是整數(如 1.5,代表 1 徽與 2 徽之間)時,通過 “線性插值” 計算精準的 “有效弦長比例 l”—— 空弦(fret_num=0)時 l=1/8,13 徽以上時 l=7/8 + 插值,1-13 徽間則基于mic_positions(徽位弦長比例表)計算,確保任意位置的音高都精準;
  2. 頻率換算
    無論是泛音還是按音,均通過 “空弦基頻 ÷ 有效弦長比例 l” 得到實際發聲頻率(原理:弦長越短,頻率越高,符合物理規律),僅通過 “諧波數量” 區分兩種演奏方式的音色(泛音諧波少更空靈,按音諧波多更厚重)。

音頻生成與播放流程

頻率確定后,函數完成 “音色合成→播放” 的閉環:

  1. 音色參數配置
    自動生成諧波相關參數 —— 振幅按 “1/n” 規律衰減(n 為諧波序號,符合真實弦振規律)、相位隨機(避免音色單調)、衰減系數隨諧波序號增大而減小(高頻諧波先衰減,模擬古琴余音特點);
  2. 音頻合成與播放
    調用string_pluck函數(弦振音頻合成函數),基于上述參數生成時域音頻信號;再通過audioplayer創建播放器,播放音頻(默認持續 1 秒后停止,避免余音過長干擾后續操作);
  3. 視覺聯動
    調用draw_point函數,在虛擬古琴界面上標記當前演奏的 “弦 - 徽位置”(如弦 3 的 5 徽處畫點),實現 “聽覺 + 視覺” 的同步反饋。

核心功能總結

該函數的價值在于 “把抽象的演奏指令(弦、法、位)轉化為可聽的古琴聲音”,既還原了真實古琴的物理發聲規律(弦長與頻率的關系、泛 / 按音的音色差異),又通過參數化設計實現了 “任意弦、任意徽、任意演奏方式” 的靈活發聲,是連接 “虛擬界面交互” 與 “音頻輸出” 的關鍵橋梁。

三、撥弦發聲函數

function [y, t] = string_pluck(fundamental_freq, num_harmonics, harmonic_amps, harmonic_phases, decay_factor, duration, Fs)% 輸入參數:% fundamental_freq: 基頻% num_harmonics: 諧波數量% harmonic_amps: 諧波振幅比例,長度為 num_harmonics 的向量% harmonic_phases: 諧波相位,長度為 num_harmonics 的向量% decay_factor: 衰減系數,范圍在 0 到 1 之間% duration: 聲音持續時間% Fs: 采樣頻率    % 生成時間向量t = 0:1/Fs:duration-1/Fs;y = zeros(size(t));% 生成弦樂撥弦的音色for k = 1:num_harmonicsfreq = k * fundamental_freq;amp = harmonic_amps(k);phase = harmonic_phases(k);decay=decay_factor(k);% 生成諧波分量y_harmonic = amp * sin(2*pi*freq*t + phase);% 應用衰減y_harmonic = y_harmonic.* exp(decay*t);% 疊加諧波分量y = y + y_harmonic;end
end

string_pluck函數是古琴(或其他弦樂器)數字化模擬系統中的 “音色合成引擎”,其核心功能是根據輸入的聲學參數,生成具有真實弦振特性的音頻信號。它通過數學建模的方式,模擬弦樂器被撥奏后的振動規律,最終輸出可播放的時域音頻數據。

核心功能與輸入輸出

  • 核心作用:將抽象的聲學參數(基頻、諧波、衰減等)轉化為具體的音頻信號,模擬弦樂器撥弦發聲的物理過程。
  • 輸入參數:包含 7 個關鍵參數,全面定義了聲音的基本特征:
    • fundamental_freq:基頻(決定音高的核心參數)
    • num_harmonics:諧波數量(決定音色豐富度)
    • harmonic_amps:諧波振幅比例(決定音色特點)
    • harmonic_phases:諧波相位(影響音色細節)
    • decay_factor:衰減系數(決定聲音的持續特性)
    • duration:聲音持續時間(單位:秒)
    • Fs:采樣頻率(標準為 44100Hz,即音頻的 “分辨率”)
  • 輸出結果
    • y:生成的音頻信號(時域波形數據)
    • t:對應的時間向量(與音頻信號同步的時間軸)

工作原理:從諧波疊加到真實音色

函數采用 “多諧波疊加” 的經典弦樂合成方法,模擬真實弦振動的物理特性,核心步驟分為 3 步:

  1. 時間向量生成
    首先創建與音頻時長匹配的時間軸?t,計算公式為?t = 0:1/Fs:duration-1/Fs,確保每個采樣點都對應精確的時間位置(例如 44100Hz 采樣率下,每個點間隔約 0.0000227 秒)。

  2. 諧波分量計算
    循環生成每個諧波的振動波形(共?num_harmonics?個):

    • 每個諧波的頻率為 “基頻的整數倍”(freq = k * fundamental_freq),符合弦振動的物理規律(弦振動會同時產生基頻和整數倍諧波);
    • 每個諧波的振幅由?harmonic_amps(k)?決定(通常高頻諧波振幅更低);
    • 每個諧波的初始相位由?harmonic_phases(k)?控制(隨機相位可避免不同諧波間的固定干涉,使音色更自然)。
  3. 衰減與疊加

    • 對每個諧波分量應用衰減:y_harmonic = y_harmonic .* exp(decay * t),模擬真實弦振動的能量損耗(高頻諧波通常衰減更快);
    • 將所有諧波分量疊加:y = y + y_harmonic,最終形成完整的弦樂音色波形。

關鍵設計:貼近真實弦樂器的特性

  • 諧波結構:通過整數倍諧波模擬弦的振動模式,符合弦樂器 “基頻 + 泛音” 的頻譜特點;
  • 振幅衰減:使用指數衰減函數?exp(decay * t)?模擬弦振動的能量耗散,使聲音有 “起音 - 持續 - 衰減” 的自然過程;
  • 參數靈活性:通過調整諧波數量、振幅比例和衰減系數,可模擬不同弦樂器(古琴、吉他、小提琴等)或同一種樂器的不同演奏技法(如古琴的泛音、按音)。

string_pluck函數是連接 “聲學參數” 與 “可聽聲音” 的關鍵模塊,它通過數學建模的方式,精準復現了弦樂器發聲的物理原理。在古琴模擬系統中,它接收play_note函數傳遞的音高和演奏方式參數,最終生成符合古琴音色特點的音頻信號,為虛擬演奏提供了核心的聲音輸出能力。

三、其他函數

function draw_point(i, l)% 輸入參數:% i: 琴弦弦號,從 1 到 7 的整數% l: 有效弦長,表示按音位置% 假設 x_start 和 x_end 是徽位圖的起始和結束 x 坐標,y_left_pos 和 y_right_pos 是左右位置數組,line_widths 是線寬數組x_start = 0.1;    x_end = 0.9;y_left_pos = [0.54224,0.52816,0.51408,0.50000,0.48592,0.47184,0.45776];y_right_pos = [[0.57040,0.54693,0.52346,0.50000,0.47653,0.45306,0.42960]];line_widths = [3.2 3 2.6 2.3 2 1.6 1.3];     
%     % 生成一個唯一的標記用于刪除
%     marker_id = ['marker_', num2str(i), '_', num2str(l)]    
%     % 檢查是否存在之前繪制的標記,如果存在則刪除
%     if ishandle(findobj('Tag', marker_id))
%         delete(findobj('Tag', marker_id));
%     end    % 生成一個唯一的標記用于刪除marker_id = 'marker_'; % 檢查是否存在之前繪制的標記,存在則刪delete(findobj('Tag', marker_id));   % 繪制徽位圖上的點h = plot(x_end - l*(x_end - x_start), (y_left_pos(i)- y_right_pos(i))*l+y_right_pos(i), 'ro', 'MarkerSize',line_widths(i)+2, 'MarkerFaceColor', 'r');% 為當前繪制的點設置標記set(h, 'Tag', marker_id);hold on;
end
% 讀取 new.wav 文件
[audio, Fs] = audioread('new.wav');% 計算時頻圖
window = hamming(256); % 使用漢明窗,窗口長度為 256
noverlap = 128; % 窗口重疊長度為 128
nfft = 512; % FFT 點數為 512% 使用 spectrogram 函數計算并繪制時頻圖
spectrogram(audio, window, noverlap, nfft, Fs, 'yaxis');% 添加標題和軸標簽
title('Time-Frequency Spectrogram of new.wav');
xlabel('Time (s)');
ylabel('Frequency (Hz)');% 添加顏色條
colorbar;
function freq = fr_of(note, octave)% 十二平均律中相鄰半音的頻率比semitone_ratio = 2^(1/12);% 以 A4 = 440Hz 為基準base_A4 = 440;% 計算 A 在不同八度的頻率base_A = base_A4 * 2^(octave - 4);switch notecase 'C'freq = base_A / (semitone_ratio)^9;case 'Db' % 將 bD 等同于 #Ccase '#C'freq = base_A / (semitone_ratio)^8;case 'D'freq = base_A / (semitone_ratio)^7;case 'Eb' % 將 bE 等同于 #Dcase '#D'freq = base_A / (semitone_ratio)^6;case 'E'freq = base_A / (semitone_ratio)^5;case 'F'freq = base_A / (semitone_ratio)^4;case 'Gb' % 將 bG 等同于 #Fcase '#F'freq = base_A / (semitone_ratio)^3;case 'G'freq = base_A / (semitone_ratio)^2;case 'Ab' % 將 bA 等同于 #Gcase '#G'freq = base_A / (semitone_ratio)^1;case 'A'freq = base_A;case 'Bb' % 將 bB 等同于 #Acase '#A'freq = base_A * semitone_ratio;case 'B'freq = base_A * (semitone_ratio)^2;otherwiseerror('Invalid note name');endend
function [marker, tenth] = l_to_marker(l)% l: 等效弦長    % 徽位位置(距離琴弦右側的有效長度為)% 徽位與琴弦右側長度倍數關系的數據表mic_positions = [1/8; 1/6; 1/5; 1/4; 1/3; 2/5; 1/2; 3/5; 2/3; 3/4; 4/5; 5/6; 7/8];marker_num=['一','二','三','四','五','六','七','八','九','十','十一','十二','十三'];marker_tenth=['一','二','三','四','五','六','七','八','九'];    % 找到徽位index = find(l < mic_positions, 1, 'first')-1;if isempty(index)index=13;%只有13徽讀取不到。marker='十三';tenth_index = round((l - mic_positions(index))* 80);elseif index == 0marker='零';% 對于一徽之內,特殊處理,分為十等份tenth_index= round(l*80);else  marker=marker_num(index);tenth_index = round((l - mic_positions(index)) / (mic_positions(index+1) - mic_positions(index)) * 10);endif tenth_index == 0tenth = '整';elseif tenth_index ==10tenth = '整';marker=marker_num(index+1);elsetenth = marker_tenth(tenth_index);end
end
function [noteout, note_str, octave, cent_offset] = nt_of(freq)% 十二平均律中相鄰半音的頻率比base_A4 = 440;octave = 0;% 將頻率調整到 A4 所在的八度范圍while freq < base_A4 / 2freq = freq * 2;octave = octave - 1;endwhile freq >= base_A4 * 2freq = freq / 2;octave = octave + 1;end% 計算相對于 A4 的音分數cents = 1200 * log2(freq / base_A4);% 計算半音數semitones = round(cents / 100);        % 計算音分偏移量cent_offset = mod(cents, 100);if cent_offset >= 50cent_offset = cent_offset - 100;endif cent_offset <= -50cent_offset = cent_offset + 100;end% 處理八度變化if semitones >= 12octave = octave + floor(semitones / 12);semitones = mod(semitones, 12);elseif semitones < 0octave = octave + floor(semitones / 12);semitones = mod(semitones, 12);endswitch semitonescase 0note = 'A';case 1note = 'A#';case 2note = 'B';case 3note = 'C';case 4note = 'C#';case 5note = 'D';case 6note = 'D#';case 7note = 'E';case 8note = 'F';case 9note = 'F#';case 10note = 'G';case 11note = 'G#';endnote_str = note;octave = octave + 4; % 將八度調整到實際的音樂八度范圍if cent_offset >= 0noteout = [note_str, num2str(octave), '+', num2str(abs(cent_offset))];elsenoteout = [note_str, num2str(octave), '-', num2str(abs(cent_offset))];endend
function [note_out, badu]=num2note(num,octave,key)
%key調:輸入1234567
%    CDEFGAB
% 1.5是#C或bD;2.5是#D或bC;4.5是#F或bG;5.5是#G或bA;6.5是#A或bB
%唱名到音名的轉換
if (key>6.4 || key<2.1)badu=octave;%和C調一樣
elsebadu=octave+1;
end
switch numcase 1num_offset=0;%Ccase 1.5num_offset=1;%C#case 2num_offset=2;%Dcase 2.5num_offset=3;%D#case 3num_offset=4;case 4num_offset=5;case 4.5num_offset=6;case 5num_offset=7;case 5.5num_offset=8;case 6num_offset=9;case 6.5num_offset=10;case 7num_offset=11;
end
num=num_offset;
switch keycase 1offset=0;%Ccase 1.5offset=1;%C#case 2offset=2;%Dcase 2.5offset=3;%D#case 3offset=4;case 4offset=5;case 4.5offset=6;case 5offset=7;case 5.5offset=8;case 6offset=9;case 6.5offset=10;case 7offset=11;
end
key=offset;
pitch=key+num;
badu_add=floor(pitch/12);
seminote=pitch - badu_add;switch seminote+3case 12note = 'A';case 13note = 'A#';case 14note = 'B';case 3note = 'C';case 4note = 'C#';case 5note = 'D';case 6note = 'D#';case 7note = 'E';case 8note = 'F';case 9note = 'F#';case 10note = 'G';case 11note = 'G#';otherwiseerror('Invalid key name');       endnote_out=note;
end

將所有函數和腳本文件按照對應名稱存好放置于同一文件夾即可運行,快來試試你的賽博樂器吧~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/95646.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/95646.shtml
英文地址,請注明出處:http://en.pswp.cn/web/95646.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

畢業項目推薦:67-基于yolov8/yolov5/yolo11的大棚黃瓜檢測識別系統(Python+卷積神經網絡)

文章目錄 項目介紹大全&#xff08;可點擊查看&#xff0c;不定時更新中&#xff09;概要一、整體資源介紹技術要點功能展示&#xff1a;功能1 支持單張圖片識別功能2 支持遍歷文件夾識別功能3 支持識別視頻文件功能4 支持攝像頭識別功能5 支持結果文件導出&#xff08;xls格式…

無人機小尺寸RFSOC ZU47DR板卡

整板尺寸&#xff1a;120*120mmFPGA: XCZU47DR-2FFVE1156I;DDR&#xff1a;PS側8GB 2400Mhz*64bit / PL側 4GB 2400Mhz*32bit&#xff1b;2路(QSP0QSPI1)/單片512Mb、共計1Gb&#xff1b;千兆以太網&#xff1a;1路&#xff08;PS側&#xff09;&#xff1b;主要接口資源如下&a…

LangGraph(一):入門從0到1(零基礎)

文章目錄LangGraph入門從0到10?? 安裝 & 確認環境1?? 把 LangGraph 想象成「自動化的做菜流水線」2?? 最小可運行例子&#xff1a;一句話復讀機3?? 加一個小節點&#xff1a;把用戶輸入變大寫4?? 條件邊&#xff1a;如果用戶說 quit 就結束&#xff0c;否則復讀5…

學習數據結構(16)快速排序

快速排序的基本思想&#xff1a;快速排序是Hoare于1962年提出的一種二叉樹結構的交換排序方法&#xff0c;其基本思想為&#xff1a;任取待排序元素序列中的某元素作為基準值&#xff0c;按照該基準值將待排序集合分割成兩子序列&#xff0c;左子序列中所有元素均小于基準值&am…

uni-app iOS 上架常見問題與解決方案,實戰經驗全解析

uni-app 讓開發者能夠“一套代碼&#xff0c;多端運行”&#xff0c;極大降低了開發成本。 但當應用進入 iOS 上架階段 時&#xff0c;不少團隊發現流程并沒有想象中那么順利&#xff1a;證書問題、打包失敗、上傳出錯、審核被拒……這些都可能讓項目卡殼。 本文結合實際案例&a…

洗衣機的智能升級集成方案WT2606B屏幕驅動+AI語音控制

2025&#xff0c;洗衣機市場正從功能滿足轉向體驗升級&#xff0c;企業正面臨哪些轉型難點?一文為您解讀洗衣機行業智能化升級之路。傳統洗衣機就像是一個"沉默的工人"&#xff0c;只能通過簡單的LED指示燈告訴你它在工作&#xff0c;卻無法讓你真正了解它在干嘛。用…

機器學習進階,梯度提升機(GBM)與XGBoost

梯度提升機&#xff08;Gradient Boosting Machine, GBM&#xff09;&#xff0c;特別是其現代高效實現——XGBoost。這是繼隨機森林后自然進階的方向&#xff0c;也是當前結構化數據競賽和工業界應用中最強大、最受歡迎的算法之一。為什么推薦XGBoost&#xff1f; 與隨機森林互…

【ARMv7】開篇:掌握ARMv7架構Soc開發技能

本專欄&#xff0c;開始與大家共同總結使用ARMv7系列CPU的Soc開發技能。大概匯總了一下&#xff0c;后面再逐步完善下面的思維導圖。簡單說說&#xff1a;與通用的ARMv7-A/R相比&#xff0c;以STM32F為代表的ARMv7-M架構有以下關鍵區別和重點&#xff1a;無MMU&#xff0c;有MP…

【學術會議論文投稿】JavaScript在數據可視化領域的探索與實踐

【ACM出版 | EI快檢索 | 高錄用】2024年智能醫療與可穿戴智能設備國際學術會議&#xff08;SHWID 2024&#xff09;_艾思科藍_學術一站式服務平臺 更多學術會議請看 學術會議-學術交流征稿-學術會議在線-艾思科藍 目錄 引言 JavaScript可視化庫概覽 D3.js基礎入門 1. 引入…

CSS基礎學習步驟

好的&#xff0c;這是一份為零基礎初學者量身定制的 **CSS 學習基礎詳細步驟**。我們將從最根本的概念開始&#xff0c;通過一步一步的實踐&#xff0c;帶你穩穩地入門。 第一步&#xff1a;建立核心認知 - CSS 是做什么的&#xff1f; 1. 理解角色&#xff1a; HTML&…

MTK Linux DRM分析(三十七)- MTK phy-mtk-hdmi.c 和 phy-mtk-hdmi-mt8173.c

一、簡介 HDMI PHY驅動 HDMI 的物理層接口主要就是 HDMI Type-A 接口(19 pin),除此之外還有 Type-B、Type-C(Mini HDMI)、Type-D(Micro HDMI)、Type-E(車載專用)。 1. HDMI Type-A(常見 19-pin 標準接口) HDMI Type-A Connector Pinout ========================…

【人工智能學習之MMdeploy部署踩坑總結】

【人工智能學習之MMdeploy部署踩坑總結】報錯1&#xff1a;TRTNet: device must be a GPU!報錯2&#xff1a;Failed to create Net backend: tensorrt報錯3&#xff1a;Failed to load library libonnxruntime_providers_shared.so1. 確認庫文件是否存在2. 重新安裝 ONNX Runti…

力扣516 代碼隨想錄Day16 第一題

找二叉樹左下角的值class Solution { public:int maxd0;int result;void traversal(TreeNode* root,int depth){if(root->leftNULL&&root->rightNULL){if(depth>maxd){maxddepth;resultroot->val;}}if(root->left){depth;traversal(root->left,depth…

網格圖--Day07--網格圖DFS--LCP 63. 彈珠游戲,305. 島嶼數量 II,2061. 掃地機器人清掃過的空間個數,489. 掃地機器人,2852. 所有單元格的遠離程度之和

網格圖–Day07–網格圖DFS–LCP 63. 彈珠游戲&#xff0c;305. 島嶼數量 II&#xff0c;2061. 掃地機器人清掃過的空間個數&#xff0c;489. 掃地機器人&#xff0c;2852. 所有單元格的遠離程度之和 今天要訓練的題目類型是&#xff1a;【網格圖DFS】&#xff0c;題單來自靈茶山…

多功能修改電腦機器碼序列號工具 綠色版

多功能修改電腦機器碼序列號工具 綠色版電腦機器碼序列號修改軟件是一款非常使用的數據化虛擬修改工具。機器碼修改軟件可以虛擬的定制您電腦上的硬件信息&#xff0c;軟件不會對您的電腦造成傷害。軟件不需要您有專業的知識&#xff0c;就可以模擬一份硬件信息。機器碼修改軟…

React Hooks深度解析:useState、useEffect及自定義Hook最佳實踐

React Hooks自16.8版本引入以來&#xff0c;徹底改變了我們編寫React組件的方式。它們讓函數組件擁有了狀態管理和生命周期方法的能力&#xff0c;使代碼更加簡潔、可復用且易于測試。本文將深入探討三個最重要的Hooks&#xff1a;useState、useEffect&#xff0c;以及如何創建…

期權平倉后權利金去哪了?

本文主要介紹期權平倉后權利金去哪了&#xff1f;期權平倉后權利金的去向需結合交易角色&#xff08;買方/賣方&#xff09;、平倉方式及市場價格變動綜合分析&#xff0c;具體可拆解為以下邏輯鏈條。期權平倉后權利金去哪了&#xff1f;1. 買方平倉&#xff1a;權利金的“差價…

2025國賽C題題目及最新思路公布!

C 題 NIPT 的時點選擇與胎兒的異常判 問題 1 試分析胎兒 Y 染色體濃度與孕婦的孕周數和 BMI 等指標的相關特性&#xff0c;給出相應的關系模 型&#xff0c;并檢驗其顯著性。 思路1&#xff1a;針對附件中孕婦的 NIPT 數據&#xff0c;首先對數據進行預處理&#xff0c;并對多…

NLP技術爬取

“NLP技術爬取”這個詞組并不指代一種單獨的爬蟲技術&#xff0c;而是指將自然語言處理&#xff08;NLP&#xff09;技術應用于網絡爬蟲的各個環節&#xff0c;以解決傳統爬蟲難以處理的問題&#xff0c;并從中挖掘出更深層次的價值。簡單來說&#xff0c;它不是指“用NLP去爬”…

讓錄音變得清晰的軟件:語音降噪AI模型與工具推薦

在數字內容創作日益普及的今天&#xff0c;無論是播客、線上課程、視頻口播&#xff0c;還是遠程會議&#xff0c;清晰的錄音質量都是提升內容專業度和觀眾體驗的關鍵因素之一。然而&#xff0c;由于環境噪音、設備限制等因素&#xff0c;錄音中常常夾雜各種干擾聲音。本文將介…