9313浏览
查看: 9313|回复: 15

“神笔马良”是如何炼成的

[复制链接]
本帖最后由 robo027 于 2017-9-4 00:14 编辑

“神笔马良”是如何炼成的图2

很久很久以前,有个孩子名字叫马良。他梦想能成为一名艺术家,但家里很贫苦,仅仅靠他砍柴、割草换来的钱过日子。他从小喜欢音乐,可是他没有电子琴也没有架子鼓,他仅仅只有一台破电脑一些电子零件和一支毛笔。然而这些阻碍并没有终止他对梦想的追求,于是,他拿起毛笔,在纸上画了一架电子琴,配合一些所学到的电子硬件软件的相关知识。弄出了这么个玩意儿:



不光如此他还试着去画了一套架子鼓,也玩了起来:


“神笔马良”是如何炼成的图13

他实现了自己的梦想。马良也因此一画成名,当上总经理,出任CEO,迎娶白富美,走上人生巅峰。
“神笔马良”是如何炼成的图1

我们从小就看过《神笔马良》的动画,也曾梦想有一支马良的”神笔“。
在今天,科技让我们拉近了与梦想的距离。Arduino控制器+导电墨水就可以实现这个梦想。
“神笔马良”是如何炼成的图12下面让我来做一个Touchboard的大致介绍和midi玩法教学,一旦你掌握了,其实这块板也差不多弄明白怎么玩了。
“神笔马良”是如何炼成的图4

购买链接在这https://www.dfrobot.com.cn/goods-1176.htm

拿到板子后我的建议还是先到官网大致看看。虽然全英文的,但我们有翻译器嘛不是。
这块板也可以说是集成了数字音乐模块VS1053,电容触摸模块MPR121的Arduino Leonardo,非常漂亮精致。而且可以用全能来形容它。
大致有以下几个功能:
“神笔马良”是如何炼成的图6
除了可以胜任Arduino所有功能
“神笔马良”是如何炼成的图8
还可以当MakeyMakey玩,用触摸的方式发送键盘信号。然后用键盘信号去操作电脑里的游戏,音乐软件等。这个就不多介绍了。
“神笔马良”是如何炼成的图5
另外它还支持内存卡里音频文件的读取,你可以录一段声音或是放一首歌曲或是找一些乐器的采样声音用GOLDwave转成MP3,然后按"TARCK000.mp3,TARC001.mp3...”的格式命名放到卡的根文件,这样接块电池插上耳机或音箱,用导电漆在纸上或墙上画一些有创意的画和线连到相应的键位(E0,E1...)就可以了,这样用手摸画就可以发出相应的声音从而可以完成很多互动表演。
VS1053芯片里还内置了一些MIDI音色可选,连内存卡都不用,接上音箱,直接通过修改代码调用相应的乐器就可以演奏了。
“神笔马良”是如何炼成的图7
它还可以发出MIDI信号,比如把我之前的MIDI鼓机升级成涂鸦鼓机结合Ableton Live或IOS/OSX上的GarageBand玩出更多花样。
因为导电墨水会因为自身浓度,干湿度、涂抹环境,涂抹距离、厚度等诸多因素,导致阻值不同。继而影响操作,所以他并不是一套代码就能通吃的。 会带来接下来我着重讲讲怎么调试:
首先我们需要在官网上下载一个类似补丁的东西
windows点此
Mac点此
下好后直接安装,注意在选择安装盘符的时候必须选择ArduinoIDE对应的文件夹。装好后运行IDE你就会发现IDE有一些变化:
“神笔马良”是如何炼成的图9
在工具---开发板的子菜单里你会发现多了两个可以选择的名称,一个是串口通信,另外一个是USBmidi通信。在这里需要说明的是除了你要用它来发送MIDI信号给电脑或手机选择第二个,其他的例程基本上都使用第一个板。
接下来看例程:
“神笔马良”是如何炼成的图10
点开文件----项目文件夹,我用midi_interface_generic做个示范,先翻译了部分注释:
[mw_shl_code=csharp,true]//*******************************************************************************/

// compiler error handling




//*******************************************************************************/

// compiler error handling
#include "Compiler_Errors.h"

#include <MPR121.h>
#include <Wire.h>
#include "Midi_object.h"

MIDIEvent e;

#define numElectrodes 12
midi_object_t MIDIobjects[numElectrodes]; //创建一个要使用的MIDI对象数组(每个电极一个)

void setup() {
  Serial.begin(9600);

  pinMode(LED_BUILTIN, OUTPUT);

  MPR121.begin(0x5C);
  MPR121.setInterruptPin(4);

  // *************************
  // Proximity (CC) electrodes
  // *************************

//将电极0设置为连接到控制器102的代理映射控制器
  MIDIobjects[0].type = MIDI_CONTROL;
  MIDIobjects[0].controllerNumber = 102; // 102..119在MIDI规范中未定义
  MIDIobjects[0].inputMin = 520;
// note than inputMin这里大于inputMax

//这意味着你的手越接近传感器
                                  //输出值越高
                                  //反转映射,使inputMax大于inputMin
  MIDIobjects[0].inputMax = 480;  // inputMin和inputMax之间的距离越远
                                  //传感器工作范围越大
                                  // the larger of a range the sensor will work over
  MIDIobjects[0].outputMin = 0;   //控制器的最小输出 - 最小有效值为0
  MIDIobjects[0].outputMax = 127; //控制器的最大输出 - 最大有效值为127



//将电极1设置为连接到控制器103的原始映射控制器
  MIDIobjects[1].type = MIDI_CONTROL;
  MIDIobjects[1].controllerNumber = 103;
  MIDIobjects[1].inputMin = 520;  
  MIDIobjects[1].inputMax = 480;  
  MIDIobjects[1].outputMin = 0;   
  MIDIobjects[1].outputMax = 127;


//将电极2设置为连接到控制器104的代理映射控制器
  MIDIobjects[2].type = MIDI_CONTROL;
  MIDIobjects[2].controllerNumber = 104;
  MIDIobjects[2].inputMin = 520;  
  MIDIobjects[2].inputMax = 480;  
  MIDIobjects[2].outputMin = 0;  
  MIDIobjects[2].outputMax = 127;

  // set up electrode 3 as a proxmity mapped controller attached to controller 105
  MIDIobjects[3].type = MIDI_CONTROL;
  MIDIobjects[3].controllerNumber = 105;
  MIDIobjects[3].inputMin = 520;  
  MIDIobjects[3].inputMax = 480;  
  MIDIobjects[3].outputMin = 0;  
  MIDIobjects[3].outputMax = 127;

  // set up electrode 4 as a proxmity mapped controller attached to controller 106
  MIDIobjects[4].type = MIDI_CONTROL;
  MIDIobjects[4].controllerNumber = 106;
  MIDIobjects[4].inputMin = 730;  
  MIDIobjects[4].inputMax = 710;  
  MIDIobjects[4].outputMin = 0;   
  MIDIobjects[4].outputMax = 127;

  // set up electrode 5 as a proxmity mapped controller attached to controller 107
// MIDIobjects[5].type = MIDI_CONTROL;
  //MIDIobjects[5].controllerNumber = 107;
// MIDIobjects[5].inputMin = 520;  
  //MIDIobjects[5].inputMax = 480;  
// MIDIobjects[5].outputMin = 0;  
//  MIDIobjects[5].outputMax = 127;

  // set up electrode 6 as a proxmity mapped controller attached to controller 108
// MIDIobjects[6].type = MIDI_CONTROL;
// MIDIobjects[6].controllerNumber = 108;
  //MIDIobjects[6].inputMin = 520;  
// MIDIobjects[6].inputMax = 480;  
// MIDIobjects[6].outputMin = 0;   
// MIDIobjects[6].outputMax = 127;

  // set up electrode 7 as a proxmity mapped controller attached to controller 109
//  MIDIobjects[7].type = MIDI_CONTROL;
  //MIDIobjects[7].controllerNumber = 109;
  //MIDIobjects[7].inputMin = 520;
// MIDIobjects[7].inputMax = 480;  
// MIDIobjects[7].outputMin = 0;   
  //MIDIobjects[7].outputMax = 127;

  // set up electrode 8 as a proxmity mapped controller attached to controller 110
  //MIDIobjects[8].type = MIDI_CONTROL;
  //MIDIobjects[8].controllerNumber = 110;
//MIDIobjects[8].inputMin = 520;
// MIDIobjects[8].inputMax = 480;  
// MIDIobjects[8].outputMin = 0;   
// MIDIobjects[8].outputMax = 127;

  // set up electrode 9 as a proxmity mapped controller attached to controller 111
// MIDIobjects[9].type = MIDI_CONTROL;
  //MIDIobjects[9].controllerNumber = 111;
// MIDIobjects[9].inputMin = 520;
  //MIDIobjects[9].inputMax = 480;  
//  MIDIobjects[9].outputMin = 0;   
//  MIDIobjects[9].outputMax = 127;

  // set up electrode 10 as a proxmity mapped controller attached to controller 112
//  MIDIobjects[10].type = MIDI_CONTROL;
  //MIDIobjects[10].controllerNumber = 112;
// MIDIobjects[10].inputMin = 520;
  //MIDIobjects[10].inputMax = 480;
  //MIDIobjects[10].outputMin = 0;   
  //MIDIobjects[10].outputMax = 127;

  // set up electrode 11 as a proxmity mapped controller attached to controller 113
//  MIDIobjects[11].type = MIDI_CONTROL;
// MIDIobjects[11].controllerNumber = 113;
// MIDIobjects[11].inputMin = 520;
// MIDIobjects[11].inputMax = 480;  
// MIDIobjects[11].outputMin = 0;   
// MIDIobjects[11].outputMax = 127;

  // ***********************
  //触摸(注)电极
  // ***********************

//如果要将电极配置为音符输出(而不是接近)
  // CC)你需要做以下两件事情:
  //
  // 1.取消注释下面的部分
  //
  // 2.完全注释“接近(CC)电极”部分。这确保
  //这两个部分不会相互干扰。
  //

//您也可以在两者之间选择,例如具有电极0作为
  //接近电极和电极1作为触摸电极。你这样做:
  //
  // 1.在“接近(CC)电极”中注释与电极1相关的线
  // section  - 这是以“MIDIobjects [1]”开头的六行
  //
  // 2.取消注释“触摸(注)电极”中与电极1相关的线条
  //部分 - 这是下面的4行,以“MIDIobjects [1]”开头
  //
  //要记住的重要事情是,您不能有两个活动的部分
  //相同的电极。


  // // set up electrode 0 as a touch sensitive key attached to note 60
  // MIDIobjects[0].type = MIDI_NOTE;
  // MIDIobjects[0].noteNumber = 60;       // middle C
  // MIDIobjects[0].touchThreshold = 50;   // always make sure that the touch threshold is
  // MIDIobjects[0].2releaseThreshold = 2; // larger than the release threshold - larger values
  //                                       // are less sensitive (and more robust)
  //
  // // set up electrode 1 as a touch sensitive key attached to note 61
  // MIDIobjects[1].type = MIDI_NOTE;
  // MIDIobjects[1].noteNumber = 61;           
  // MIDIobjects[1].touchThreshold = 50;  
  // MIDIobjects[1].releaseThreshold = 20;
  //
  // // set up electrode 2 as a touch sensitive key attached to note 62
  // MIDIobjects[2].type = MIDI_NOTE;
  // MIDIobjects[2].noteNumber = 62;           
  // MIDIobjects[2].touchThreshold = 50;  
  // MIDIobjects[2].releaseThreshold = 20;
  //
  // // set up electrode 3 as a touch sensitive key attached to note 63
  // MIDIobjects[3].type = MIDI_NOTE;
  // MIDIobjects[3].noteNumber = 63;
  // MIDIobjects[3].touchThreshold = 50;  
  // MIDIobjects[3].releaseThreshold = 20;
  //
  // // set up electrode 4 as a touch sensitive key attached to note 64
  // MIDIobjects[4].type = MIDI_NOTE;
  // MIDIobjects[4].noteNumber = 64;           
  // MIDIobjects[4].touchThreshold = 50;  
  // MIDIobjects[4].releaseThreshold = 20;
  //
  // // set up electrode 5 as a touch sensitive key attached to note 65
MIDIobjects[5].type = MIDI_NOTE;
MIDIobjects[5].noteNumber = 65;
MIDIobjects[5].touchThreshold = 50;  
MIDIobjects[5].releaseThreshold = 20;

// set up electrode 6 as a touch sensitive key attached to note 66
MIDIobjects[6].type = MIDI_NOTE;
MIDIobjects[6].noteNumber = 66;
MIDIobjects[6].touchThreshold = 50;  
MIDIobjects[6].releaseThreshold = 20;

  // // set up electrode 7 as a touch sensitive key attached to note 67
MIDIobjects[7].type = MIDI_NOTE;
MIDIobjects[7].noteNumber = 67;
MIDIobjects[7].touchThreshold = 50;  
MIDIobjects[7].releaseThreshold = 20;
  //
  // // set up electrode 8 as a touch sensitive key attached to note 68
MIDIobjects[8].type = MIDI_NOTE;
MIDIobjects[8].noteNumber = 68;
MIDIobjects[8].touchThreshold = 50;  
MIDIobjects[8].releaseThreshold = 20;
  //
  // // set up electrode 9 as a touch sensitive key attached to note 69
MIDIobjects[9].type = MIDI_NOTE;
MIDIobjects[9].noteNumber = 69;
MIDIobjects[9].touchThreshold = 50;  
MIDIobjects[9].releaseThreshold = 20;
  //
  // // set up electrode 10 as a touch sensitive key attached to note 70
MIDIobjects[10].type = MIDI_NOTE;
MIDIobjects[10].noteNumber = 70;
MIDIobjects[10].touchThreshold = 50;  
MIDIobjects[10].releaseThreshold = 20;
  //
  // // set up electrode 11 as a touch sensitive key attached to note 71
MIDIobjects[11].type = MIDI_NOTE;
MIDIobjects[11].noteNumber = 71;
MIDIobjects[11].touchThreshold = 50;  
MIDIobjects[11].releaseThreshold = 20;




//设置要求它的电极的触发和释放阈值
  for(int i=0; i<numElectrodes; i++){
    if(MIDIobjects.type == MIDI_NOTE){
      MPR121.setTouchThreshold(i, MIDIobjects.touchThreshold);
      MPR121.setReleaseThreshold(i, MIDIobjects.releaseThreshold);
    }
  }     

  // start with fresh data
  MPR121.updateAll();
}

void loop() {

//检查笔记电极
  if(MPR121.touchStatusChanged()){
    MPR121.updateTouchData();
    for(int i=0; i<numElectrodes; i++){
      if(MIDIobjects.type==MIDI_NOTE){
//如果这是一个笔记型对象...
        e.type = 0x08;
        e.m2 = MIDIobjects.noteNumber; //设置笔记号码
        e.m3 = 127;  //最大音量
        if(MPR121.isNewTouch(i)){

//如果我们有新的触摸,打开板载LED和
          //发送一个“note on”消息,并附上适当的注释集
          digitalWrite(LED_BUILTIN, HIGH);
          e.m1 = 0x90;
        } else if(MPR121.isNewRelease(i)){

//如果我们有一个新的版本,关闭板载LED和
          //发送“note off”消息
          digitalWrite(LED_BUILTIN, LOW);
          e.m1 = 0x80;
        } else {

//设置一个标志来做任何事情
          e.m1 = 0x00;  
        }

//只需要发送USB MIDI消息即可
        if(e.m1 != 0x00){
          MIDIUSB.write(e);
        }
      }
    }
  }

  MPR121.updateFilteredData();


//现在检查控制器电极
  for(int i=0; i<numElectrodes; i++){
    if(MIDIobjects.type==MIDI_CONTROL){
//如果我们有一个控件类型的对象...
      Serial.print("E");
      Serial.print(i);
      Serial.print(":");                          //这会打印一些串行调试数据,以方便映射
      Serial.println(MPR121.getFilteredData(i));  
//例如E11:567表示E11的值为567(这是输入数据)


//从输入中输出正确映射的值
      e.m3 = (unsigned char)constrain(map(MPR121.getFilteredData(i), MIDIobjects.inputMin, MIDIobjects.inputMax, MIDIobjects.outputMin, MIDIobjects.outputMax), 0, 127);

      if(e.m3!=MIDIobjects.lastOutput){
//如果自上次更改以来,只输出一个新的控制器值

        MIDIobjects.lastOutput=e.m3;

        e.type = 0x08;
        e.m1 = 0xB0; // control change message
        e.m2 = MIDIobjects.controllerNumber;    //选择正确的控制器编号 - 应使用数字

//在102到119之间,除非你知道你在做什么
        MIDIUSB.write(e);
      }
    }
  }


//刷新USB缓冲区,以确保发送所有音符
  MIDIUSB.flush();

  delay(10);
// 10ms延迟给USB MIDI目标时间赶上

}
[/mw_shl_code]


翻译的部分因为用的谷歌有的语句不通,但不影响理解,看完就差不多知道怎么去调试了。
我截取了两段关系到每个按键灵敏程度以及发出的MIDI信号是数字还是模拟(数字信号--开关--琴键,模拟信号--阀值--旋钮)

数字信号:             MIDIobjects[11].type = MIDI_NOTE;
       MIDIobjects[11].noteNumber = 36;             //这里是指发出去的MIDI信号的CC值,在我MIDI鼓机那篇文章中我有讲过)
       MIDIobjects[11].touchThreshold = 40;     
       MIDIobjects[11].releaseThreshold = 20;  //这里的40和20是指一个触发的区间,数值越小意味着越灵敏,相当于你的手可以拿开的更远,实现空中打鼓就是把他们改成个位数行了。
模拟信号:
       MIDIobjects[11].type = MIDI_CONTROL;
       MIDIobjects[11].controllerNumber = 112;  //CC值,在CC信号的表中102-119是没有被定义的,也就是说你可以自己定义 Live界面上的功能映射。
       MIDIobjects[11].inputMin = 755;
       MIDIobjects[11].inputMax = 770; //这个和上面数字信号触发的区间差不多,但是需要去调试,没调试有可能根本触发不了旋钮。怎么调试下面讲解
       MIDIobjects[11].outputMin = 0;
MIDIobjects[11].outputMax = 127;
调试的过程:
“神笔马良”是如何炼成的图11
无非就是打开串口通信的窗口,然后看一看里面跳动的数值,然后你用手指从画上某个类旋钮功能键的可变区域范围内来回刷,观察最大和最小读数,(一定要结合项目每个按键去调试)取一个高效的区间。填到上面的nputMin 和inputMax 里面即可。这样调试下来,这块板才算真正的适配到了项目中。

材料的话就墨水笔,和纸,木板,塑料板,等等反正不导电的都可以当作画板。这块板玩的就是墨水与创意。
“神笔马良”是如何炼成的图3
MP3的玩法不能同时按下多个按键,家庭的墙面装饰,英语课,音乐课什么的增添一些艺术感和科技感。因为这时候他可能要被挂在墙上。所以能简化尽量简化。(一个板一个音箱即可)

MIDI玩法就比较多元化了,不管是电脑,手机,室内室外都可以被支持,而且还可以同时发出去多个按键的CC值,尤其配合GarageBandAPP就相当于一部万能乐器了。真正实现画什么乐器就玩什么乐器。我开篇胡编滥造的神笔马良的段子,就源自于此。最后我想说好的音乐其实不在于用多名贵的乐器去演奏,而在于我们怎么去玩。   
最后想说一下这个导电漆
我觉得价格确实偏高了。最开始用铅笔啊,石墨粉+各种胶,不是没用就是达不到理想效果,以至于让我不得不把我的工作间变成了化学实验室。翻阅了大量的资料,做了大量的尝试,当然前期也吸进去了不少毒气。进过一次医院,最终找到了我认为比官网的漆还要好的材料,第一,水性,快干。第二环保且无味,第三,可以灌进笔里画,第四,导电性不输。第五成本降低。后面的就不接着说了。我真的只是介绍这块板子来的。

好了就介绍到这里,如果有任何需要纠正的或我没有说清楚的地方请帮我及时指出。如果还需要这块板其他例程的讲解也可以下方留言,第一时间回复,谢谢大家。







IMG_0939_update_1000x500-720x415.jpg

robo027  初级技匠
 楼主|

发表于 2017-9-5 22:17:10


感觉这个有很高的可玩性。左边控制音量,中间两个我还不太清楚怎么形容,貌似乐器声场什么之类的,右边就是控制音调的。
回复

使用道具 举报

hnyzcj  版主

发表于 2017-9-4 19:31:37

完美
回复

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-9-5 00:22:24

我在以前听过一期《闲白电台》的节目,里面提到过一种乐器叫“特雷门琴”,其实我觉得这个板最好玩也是最厉害的地方在于他竟然可以做“特雷门琴”(例程里的MIDI_Theremin)
科普一下”特雷门琴“是世界上唯一一种不需要身体接触的电子乐器。原理是利用两个感应人体与大地的分布电容的LC 振荡器工作单元分别产生震荡的频率与大小变化而工作。圆形天线是用来调节音量的,手越靠近,声音越小。垂直的天线用来调节频率,手越靠近,音调越高。演奏的关键是了解双手的位置与所发出的音符之间的关系。
想想就很难,以至于全世界一共有20位特雷门琴演奏家。想走向世界的话可以先做一个练练。

明天出个视频
回复

使用道具 举报

Forgotten  版主

发表于 2017-9-5 09:04:08

前排膜拜 玩艺术的就四不一样
回复

使用道具 举报

安卓机器人  中级技神

发表于 2017-9-5 11:13:52

一列超声或红外作音乐键盘
回复

使用道具 举报

gray6666  初级技神

发表于 2017-9-5 14:05:33

好创意,赞一个
回复

使用道具 举报

luna  初级技神

发表于 2017-9-15 13:57:59

玩得好6!!第二个架子鼓一度以为是口技,特别有趣
回复

使用道具 举报

好奇吖斌  高级技师

发表于 2017-9-15 18:22:09

我喜欢这个东西,MakeyMakey也可以实现这样的功能吗?
回复

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-9-16 09:59:35

luna 发表于 2017-9-15 13:57
玩得好6!!第二个架子鼓一度以为是口技,特别有趣

是口技是口技,我跟洛桑学过艺。:lol
回复

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-9-16 10:04:55

好奇吖斌 发表于 2017-9-15 18:22
我喜欢这个东西,MakeyMakey也可以实现这样的功能吗?

makey的话至少还得加上一个VS1053,但是这个体积就大了,不太方便。
回复

使用道具 举报

fuyaowen  学徒

发表于 2017-10-8 13:54:28

LZ费劲心思,排除万难,冒着进医院的生命危险,神农尝百草的精神为我们留下的那个导电漆,能不能与世人分享一下啊
回复

使用道具 举报

胡秩通  高级技师

发表于 2017-11-16 21:22:50

厉害了!!!
回复

使用道具 举报

zttcg  学徒

发表于 2018-3-28 10:45:44

这个好有趣
回复

使用道具 举报

myrazhang  见习技师

发表于 2018-3-29 17:54:45

interesting!
回复

使用道具 举报

 初级技匠

发表于 2022-5-20 09:01:19

架子鼓那个视频有点儿废脚啊…………
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail