C++入門: 用簡譜輕鬆自定義midi音樂;[聖誕賀卡與鈴兒響叮噹;]

yy-2020發表於2020-12-24

音樂賀卡midiMusic_v0.exe;

–用簡譜輕鬆自定義midi音樂;[聖誕樹與鈴兒響叮噹;]

下載連結:
音樂賀卡midiMusic_v0.exe;

/*/
編譯說明:
1.在版本號v6前加 * 號同時去掉v5前的 * 號,可切換到生日賀卡;
2.程式精簡,註釋詳細;採用簡譜編曲,大大降低初學難度;
3.程式結構;
本程式為模組化程式設計風格,由三部分構成;
(1)專案自定義部分;
(2)專案主程式;
(3)專案本地函式;

//----------------------------------------------+------------------------------------------------*/
//最簡單的MIDI程式;[C++編譯;]
//v0;20201223;"音樂賀卡midiMusic_v0";[src@midiMusic.cpp;]
//v6;20201222;"音樂賀卡beepMusic_v6";[src@beepMusic.cpp;]
//----------------------------------------------*/
//#include <graphics.h>   //引用圖形庫標頭檔案;
#include <windows.h>	//WinAPI庫;
#include <iostream>
//#include <map>
//#gragma comment(lib,"winmm.lib")
using namespace std;

//----------------------------------------------*/
//MIDI引數說明:
//--針對庫函式midiOutOpen();midiOutShortMsg()@"winmm.lib"; 
//音量volume: 0x00~0x7f;
//樂器tone: 0x90~0x9f;--其中0x99為鼓;其餘為鋼琴;
//音階keyb: 0x00~0x7f;--其中0x3c=中央C=60=C4=(4+1)*12;C5=72;C8=108;C1=24;A0=21;Rest=0;
//音符note: MIDI資訊noteMsg格式合成;音量<<16+音階<<8+樂器;
//----------------------------------------------+------------------------------------------------*/
  • //proj自定義部分;
//----------------------------------------------*/
//定義巨集:
#define d		7					//定義c調d=0;[變調取值d=0~11;]
#define C(oct)	(((oct)+1)*12)		//定義c調1的8度轉換巨集;[取值oct=0~8;]
#define N(o,s)	(C(o)+(s)+d)		//定義音符Note(o,s)=八度o[0~8]+簡譜音階s[1~7]+變調d[0~11];
#define msgFmt(p)	((volume<<16)+(N(m,simple[song[p]-'1'])<<8)+tone)	//定義音符資訊格式合成;
//定義歌唱音域voiceOct;中央C=mC=4;[88鍵鋼琴A0~C8共7.4個8度=7*12+4鍵;]
//enum voiceOct{vlC=2,lC,mC=4,hC,uhC=6};
//----------------------------------------------*/
//v0;定義歌曲簡譜;
const char song[]={
	//上學歌;d=C;2/4;
	//"12 31 5-|66 `16 5-|66 `1_ 56 3_|65 35 31 23 1- ||"
	//鈴兒響叮噹;等效簡譜d=G;4/4;
	",5321 ,5- |,5321 ,6- |,6432 ,7- | 55 42 3- |"
	",5321 ,5- |,5321 ,6- |,6432555_ | 65 42 1- |"
	"333_ 333_ | 3512  3- | 4444433_ | 32212_5_ |"
	"333_ 333_ | 3512  3- | 4444433_ | 55 42 1- ||"
};
//定義簡譜音階scale到12平均律keyb的對映;s[1~7]-'1'=scale[0~6];[simpleScale;]
const int simple[]={0,2,4,5,7,9,11};
//----------------------------------------------+------------------------------------------------*/
  • //proj主程式;
//----------------------------------------------*/
//定義全域性變數;
int volume=0x7f;	//音量;
int tone=0x90;		//音色;[樂器編號;]
int noteMsg=0;		//音符;[音符資訊;]
int t=250;			//延時;[單位時值;]
int m=4;			//八度;中音組m=C4;[@88鍵鋼琴;]
//本地函式宣告;
void xcolor(int p);		//自動變色子程式;--簡譜1~7對映到顏色case 8~14;
void shape();			//形狀顯示子程式;--圖形輪廓曲線s[]=shape;
void midiNote(HMIDIOUT handle,int p);	//簡譜字元MIDI發聲子程式;--字元指標p;
//----------------------------------------------*/
//v0;主函式;
int main()
{
	system("title 音樂賀卡midiMusic_v0");		//設定cmd視窗標題;
	system("mode con cols=43 lines=20");		//設定cmd視窗寬高=字元數;
	HMIDIOUT handle;							//定義儲存MIDI輸出裝置控制程式碼的變數;
	midiOutOpen(&handle,0,0,0,CALLBACK_NULL);	//開啟並獲取midi裝置控制程式碼@handle;
	while(1)
	{
		int i=0;				//簡譜song[]的索引指標變數p;
		while(song[i]!='|'||song[i+1]!='|')
		{
			if(song[i]!='|')printf("%c",song[i]);
			else{
				printf("\n");
				xcolor(i+2);	//自動變色子程式;--簡譜1~7對映到顏色case 8~14;
				shape();		//形狀顯示子程式;--圖形輪廓曲線s[]=shape;
			}
			midiNote(handle,i);	//簡譜字元MIDI發聲子程式;
			i++;
		}printf("\n--0x%x--\n",++tone);
		if(tone>0x9f)break;
	}midiOutClose(handle);		//關閉midi裝置;
	return 0;
}
//----------------------------------------------+------------------------------------------------*/
  • //proj本地函式;
//----------------------------------------------*/
//v0;音符MIDI發聲子程式;[音樂核心函式;]
//函式介面&引用;
//形參;		[音符指標p;]
//全域性常量;	[歌曲資料song[];鍵盤定義keyb[];最小單位延時t;]
//庫函式;	[蜂鳴器發聲_beep(frequency,delay)@<stdlib.h>;]
void midiNote(HMIDIOUT handle,int p)	//簡譜字元MIDI發聲子程式;--字元指標p;
{
	switch(song[p])
	{
	case ' ':
	case '|':break;
	case '0':
	case '_':Sleep(t);break;
	case '-':Sleep(t*3);break;
	case '`':m++;break;
	case ',':m--;break;
	default:
		noteMsg=msgFmt(p);
		midiOutShortMsg(handle,noteMsg);	//midi音符發聲;
		Sleep(t);m=4;
	}

}
//----------------------------------------------*/
//v6;聖誕樹顯示子程式;--3級註釋;[視窗尺寸45*20;單位是字元;其中,心形尺寸=35字元寬*15行;]
//字串帶格式列印;[函式原型printf(const char *, ...);--變參函式;%和*均可增加引數;]
//printf格式串("%*.*s")=>(tLen(i).sLen(i),a);[*號增加2個引數,%增加1個引數;共4個引數;]
//
//定義常量陣列;--聖誕樹字串a;樹形輪廓資料s;
//const char a[]={"We wish you a Merry Christmas And Happy New Year !"};//主體字串alpha;
const char a[]={"Merry Christmas & Happy New Year!"};	//主體字串alpha;[共35字元;]
const int  s[]={17,15,13,11,13,11,9,7,9,7,5,3,1,15,15};	//輪廓shape[15];[共15行;]
//定義巨集;
#define X0 4					//左邊距;--預留4個字元;[命名X0;意為起始x座標從0開始;]
#define sLen(i) (35-s[i]*2)		//巨集函式;--計算第i行字串長度 string Length;[公式1;]
#define tLen(i) (X0+35-s[i])	//巨集函式;--計算第i行加左邊總長度 total Length;[公式2;]

void shape()	//形狀顯示子程式;--圖形輪廓曲線s[]=shape;
{
//	列印祝福語英文;--從0~14行,依次逐行列印字元圖形;
//	printf("\n\n%*.*s\n", tLen(0), sLen(0), h);		//頭部h[];--單獨列印第0行;
	printf("\n\n\n");		//頭部空行;--空3行;[為了上下對稱,後邊文字也留3行;]
    for(int i=0;i<15;i++)							//圖形高15行;行數i=0~14;
        printf("%*.*s\n", tLen(i), sLen(i), a);		//主體a[];--迴圈列印第0~14行;
//	列印祝福語中文;
    printf("\n恭祝聖誕與新年快樂!\n");				//下部3行;--空1行,文字1行;音符顯示預留1行;
}
//----------------------------------------------*/
/*/v5;心形顯示子程式;--3級註釋;[視窗尺寸45*20;單位是字元;其中,心形尺寸=35字元寬*15行;]
//字串帶格式列印;[函式原型printf(const char *, ...);--變參函式;%和*均可增加引數;]
//printf格式串("%*.*s")=>(tLen(i).sLen(i),a);[*號增加2個引數,%增加1個引數;共4個引數;]

//定義常量陣列;--心形字串h,a;心形輪廓資料s;
const char h[]={"Happy          to You !"};				//頭部字串head;[僅佔第0行;]
const char a[]={"Happy Birthday to You ! Happy Birth"};	//主體字串alpha;[共35字元;]
const int  s[]={7,3,1,0,0,1,3,5,7,9,11,13,15,16,17};	//輪廓shape[15];[共15行;]
//
//定義巨集;
#define X0 5					//左邊距;--預留5個字元;[命名X0;意為起始x座標從0開始;]
#define sLen(i) (35-s[i]*2)		//巨集函式;--計算第i行字串長度 string Length;[公式1;]
#define tLen(i) (X0+35-s[i])	//巨集函式;--計算第i行加左邊總長度 total Length;[公式2;]

void shape()	//形狀顯示子程式;--圖形輪廓曲線s[]=shape;
{
//	列印祝福語英文;--從0~14行,依次逐行列印心形;
	printf("\n\n%*.*s\n", tLen(0), sLen(0), h);		//頭部h[];--單獨列印第0行;
    for(int i=1;i<15;i++)							//行數i=1~14;
        printf("%*.*s\n", tLen(i), sLen(i), a);		//主體a[];--迴圈列印第1~14行;
//	列印祝福語中文;
    printf("\n祝你生日快樂!\n");
}
//----------------------------------------------*/
//v5;自動變色子程式;--預設16色重新排序;[頻率升序;集中亮色;]
//	system("pause");
//	system("color 0##c");	//設定cmd視窗背景色/前景色;--青色3/亮白f;
//	c=(c+1)%16;				//c=0~15;取16的餘數;
//定義巨集;
#define is(p)	(song[p]!=0)	//判斷is音符;--為假是休止符=0;可用l(0)表示;
#define c_idx	(song[p]%7+8)	//顏色索引巨集;簡譜1~7=>0~6對映到顏色8~14;[公式3;]
//隨簡譜音符1~7變色;
void xcolor(int p)		//自動變色子程式;--簡譜1~7對映到顏色case 8~14;
{
	if(is(p))switch(c_idx)	//變色索引引數c_idx;--如果is(p)為假,則為休止符;
	{										  
	case  1: system("color 04");break;		//4 = 紅色    
	case  2: system("color 06");break;		//6 = 黃色    
	case  3: system("color 02");break;		//2 = 綠色    
	case  4: system("color 03");break;		//3 = 青色  
	case  5: system("color 01");break;		//1 = 藍色    
	case  6: system("color 05");break;		//5 = 紫色    
	case  7: system("color 07");break;		//7 = 白色    
	case  8: system("color 0c");break;		//C = 亮紅色
	case  9: system("color 0e");break;		//E = 亮黃色
	case 10: system("color 0a");break;		//A = 亮綠色
	case 11: system("color 0b");break;		//B = 亮青色
	case 12: system("color 09");break;		//9 = 亮藍色
	case 13: system("color 0d");break;		//D = 亮紫色
	case 14: system("color 0f");break;		//F = 亮白色
	case 15: system("color 08");break;		//8 = 灰色
	default: system("color");break;			//0 = 黑色;[恢復con預設色;]  
	}
	else system("cls");	//休止符清屏;
}
//----------------------------------------------+------------------------------------------------*/

在這裡插入圖片描述
在這裡插入圖片描述

相關文章