# バッファからグラフを描く

## バッファとは

一定の時間データを保持する機構。ここでは、1フレームごとに新しい脳波を取得して、300フレーム（約5秒）前のデータまで保持する。

<figure><img src="https://401456337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsuKkxdoQ8ipy9uxnNRNp%2Fuploads%2FjCmlLP73JR21za1uft7u%2Fbuffer.gif?alt=media&#x26;token=0664b4e2-4c0d-45e6-9c61-2724d610d100" alt=""><figcaption><p>実行画面</p></figcaption></figure>

## サンプルコード：

* 実行手順
  * Vieを装着し、Vie StreamでVieに接続
  * 「計測開始(Activate Sensor)」ボタンを押す
  * 「OSC転送(OSC Streaming)」ボタンを押す
  * 「ポート番号」と「デバイス識別子」を確認。（通常はそれぞれ、65001、1）
  * コードの実行
  * キーボードの1\~5キーで脳波を切り替える

{% file src="<https://401456337-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FsuKkxdoQ8ipy9uxnNRNp%2Fuploads%2FDONVS7x1lWMwLCMKhR60%2Fsample02_buffer.zip?alt=media&token=5a0d3cc9-1887-4648-b53a-f65eb3a948ba>" %}

## サンプルコードの解説

### クラスの用意

Delta, Theta, Alpha, Beta, Gammaの数値をまとめて保持するクラスを用意する

{% code overflow="wrap" %}

```processing
//脳波格納用のクラス
class BrainWave{
  
  public float delta;
  public float theta;
  public float alpha;
  public float beta;
  public float gamma;
  
  BrainWave(){
    this.delta =0.0;
    this.theta =0.0;
    this.alpha =0.0;
    this.beta =0.0;
    this.gamma =0.0;
  }
  
  void set(float d,float t,float a,float b,float g){
    this.delta =d;
    this.theta =t;
    this.alpha =a;
    this.beta =b;
    this.gamma =g;
  }
  
}
```

{% endcode %}

### バッファの準備

```processing
////左と右の脳波を一定時間格納するバッファ、左用と右用
ArrayList<BrainWave> bwBufferLeft  = new ArrayList<BrainWave>();
ArrayList<BrainWave> bwBufferRight = new ArrayList<BrainWave>();

//バッファサイズ（300フレーム分のバッファ）
int bwBufferSize = 300;

void setup() {
  //中略
  //バッファを初期化する
  for(int i=0; i<bwBufferSize; i++){
    bwBufferLeft.add( new BrainWave() );
    bwBufferRight.add( new BrainWave() );
  }
}
```

### 毎フレームごとにバッファにデータを追加しつつ先頭を削除

```processing
void draw() {

  //中略
  
  //左脳波をバッファに格納
  BrainWave bwLeft = new BrainWave();
  bwLeft.set(waveLeft[0],waveLeft[1], waveLeft[2], waveLeft[3], waveLeft[4]);
  bwBufferLeft.add(bwLeft);
  
  //右脳波をバッファに格納
  BrainWave bwRight = new BrainWave();
  bwRight.set(waveRight[0],waveRight[1], waveRight[2], waveRight[3], waveRight[4]);
  bwBufferRight.add(bwRight);
  
  //バッファサイズが上限に達したら先頭を削除
  if(bwBufferLeft.size() > bwBufferSize){
    bwBufferLeft.remove(0);
  }
  if(bwBufferRight.size() > bwBufferSize){
    bwBufferRight.remove(0);
  }
  //中略
}
```

## beginShape() , vertex(), endShape()について

次のように書くと、(x0,y0)、(x1,y1)、(x2,y2)の各頂点を結ぶ線が描ける。

```processing
noFill();
beginShape();
vertex(x0, y0);
vertex(x1, y1);
vertex(x2, y2);
endShape();
```

### バッファを折れ線グラフとして描画

```processing
void draw() {

  //中略
  
  //左のバッファの折れ線グラフ
  beginShape();
  
  //バッファの先頭から最後まで格納されているBrainWaveのインスタンスにアクセスして数値を取得
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      //bwBufferLeft.get(i)で先頭からi番目のBrainWaveインスタンスにアクセス
      //bwBufferLeft.get(i).deltaで、インスタンスに保持されているdeltaの数値を取得
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    //折れ線グラフ上の点(x,y)を計算
    float x = 30 + i;
    float y = -1 * wave;
    //頂点を登録
    vertex(x,y);
  }
  endShape();
  //中略
}
```

### バッファを円環グラフとして描画

```processing
void draw() {

  //中略
  
　　　　//バッファの描画2:円環グラフ
  float centerX = 180;
  float centerY = height*0.7; 
  
  //左のバッファ
  beginShape();
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    //バッファ内のデータを全て描画するのに4周分とすると
    //2.0Pi * 4 / bwBufferSizeで1バッファあたりの角度が求まる。
    //取得した数値waveは中心からの距離に対応させ、頂点の座標(x,y）を求める
    float x = wave * cos( 8.0*PI/bwBufferSize * i)+centerX;
    float y = wave * sin( 8.0*PI/bwBufferSize * i)+centerY;
    color cl =  unhex(colorHex[selectedWaveByKey]);
    //古いバッファ値はアルファが低く（薄く）なるようにする
    float alpha = 255.0 * (float)i / (float)bwBufferLeft.size();
    
    //vertex関数の直前に色指定（stroke() or fill()）することでその頂点固有の色を指定できる。
    stroke(red(cl), green(cl), blue(cl),alpha);
    vertex(x,y);
  }
  endShape();
  //中略
}
```

## プログラム全体

{% code overflow="wrap" lineNumbers="true" %}

```processing
import oscP5.*;
import netP5.*;

//OSCP5クラスのインスタンス
OscP5 oscP5;

float [] waveLeft  = new float[5];
float [] waveRight = new float[5];

//左と右の脳波を一定時間格納するバッファ、左用と右用
ArrayList<BrainWave> bwBufferLeft  = new ArrayList<BrainWave>();
ArrayList<BrainWave> bwBufferRight = new ArrayList<BrainWave>();

//バッファサイズ（300フレーム分のバッファ）
int bwBufferSize = 300;

int selectedWaveByKey = 0;

String [] colorHex = {"FF034AA6", "FF72B6F2", "FF73BFB1", "FFF2A30F", "FFF26F63"};
String [] bandName = {"Delta", "Theta", "Alpha", "Beta", "Gamma"};

void setup() {
  size(800,600,P2D);
  frameRate(60);
  //ポートを65001に設定して新規にOSCP5のインスタンスを生成
  oscP5 = new OscP5(this,65001);
  
  //バッファを初期化する
  for(int i=0; i<bwBufferSize; i++){
    bwBufferLeft.add( new BrainWave() );
    bwBufferRight.add( new BrainWave() );
  }
  textSize(15);
}

void draw() {
  background(0);
  noStroke();
  
  //左脳波をバッファに格納
  BrainWave bwLeft = new BrainWave();
  bwLeft.set(waveLeft[0],waveLeft[1], waveLeft[2], waveLeft[3], waveLeft[4]);
  bwBufferLeft.add(bwLeft);
  
  //右脳波をバッファに格納
  BrainWave bwRight = new BrainWave();
  bwRight.set(waveRight[0],waveRight[1], waveRight[2], waveRight[3], waveRight[4]);
  bwBufferRight.add(bwRight);
  
  //バッファサイズが上限に達したら先頭を削除
  if(bwBufferLeft.size() > bwBufferSize){
    bwBufferLeft.remove(0);
  }
  if(bwBufferRight.size() > bwBufferSize){
    bwBufferRight.remove(0);
  }
  
  //ラベル
  fill(255);
  text("Left", 30, 30);
  text("Right", 430, 30);
  
  //waveLeftの描画
  for(int i=0;i<5;i++){
    fill(unhex(colorHex[i]));
    rect(130, 50+30*i, waveLeft[i], 20);
    fill(255);
    text(bandName[i], 30, 65+30*i);
    text(floor(waveLeft[i])+"%", waveLeft[i]+140, 65+30*i );
  }
  
  //waveRightの描画
  for(int i=0;i<5;i++){
    fill(unhex(colorHex[i]));
    rect(530, 50+30*i, waveRight[i], 20);
    fill(255);
    text(bandName[i], 430, 65+30*i);
    text(floor(waveRight[i])+"%", waveRight[i]+540, 65+30*i );
  }
  

  
  //バッファの描画1:折れ線グラフ
  pushMatrix();
  translate(0,height/2);
  
  //左のバッファ
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  rect(30, -100, bwBufferSize, 100);
  stroke(unhex(colorHex[selectedWaveByKey]));
  beginShape();
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    float x = 30 + i;
    float y = -1 * wave;
    vertex(x,y);
  }
  endShape();
  
  //右のバッファ
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  rect(430, -100, bwBufferSize, 100);
  stroke(unhex(colorHex[selectedWaveByKey]));
  beginShape();
  for(int i=0; i<bwBufferRight.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferRight.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferRight.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferRight.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferRight.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferRight.get(i).gamma;
    }
    float x = 430 + i;
    float y = -1 * wave;
    vertex(x,y);
  }
  endShape();
  popMatrix();
  
  //バッファの描画2:円環グラフ
  float centerX = 180;
  float centerY = height*0.7; 
  
  //左のバッファ
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  ellipse(centerX,centerY,200,200);
  ellipse(centerX,centerY,100,100);
  beginShape();
  for(int i=0; i<bwBufferLeft.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferLeft.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferLeft.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferLeft.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferLeft.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferLeft.get(i).gamma;
    }
    float x = wave * cos( 8.0*PI/bwBufferSize * i)+centerX;
    float y = wave * sin( 8.0*PI/bwBufferSize * i)+centerY;
    color cl =  unhex(colorHex[selectedWaveByKey]);
    float alpha = 255.0 * (float)i / (float)bwBufferLeft.size();
    stroke(red(cl), green(cl), blue(cl),alpha);
    
    vertex(x,y);
  }
  endShape();

  //右のバッファ
  centerX = 590;
  
  noFill();
  strokeWeight(2);
  stroke(50,50,50);
  ellipse(centerX,centerY,200,200);
  ellipse(centerX,centerY,100,100);
  beginShape();
  for(int i=0; i<bwBufferRight.size();i++){
    float wave = 0;
    if(selectedWaveByKey == 0){
      wave = bwBufferRight.get(i).delta;
    }
    else if(selectedWaveByKey == 1){
      wave = bwBufferRight.get(i).theta;
    }
    else if(selectedWaveByKey == 2){
      wave = bwBufferRight.get(i).alpha;
    }
    else if(selectedWaveByKey == 3){
      wave = bwBufferRight.get(i).beta;
    }
    else if(selectedWaveByKey == 4){
      wave = bwBufferRight.get(i).gamma;
    }
    float x = wave * cos( 8.0*PI/bwBufferSize * i)+centerX;
    float y = wave * sin( 8.0*PI/bwBufferSize * i)+centerY;
    color cl =  unhex(colorHex[selectedWaveByKey]);
    float alpha = 255.0 * (float)i / (float)bwBufferRight.size();
    stroke(red(cl), green(cl), blue(cl),alpha);
    
    vertex(x,y);
  }
  endShape();
  
  
  
  //インタラクションガイド
  fill(255);
  text("Press key \"1,2,3,4,5\" to select a wave.",30,height-10);

}

//OSCメッセージを受信した際に実行するイベント
void oscEvent(OscMessage msg) {
  
  if(msg.checkAddrPattern("/wave/L/1")==true) {   
    for(int i=0;i<5;i++){
      waveLeft[i] = msg.get(i).floatValue();
    }    
  }
  if(msg.checkAddrPattern("/wave/R/1")==true) {   
    for(int i=0;i<5;i++){
      waveRight[i] = msg.get(i).floatValue();
    }    
  }

}

//脳波格納用のクラス
class BrainWave{
  
  public float delta;
  public float theta;
  public float alpha;
  public float beta;
  public float gamma;
  
  BrainWave(){
    this.delta =0.0;
    this.theta =0.0;
    this.alpha =0.0;
    this.beta =0.0;
    this.gamma =0.0;
  }
  
  void set(float d,float t,float a,float b,float g){
    this.delta =d;
    this.theta =t;
    this.alpha =a;
    this.beta =b;
    this.gamma =g;
  }
  
}

void keyPressed(){
 
  if(key == '1'){
    selectedWaveByKey = 0;
  }
  
  if(key == '2'){
    selectedWaveByKey = 1;
  }
  
  if(key == '3'){
    selectedWaveByKey = 2;
  }
  
  if(key == '4'){
    selectedWaveByKey = 3;
  }
  
  if(key == '5'){
    selectedWaveByKey = 4;
  }
  
  
}
```

{% endcode %}
