查看: 7920|回复: 22

如果我是DJ,你有Freestyle吗?-----自制MIDI鼓机

[复制链接]
2017-08-22 155426.jpg

十年前我们还在说:“嘻哈在中国就赚不到钱,就像咸菜里面看不到盐。”十年后的这个夏天什么节目最火?
当然是《中国有嘻哈》,个人觉得艾福杰尼,GAI爷,PGone到底谁能拿冠军其实不重要。重要是让我们看到了中国rapper们真的比我学生时期的那一代人的厉害很多。
自从上次做了一个"LaunchBox"后,我就在节目里看到了这货,
捕获.JPG
就是一般中场会有一名Raper和一个女DJ演绎的一段当期节目的概括。我觉得是时候要做一个稍微“有样”点的MiDIiController了。
可是。。。。这该如何下手啊,翻山越岭翻资料,才懂了一个大概,了解了那些旋钮就是电位器,推子就是滑动电阻器,按键和灯是分开占用针脚的,那个搓盘,呵呵,原来是编码器做的。接下来我会就这几个步骤来分享一下我制作的过程,包括按键电位器等的接法会有。到加工外形时的小技巧也会有。我尽量入门的方式去写,希望更多的朋友看完后也可以尝试自己做一个出来。
选型
花了两个月时间,做过很多外观上的尝试,买了不少按键,电位器,推子往往都是买回来才发现不好用,大部分时间都是在等快递。所想给那些同样想做的朋友们一种我认为不错组合。
控制器:首先,要支持USBMiDi协议。我最开始考虑用Arduino Leonardo,后来发现Teensy是做MiDi更好的选择。这里放出来对比的一张图:
未命名_副本.jpg
我在这个项目上选择Teensy的原因很简单,引脚比较多。
按键:这两个月我试过很多种型号的按钮,但是大多数都是不满意的,要满足按下力度轻,机械手感,抖动小,这几个要求的还是得向大家推荐日本sanwa街机按键,虽然有点小贵,但是按下的感觉可以用“干脆,爽快”来形容。 timg (2).jpg
电位器:电位器名称一般包含“字母”+“最大阻值”的组合,前面的字母代表这个电阻器在调整时,阻值是均匀改变的还是曲线式改变的(比如开始扭改变很小,后面扭一点改变就很大)B10K,A50K,可以根据不同的用途来选择合适的种类,B开头比较常见,也就是均匀分布的,阻值大小的话, 常见的B10K,B50K试过都可以,后面也可以在代码和MIDI软件中进行调试。电位器选择上面有螺纹送固定螺丝垫片的,考虑手感的话ALPS是不二的选择。

===============================

滑变电阻:推子的话和上面电位器类似,还是手感问题,力度要越轻越好,0阻力是追求,当然这是不可能的。忘记了还有长度的选择,要根据自己外壳的尺寸和布局来。
2017-08-22 144354_副本.jpg
外壳材料:木盒,亚克力板,3D打印,电木板等等看自己爱好了。


制作过程
实验过程:省略
布局:有了上面的选型指南,和实验,我想大概也就可以开始布局了。
参考一些国外Controller外观,结合Teensy++2.0的针脚数
wiring_pinout2_副本.png 123.jpg


安排了4X4的按键矩阵+4个Banks选择按钮,4个旋钮,3个推子,算一算16按键+16灯+4Banks +4旋钮+3推子=43个引脚。刚好Teensy++2.0有45个。


==========================


TEENSY的使用方面可以点这里。概括的说就是下一个1.06ArduinoIDE和一个teensy的补丁+teensyloader,补丁复制粘贴进IDE的文件夹替换掉原来的文件,然后在上传程序时选择相应的板子,当你点上传时,自动会启动loader并运行。其他都一样


外壳加工:如果你会CAD,那么直接要一些板材厂家加工好发给你是最好的。自己加工的话有时候难避免一切偏差和划伤板面的事情发生。如果你和我一样想自己用电钻什么的自己开孔,在量好所有元器件的尺寸后就开始作图了,作图时一定要选择一张薄一点的纸,可以在电脑上画图然后把薄纸放在屏幕上画孔位,然后把纸裁到板面一样大,贴在上面在进行开孔等操作。街机按钮一般分30MM和24MM的直径,开孔器选比这个尺寸多1-2MM是比较合适的,到时候比较好安装按键。 别忘了四个角也要预留孔位,到时候安装铜柱。
2017-08-09 184130.jpg 2017-08-09 234006.jpg


组装与接线
安装街机按钮一般有两个引脚,带单色灯的话多两个,最下面两个大的是开关脚,一个公共端GND,另一个接到teensy上的任意脚
灯的话和按键一样,一个GND一个接到其他的引脚上。
电位器一般是三个脚,中间脚是接模拟口的(38-45号引脚)两边的脚分配给GND和5V,左右都可以。一般左边那只接GND
推子一般有单联和双联,单联推子,三个脚2+1的结构,单独脚的一边接GND,它的正对面接5V旁边接在TEENSY模拟端口。双联推子2+4的结构。2个的那边属于GND,这两支GND引脚选择最靠边的一支,正对面和正对面的旁边接法和上面一样,另外三支可以不用折起来。

电位器和推子在焊接导线时注意最好时外面先套一小截热缩管,避免引脚暴露在外而导致的一些读数不稳的问题。
所有GND,5V,端口可以分别用一根线串。为了相对整洁而且这么做可以大大节省成本与空间。
需要5V稳压供电。
总结一下所需物品清单:
Teensy++2.0;
街机按钮x16;
按钮灯的接口配套端子线1.25间距x16;
(12x12的四脚按键+按键帽)x4;
(电位器+旋钮帽)x4;
(滑变电阻+推子帽)x3;
5V稳压模块。
18650锂电池x1;

自锁开关x1;
面包板x1;
导线若干;
3mm铜柱x4;
3MM公螺x4母,螺X4
垫片若干;
miniusb接口数据线x1.


=============

连线图(画了一下图,线太多导致自己都看不懂了。所以干脆发了一个简化的图,也应该体现出来了:黑色是16个按键的对应接口。
红色是LED的16个接口,
黄色代表四个旋钮,三个推子
蓝色代表四个BANKs也就是摇杆的四个接口。
teensy++2.0_副本.png

2017-08-20 205032.jpg

上漆的过程省略,完成图:
2017-08-15 235835.jpg
代码
代码部分是参照Arduino,Teensy官网的usbmidi说明以及国外玩家的的代码后进行的一些改动,如果你和我一样都是使用的teensy++2.0,且懒得看,直接复制上传就可以。在灯光的控制上可以有很多方法,复用器扩充引脚我还不会。所以你要问我Leonardo怎么做我只能说声抱歉了,MEGA引脚虽够但是好像芯片不支持。另外我还有一套混音器的代码,下个作品吧。。。
[C#] 纯文本查看 复制代码
//teensy++ code for arcade warrior[/i]
[i]//[/i]tomash ghz
[i]//www.tomashg.com[/i]
 
[i]#include <Bounce.h>[/i]
 
[i]//debugging will print out in serial instead of midi[/i]
[i]boolean debugging=false;[/i]
[i]boolean traktorrr=false;[/i]
 
[i]//channel number for midi messages[/i]
[i]int midiChannel=3;[/i]
 
[i]//pin numbers for elements[/i]
 
[i]int leds[16] = {[/i]
 
[i]16,17,18,19,[/i]
[i]20,21,22,27,[/i]
[i]28,29,30,31,[/i]
[i]32,33,38,35[/i]
 
 
[i]};[/i]
 
[i]int buttons[16]= {[/i]
[i]0,1,2,3,[/i]
[i]4,5,6,7,[/i]
[i]8,9,10,11,[/i]
[i]12,13,14,15[/i]
[i]};[/i]
 
[i]int knobs[4]= {[/i]
[i]  41, 42, 39, 40[/i]
[i]};[/i]
 
[i]int faders[3]= {[/i]
[i]  45, 44, 43[/i]
[i]};[/i]
 
[i]//bank[/i]
[i]int bank=0;[/i]
 
[i]// pins for joystick buttons[/i]
[i]int joystic[4]= {[/i]
[i]  23,24,25,26[/i]
[i]};[/i]
 
[i]// variables to store values[/i]
[i]Bounce *buttonState[16];[/i]
[i]int knobVal[4];[/i]
[i]int faderVal[3];[/i]
[i]boolean joysticState[4];[/i]
[i]int joysticVal[4]; // save the joystic cc values[/i]
[i]boolean ledState [ 16 ];[/i]
 
[i]Bounce jUp = Bounce( joystic[0], 10 );[/i]
[i]Bounce jDown = Bounce( joystic[1], 10 );[/i]
[i]Bounce jLeft = Bounce( joystic[2], 10 );[/i]
[i]Bounce jRight = Bounce( joystic[3], 10 );[/i]
 
[i]int comboState=0; //state of the current combo[/i]
[i]int temp;[/i]
 
[i]//initialize values and set modes[/i]
[i]void setup() {[/i]
 
[i]  //DEBUG[/i]
 
 
[i]  //arcade buttons[/i]
[i]  for (int i=0;i<16;i++) {[/i]
[i]    pinMode(buttons, INPUT_PULLUP);[/i]
[i]    buttonState= new Bounce(buttons, 5);[/i]
[i]  }[/i]
 
[i]  pinMode(6, OUTPUT); //hope this doesnt fry the led [/i]
 
[i]  //joystick buttons[/i]
[i]  for (int i=0;i<4;i++) {[/i]
[i]    pinMode(joystic, INPUT_PULLUP);[/i]
[i]    joysticVal=0;[/i]
[i]  }[/i]
 
[i]  // LEDS[/i]
[i]  for (int i=0;i<16;i++) {[/i]
[i]    pinMode(leds, OUTPUT);[/i]
[i]    digitalWrite(leds, HIGH);[/i]
[i]    delay(50);[/i]
[i]    digitalWrite(leds, LOW);[/i]
[i]  }[/i]
 
[i]  //switch to traktor mode[/i]
[i]  // to switch hold the lower left and right buttons while the device is booting[/i]
[i]  for (int i=0;i<10;i++) {[/i]
[i]    digitalWrite(leds[0], HIGH);[/i]
[i]    delay(100);[/i]
[i]    digitalWrite(leds[0], LOW);[/i]
[i]    delay(100);[/i]
 

 

[i]    }[/i]
[i]  }[/i]
 
 
[i]void loop() {[/i]
[i]  //read buttons[/i]
[i]for (int i=0;i<16;i++) {[/i]
 
[i]    if (buttonState->update()) {//state changed[/i]
 
[i]      if (buttonState->read()==LOW) {//is pressed[/i]
[i]        midiNoteOnOff(true, i+36+bank*16);[/i]
[i]      }[/i]
[i]      else {[/i]
[i]        midiNoteOnOff(false, i+36+bank*16);[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }//end loop[/i]
 
[i]  //read knobs and faders[/i]
[i]  for (int i=0;i<4;i++) {[/i]
[i]    temp=map(analogRead(knobs), 0, 1023, 0, 127);[/i]
 
[i]    if (temp!=knobVal) { //value changed[/i]
[i]      midiCC(temp, knobVal, i*2+16+bank*17);[/i]
[i]    }[/i]
[i]    knobVal=temp;[/i]
[i]  }// end loop[/i]
 
[i]    for (int i=0;i<3;i++) {[/i]
[i]    temp=map(analogRead(faders), 0, 1023, 0, 127);[/i]
 
[i]    if (temp!=faderVal) { //value changed[/i]
[i]      midiCC(temp, faderVal, i*2+24+bank*17);[/i]
[i]    }[/i]
[i]    faderVal=temp;[/i]
[i]  }// end loop[/i]
[i]for (int i=0;i<16;i++) {[/i]
[i]    if (buttonState->read()==LOW)[/i]
[i]   { digitalWrite(leds,HIGH);[/i]
[i]    digitalWrite(leds+1, HIGH);[/i]
[i]    digitalWrite(leds-1, HIGH);[/i]

[i]    digitalWrite(leds+2, HIGH);[/i]
[i]    digitalWrite(leds-2, HIGH);[/i]

[i]}[/i]
[i]else  {[/i]
[i]        digitalWrite(leds, LOW);[/i]



 
[i]      }[/i]
[i]}[/i]
[i]    // read joystic guestures[/i]
[i]  readJoystic();[/i]
 
[i]  // update [/i]leds[i] depending on [/i]bank

 
[i]  // update leds[/i]
 
 
[i]  //recieve MIDI messages[/i]
[i]  if (!debugging) {[/i]
[i]    usbMIDI.read();[/i]
[i]  }[/i]
[i]}[/i]
 
[i]// function to handle noteon outgoing messages[/i]
[i]void midiNoteOnOff(boolean s, int n) {[/i]
 
[i]  //check if the key pressed is part of any secret combo[/i]
[i]  if ([/i]traktorrr[i]) {[/i]
[i]    checkCombo(s);[/i]
[i]  }[/i]
 
[i]  if (s) {[/i]
[i]    if (debugging) {//debbuging enabled[/i]
[i]      Serial.print("Button ");[/i]
[i]      Serial.print(n);[/i]
[i]      Serial.println(" pressed.");[/i]
[i]    }[/i]
[i]    else {[/i]
[i]      usbMIDI.sendNoteOn(n, 127, midiChannel);[/i]
[i]    }[/i]
[i]  }[/i]
[i]  else {[/i]
[i]    if (debugging) {//debbuging enabled[/i]
[i]      Serial.print("Button ");[/i]
[i]      Serial.print(n);[/i]
[i]      Serial.println(" released.");[/i]
[i]    }[/i]
[i]    else {[/i]
[i]      usbMIDI.sendNoteOff(n, 0, midiChannel);[/i]
[i]    }[/i]
[i]  }[/i]
[i]}[/i]
 
[i]//function to check for secret combos[/i]
[i]void checkCombo(boolean s) {[/i]
 
[i]  // from MIDI Fighter Pro documentation:[/i]
 
[i]  // COMBOS[/i]
[i]  //[/i]
[i]  //   A          B           C           D           E[/i]
[i]  // +--------+ +--------+  +--------+  +--------+  +--------+[/i]
[i]  // |        | |        |  |        |  |        |  |        |[/i]
[i]  // |        | |        |  |  3 4   |  |        |  |u       |[/i]
[i]  // |        | |n n n n |  |  1 2   |  |a b c d |  |l r A B |[/i]
[i]  // |1 2 3 4 | |        |  |        |  |        |  |d       |[/i]
[i]  // +--------+ +--------+  +--------+  +--------+  +--------+[/i]
[i]  //                                     a-b-c-c-d   uuddlrlrBA[/i]
[i]  //[/i]
[i]  // Combos retain a NoteOn while the final key is depressed and emit a NoteUp[/i]
[i]  // when it is released.[/i]
[i]  // Combo A               G#-2[/i]
[i]  // Combo B               A-2[/i]
[i]  // Combo C               A#-2[/i]
[i]  // Combo D               B-2[/i]
[i]  // Combo E        C-1[/i]
 
 
[i]  // lets simplify things a bit :)[/i]
[i]  //   A          B           C           D           E[/i]
[i]  // +--------+ +--------+  +--------+  +--------+  +--------+[/i]
[i]  // |        | |        |  |        |  |        |  |        |[/i]
[i]  // |        | |        |  |  x x   |  |        |  |x       |[/i]
[i]  // |        | |x x x x |  |  x x   |  |  x x x |  |    x x |[/i]
[i]  // |x x x x | |        |  |        |  |        |  |x       |[/i]
[i]  // +--------+ +--------+  +--------+  +--------+  +--------+[/i]
 
 
[i]  //no combo active and a button is pressed[/i]
[i]  if ((comboState==0)&&(s)) {[/i]
[i]    // combo A[/i]
[i]    if ((buttonState[0]->read()==LOW)[/i]
[i]      &&(buttonState[1]->read()==LOW)[/i]
[i]      &&(buttonState[2]->read()==LOW)[/i]
[i]      &&(buttonState[3]->read()==LOW)) {[/i]
[i]      comboState=1;[/i]
[i]      usbMIDI.sendNoteOn(8, 127, midiChannel);[/i]
[i]    }[/i]
[i]    else[/i]
[i]      //combo B[/i]
[i]      if ((buttonState[4]->read()==LOW)[/i]
[i]        &&(buttonState[5]->read()==LOW)[/i]
[i]        &&(buttonState[6]->read()==LOW)[/i]
[i]        &&(buttonState[7]->read()==LOW)) {[/i]
[i]        comboState=2;[/i]
[i]        usbMIDI.sendNoteOn(9, 127, midiChannel);[/i]
[i]      }[/i]
[i]      else[/i]
[i]        //combo C[/i]
[i]        if ((buttonState[5]->read()==LOW)[/i]
[i]          &&(buttonState[6]->read()==LOW)[/i]
[i]          &&(buttonState[9]->read()==LOW)[/i]
[i]          &&(buttonState[10]->read()==LOW)) {[/i]
[i]          comboState=3;[/i]
[i]          usbMIDI.sendNoteOn(10, 127, midiChannel);[/i]
[i]        }[/i]
[i]        else[/i]
[i]          //combo D[/i]
[i]          if ((buttonState[5]->read()==LOW)[/i]
[i]            &&(buttonState[6]->read()==LOW)[/i]
[i]            &&(buttonState[7]->read()==LOW)) {[/i]
[i]            comboState=4;[/i]
[i]            usbMIDI.sendNoteOn(11, 127, midiChannel);[/i]
[i]          }[/i]
[i]          else[/i]
[i]            //combo E[/i]
[i]            if ((buttonState[0]->read()==LOW)[/i]
[i]              &&(buttonState[8]->read()==LOW)[/i]
[i]              &&(buttonState[6]->read()==LOW)[/i]
[i]              &&(buttonState[7]->read()==LOW)) {[/i]
[i]              comboState=5;[/i]
[i]              usbMIDI.sendNoteOn(12, 127, midiChannel);[/i]
[i]            }[/i]
[i]  }[/i]
[i]  else if ((comboState!=0)&&(!s)) {//combo was active and released[/i]
[i]    switch(comboState) {[/i]
[i]    case 1:[/i]
[i]      usbMIDI.sendNoteOff(8, 0, midiChannel);[/i]
[i]      break;[/i]
[i]    case 2:[/i]
[i]      usbMIDI.sendNoteOff(9, 0, midiChannel);[/i]
[i]      break;  [/i]
[i]    case 3:[/i]
[i]      usbMIDI.sendNoteOff(10, 0, midiChannel);[/i]
[i]      break;[/i]
[i]    case 4:[/i]
[i]      usbMIDI.sendNoteOff(11, 0, midiChannel);[/i]
[i]      break;  [/i]
[i]    case 5:[/i]
[i]      usbMIDI.sendNoteOff(12, 0, midiChannel);[/i]
[i]      break;[/i]
[i]    }[/i]
[i]    comboState=0;[/i]
[i]  }[/i]
[i]}[/i]
 
[i]// function to handle cc outgoing messages[/i]
[i]void midiCC(int v, int [/i]oldv[i], int n) {[/i]
[i]  if (debugging) {//debbuging enabled[/i]
[i]    Serial.print("Potentiometer ");[/i]
[i]    Serial.print(n);[/i]
[i]    Serial.print(" changed value to ");[/i]
[i]    Serial.println(v);[/i]
[i]  }[/i]
[i]  else {[/i]
[i]    usbMIDI.sendControlChange(n, v, midiChannel);[/i]
 
[i]    //send the advanced [/i]traktor[i] midi messages[/i]
 
[i]    // 0  3            64           124 127[/i]
[i]    // |--|-------------|-------------|--| - full range[/i]
[i]    //[/i]
[i]    // |0=======================127| - CC A[/i]
[i]    // |0=========105| - CC B[/i]
[i]    //[/i]
[i]    // |__|on____________________________| - note A[/i]
[i]    // |off___________________________|on| - note B[/i]
[i]    //    3                          124[/i]
 
[i]    if (traktorrr) {[/i]
 
[i]      if ((v>3)&&(oldv<=3)) { // send the 0 value note on[/i]
[i]        usbMIDI.sendNoteOn(n+84, 127, midiChannel);[/i]
[i]      }[/i]
[i]      else if ((v<=3)&&(oldv>3)) {[/i]
[i]        usbMIDI.sendNoteOff(n+84, 127, midiChannel);[/i]
[i]      }[/i]
[i]      if ((v>124)&&(oldv<=124)) { // send the 127 value note on[/i]
[i]        usbMIDI.sendNoteOn(n+85, 127, midiChannel);[/i]
[i]      }[/i]
[i]      else if ((v<=124)&&(oldv>124)) {[/i]
[i]        usbMIDI.sendNoteOff(n+85, 127, midiChannel);[/i]
[i]      }[/i]
 
[i]      if (v<=64) //send secondary cc[/i]
[i]        usbMIDI.sendControlChange(n+1, map(v, 0, 64, 0, 105), midiChannel);[/i]
[i]    }[/i]
[i]  }[/i]
[i]}[/i]
 
[i]void readJoystic() {[/i]
[i]  //up joystick[/i]
[i]  if ( jUp.update() ) {//state changed[/i]
[i]    if ( jUp.read() != HIGH) {// it is pressed[/i]
 
[i]      if ( joysticState[0] == LOW ) {//last state was low[/i]
[i]        joysticState[0] = HIGH;[/i]
[i]        midiNoteOnOff(true, 4);[/i]
[i]      }[/i]
[i]    }[/i]
[i]    else {// it was released[/i]
[i]      if ( joysticState[0] == HIGH ) {//last state was low[/i]
[i]        joysticState[0] = LOW;[/i]
[i]        joysticVal[0]=0;[/i]
 
[i]        if (debugging) {[/i]
[i]          Serial.println(joysticVal[0]);[/i]
[i]        }[/i]
[i]        else {[/i]
[i]          usbMIDI.sendControlChange(30, joysticVal[0], midiChannel);[/i]
[i]        }[/i]
[i]        //midiNoteOnOff(true,4);[/i]
[i]        midiNoteOnOff(false, 4);[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }[/i]
[i]  else {//state didnot change[/i]
[i]    if ( jUp.read() != HIGH) {//is held on[/i]
[i]      if (jUp.duration()>500) {// was held longer than half sec[/i]
[i]        if (jUp.duration()%100>90) {//increment the value[/i]
[i]          joysticVal[0]++;[/i]
[i]          joysticVal[0]=constrain(joysticVal[0], 0, 127);[/i]
[i]          if (debugging) {[/i]
[i]            Serial.println(joysticVal[0]);[/i]
[i]          }[/i]
[i]          else {[/i]
[i]            usbMIDI.sendControlChange(30, joysticVal[0], midiChannel);[/i]
[i]          }[/i]
[i]        }[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }[/i]
 
[i]  //down joystick[/i]
[i]  if ( jDown.update() ) {//state changed[/i]
[i]    if ( jDown.read() != HIGH) {// it is pressed[/i]
 
[i]      if ( joysticState[1] == LOW ) {//last state was low[/i]
[i]        joysticState[1] = HIGH;[/i]
[i]        midiNoteOnOff(true, 5);[/i]
[i]      }[/i]
[i]    }[/i]
[i]    else {// it was released[/i]
[i]      if ( joysticState[1] == HIGH ) {//last state was low[/i]
[i]        joysticState[1] = LOW;[/i]
[i]        joysticVal[1]=0;[/i]
 
[i]        if (debugging) {[/i]
[i]          Serial.println(joysticVal[1]);[/i]
[i]        }[/i]
[i]        else {[/i]
[i]          usbMIDI.sendControlChange(31, joysticVal[1], midiChannel);[/i]
[i]        }[/i]
[i]        //midiNoteOnOff(true,5);[/i]
[i]        midiNoteOnOff(false, 5);[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }[/i]
[i]  else {//state didnot change[/i]
[i]    if ( jDown.read() != HIGH) {//is held on[/i]
[i]      if (jDown.duration()>500) {// was held longer than half sec[/i]
[i]        if (jDown.duration()%100>95) {//increment the value[/i]
[i]          joysticVal[1]++;[/i]
[i]          joysticVal[1]=constrain(joysticVal[1], 0, 127);[/i]
[i]          if (debugging) {[/i]
[i]            Serial.println(joysticVal[1]);[/i]
[i]          }[/i]
[i]          else {[/i]
[i]            usbMIDI.sendControlChange(31, joysticVal[1], midiChannel);[/i]
[i]          }[/i]
[i]        }[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }[/i]
 
[i]  //left joystick[/i]
[i]  if ( !jLeft.update() ) {//state didnot change[/i]
[i]    if ( jLeft.read() != HIGH) {//is held on[/i]
[i]      if (traktorrr) {[/i]
[i]        if (jLeft.duration()%100>85)//increment the value[/i]
[i]          usbMIDI.sendControlChange(32, 63, midiChannel); //act as rotary encoder[/i]
[i]      }[/i]
[i]      if ( joysticState[2] == LOW ) {//last state was low[/i]
[i]        joysticState[2] = HIGH;[/i]
 
[i]        if (!traktorrr) { // decrease the bank number[/i]
[i]          if (bank==0)[/i]
[i]            bank=3;[/i]
[i]          else[/i]
[i]            bank=bank-1;[/i]
[i]        }[/i]
[i]        else[/i]
[i]          usbMIDI.sendNoteOn(0, 127, midiChannel);[/i]
[i]      }[/i]
[i]    }[/i]
[i]    else {// it was released[/i]
[i]      if ( joysticState[2] == HIGH ) {//last state was low[/i]
[i]        joysticState[2] = LOW;[/i]
[i]        usbMIDI.sendNoteOff(0, 127, midiChannel);[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }[/i]
 
[i]  //right joystick[/i]
[i]  if ( !jRight.update() ) {//state didnot change[/i]
[i]    if ( jRight.read() != HIGH) {//is held on[/i]
[i]      if (traktorrr) {[/i]
[i]        if (jRight.duration()%100>85)//increment the value[/i]
[i]          usbMIDI.sendControlChange(32, 65, midiChannel); //act as rotary encoder[/i]
[i]      }[/i]
 
[i]      if ( joysticState[3] == LOW ) {//last state was low[/i]
[i]        joysticState[3] = HIGH;[/i]
 
[i]        if (!traktorrr) // increase the bank number[/i]
[i]            bank=(bank+1)%4;[/i]
[i]        else[/i]
[i]          usbMIDI.sendNoteOn(0, 127, midiChannel);[/i]
[i]      }[/i]
[i]    }[/i]
[i]    else {// it was released[/i]
[i]      if ( joysticState[3] == HIGH ) {//last state was low[/i]
[i]        joysticState[3] = LOW;[/i]
[i]        usbMIDI.sendNoteOff(0, 127, midiChannel);[/i]
[i]      }[/i]
[i]    }[/i]
[i]  }[/i]
[i]}[/i]
 
[i]//event handlers for recieved note ons



原本的代码来自这里,这里需要说明的是在BANKS选择的时候,他是用的一个摇杆,我是觉得在这个上面装个摇杆怪怪的。用了四个按键代替,另外我们可以看到作者设计了Combo(我理解为组合按键触发事件)我认为这太棒了,所以就保留了这部分,至于到底怎么搓出来。。。慢慢研究吧。好了,代码上传后如果不出什么问题。就应该可以玩耍了。等等,声音来自哪里?好,接下来进入最后一部分,如何去玩耍?

MiDi音源
之前做的"LaunchBox"是模拟传输键盘的键值到PC上面的软件再去映射到声音文件发出。但是MIDI就不一样了,它向电脑或者音源上发送的是CC协议,CC控制协议就是Continuous Controller,直译过来是连续控制器。在MIDI里面,CC是一种规格为128种不同信息、可用于不同通道的一种MIDI信息,很多CC值是已经默认分配了功能,例如7号CC值为音量,10号CC值为声像等等,也有很多CC是没有被分配功能,在控制器上就可以调用这些CC值了,专业性的我就不太懂了,找到一张图分享给大家:
2642-160G21KU3Q9.jpg
代码中有一段usbMIDI.sendNoteOn(n, 127, midiChannel); 其中 n代表音符,127代表按下的力度,midichannel代表通道,这就说明可以互不影响的同时按下很多键并同时识别并播放出相应通道和力度的音符对应的你设置的歌曲片段。这就要比模拟键盘的方式传输的内容更丰富,精准。 如果感兴趣的话可以搜搜相关的内容看看。
    大概了解了MiDi协议后,就开始找编辑软件,因为是标准的MIDI协议通信,所以理论上Ableton Live,CuBase,Traktor,水果等等都可以用,反正都没接触过,都要学习,Live是在找资料过程中出现的频率最多的,就它了。

ab.JPG

幸运的是国内有专门的网站(http://www.abletive.com/)去学习这款软件.

软件下载,
http://www.abletive.com/sharing/software-plugins/ableton-live-9-update(链接已失效)
教程视频,
https://www.bilibili.com/video/av1427160/?from=search&seid=3027609029783603053
如果你做出来了,并且迫不及待的想体验一把,那软件安装好后下载我留下的工程文件运行即可。好了,下面到了献丑时间:


补充:如果拿到户外玩,没电脑,IPAD或苹果手机也可以识别,前提是要买一条lightning的线
u=880608109,3635720403&amp;fm=26&amp;gp=0.jpg

买之前要注意的IOS的版本,10.2 ,10.3得版本得买不同的线 买之前问清楚卖家,像GarageBand,SampleTank都支持外接midi设备, 我那个安卓手机坏了,但我想用OTG线连上应该也没问题。=========

后记:实话说,做它出来不是很顺利,中途经历过很多次失败想放弃的,但第二天还是依旧找资料找原因。我只是把较为顺利的过程记录下来与朋友们分享,方便大家,少走弯路。但这不是最后的作品,我以后有时间还会对它进行升级的。好了,就介绍到这里,如果你有兴趣也做一个,欢迎跟帖贴出你的作品,我不是一个音乐专业的人,如果有错误也感谢您纠正我的一些错误。

附工程和按键映射的设置
工程包大家可以下载我留下的,包括两个一个是我玩的<<idon'tmeanto>>还有一个是稍微复杂的疯狂的扎克。可以切换不同的BANK。工程放到我的文档或者桌面都可以
映射文件直接解压到
C:\ProgramData\Ableton\Live 9 Suite\Resources\MIDI Remote Scripts文件夹内
然后进Live的options---preferences----linkmidi那一栏照着我设置就可以了
213.JPG
也可以在DJTT中下载到更多的工程以及映射。
我大部分时间都花在了这个网站包括街机按钮的选择,还有TomasG的博客。

捕获.JPG


工程分卷 1.rar

18 MB, 下载次数: 68, 下载积分: 创造力 -1

工程分卷 2.rar

11.3 MB, 下载次数: 86, 下载积分: 创造力 -1

映射.rar

25.58 KB, 下载次数: 12, 下载积分: 创造力 -1

hnyzcj  超级版主

发表于 2017-8-22 20:03:50

点评

大神带我飞哇  发表于 2017-8-23 15:37
回复 支持 反对

使用道具 举报

heinau  高级技匠

发表于 2017-8-23 11:02:08

效果好赞啊!完成品简直看不出来是手工做出来的呢
楼主演奏的也很不错,很喜欢那清脆的按键的节奏感
回复 支持 反对

使用道具 举报

zbl  管理员

发表于 2017-8-23 11:18:07

超赞!!!

那句“就像咸菜里面看不到盐”印象深刻,
回复 支持 反对

使用道具 举报

hnyzcj  超级版主

发表于 2017-8-23 17:41:24

zbl 发表于 2017-8-23 11:18
超赞!!!

那句“就像咸菜里面看不到盐”印象深刻,

后半句呢,吃起来如何
回复 支持 反对

使用道具 举报

Forgotten  版主

发表于 2017-8-23 22:07:25

帅气,膜拜楼主
回复 支持 反对

使用道具 举报

miaoichi  见习技师

发表于 2017-8-29 10:07:45

厉害了 顶一个
回复 支持 反对

使用道具 举报

阿斗  高级技师

发表于 2017-8-30 08:51:43

先蹦起来再说
回复 支持 反对

使用道具 举报

gray6666  高级技匠

发表于 2017-9-5 10:28:36

效果好赞啊,厉害了我的哥。。。。。。。。。。。
回复 支持 反对

使用道具 举报

刺头一哥  见习技师

发表于 2017-9-7 14:05:00


到处都能看到你
回复 支持 反对

使用道具 举报

刺头一哥  见习技师

发表于 2017-9-7 14:08:38


到处都能看到你
回复 支持 反对

使用道具 举报

hnyzcj  超级版主

发表于 2017-9-8 06:25:22


到处看到你
回复 支持 反对

使用道具 举报

安卓机器人  初级技神 来自手机

发表于 2017-9-9 08:08:24

创客教育STEAM~A
回复 支持 反对

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-9-9 15:59:24


三弟好~
回复 支持 反对

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-9-9 16:02:56


大哥好~
回复 支持 反对

使用道具 举报

hnyzcj  超级版主

发表于 2017-9-9 19:14:38


哈哈,你都开始搞排名了
回复 支持 反对

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-9-9 23:10:56

hnyzcj 发表于 2017-9-9 19:14
哈哈,你都开始搞排名了

不是排名,不是排名,想打个招呼,思前想后,还是这样称呼较好啊哈哈哈
回复 支持 反对

使用道具 举报

hnyzcj  超级版主

发表于 2017-9-10 06:02:46

robo027 发表于 2017-9-9 23:10
不是排名,不是排名,想打个招呼,思前想后,还是这样称呼较好啊哈哈哈 ...

知道知道,哈哈哈,以后大家多交流。
回复 支持 反对

使用道具 举报

长沙小黑  初级技师

发表于 2017-11-1 12:13:22

我编译的时候这里出线了故障?是怎么回事类?  digitalWrite(leds, LOW);
expected primary-expression before '/' token
回复 支持 反对

使用道具 举报

robo027  初级技匠
 楼主|

发表于 2017-11-10 10:25:26

长沙小黑 发表于 2017-11-1 12:13
我编译的时候这里出线了故障?是怎么回事类?  digitalWrite(leds, LOW);
expected primary-expression bef ...

我也不知道出了什么问题,我改正过来了 ,你可以选择从新复制或去掉那一大串只保留一个
回复 支持 反对

使用道具 举报

Nolovenodie丶  学徒

发表于 2018-7-17 03:10:51

赞!!!
回复 支持 反对

使用道具 举报

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

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
wifi气象站

硬件清单

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

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

mail