今天写点不一样的东西,每次唱歌的时候都会发现一个问题,原调要么太高要么太低,我们就要找一个合适的调唱起来才能更得心应手。所以在伴奏的时候我们就需要变换调式。
比如说1645的和弦行进在C大调是什么变换成G大调又是什么,今天我们先研究第一部分,按照我们的想法画出指定的和弦。老规矩先看成品。
流程:先画出指板再找出手指所按品位。
1.指板,这个其实就是简单的画线没什么好讲的,熟悉六线谱的人都知道,和弦图上从上往下依次是一弦到六弦还有三个品。此处只要留出起始位置的坐标就可以,便于在后期多个图时调整位置。
int FretWidth = 40, FretHeight = 20;//品的宽度,弦距
private void FretBoard(int StartX, int StartY)//指板
{
Point point = new Point();
point.X = StartX;
point.Y = StartY;
Graphics gra = this.picBackground.CreateGraphics();
Pen p = new Pen(Color.Black, 2);
for (int i = 0; i < 6; i++)
{
gra.DrawLine(p, StartX, StartY + i * FretHeight, StartX + 3 * FretWidth, StartY + i * FretHeight);// 1
Fret(i, FretNum[i], point);//手指的位置
}
for (int i = 0; i < 4; i++)
{
gra.DrawLine(p, StartX + i * FretWidth, StartY, StartX + i * FretWidth, StartY + 5 * FretHeight);// 1
}
}
2.手指位置,在品位上画一个黑色的小点来代表手指,在上面的代码中我们所用的Fret方法就是手指位置的获取方法,表示第几弦第几品放手指。
private void Fret(int GuitarStrings, int FretNum, Point point)//品级(参数1代表第几根弦,参数二代表第几品,位置(X,Y))
{
if (FretNum == 0)
{
return;
}
FretNum--;//FretNum获取的数字-1来对应品级
int Radius = 10;
Graphics gra = this.picBackground.CreateGraphics();
Brush bush = new SolidBrush(Color.Black);//填充的颜色
gra.FillEllipse(bush, point.X + FretWidth / 2 + 40 * FretNum - Radius / 2, point.Y + 20 * GuitarStrings - Radius / 2, Radius, Radius);//手指(品位上的黑色小点)
}
3.接下来就是本次的难点,我要怎么知道在几弦什么调应该按几品?这里就需要一个数组来盛放品位(0代表空弦,1代表1品以次类推;全局变量)。
int[] FretNum ={0,0,0,0,0,0 };//一到六弦(0:空弦,1:一品...)
4.找对应调对应弦的品位,首先创建一个C大调的12平均律作为基准。Test方法为任意调在C大调的12平均律中的位置,依次来推算其他调的十二平均律。twelveAverageLawNow数组存放当前调式的十二平均律。然后再指板上前四个品位找出当前调式是否有对应的根音、三度音、五度音(大调式和弦由根音三度音和五度音构成)。
string[] twelveAverageLaw = new string[] { "C","#C", "D", "#D", "E", "F", "#F", "G", "bA", "A", "bB", "B" };//C大调
private void Chord(string mode)//和弦
{
string[] twelveAverageLawNow = new string[12] { "", "", "", "", "", "", "", "", "", "", "", "" };
txtMode.Text = "";
for (int i = 0; i < 12; i++)
{
//MessageBox.Show(Test(mode).ToString());
twelveAverageLawNow[i] = i + Test(mode) > 11 ? twelveAverageLaw[i + Test(mode) - 12] : twelveAverageLaw[i + Test(mode)];
txtMode.Text += twelveAverageLawNow[i] + " ";
}
//MessageBox.Show("根音:"+twelveAverageLawNow[0].ToString()+ " 3度音:" + twelveAverageLawNow[4].ToString()+ " 5度音:" + twelveAverageLawNow[7].ToString());
//重复的工作都交给循环来做
//FretNum[0] = Test3(twelveAverageLawNow, "E");
//FretNum[1] = Test3(twelveAverageLawNow, "B");
//FretNum[2] = Test3(twelveAverageLawNow, "G");
//FretNum[3] = Test3(twelveAverageLawNow, "D");
//FretNum[4] = Test3(twelveAverageLawNow, "A");
//FretNum[5] = Test3(twelveAverageLawNow, "E");
string[] openStrings = new string[6] { "E", "B", "G", "D", "A", "E" };
for (int i = 0; i < 6; i++)
{
FretNum[i] = Test3(twelveAverageLawNow, openStrings[i]);
}
}
private int Test(string mode)//获取当前调式在C大调十二平均律中的位置
{
for (int i = 0; i < 12; i++)
{
if (twelveAverageLaw[i] == mode)
{
return i;
}
}
return 0;
}
5.这个方法是在当前的弦上找出对应的音,比如一弦空弦:E、一品:F、二品:#F、三品:G,C和弦根音为C、三度音为E、五度音为G那么久输出E,C和弦一弦就为空弦。D和弦根音为D、三度音为#F、五度音为A那么久输出#F,D和弦一弦就为二品。其他弦和品位也是通用的规律。
private int Test3(string[] twelveAverageLawNow,string mode)
{
string[] FretNum0 = { "", "", "", "", "", "", "", "", "", "", "", "" };//
for (int i = 0; i < 12; i++)
{
//MessageBox.Show(Test(mode).ToString());
FretNum0[i] = i + Test(mode) > 11 ? twelveAverageLaw[i + Test(mode) - 12] : twelveAverageLaw[i + Test(mode)];
}
//string[] FretNum1 = { "E", "F", "#F", "G" };
//string[] FretNum2 = { "B", "C", "#C", "D" };
//string[] FretNum3 = { "G", "#G", "A", "bB" };
//string[] FretNum4 = { "D", "#D", "E", "F" };
//string[] FretNum5 = { "A", "bB", "B", "C" };
//string[] FretNum6 = { "E", "F", "#F", "G" };
txtMode.Text = "";
for (int i = 0; i < 4; i++)
{
txtMode.Text += FretNum0[i];
if (FretNum0[i] == twelveAverageLawNow[0] || FretNum0[i] == twelveAverageLawNow[4] || FretNum0[i] == twelveAverageLawNow[7])
{
return i;
}
}
return 0;
}
6.按钮的单击事件
int num = 0;
private void btnClick_Click(object sender, EventArgs e)
{
//MessageBox.Show(cobMode.SelectedText.ToString()+" "+ cobMode.SelectedItem.ToString()+" "+ cobMode.SelectedValue.ToString());return;
Graphics gra = this.picBackground.CreateGraphics();
Chord(cobMode.Text.ToString());//和弦
FretBoard(10 + (FretWidth * 3 + 40) * num, 10);
num++;
if (num>7)
{
num = 0;
gra.Clear(this.BackColor);//清除
}
}
问题:眼尖的小伙伴可能已经看出问题来了D和弦怎么是D/#F,我也比较好奇按理说一弦和六弦应该都是一样的比如其他和弦一弦和六弦都是同步的,毕竟空弦音都是E(标准调弦),为什么在正常的D和弦里六弦都是不发音的(有一个小X)。还有大横按为了方便按取的音没有就近原则,比如B和弦二弦空弦音为根音B,但是为了方便取了四品的#D(bE),等待下篇进行优化。
大家有问题或者发现不对的踊跃留言啊。