求指点,关于代码(关于音调演奏)-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 6900|回复: 6

[已解决] 求指点,关于代码(关于音调演奏)

[复制链接]
发表于 2012-8-19 15:43 | 显示全部楼层 |阅读模式
本帖最后由 珜羽 于 2012-8-21 02:38 编辑

各位大神,下面是一个关于音调演奏的代码:

int dacPins[] = {
  2, 4, 7, 8};
int sin16[] = {
  7, 8, 10, 11, 12, 13, 14, 14, 15, 14, 14, 13, 12, 11,
  10, 8, 7, 6, 4, 3, 2, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6};
int lowToneDurations[] = {
  120, 105, 98, 89, 78, 74, 62};   
//                                          A    B    C    D     E    F   G           
int highToneDurations[] = {
  54, 45, 42, 36, 28, 26, 22 };
//                                           a   b    c    d    e     f     g

char* song = "e e ee e e ee e g c d eeee f f f f f e e e e d d e dd gg e e ee e e ee e g c d eeee f f f f f e e e g g f d cccc";

void setup()                 
{
  for (int i = 0; i < 4; i++)
  {
    pinMode(dacPins, OUTPUT);
  }
}

void loop()                    
{
  int i = 0;
  char ch = song[0];
  while (ch != 0)
  {
    if (ch == ' ')
    {
      delay(75);
    }
    else if (ch >= 'A' and ch <= 'G')
    {
      playNote(lowToneDurations[ch - 'A']);
    }
    else if (ch >= 'a' and ch <= 'g')
    {
      playNote(highToneDurations[ch - 'a']);
    }
    i++;
    ch = song;
  }  
  delay(5000);
}


void playNote(int pitchDelay)
{
  long numCycles = 5000 / pitchDelay + (pitchDelay / 4);
  for (int c = 0; c < numCycles; c++)
  {
    for (int i = 0; i < 32; i++)
    {
      setOutput(sin16);
      delayMicroseconds(pitchDelay);
    }
  }
}

void setOutput(byte value)
{
  digitalWrite(dacPins[3], ((value & 8) > 0));
  digitalWrite(dacPins[2], ((value & 4) > 0));
  digitalWrite(dacPins[1], ((value & 2) > 0));
  digitalWrite(dacPins[0], ((value & 1) > 0));
}




有三点看不懂的:
第一:
int sin16[] = {7, 8, 10, 11, 12, 13, 14, 14, 15, 14, 14, 13, 12, 11,
10, 8, 7, 6, 4, 3, 2, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6};
int lowToneDurations[] = {120, 105, 98, 89, 78, 74, 62};
这两个数组,分别代表什么意思?作用是什么?
第三:long numCycles = 5000 / pitchDelay + (pitchDelay / 4);
这个循环次数的公式怎么得来的,代表什么意思呢?
第二: digitalWrite(dacPins[0], ((value & 1) > 0));
这行代码中>0代表什么意思?


求各位大神指点啊,谢谢!


附电路图:
Jingle Bells.JPG

发表于 2012-8-20 10:22 | 显示全部楼层
额。图纸挂了。
 楼主| 发表于 2012-8-20 15:45 | 显示全部楼层
珜羽 发表于 2012-8-20 10:22
额。图纸挂了。

更新了图纸......求指点,三克油~~
发表于 2012-8-21 02:34 | 显示全部楼层
本帖最后由 珜羽 于 2012-8-21 02:37 编辑

从图纸上看,用D2 D4 D7 D8和外部的R2R电阻网络组成了4位DAC,输出的信号通过电容耦合给IC1放大。驱动喇叭发声。

int sin16[] = {7, 8, 10, 11, 12, 13, 14, 14, 15, 14, 14, 13, 12, 11,
              10, 8, 7, 6, 4, 3, 2, 1, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6};

这个数组就是D2 D4 D7 D8输出的时候四个脚各对应的数据。四位DAC就是2的四次方,即16,所以数组最大的值是15(从0开始数),且数组的数据个数为32个,即用32个点来描绘正弦波。如下图所示:
123.JPG


int lowToneDurations[] = {120, 105, 98, 89, 78, 74, 62};   
//                                          A    B    C    D     E    F   G           
int highToneDurations[] = { 54, 45, 42, 36, 28, 26, 22 };
//                                           a   b    c    d    e     f     g
这两个数组,保存着七音符(哆来咪发梭拉西哆)和更高一阶的音节的频率。

void loop() 里的函数负责读取字符串,解析出音节后传递给playNote(int pitchDelay)
void playNote(int pitchDelay)根据传来的音调,计算DAC输出的值,以及每个点之间的延时(改变了频率)

void setOutput(byte value)负责将传入的数据解析成IO的状态。


long numCycles = 5000 / pitchDelay + (pitchDelay / 4); 和 int highToneDurations[], int lowToneDurations[]是要结合起来看的。参考 http://hi.baidu.com/heartlikewater/item/98a9552a59f766c3ee10f14c

乐音和音节
我们生活的世界充满了各种声音。优美动听的音乐可以陶冶情操,给人以美的享受,而电锯锯木的声音、小刀刮玻璃的声音使人感到刺耳难听。可见,声音可以分为两种:前一种悦耳动听的声音叫做乐音,后一种令人厌烦的声音叫做噪声。
那么,从物理学的角度看一看,乐音和噪声的差别是什么呢?
既然乐音具有确定的周期和频率,一种乐音的音调就是确定的。在音乐理论中,把一组音按音调高低的次序排列起来就成为音节,也就是大家都知道的:dou,ruai,mi,fa,sou,la, xi,dou。
有趣的是,高音dou的频率正好是中音dou频率的2倍,而且音节中各音的频率跟dou的频率之比都是整数之比。
频率增加一倍,音程高出8度。实际上这只对于中等音高是正确的.人的感觉十分复杂,对于高音段来说,频率要增加一倍多,听起来音高才高出一个8度。
尽管如此,科学家们还是可以通过音乐家的实际测听,确定音高和频率的对应关系,并且据此设计出优美动听的电子乐器。
C调音节和D调音节中各音的频率表
唱名    C调(Hz)       D调(Hz)
dou     264             297
ruai    297             334
mi      330             371
fa      352             396
sou     396             446
la      440             495
xi      495             557
dou(高) 528             594
L1 131 L2 147 L3 165 L4 175 L5 196 L6 220 L7 247
N1 262 N2 296 N3 330 N4 349 N5 392 N6 440 N7 494
H1 523 H2 587 H3 659 H4 698 H5 784 H6 880 H7 988
I1 1047 I2 1175 I3 1319 I4 1397 I5 1568 I6 1760 I7 1976

一个节拍延时 2400 分为 1/2节拍…………1/8节拍 依次除以2即可


关于你的第二个问题我就不想解释了。。。
发表于 2012-8-21 02:39 | 显示全部楼层
另:请学习怎么让自己的代码看的直观点。。。之前的让我看的很头疼,替你编辑了下了
 楼主| 发表于 2012-8-21 09:02 | 显示全部楼层
珜羽 发表于 2012-8-21 02:39
另:请学习怎么让自己的代码看的直观点。。。之前的让我看的很头疼,替你编辑了下了 ...

基本明白了..先谢版主,晚点再仔细琢磨琢磨.....第二个问题,那个>0是判断用的,不过这判断加不加貌似没什么影响.......三克油!!!
发表于 2012-8-21 09:41 | 显示全部楼层
爱上Arduino 发表于 2012-8-21 09:02
基本明白了..先谢版主,晚点再仔细琢磨琢磨.....第二个问题,那个>0是判断用的,不过这判断加不加貌似没 ...

必须加,你自己琢磨琢磨。。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-1 01:39 , Processed in 0.195444 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表