多摩美 - “iTamabi” – iPhoneアプリ開発プロジェクト 2010
openFrameworks + iPhone マルチタッチイベントの取得、音アプリを作る
サンプルファイルのダウンロード
サンプルファイルは以下のリンクよりダウンロードしてください。
- サンプルファイル iTamabi100517.zip (Zip形式 347KB)
マルチタッチイベントの取得
マルチタッチの情報が取得できるイベント
定義 | 機能 |
---|---|
touchDown | 画面をタッチした瞬間に実行される |
touchMoved | 画面をタッチして移動した際に実行される |
touchUp | タッチしていた画面から離れた瞬間実行される |
touchDoubleTap | ダブルタップ(素早く2回画面をタップ)した瞬間に実行される |
タッチされた情報は、以下のように格納される
- touch.id – 現在タッチされたポイントのID (0〜4)
- touch.x – 現在タッチされたポイントのx座標
- touch.y- 現在タッチされたポイントのy座標
- とりだしたタッチの座標情報は、配列に格納すると便利
- 配列 – 簡単な配列の説明「情報のロッカーみたいなもの」
マルチタッチイベントの取得1
- タッチした全ての場所に円を描く
- ofPointクラスを利用して、タッチした座標を1つのインスタンス(変数)で管理している
- [ofPointのインスタンス].x – X座標
- [ofPointのインスタンス].y – Y座標
- さらにそのofPointのクラスを配列にして、5つのポイントをtouchLocという配列で一括して管理している
- touchDownした際に配列toucLocに座標を記録して、drawで記録された座標を中心に円を描いている
testApp.h
[code language=”cpp”]
#pragma once
#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
class testApp : public ofxiPhoneApp {
public:
void setup();
void update();
void draw();
void exit();
void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);
void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);
//タッチした座標の配列(5コ)
ofPoint touchLoc[5];
};
[/code]
testApp.mm
[code language=”cpp”]
#include "testApp.h"
//————————————————————–
void testApp::setup(){
// タッチイベントの登録
ofRegisterTouchEvents(this);
// 加速度センサの初期化
ofxAccelerometer.setup();
// iPhone警告メッセージの取得
ofxiPhoneAlerts.addListener(this);
//背景色を黒に
ofBackground(0,0,0);
//アルファ値を使用する
ofEnableAlphaBlending();
//円の解像度の設定を32に
ofSetCircleResolution(32);
//タッチポイントを初期化、画面の外に
for (int i=0; i<5; i++) {
touchLoc[i].set(-100, -100);
}
}
//————————————————————–
void testApp::update(){
}
//————————————————————–
void testApp::draw(){
//タッチした位置を取得して、円を描く
for (int i=0; i<5; i++) {
ofSetColor(31, 127, 255,127);
ofCircle(touchLoc[i].x, touchLoc[i].y, 60);
ofSetColor(255, 255, 255);
ofDrawBitmapString("touch:"
+ ofToString(i,0)
+ " = ("
+ ofToString(touchLoc[i].x,0)
+ ", "
+ ofToString(touchLoc[i].y,0)
+ ")",
2, 12*i+12);
}
}
//————————————————————–
void testApp::exit(){
}
//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチした場所を取得
touchLoc[touch.id].set(touch.x, touch.y);
}
//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//タッチしながら動かした場所を取得
touchLoc[touch.id].set(touch.x, touch.y);
}
//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//画面から指が離れたら、位置を画面外に
touchLoc[touch.id].set(-100, -100);
}
//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::lostFocus(){
}
//————————————————————–
void testApp::gotFocus(){
}
//————————————————————–
void testApp::gotMemoryWarning(){
}
//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]
マルチタッチイベントの取得2
- タッチした場所から円が徐々に拡大していくように変更してみる
testApp.h
[code language=”cpp”]
#pragma once
#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
class testApp : public ofxiPhoneApp {
public:
void setup();
void update();
void draw();
void exit();
void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);
void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);
//タッチした座標
ofPoint touchLoc[5];
//円のサイズ
float circleSize[5];
};
[/code]
testApp.mm
[code language=”cpp”]
#include "testApp.h"
//————————————————————–
void testApp::setup(){
// タッチイベントの登録
ofRegisterTouchEvents(this);
// 加速度センサの初期化
ofxAccelerometer.setup();
// iPhone警告メッセージの取得
ofxiPhoneAlerts.addListener(this);
//背景色を黒に
ofBackground(0,0,0);
//アルファ値を使用する
ofEnableAlphaBlending();
//円の解像度の設定を32に
ofSetCircleResolution(128);
ofSetFrameRate(30);
//タッチポイントを初期化、画面の外に
for (int i=0; i<5; i++) {
touchLoc[i].set(-100, -100);
}
}
//————————————————————–
void testApp::update(){
//タッチポイントの数だけくりかえし
for (int i=0; i<5; i++) {
//もし円のサイズが0より大きく、画面の高さよりも小さかったら
if(circleSize[i]>0 && circleSize[i]<ofGetHeight()){
//円のサイズを増加させる
circleSize[i]+=3;
} else {
//それ以外だったら、円の大きさを0にリセット
circleSize[i]=0;
}
}
}
//————————————————————–
void testApp::draw(){
//タッチした位置を取得して、円を描く
for (int i=0; i<5; i++) {
if(circleSize[i]>0 && circleSize[i]<ofGetHeight()){
ofSetColor(31,127,255,100);
//拡大する円のサイズを指定して円を描く
ofCircle(touchLoc[i].x, touchLoc[i].y, circleSize[i]);
ofSetColor(255, 255,255);
}
}
//ログの出力
for (int i=0; i<5; i++) {
ofDrawBitmapString("touch:"
+ ofToString(i,0)
+ " = ("
+ ofToString(touchLoc[i].x,0)
+ ","
+ ofToString(touchLoc[i].y,0)
+ "), size = "
+ ofToString(circleSize[i], 0),
2, 12*i+2);
}
}
//————————————————————–
void testApp::exit(){
}
//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチした場所を取得
touchLoc[touch.id].set(touch.x, touch.y);
circleSize[touch.id]=1;
}
//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//タッチしながら動かした場所を取得
touchLoc[touch.id].set(touch.x, touch.y);
}
//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::lostFocus(){
}
//————————————————————–
void testApp::gotFocus(){
}
//————————————————————–
void testApp::gotMemoryWarning(){
}
//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]
音を鳴らす
- iPhoneの音系アプリの紹介 – Bloom、SoundDrop、Rain、VectorRain ..etc
- openFrameworksを使うと、こうした「音のおもちゃ」が簡単に作れる!!
- openFrameworks for iPhoneで音を鳴らすには – OpenALを使用する
- OpenAL – クロスプラットフォームのオーディオAPI
- 3次元定位オーディオを効率よく表現するように設計されている
- OpenGLとの相性が良い
- openFrameworksで、OpenALを利用するプロジェクトには、ofxALSoundPlayerアドオンのファイルが入っている必要がある
- 「グループとファイル」の「addons」を右クリックして、「追加」→「既存のファイル」を選択
- ofxALSoundPlayerのフォルダを追加する
- [oFのフォルダ]/apps/iPhoneSpecificExamples/OpenAlExample/src/ofxALSoundPlayer
caf形式のサウンドファイルの準備
- iPhoneでサウンドファイルを扱うには、Core Audio Format(.caf)という形式に変換する必要がある
- ターミナルから、”/usr/bin/afconvert”コマンドを使用して、AIFFファイルをCAFファイルに変換することが可能
% afconvert -f caff -d ima4 -d LEI16@22050 -c 1 -o [出力ファイル名].caf [入力ファイル名].wav
- FreeSoundプロジェクトから、好きな音を探してきて、CAFファイルに変換してみる
OpenALの利用1 – マルチタッチとの組み合せ
- マルチタッチのサンプルと組み合わせてみる
- touchDownした瞬間に、音を鳴らす
- X座標の情報を、音の左右の定位(パン)に利用
- Y座標の情報を、音程に利用
testApp.h
[code language=”cpp”]
#pragma once
#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
#include "ofxALSoundPlayer.h"
class testApp : public ofxiPhoneApp {
public:
void setup();
void update();
void draw();
void exit();
void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);
void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);
//OpenALを利用して音を再生するプレーヤー(5つ)
ofxALSoundPlayer synth[5];
//タッチした座標情報(5つ)
ofPoint touchLoc[5];
//円の大きさ情報(5つ)
float circleSize[5];
};
[/code]
testApp.mm
[code language=”cpp”]
#include "testApp.h"
//————————————————————–
void testApp::setup(){
// タッチイベントの登録
ofRegisterTouchEvents(this);
// 加速度センサの初期化
ofxAccelerometer.setup();
// iPhone警告メッセージの取得
ofxiPhoneAlerts.addListener(this);
//背景色を黒に
ofBackground(0,0,0);
//アルファ値を使用する
ofEnableAlphaBlending();
//円の解像度の設定を32に
ofSetCircleResolution(128);
ofSetFrameRate(30);
//タッチポイントを初期化、画面の外に
for (int i=0; i<5; i++) {
touchLoc[i].set(-100, -100);
}
//CAFファイルをロードして、Synthにわりあて
for(int i=0;i<5;i++){
synth[i].loadSound("glockenspiel.caf");
}
}
//————————————————————–
void testApp::update(){
//タッチポイントの数だけくりかえし
for (int i=0; i<5; i++) {
//もし円のサイズが0より大きく、画面の高さよりも小さかったら
if(circleSize[i]>0 && circleSize[i]<ofGetHeight()){
//円のサイズを増加させる
circleSize[i]+=3;
} else {
//円の大きさを0にリセット
circleSize[i]=0;
}
}
}
//————————————————————–
void testApp::draw(){
//タッチした位置を取得して、円を描く
for (int i=0; i<5; i++) {
if(circleSize[i]>0 && circleSize[i]<ofGetHeight()){
ofSetColor(31,127,255,100);
//拡大する円のサイズを指定して円を描く
ofCircle(touchLoc[i].x, touchLoc[i].y, circleSize[i]);
ofSetColor(255, 255,255);
}
}
//ログの出力
for (int i=0; i<5; i++) {
ofDrawBitmapString("touch:"
+ ofToString(i,0)
+ " = ("
+ ofToString(touchLoc[i].x,0)
+ ","
+ ofToString(touchLoc[i].y,0)
+ "), size = "
+ ofToString(circleSize[i], 0),
2, 12*i+6);
}
}
//————————————————————–
void testApp::exit(){
}
//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチした場所を取得
touchLoc[touch.id].set(touch.x, touch.y);
circleSize[touch.id]=1;
synth[touch.id].setPitch(0.5 + touch.y / ofGetHeight());
synth[touch.id].setLocation(touch.x/(float)ofGetWidth()*2-1.0, 0,0);
synth[touch.id].play();
}
//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//タッチしながら動かした場所を取得
touchLoc[touch.id].set(touch.x, touch.y);
synth[touch.id].setPitch(0.5 + touch.y / ofGetHeight());
synth[touch.id].setLocation(touch.x/(float)ofGetWidth()*2-1.0, 0,0);
}
//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::lostFocus(){
}
//————————————————————–
void testApp::gotFocus(){
}
//————————————————————–
void testApp::gotMemoryWarning(){
}
//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]
OpenALの利用2 – Bloomっぽいアプリを作る
- タッチした演奏情報を記録して、くりかえし演奏させてみたい (超簡易シーケンサー?)
- 次の方法で簡単に実装可能
- タッチした瞬間に音を鳴らす
- タッチした座標を中心にして、円が一定速度で拡大していく
- 円が一定の大きさより大きくなったら、最小のサイズに戻す
- 最小のサイズに戻す際に、また音を鳴らす
- 調整のある音階を鳴らしてみたい
- 音階の比率をあらかじめ定義しておく
- (純正律の)ドレミファソラシは、下記の比率になる
- 1 : 9/8 : 5/4 : 4/3 : 3/2 : 5/3 : 15/8
- タッチした際のY座標からピッチを決めるようにする
testApp.h
[code language=”cpp”]
#pragma once
#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
#include "ofxALSoundPlayer.h"
//最大発音数を定義 (20)
#define NUM_SYNTH 20
class testApp : public ofxiPhoneApp {
public:
void setup();
void update();
void draw();
void exit();
void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);
void lostFocus();
void gotFocus();
void gotMemoryWarning();
void deviceOrientationChanged(int newOrientation);
//サウンドプレーヤーの配列
ofxALSoundPlayer synth[NUM_SYNTH];
//円の大きさ情報の配列
float circleSize[NUM_SYNTH];
//タッチした座標情報の配列
ofPoint touchLoc[NUM_SYNTH];
//現在タッチした数(0〜20)
int currentTouch;
//音階を生成するための比率
float pitchRatio[7];
//演奏した音程の記録
float noteTable[NUM_SYNTH];
};
[/code]
testApp.mm
[code language=”cpp”]
#include "testApp.h"
//————————————————————–
void testApp::setup(){
// タッチイベントの登録
ofRegisterTouchEvents(this);
// 加速度センサの初期化
ofxAccelerometer.setup();
// iPhone警告メッセージの取得
ofxiPhoneAlerts.addListener(this);
//背景色を黒に
ofBackground(0,0,0);
//アルファ値を使用する
ofEnableAlphaBlending();
//円の解像度の設定を32に
ofSetCircleResolution(128);
ofSetFrameRate(30);
//タッチポイントを初期化、画面の外に
for (int i=0; i<NUM_SYNTH; i++) {
touchLoc[i].set(-100, -100);
synth[i].loadSound("glockenspiel.caf");
}
//現在タッチされた数
currentTouch = 0;
//音階を生成
pitchRatio[0]= 1.0;
pitchRatio[1]= 9.0/8.0;
pitchRatio[2]= 5.0/4.0;
pitchRatio[3]= 4.0/3.0;
pitchRatio[4]= 3.0/2.0;
pitchRatio[5]= 5.0/3.0;
pitchRatio[6]= 15.0/8.0;
}
//————————————————————–
void testApp::update(){
//タッチポイントの数だけくりかえし
for (int i=0; i<NUM_SYNTH; i++) {
//もし円のサイズが0より大きく、画面の高さよりも小さかったら
if(circleSize[i]>0 && circleSize[i]<ofGetHeight()){
//円のサイズを増加させる
circleSize[i]+=3;
} else {
if(touchLoc[i].x > 0 && touchLoc[i].y > 0){
//円の大きさを1にリセットして、サウンドを再度鳴らす
//記録されている音が順番にパターンとして生成される
circleSize[i]=1;
synth[i].setPitch(noteTable[i]);
synth[i].setLocation(touchLoc[i].x/(float)ofGetWidth()*2-1.0, 0,0);
synth[currentTouch].setVolume(0.2);
synth[i].play();
}
}
}
}
//————————————————————–
void testApp::draw(){
//タッチした位置を取得して、円を描く
for (int i=0; i<NUM_SYNTH; i++) {
if(circleSize[i]>0 && circleSize[i]<ofGetHeight()){
ofSetColor(31,127,255,200);
ofNoFill();
ofSetLineWidth(4);
//拡大する円のサイズを指定して円を描く
ofCircle(touchLoc[i].x, touchLoc[i].y, circleSize[i]);
ofSetColor(255, 255,255);
}
}
}
//————————————————————–
void testApp::exit(){
}
//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチした場所を取得
touchLoc[currentTouch].set(touch.x, touch.y);
circleSize[currentTouch]=1;
//タッチしたY座標から、ピッチを選択
noteTable[currentTouch] = pitchRatio[int(7.0*touch.y/ofGetHeight())] * 0.5;
synth[currentTouch].setPitch(noteTable[currentTouch]);
//パンを設定
synth[currentTouch].setLocation(touch.x/(float)ofGetWidth()*2-1.0, 0,0);
//音量を設定
synth[currentTouch].setVolume(0.2);
//音を鳴らす
synth[currentTouch].play();
currentTouch++;
if (currentTouch>NUM_SYNTH-1) {
currentTouch = 0;
}
}
//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}
//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
//ダブルタップでリセット
for (int i=0; i<NUM_SYNTH; i++) {
circleSize[i]=0;
touchLoc[i].set(-100, -100);
}
}
//————————————————————–
void testApp::lostFocus(){
}
//————————————————————–
void testApp::gotFocus(){
}
//————————————————————–
void testApp::gotMemoryWarning(){
}
//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]