iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 15
0

不囉唆,先來 demo。

0. 今日工事

  • 打磨、拋光、接電線
  • Interactivity
  • 旋鈕 の connect

https://ithelp.ithome.com.tw/upload/images/20180103/201078289V3EDgPNQ8.jpg

1. 打磨、拋光、接電線

一系列的奮戰與血光當中,戰鼓已經響起,沈睡的力量都已經被召喚出了峽谷。合成器的旋鈕打磨拋光,內部的聲音元件也大致就定位,接下來就是把旋鈕的電線給接上,開始全身震動模式啦!

這篇主要分成兩個部分

  1. 將旋鈕的 data 送進 vsynth—3002 的核心部分
  2. 決定要將哪些數字 mapping 到什麼聲音的參數上面。

2. Interactivity

source code

React

使用React當作 framework,我所有的旋鈕都是以 React Component 的架構來製作。我整個合成器的面板都放在Block這個 React Component 當中。

// block.js
class Block extends Component {

  render() {
    const n = this.number;
    const { on, position, data } = this.state;
    return (
      <div className={styles.container}>
        <div className={styles.table}>
          {data.map((row, r) => (
            <div key={uuid4()} className={`${styles.row}`}>
              {row.map((d, c) =>
                <Knob
                  key={uuid4()}
                  r={r}
                  c={c}
                  onEnter={this.setPosition}
                  onMouseDown={this.handleMouseDown}
                  onWheel={this.handleWheel}
                  value={d}
                  active={r === position.r && c === position.c}
                />
              )}
            </div>
          ))}
        </div>
      </div>
    );
  }
}

而在Block裡面,每個旋鈕都是叫做Knob的 Component。這樣的版型因為整個都是方形的像是 grid 一樣的東西,我最後決定要用flexbox去切割版型。

https://ithelp.ithome.com.tw/upload/images/20180103/20107828s46S9lOLi9.png

/* block.module.scss */
.table {
  width: 100%;
  height: 100%;

  display: flex;
  flex-flow: column;
  justify-content: space-around;
}

.row {
  height: 100vh;

  display: flex;
  flex-flow: row;
  justify-content: space-around;
}

用 react 實作的時候,習慣盡量把底層的 component(KnobButton)寫成 pure function,所有的 state 都只放在Block裡面。像是所有的旋鈕的數字都是存在Blockstate當中

wheel && mouse drag

旋鈕最滑順的互動應該就是用 wheel 的方式了,不用點擊就可以直接調變參數。但是有時候onMouseEnter等的 callback 不太穩定。所以也加入 Mouse Drag 的方式,讓使用者可以點擊後拖曳去改變旋鈕的參數。

請試玩旋鈕

3. 旋鈕 の connect

我將整組鼓組打包在一個叫做Vsynth的 class 裡面,並制定一個 update 參數的 API:

class Vsynth {
    constuctor() {
        // 設定所有的樂器與聲音
    }

    updateValue(r, c, vi) {
        // vi: 0 ~ 360
        // mapping vi 這個數字到樂器參數上
        // 範例:
        // 假如音量需要 0 ~ -40(dB),就做下面的轉換
        //    this.kick.synth.volume = vi * (-1 / 9);
    }
}

我將Vsynth的 instance 放在 block 的 state 裡面一起管理,透過handleWheelmousemove等等的 event、callback 呼叫updateValue去改變參數。

lerp

但是假如個數字都要這樣從 0 ~ 360 去算我們到底需要哪些,再做加減乘除就太煩了。我直接寫了一個function lerp負責這樣的換算:

// lerp.js
export default function (low, high, from, to, v) {
	const ratio = (v - low) / (high - low);
	return from + (to - from) * ratio;
}

假設 v 介於lowhigh之間,會把v這個數字線性轉換到fromto裡面。

實際例子

// vsynth.js
...

updateValue(r, c, vi) {
  const v = vi / 360; // 先將 vi 從 0 ~ 360 轉化到 0 ~ 1 上
  // r 是 row 的 index
  // c 是 column 的 index
  switch (r) {
    case 0:
      switch (c) {
        case 0:
          this.kick.synth.envelope.decay = lerp(0, 1, 0.4, 6.0, v);
          break;
        case 1:
          this.kick.synth.envelope.attack = lerp(0, 1, 0.001, 0.3, v);
          break;
        default:
          break;
      }
      break;
    default:
      break;
}
...

我把最左上角(0, 0)的旋鈕 mapping 到大鼓(kick)的 envelope 的 decay 上面,第二個(0, 1)的旋鈕 mapping 到大鼓(kick)的 envelope 的 attack 上面。聽聽看!

source code

4. 請愛CYBER の audio / VISUAL

接上了,終於接上了。音響已經開啟,派對蓄勢待發...
請繼續期待 web 的 audio / VISUAL。
請繼續思考 web 的 audio / VISUAL。

關於作者

Vibert Thio

致力於將對於技術的深度研究轉化為新型態藝術創作的能量,並思考技術的拓展/侷限與其對於藝術論述/呈現的影響。專長為數位藝術創作、音像程式設計、互動設計,喜愛即時運算的臨場感與不可預測。


上一篇
§d14§ 振盪器派對!演算 の 鼓組!snare進行曲!
下一篇
§d16§ 庭院造景師!真.模型職人!3D 白痴作戰計畫。(一)
系列文
aesthEtic,CYBERの audio / VISUAL,網頁中的聲音與影像研究30

尚未有邦友留言

立即登入留言