yoppa.org


iTamabiアプリ発表

iTmabiの履修者の方々の開発したiPhoneアプリです。


ACCEL SEQUENCER

iPhoneをシェイクすることで音を入力していく、ステップシーケンサー。音色のセットを切り替えることも可能。複数台のiPhoneでセッションをすると楽しい。

  • 馬場美沙紀 (情報芸術)
  • 加治 洋紀 (情報芸術)
  • 出雲優子 (情報芸術)
  • 星野泰宏 (情報芸術)

barcode clock

現在の時間をバーコードで表示する時計アプリ。表示されるのは、実際に読み取り可能な本物のバーコード。

  • 長谷川昇平 (情報デザイン)

A Cloclwork Light

光の粒が時間の変化とともに飛び散りながら変化する。表示される光は、実際にライトを撮影して素材にしている。

  • 林響太朗 (情報デザイン)
  • 梶原恵 (情報デザイン)
  • 浮島佳祐 (情報デザイン)

Draw Sound

画面上を指で線を描くと、その形からメロディーが生まれる。

  • 長谷川昇平 (情報デザイン)

dripple

画面をタップすると、波紋が拡がり、水滴が落ちる音で音楽を奏でる。

  • 中谷綾花 (グラフィックデザイン)

DropClock

重力によってデジタル時計の文字がiPhoneの傾きと一致して、重力によって崩れていく。しばらくするとまた文字が表示され、また崩れるという繰り返し。

  • 高橋昂司 (情報芸術)

GulinClock

デジタル時計の後ろで、物理演算によって運動する球体が動きまわる。

  • 中谷 嵩 (プロダクトデザイン)

hagunet planet

ネコのキャラクターを操作して敵を避けていく、本格的なアクションゲーム。画面をタッチしてロケットの推進力をコントロールする。

  • 櫻井瑶子 (情報デザイン)

未来派気取り

二進数の数値によって時間がリアルタイムに変化し、経過していく過程をビジュアライズしている。

  • 土居下太意 (情報芸術)

montage

モンタージュ写真を作成するアプリ。画面をタップして、目と鼻と口を左右にスライドさせて、様々なキャラクターの断片から新たな顔を生成する。

  • 中森源 (情報デザイン)

PANDA

パンダのキャラクターが上下にバウンド。画面をタップするとバウンドのスピードが変化する。

  • 難波江明香 (油絵)

Potope

iPhoneのカメラで撮影した写真の色情報を分析して、万華鏡のような模様がアニメーションする。

  • 矢野哲太郎 (情報芸術)

PIKADOOOM

iPhoneのマイクを通して入力された周囲の音にあわせて、空から稲妻が落ちてくる。

  • 笠井明日菜 (情報デザイン)

Rough Coaster

手書きアニメーションによる、3Dローラーコースター。

  • 芹澤 諒 (情報デザイン)

sensitiveA

一見普通のアナログ時計だが、画面をタッチすると敏感(sensitive)に反応して針が震える。

  • 杉浦知実 (情報デザイン)

sensitiveD

Sensiteive A のデジタル版。画面タッチでデジタルの数値が敏感に反応する。

  • 杉浦知実 (情報デザイン)

SoundSwitch

マトリクス上にならんだスイッチをON/OFFすることで演奏するシーケンサー。スイッチの状態とONにするタイミングで、リズムパターンを生成する。

  • 木村功平 (情報芸術 大学院)

一日時計タマビ行き

時計の背景に、実際の時間と連動して多摩美の一日の様子が変化する。

  • 藤野雅子 (情報デザイン)

Tamabi百景

キャンパスの地図上に表示されたポイントをクリックすると、その場所で描かれた絵画やイラストが表示される。地図と連動したポートフォリオ。

tamanekorogashi

多摩美に生息する猫の写真のスライドショー。画面をタップすると、運動する円を配置できる。

  • 今泉杏奈 (情報芸術)

あたりゲーム

3人の中から一人のあたりを決める抽選ゲーム。それぞれ自分の色を決めて、回転する円が一番上の位置に来たらあたりになる。

  • リム メグミ
  • ジャン ウンス
  • アン ヘリム

openFrameworksを、iOS4用にビルドする

openFrameworksを、iPhoneのiOS4用にビルドする方法について解説します。このページでは、下記の環境でテストしています。

Xcodeと、iOS SDKの最新版をダウンロードする

XcodeとiOSX SDKの最新版を、Apple Developper Center (ADC) からダウンロードしてインストールします。iPhone Dev CenterのURL (http://developer.apple.com/iphone/) にアクセスし、登録したADCのアカウントでログインした上で、「iOS SDK 4」のタブを選択します。「Downloads」のメニューより、「Xcode 3.2.3 and iOS SDK 4.0.1」を選択し、ダウンロードします。

ダウンロードしたディスクイメージをダブルクリックしてマウントし、インストーラーを起動して、XCodeとiPhone SDKをインストールします。

FreeImageのライブラリをダウンロード

下記のリンクより、iOS4用にビルドし直されたバージョンのFreeImageのライブラリをダウンロードします。

FreeImageのライブラリを入れ替え

openFrameworksの配布パッケージ内のFreeImageのライブラリを、ダウンロードしたiOS4用のライブラリと入れ替えます。

既存のライブラリを消去します。

  • of_preRelease_v0061_iPhone_FAT-pre3/libs/FreeImage/lib/iphone/libFreeImage_iphone_universal.a


既存のFreeImageのライブラリは消去 (画像をクリックで拡大)

同じフォルダにダウンロードしたライブラリ(2種類)をインストールします。iOS4用のライブラリは、ダウンロードしたフォルダの「FreeImage/lib/iphone/」以下にあります。その中身を以下の場所にコピーします。

  • of_preRelease_v0061_iPhone_FAT-pre3/libs/FreeImage/lib/iphone/libfreeimage-iphone.a
  • of_preRelease_v0061_iPhone_FAT-pre3/libs/FreeImage/lib/iphone/libfreeimage-iphonesimulator.a


ライブラリをiOS4用のものに置き換えた状態 (画像をクリックで拡大)

※ includeフォルダの中身は変更の必要はありません。

openFrameworksのプロジェクトにFreeImageライブラリを追加

まず、XCode 3.2.3で、openFrameworksの既存のプロジェクトファイルをオープンします。左側の「グループとファイル」のリストから、FreeImageのiPhone用ライブラリのフォルダ内にある古いライブラリを選択します。

  • [プロジェクトのアイコン]/libs/core/core libraries/FreeImage/lib/iphone/libFreeImage_iphone_universal.a

ファイルを選択した状態で、Deleteキー、もしくは右クリックで表示されるリストから「削除」を選択して、ファイルを削除します。


プロジェクト内の古いFreeImageライブラリ

次に、ライブラリが格納されていたiphoneフォルダを右クリックして、「追加」→「既存のファイルの追加」を選択します。ファイルの選択画面が表示されるので、iOS4用のライブラリを選択して、「追加」を選びます。

  • of_preRelease_v0061_iPhone_FAT-pre3/libs/FreeImage/lib/iphone/libfreeimage-iphone.a
  • of_preRelease_v0061_iPhone_FAT-pre3/libs/FreeImage/lib/iphone/libfreeimage-iphonesimulator.a


FreeImgeライブラリ内のiphoneフォルダに既存ファイルを追加する


ライブラリをiOS4用のもので入れ替えた状態

この操作は、プロジェクトを新規に作成する際に毎回必要となります。ライブラリーをiOS4用に設定した空のプロジェクトファイルを作成して、新規に「EmptyProject」という名前で保存して再利用すると、次回はその「EmptyProject」をコピーすることで設定済みの状態から初めることが可能です。

Xcodeビルド設定の変更

iOS4に更新した関係で、以前のプロジェクトファイルに設定されていた、ビルドの設定が使えなくなっています。最新版の環境にあわせて、ビルドの設定をする必要があります。設定箇所は2箇所です。

「グループとファイル」のリストの一番上にある、プロジェクトのアイコンを選択した状態で、メニューバーから「情報」を選択し、設定画面が表示されるので、「ビルド」のタブを選択。

  • 「アーキテクチャ」→「ベースSDK」の設定を、「iPhoneデバイス 4.0」に

「グループとファイル」のリストの「ターゲット」の中にある実行ファイルのアイコン(例:emptyExample)を選択した状態で、プロジェクトファイルと同様に変更。

  • 「アーキテクチャ」→「ベースSDK」の設定を、「iPhoneデバイス 4.0」に


ベースSDKの変更

iPhone実機で動かす場合には、ofxiphone-info.plistの設定や、コード署名IDの設定を行います。
あとは、メニューバーの「概要」で、「Simulator」か「Device」かを選択し、「ビルドと実行」ボタンを押して実行します。


SimulatorかDeviceかを選択

追記:iPad (3.2 or 3.2.1) 用にビルドする

iPad用にビルドするには、上記のiOS4の設定と同じ操作をした後で、追加で以下の設定をすることでビルドが可能となります。

「グループとファイル」から、「ターゲット」内にある実行ファイル (例:emptyExample) を選択し、右クリックします。表示されるメニューから「現在のターゲットをiPad用にアップグレード」を選択します。


ターゲットをiPad用にアップグレード

アップグレードの形式を、iPhoneとiPadで共通の1つのユニバーサルアプリケーションにまとめるか、2つの独立したアプリケーションにするかを選択します。この説明では、1つのユニバーサルアプリケーションを選択しています。


アップグレードの形式を選択

最後にメニュバーの「概要」のプルダウンメニューから「アクティブな実行可能ファイル」の中からiPad用の実行可能ファイルを選択します。


実行可能ファイルをiPadで選択

これで設定は完了です。「ビルドして実行」ボタンを押すと、シミュレータ、またはiPad実機でopenFrameworksのアプリケーションが動作します。


openFrameworks for iPhone:お絵描きアプリを作る

今日の内容

  • ドロー(お絵描き)アプリをつくる
  • 簡単なサンプルから徐々に複雑なサンプルへと進めていきます

ドロー系アプリのサンプル

  • FatTag Deluxe Katsu Edition! http://fffff.at/fattag-deluxe-katsu-edition
    • いろいろな写真を背景にタギング(落書き)することができる
    • スプレーで描いた際のインクの垂れなどをリアルに再現

ドローアプリを作る

ステップ1:タッチした軌跡に円を描く

  • touchDownとtouchMoveした際のX座標とY座標を取得
  • 取得した座標の場所に円を描いていく
  • 円の連なりで線を描いていく

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; //画面をタッチしている場所
bool drawing; //ドロー中かどうか
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

//横位置で起動
iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//画面の基本設定
ofBackground(255, 255, 255);
ofSetBackgroundAuto(false);
drawing = false;
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//もし現在ドロー中だったら
if (drawing) {
//色を黒に
ofSetColor(0, 0, 0);
//タッチしている場所に円を描く
ofCircle(touchLoc.x, touchLoc.y, 10);
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//ドロー中に
drawing = true;
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//ドローを終了
drawing = false;
}

//————————————————————–
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; //現在タッチしている場所
ofPoint lastTouchLoc; //ひとつ前のタッチしている場所
bool drawing; //ドロー中かどうか
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

//横位置で起動
iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//画面基本設定
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
ofSetLineWidth(3);
ofEnableSmoothing();

drawing = false;
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//もしドロー中だったら
if (drawing) {
ofSetColor(0, 0, 0);
//ひとつ前のタッチした座標から現在の座標まで線を描く
ofLine(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y);
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//ドロー中に
drawing = true;
//ひとつ前の座標を記録
lastTouchLoc = touchLoc;
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//ドローを終了
drawing = false;
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
ofSetColor(255, 255, 255);
ofRect(0, 0, ofGetWidth(), ofGetHeight());
}

//————————————————————–
void testApp::lostFocus(){

}

//————————————————————–
void testApp::gotFocus(){

}

//————————————————————–
void testApp::gotMemoryWarning(){

}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){

}
[/code]

ステップ3:線の太さを変化させる

  • 前のタッチした座標から、現在の座標までの移動した距離を測定
  • 移動した距離に応じて線の太さを変化させる
    • 移動距離が長いときは細い線で
    • 移動距離が短いときには太い線で
  • 筆で書いたような効果

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; //現在タッチしている場所
ofPoint lastTouchLoc; //ひとつ前のタッチしている場所
bool drawing; //ドロー中かどうか
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

//横位置で起動
iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//画面基本設定
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
ofEnableSmoothing();
drawing = false;
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//ドロー中だったら
if (drawing) {
//前のタッチした座標と現在の座標の距離を算出
float dist = ofDist(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y);
//線の太さを決定
float lineWidth = 14 – dist * 0.5;
//4ピクセルよりは細くならないように
if (lineWidth < 4) {
lineWidth = 4;
}
ofSetColor(0, 0, 0);
//算出した太さで円を描く
ofCircle(touchLoc.x, touchLoc.y, lineWidth);
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//ドロー中に
drawing = true;
//ひとつ前の座標を記録
lastTouchLoc = touchLoc;
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//ドローを終了
drawing = false;
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
//ダブルタップで画面をリセット
drawing = false;
ofSetColor(255, 255, 255);
ofRect(0, 0, ofGetWidth(), ofGetHeight());
}

//————————————————————–
void testApp::lostFocus(){

}

//————————————————————–
void testApp::gotFocus(){

}

//————————————————————–
void testApp::gotMemoryWarning(){

}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){

}
[/code]

ステップ4:よりなめらかな線に

  • 線が細くなった際に、線が切れぎれになってしまう問題に対処
  • 座標を一気に移動するのではなく、補完していくことで、なめらかな線にしている

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; //現在タッチしている場所
ofPoint lastTouchLoc; //ひとつ前のタッチしている場所
bool drawing; //ドロー中かどうか
float interpolate; //補完の割合

};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

//横位置で起動
iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//画面基本設定
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
ofEnableSmoothing();
drawing = false;

//補完の割合を設定
interpolate = 0.2;
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
if (drawing) {

//前のタッチした座標と現在の座標の距離を算出
float dist = ofDist(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y);
//線の太さを決定
float lineWidth = 16 – dist * 0.2;
//6ピクセルよりは細くならないように
if (lineWidth < 6) {
lineWidth = 6;
}
ofSetColor(0, 0, 0);
//座標を一定の割合で補完している
lastTouchLoc += (touchLoc – lastTouchLoc) * interpolate;
//円を描く
ofFill();
ofCircle(lastTouchLoc.x, lastTouchLoc.y, lineWidth);
ofNoFill();
ofCircle(lastTouchLoc.x, lastTouchLoc.y, lineWidth);
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
//ひとつ前の座標を記録
lastTouchLoc = touchLoc;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//ドロー中に
drawing = true;

//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//ドローを終了
drawing = false;
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
//ダブルタップで画面をリセット
drawing = false;
ofSetColor(255, 255, 255);
ofRect(0, 0, ofGetWidth(), ofGetHeight());
}

//————————————————————–
void testApp::lostFocus(){

}

//————————————————————–
void testApp::gotFocus(){

}

//————————————————————–
void testApp::gotMemoryWarning(){

}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){

}
[/code]

ステップ5:文字で描く

  • フォントを読みこんで、文字によって線を描く

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;
ofPoint lastTouchLoc;
float interpolate;
bool drawing;
ofTrueTypeFont myFont;
string letters;
float size;
int counter;
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

//横位置で起動
iPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//画面基本設定
ofSetBackgroundAuto(false);
ofBackground(255, 255, 255);
ofEnableSmoothing();
drawing = false;

//表示する文字列を設定
letters = "hello iphone!!";
counter = 0;
interpolate = 0.2;
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//文字で線を描く
float dist = ofDist(lastTouchLoc.x, lastTouchLoc.y, touchLoc.x, touchLoc.y);
float fontSize = dist;
if (fontSize < 12) {
fontSize = 12;
}
myFont.loadFont("Georgia.ttf", dist);
ofSetColor(0, 0, 0);
string newLetter = letters.substr(counter, 1);
size = myFont.stringWidth(newLetter);

if (dist > size) {
float angle = atan2(touchLoc.x – lastTouchLoc.x, lastTouchLoc.y – touchLoc.y);

ofPushMatrix();
ofTranslate(touchLoc.x, touchLoc.y);
ofRotateZ(angle * 180.0 / PI – 90);
myFont.drawString(newLetter, 0, 0);
ofPopMatrix();

counter++;
if (counter > letters.size()) {
counter = 0;
}
lastTouchLoc = touchLoc;
}

}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
//ひとつ前の座標を記録
lastTouchLoc = touchLoc;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//ドロー中に
drawing = true;

//タッチしている場所を記録
touchLoc.x = touch.x;
touchLoc.y = touch.y;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//ドローを終了
drawing = false;
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
//ダブルタップで画面をリセット
drawing = false;
ofSetColor(255, 255, 255);
ofRect(0, 0, ofGetWidth(), ofGetHeight());
}

//————————————————————–
void testApp::lostFocus(){

}

//————————————————————–
void testApp::gotFocus(){

}

//————————————————————–
void testApp::gotMemoryWarning(){

}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){

}
[/code]

サンプルファイルのダウンロード

今回の授業で紹介したプログラムのソースコードは以下からダウンロードしてください。


openFrameworks for iPhone:画像ファイルを読み込む、アニメーションを作成する

今日の内容

  • openFrameworksに画像ファイルを読み込む
  • 画像を連続して読み込んで、手書きアニメーションに挑戦!!

画像ファイルを読み込む

  • openFrameworksで、画像を扱うには、ofImageクラスを使用する
  • ofImage – freeImageライブラリをopenFrameworksで使用しやすいようにしたクラス
  • 主要な画像フォーマットに対応(PNG, JPEG, TIFF, BMP, GIF など)
  • ofImageを利用して読み込む画像ファイルは、[プロジェクトのフォルダ]/bin/data/ 以下に配置する

画像を読み込む手順

  • ofImageのインスタンスを生成
    • 例) ofImage myImage;
    • ofImageクラスのインスタンスmyImageを生成
  • 画像ファイルを読み込み
    • 例) myImage.loadImage("hoge.png");
    • bin/data フォルダ内にある、hoge.pngファイルを読み込む
  • 画像を表示
    • 例) myImage.draw(0, 0);
    • 座標(0, 0)を左上にして、画像を表示

画像を1枚読み込んで表示する

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);

//ofImageクラスのインスタンスmyImageを生成
ofImage myImage;

};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(127,127,127);

//画像ファイルの読み込み
myImage.loadImage("myImage.png");
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//読み込んだ画像ファイルを座標(0, 0)を基準点にして描画
myImage.draw(0, 0);
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

複数の画像を読み込んで順番に表示する

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

#define FRAMENUM 12 //読み込む画像の枚数

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);

//ofImageのインスタンスの配列を生成
ofImage myImage[FRAMENUM];
//現在のフレーム数を記録する変数
int currentFrame;
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(255, 255, 255);
ofSetFrameRate(24);

//連番がふられた画像を順番に読み込み
for (int i = 0; i < FRAMENUM; i++) {
//ファイル名を一時的に格納する文字列
char char1[32];
//連番のファイル名を生成
sprintf(char1, "images/myAnim%04d.png", i+1);
//画像をofImageのインスタンスの配列に読み込み
myImage[i].loadImage(char1);
}
//再生フレームを0から始める
currentFrame = 0;
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//現在のフレームの画像を表示
myImage[currentFrame].draw(0, 0);

//フレーム数をひとつ進める
currentFrame++;
//もし指定した枚数よりフレーム数が大きくなったら
//フレーム数をリセット
if (currentFrame > FRAMENUM – 1) {
currentFrame = 0;
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

テンプレートをもとにオリジナルのアニメーションを作成してみる

  • 作成する画像のフォーマットは、320 x 480のPNGファイル
  • 作成した画像は順番に、myAnim[番号].png という名前で保存していく、番号は0詰めで4桁で。
    • myAnim0001.png、myAnim0002.png、myAnim0003
  • 作成した枚数で、testApp.h で定義されている定数"FRAMENUM"を変更する
    • #define FRAMENUM 枚数
  • まずは2枚から
  • うまくいったら、枚数を増やしてみる

サンプルファイルのダウンロード

今回の授業で紹介したプログラムのソースコードは以下からダウンロードしてください。


openFrameworks for iPhone:サウンドの録音・再生

今日の内容

  • サウンドファイルの再生「Buddha Machine」的なアプリを作ってみる
  • サウンドの録音と再生を使用した音アプリに挑戦
  • 録音した音のデータをインタラクティブに操作する

サウンドファイルの再生

サンプル1:サウンドファイルの再生

  • オリジナルな"Buddha Machine"的アプリを制作できる雛形
  • サウンドファイル(caf形式)と表示する画像を入れ替えれば、そのままアプリにできるテンプレートを以下に掲載
  • 音ファイル(caf形式)は、「プロジェクトのフォルダ」→「bin」→「data」→「mySound.caf」に入れる
  • caf形式のフォーマット – リニアPCM、16bit リトルエンディアン符号付き整数、22050Hz
  • 表示する画像ファイル(PNG形式)は、「プロジェクトのフォルダ」→「bin」→「data」→「myScreen.png」に入れる
  • PNGファイルノフォーマット – PNG 320 x 480 pixel


ファイルの配置

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);

//表示する画面イメージ
ofImage image;

//OpenALを利用して音を再生するプレーヤー
ofxALSoundPlayer synth;
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

//画面イメージを読みこみ
image.loadImage("myScreen.png");

//ループ再生するcafファイルをロードして、Synthにわりあて
synth.loadLoopingSound("mySound.caf");
//読み込んだcafファイルを再生
synth.play();
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//画面を表示
image.draw(0, 0);
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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のマイク入力から音を録音したり、録音した音を再生するには、SoundStreamを使用する必要がある
  • SoundStreamは、音のサンプルのデータ自体を数値として配列に記憶し、それを再生することができる機能 → サンプリング&プレイバック

サンプリグ (標本化)とは

  • 時間的に連続した信号を一定の間隔をおいて測定することにより、離散的な(連続でない)データとして収集すること
  • 時間的に連続した信号 = アナログ信号
  • 離散的な信号 = デジタル信号

サンプリング周波数と量子化ビット数

  • サンプリング周波数 – 1秒間にいくつのサンプルを使用してサンプリングするか、単位はHz
  • 量子化ビットレイト – AD変換の際に信号を何段階の数値で表現するか、単位はbit

iPhoneシミュレータでサンプリング&プレイバックのプレビューを行う際には「Audio MIDI 設定で」下記の設定にする

  • サンプリング周波数、44.1KHz
  • 量子化ビットレイト – 24bit

Sound Streamの機能

SoundStreamを使用するにはまず ofSoundStreamSetup() で初期設定を行う、通常は、setup() の中で指定

  • ofSoundStreamSetup(int nOutputs, int nInputs, ofSimpleApp * OFSA, int sampleRate, int bufferSize, int nBuffers)
    • サウンドの録音再生の初期設定を行う
    • int nOutput – 再生する音のチャンネル数
    • int nInput – 録音する音のチャンネル数
    • ofSimpleApp * OFSA – 呼び出し元のofSimpleApp (普通は、this でOK)
    • int sampleRate – サンプリングレイト
    • int bufferSize – 音をバッファ(格納)するサイズ

Sound Streamに関連するイベント

testApp では、ofSoundStreamSetup() の設定すると音の入出力に関するイベントが発生する

  • audioReceived(float * input, int bufferSize, int nChannels)
    • 音が入力(録音)される際に発生するイベント
    • float * input – 入力された音のサンプルの配列
    • int bufferSize – バッファサイズ、一度に格納されるサンプルの長さ
    • int nChannels – チャンネル数
  • audioRequested(float * output, int bufferSize, int nChannels)
    • 音が出力(再生)される際に発生するイベント
    • float * output – 音として出力するサウンドのサンプルの配列
    • int bufferSize – バッファサイズ、一度に格納されるサンプルの長さ
    • int nChannels – チャンネル数

サンプル2:サンプリング&プレイバック

  • 音を録音して再生するという「サンプリング&プレイバック」の機能をシンプルに実現してみる
  • 画面をタッチ(touchDown)すると録音、タッチしている指を離すと(touchUp)録音した音を再生するように設計
  • 録音した音の波形を画面に表示する

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//録音・再生する音の長さ
#define LENGTH 44100 * 3

class testApp : public ofxiPhoneApp{

public:
void setup();
void update();
void draw();

void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);

void audioReceived( float * input, int bufferSize, int nChannels );
void audioRequested( float * output, int bufferSize, int nChannels );

float buffer[LENGTH]; //オーディオバッファ
int sampleRate; //サンプリングレイト
int recPos; //レコード位置
int playPos; //再生位置
int mode; //現在のモード、0:off, 1:recording, 2:play
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofBackground(0, 0, 0);
ofSetFrameRate(60);

//横位置で使用
ofxiPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//サンプリングレイトの設定
sampleRate = 44100;

//サウンド録音再生の初期化
ofSoundStreamSetup(1, 1, this, sampleRate, LENGTH, 4);

//再生モードに
mode = 2;

//録音、再生の位置を先頭に
recPos = 0;
playPos = 0;
}

//————————————————————–
void testApp::update(){
}

//————————————————————–
void testApp::draw(){
ofSetColor(255, 255, 255);

if (mode == 1) {
//録音モードの場合、recordingの表示をして、背景を青に
ofDrawBitmapString("recording", 10, 20);
ofBackground(255, 0, 0);
} else if (mode == 2) {
//再生モードの場合、playingの表示をして、背景を赤に
ofDrawBitmapString("playing", 10, 20);
ofBackground(0, 0, 255);
}

//画面の幅と録音サンプル数の比率を計算
int ratio = LENGTH / ofGetWidth();

//画面の横幅にあわせて、波形を描画
for (int i = 0; i < LENGTH; i+=ratio){
ofLine(i/ratio,ofGetHeight()/2,i/ratio,ofGetHeight()/2+buffer[i]*100.0f);
}
}

//————————————————————–
//オーディオ入力の処理
void testApp::audioReceived(float * input, int bufferSize, int nChannels){
//もし録音モードだったら
if (mode == 1) {
//バッファされたサンプルの数だけ処理
for (int i = 0; i < bufferSize*nChannels; i++){
//録音位置が設定した最大の長さに逹っしていなければ
if(recPos<LENGTH){
//バッファにサウンド入力を設定
buffer[recPos] = input[i];
//録音位置を進める
recPos++;
} else {
//もし最大位置を越えていたら、最初に戻る(ループ録音)
recPos = 0;
}

}
}
}

//————————————————————–
//オーディオ再生の処理
void testApp::audioRequested(float * output, int bufferSize, int nChannels){
//もし再生モードだったら
if (mode == 2) {
//バッファされたサンプル数だけ処理
for (int i = 0; i < bufferSize*nChannels; i++) {
//再生位置が設定した最大の長さに逹っしていなければ
if(playPos<LENGTH){
//バッファに格納したサウンドを再生
output[i] = buffer[playPos];
//再生位置を進める
playPos++;
} else {
//もし最大位置を越えていたら、最初に戻る(ループ再生)
playPos = 0;
}
}
}
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//画面をタッチすると、録音モードへ
mode = 1;
recPos = 0;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//画面をから指を離すと、再生モードへ
mode = 2;
playPos = 0;
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}
[/code]

サンプル3:録音した音をインタラクティブに操作する

  • 録音した音のピッチや音量を変化できるようにする
  • 簡易版"Sampletoy" – 参考:Sampletoy

  • 録音したサンプルを再生する際に工夫を加えてみる
  • そのままの状態で録音開始
  • 画面をタッチすると再生
  • 画面をタッチしながら横に移動すると、音のピッチが変化
  • 画面をタッチしながら縦に移動すると、音量が変化

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//録音・再生する音の長さ
#define LENGTH 44100 * 3

class testApp : public ofxiPhoneApp{

public:
void setup();
void update();
void draw();

void touchDown(ofTouchEventArgs &touch);
void touchMoved(ofTouchEventArgs &touch);
void touchUp(ofTouchEventArgs &touch);
void touchDoubleTap(ofTouchEventArgs &touch);

void audioReceived( float * input, int bufferSize, int nChannels );
void audioRequested( float * output, int bufferSize, int nChannels );

float buffer[LENGTH]; //オーディオバッファ
int sampleRate; //サンプリングレイト
int recPos; //レコード位置
float playPos; //再生位置
int mode; //現在のモード、0:off, 1:recording, 2:play
float audioLevel; //音量
float playSpeed; //再生スピード(ピッチを変更できるようFloat型で)
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone基本設定
ofRegisterTouchEvents(this);
ofBackground(0, 0, 0);
ofSetFrameRate(60);

//横位置で使用
ofxiPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);

//サンプリングレイトの設定
sampleRate = 44100;

//サウンド録音再生の初期化
ofSoundStreamSetup(1, 1, this, sampleRate, LENGTH, 4);

//録音モードに
mode = 1;

//録音、再生の位置を先頭に
recPos = 0;
playPos = 0;

playSpeed = 1.0;

}

//————————————————————–
void testApp::update(){
}

//————————————————————–
void testApp::draw(){
ofSetColor(255, 255, 255);

if (mode == 1) {
//録音モードの場合、recordingの表示をして、背景を青に
ofDrawBitmapString("recording", 10, 20);
ofBackground(255, 0, 0);
} else if (mode == 2) {
//再生モードの場合、playingの表示をして、背景を赤に
ofDrawBitmapString("playing", 10, 20);
ofDrawBitmapString("pos = " + ofToString(playSpeed, 3), 10, 40);
ofBackground(0, 0, 255);
}

//画面の幅と録音サンプル数の比率を計算
int ratio = LENGTH / ofGetWidth();

//画面の横幅にあわせて、波形を描画
for (int i = 0; i < LENGTH; i+=ratio){
ofLine(i/ratio,ofGetHeight()/2,i/ratio,ofGetHeight()/2+buffer[i]*100.0f);
}
}

//————————————————————–
//オーディオ入力の処理
void testApp::audioReceived(float * input, int bufferSize, int nChannels){
//もし録音モードだったら
if (mode == 1) {
//バッファされたサンプルの数だけ処理
for (int i = 0; i < bufferSize*nChannels; i++){
//録音位置が設定した最大の長さに逹っしていなければ
if(recPos<LENGTH){
//バッファにサウンド入力を設定
buffer[recPos] = input[i];
//録音位置を進める
recPos++;
}else {
//もし最大位置を越えていたら、最初に戻る(ループ再生)
recPos = 0;
}
}
}
}

//————————————————————–
//オーディオ再生の処理
void testApp::audioRequested(float * output, int bufferSize, int nChannels){
//もし再生モードだったら
if (mode == 2) {
//バッファされたサンプル数だけ処理
for (int i = 0; i < bufferSize*nChannels; i++) {
//再生位置が設定した最大の長さに逹っしていなければ
if(playPos<LENGTH){
//バッファに格納したサウンドを再生
output[i] = buffer[int(playPos)] * audioLevel;
//音程にあわせて、再生位置を移動する
playPos += playSpeed;
} else {
//もし最大位置を越えていたら、最初に戻る(ループ再生)
playPos = 0;
}
}
}
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//画面をから指を離すと、再生モードへ
mode = 2;
playPos = 0;

//音量を設定
audioLevel = (ofGetHeight() – touch.y) / ofGetHeight() * 3.0;
//音程を設定
playSpeed = touch.x / ofGetWidth() * 2.0;
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//音量を設定
audioLevel = (ofGetHeight() – touch.y) / ofGetHeight() * 3.0;
//音程を設定
playSpeed = touch.x / ofGetWidth() * 2.0;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
//画面をタッチすると、録音モードへ
mode = 1;
recPos = 0;
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){

}
[/code]

サンプルファイルのダウンロード

今回の授業で紹介した全てのサンプルは、下記のリンクからダウンロード可能です


openFrameworks for iPhone:時計をつくる

今日の内容

  • iPhoneで時計をつくってみる
  • openFrameworksで、現在の時刻の取得は簡単に実現可能
  • あとは、その数値を使って、いろいろな表現を試す

時刻の取得

  • openFrameworksでは、現在の時間、分、秒を取得する関数が用意されている
  • だたし、この時間はiPhone (シミュレータの場合はMac) の時計を参照しているので、常に正確とは限らない
  • 時刻を取得する関数
    • ofGetHours(); – 「時」を取得 (0〜24)
    • ofGetMinutes(); – 「分」を取得 (0〜60)
    • ofGetSeconds(); – 「秒」を取得 (0〜60)

サンプル1:時刻を表示する

  • まずは簡単に、取得した時刻を文字で表示してみる

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(0,0,0);
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//秒の取得
int s = ofGetSeconds();
//分の取得
int m = ofGetMinutes();
//時の取得
int h = ofGetHours();

//文字で表示する
ofSetColor(255, 255, 255);
string time = ofToString(h, 0) + ":" + ofToString(m, 0) + ":" + ofToString(s, 0);
ofDrawBitmapString(time, 10, 20);
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

サンプル2:デジタル時計

  • フォントを読み込んで、きれいな文字で表示
  • 時、分、秒ともに、値が10以下の時は、左に0を追加して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);
ofTrueTypeFont verdana;

};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(0,0,0);
//フォントを読み込み
verdana.loadFont("verdana.ttf",36, true, true);
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
string s, m, h;
ofSetColor(255, 255, 255);

//秒を読み込み、10以下の場合には左に0づめで2桁に
if (ofGetSeconds()<10) {
s = "0"+ofToString(ofGetSeconds(), 0);
} else {
s = ofToString(ofGetSeconds(), 0);
}
//分を読み込み、10以下の場合には左に0づめで2桁に
if (ofGetMinutes()<10) {
m = "0"+ofToString(ofGetMinutes(), 0);
} else {
m = ofToString(ofGetMinutes(), 0);
}
//時を読み込み、10以下の場合には左に0づめで2桁に
if (ofGetHours()<10) {
h = "0"+ofToString(ofGetHours(), 0);
} else {
h = ofToString(ofGetHours(), 0);
}

//読み込んだフォントで、時刻を表示
string time = h + ":" + m + ":" + s;
verdana.drawString(time, 50, ofGetHeight()/2);
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

サンプル3:アナログ時計(簡易版)

  • 取得した時刻から、アナログ時計を作成する
  • 時針、分針、秒針のそれぞれの角度を求める
  • 時針:12時間で360°変化する。1時間あたりの変化は、360 / 12 = 30°
    • 時刻から時針の角度を求める
    • 現在の時刻(時) x 30
  • 分針:60分で360°変化する。1時間あたりの変化は、360 / 60 = 6°
    • 時刻から分針の角度を求める
    • 現在の時刻(分) x 6
  • 秒針:60秒で360°変化する。1時間あたりの変化は、360 / 60 = 6°
    • 時刻から秒針の角度を求める
    • 現在の時刻(秒) x 6

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(0, 0, 0);
ofEnableSmoothing();
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//時刻を取得
int s = ofGetSeconds();
int m = ofGetMinutes();
int h = ofGetHours()%12;

//時計の大きさを設定
float clockSize = ofGetWidth()/2 – 20;

//背景に円を描く
ofSetColor(255, 255, 255);
ofNoFill();
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);
ofSetLineWidth(3);
ofSetCircleResolution(64);
ofCircle(0, 0, clockSize);

//秒針
ofPushMatrix();
ofRotateZ(s*6.0);
ofSetLineWidth(1);
ofLine(0, 0, 0, -clockSize);
ofPopMatrix();

//分
ofPushMatrix();
ofRotateZ(m*6.0);
ofSetLineWidth(2);
ofLine(0, 0, 0, -clockSize);
ofPopMatrix();

//時針
ofPushMatrix();
ofRotateZ(h*30.0);
ofSetLineWidth(4);
ofLine(0, 0, 0, -clockSize*0.75);
ofPopMatrix();
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

サンプル4:アナログ時計(完成版)

  • 作成したプログラムの表示と実際のアナログ時計と比べてみる
  • なにか違いはないだろうか?
    • 分が切り替わった瞬間の動き
    • 時間が切り替わった瞬間の動き
  • 実際の時計
    • 時針、分針も常にゆっくりと動いている
    • 時刻が変化した瞬間に動くのではなく、ゆっくりと移動して、気がつくと角度が変化している
  • 実際の分針
    • 秒の影響を受けている
    • 毎秒あたり、1/60の影響 (1分 = 60秒なので)
    • m = m + (s/60);
  • 実際の時針
    • 分の影響を受けている
    • 毎分あたり、1/60の影響 (1時間 = 60分なので)
    • h = h + (m/60);
  • 分針と時針の補正をしたアナログ時計に修正する
  • 文字盤を追加
    • 角度を変更しながら、一定間隔に目盛を刻んでいく
    • 小さな目盛:6度づつ
    • 大きな目盛:30度づつ

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(0, 0, 0);
ofEnableSmoothing();
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//時刻を取得
//秒を取得
float s = ofGetSeconds();
//秒の影響を加えた、分の算出
float m = ofGetMinutes() + (s/60.0);
//分の影響を加えた、時の算出
float h = ofGetHours()%12 + (m/60);

//時計の大きさ
float clockSize = ofGetWidth()/2 – 20;

//座標全体を中心に移動
ofTranslate(ofGetWidth()/2, ofGetHeight()/2);

//時計の背景
ofSetColor(127,127,127);
ofFill();

//分の目盛を描く
for (int i=0; i<60; i++) {
ofRotateZ(6);
ofCircle(clockSize, 0, 2);
}

//時の目盛を描く
for (int i=0; i<12; i++) {
ofRotateZ(30);
ofCircle(clockSize, 0, 4);
}

ofSetColor(255, 255, 255);
ofNoFill();

//秒針
ofPushMatrix();
ofRotateZ(s*6.0);
ofSetLineWidth(1);
ofLine(0, 0, 0, -clockSize);
ofPopMatrix();

//分
ofPushMatrix();
ofRotateZ(m*6.0);
ofSetLineWidth(2);
ofLine(0, 0, 0, -clockSize);
ofPopMatrix();

//時針
ofPushMatrix();
ofRotateZ(h*30.0);
ofSetLineWidth(4);
ofLine(0, 0, 0, -clockSize*0.75);
ofPopMatrix();
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

サンプル5:大きさによる時間の表現

  • 時刻の数値をより自由な発想で使用してみる
  • 時、分、秒、ミリ秒の値で半径を変化させながら、円を描いてみる
  • 大きさによる時計

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(0, 0, 0);
ofEnableSmoothing();
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//時刻を取得
int ms = ofGetElapsedTimeMillis() % 1000;
int s = ofGetSeconds();
int m = ofGetMinutes();
int h = ofGetHours();

//円の最大の大きさを設定
float circleSize = ofGetHeight()/8;

ofSetColor(127, 127, 127);
//ミリ秒
ofCircle(ofGetWidth()/2, ofGetHeight()/8*7, ms/1000.0*circleSize);
//秒
ofCircle(ofGetWidth()/2, ofGetHeight()/8*5, s/60.0*circleSize);
//分
ofCircle(ofGetWidth()/2, ofGetHeight()/8*3, m/60.0*circleSize);
//時
ofCircle(ofGetWidth()/2, ofGetHeight()/8, h/24.0*circleSize);}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

サンプル6:位置による時間の表現

  • 時、分、秒、ミリ秒の値で位置を変化させながら、直線を引いてみる

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);

ofTrueTypeFont verdana;
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofBackground(0, 0, 0);
ofEnableSmoothing();
ofSetBackgroundAuto(false);
ofEnableAlphaBlending();

verdana.loadFont("verdana.ttf",12, false, true);
}

//————————————————————–
void testApp::update(){

}

//————————————————————–
void testApp::draw(){
//背景
ofSetColor(0, 0, 0, 15);
ofRect(0, 0, ofGetWidth(), ofGetHeight());

//時刻を取得
int ms = ofGetElapsedTimeMillis() % 1000;
int s = ofGetSeconds();
int m = ofGetMinutes();
int h = ofGetHours();

//枠
ofSetColor(63, 63, 63);
ofSetLineWidth(1);
ofLine(0, ofGetHeight()/4, ofGetWidth(), ofGetHeight()/4);
ofLine(0, ofGetHeight()/2, ofGetWidth(), ofGetHeight()/2);
ofLine(0, ofGetHeight()/4*3, ofGetWidth(), ofGetHeight()/4*3);

//線の位置で時間を表現
ofSetColor(255, 255, 255);
ofSetLineWidth(3);
//ミリ秒
verdana.drawString(ofToString(ms, 0), ms/1000.0*ofGetWidth()+4, ofGetHeight()/8+6);
ofLine(ms/1000.0*ofGetWidth(), 0, ms/1000.0*ofGetWidth(), ofGetHeight()/4);
//秒
verdana.drawString(ofToString(s, 0), s/60.0*ofGetWidth()+4, ofGetHeight()/8*3+6);
ofLine(s/60.0*ofGetWidth(), ofGetHeight()/4, s/60.0*ofGetWidth(), ofGetHeight()/2);
//分
verdana.drawString(ofToString(m, 0), m/60.0*ofGetWidth()+4, ofGetHeight()/8*5+6);
ofLine(m/60.0*ofGetWidth(), ofGetHeight()/2, m/60.0*ofGetWidth(), ofGetHeight()/4*3);
//時
verdana.drawString(ofToString(h, 0), h/24.0*ofGetWidth()+4, ofGetHeight()/8*7+6);
ofLine(h/24.0*ofGetWidth(), ofGetHeight()/4*3, h/24.0*ofGetWidth(), ofGetHeight());
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

サンプルファイルのダウンロード

今日とりあげた全てのサンプルは、下記よりダウンロードすることができます。


openFrameworks for iPhone:MapKitを利用して地図を表示する

今日の内容

  • openFrameworks for iPhoneで、地図を表示する
  • 地図から緯度経度の情報をとりだしたり、地図上に図形を配置してみる
  • iTamabiアプリへ応用できるかも?

ofxiPhoneMapKit

  • ofxiPhoneMapKit – openFrameworksでMapKitを利用できるようにしたAddon
  • MapKitは、iPhone OS 3.0から追加された、地図の表示を扱う事ができるフレームワーク
  • MapKitを利用することで、iPhoneに付属の「マップ」アプリと同等の地図を利用することができる
  • ofxiPhoneMapKitは、最新のopenFrameworksのiPhone版であれば、既に利用できる形でインストールされている

ofxiPhoneMapKit の使用方法

  • ofxiPhoneMapKitクラスをインスタンス化する
  • あとは、そのインスタンスに様々なメソッド(関数、動作)を指定するだけで、地図に関する機能を付加していくことができる

opxiPhoneMapKit で使用可能なメソッド

  • open() – 地図を開く
  • close() – 地図を閉じる
  • void setCenter(double latitude, double longitude, bool animated = true); – 地図の中心位置を指定した緯度経度に移動する
  • void setSpan(double latitudeDelta, double longitudeDelta, bool animated = true); – 地図の表示範囲を角度で指定
  • void setSpanWithMeters(double metersLatitude, double metersLongitude, bool animated = true); – 地図の表示範囲を距離(メートル)で指定
  • void setRegion(double latitude, double longitude, double latitudeDelta, double longitudeDelta, bool animated = true); – 地図の中心位置の緯度経度と、表示範囲の角度を同時に指定
  • void setRegionWithMeters(double latitude, double longitude, double metersLatitude, double metersLongitude, bool animated = true); – 地図の中心位置の緯度経度と、表示範囲の距離を同時に指定
  • void setType(ofxiPhoneMapKitType type = OFXIPHONE_MAPKIT_MAP); – 地図の表示方法を指定する
    • 通常の地図:OFXIPHONE_MAPKIT_MAP
    • 衛星画像:OFXIPHONE_MAPKIT_SATELLITE
    • ハイブリット:OFXIPHONE_MAPKIT_HYRBID
  • void setShowUserLocation(bool b); – ユーザの位置を青い点で表示する
  • void setAllowUserInteraction(bool b); – 地図とのインタラクションの有効/無効の設定、有効にするとiPhoneのtouchイベント(testApp::touchXXXX)が無視される
  • void setAllowZoom(bool b); – ズームの有効/無効
  • void setAllowScroll(bool b); – 地図の移動の有効/無効
  • bool isUserOnScreen(); – ユーザの位置の表示がされているかどうかを調べる
  • ofxMapKitLocation getCenterLocation(); – 現在表示している地図の位置(緯度、経度)を調べる
  • ofPoint getScreenCoordinatesForLocation(double latitude, double longitude); – 地図上の位置(緯度、経度)を、画面の座標(ピクセル)に変換
  • ofxMapKitLocation getLocationForScreenCoordinates(float x, float y); – 画面の座標(ピクセル)を、地図上の位置(緯度、経度)に変換
  • ofRectangle getScreenRectForRegion(double latitude, double latitudeDelta, double longitudeDelta); – 地図上の位置(緯度、経度)と角度(°)から、四角形の領域を生成
  • ofRectangle getScreenRectForRegionWithMeters(double latitude, double longitude, double metersLatitude, double metersLongitude); – 地図上の位置(緯度、経度)と距離(メートル)から、四角形の領域を生成
  • bool isOpen(); – 現在地図が表示されているかどうかを調べる

ステップ1:地図を表示する

  • まず、ofxiPhoneMapkitを使用して、地図を表示してみる

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp, ofxiPhoneMapKitListener {

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);

//ofxiPhoneMapKitをインスタンス化
//すべての地図に関する命令は、このオブジェクトを使用する
ofxiPhoneMapKit mapKit;

//地図に関するイベント
void regionWillChange(bool animated);
void regionDidChange(bool animated);
void willStartLoadingMap();
void didFinishLoadingMap();
void errorLoadingMap(string errorDescription);
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//表示する緯度と経度を定義(多摩美の場所)
#define LATITUDE 35.61129013687765
#define LONGITUDE 139.34929847717285

//————————————————————–
void testApp::setup(){
//iPhoneの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofSetLogLevel(OF_LOG_VERBOSE);
ofEnableAlphaBlending();

//load font for displaying info
//font.loadFont("verdana.ttf", 12);

//MapViewを開く
mapKit.open();

//最初に表示する位置と、拡大率(200m x 200m)を設定
mapKit.setRegionWithMeters(LATITUDE, LONGITUDE, 200, 200);

//マップに関するイベントのリスナーを追加する
mapKit.addListener(this);

//ユーザの現在位置を表示(青い点で表示される)
mapKit.setShowUserLocation(true);

//マップの表示形式を設定
//通常の地図:OFXIPHONE_MAPKIT_MAP
//衛星画像:OFXIPHONE_MAPKIT_SATELLITE
//ハイブリット:OFXIPHONE_MAPKIT_HYRBID
mapKit.setType(OFXIPHONE_MAPKIT_MAP);
}

//————————————————————–
void testApp::update() {
}

//————————————————————–
void testApp::draw() {
}

void testApp::regionWillChange(bool animated) {
}

void testApp::regionDidChange(bool animated) {
}

void testApp::willStartLoadingMap() {
}

void testApp::didFinishLoadingMap() {
}

void testApp::errorLoadingMap(string errorDescription) {
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}

//————————————————————–
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]

ステップ2:地図の中心の緯度経度を表示する

  • 地図の中心位置の緯度と経度を取得し、地図に重ねて表示する

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp, ofxiPhoneMapKitListener {

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);

//ofxiPhoneMapKitのインスタンス
//すべての地図に関する命令は、このオブジェクトを使用する
ofxiPhoneMapKit mapKit;

//ログ出力用文字列
string log;

//地図に関するイベント
void regionWillChange(bool animated);
void regionDidChange(bool animated);
void willStartLoadingMap();
void didFinishLoadingMap();
void errorLoadingMap(string errorDescription);
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//表示する緯度と経度を定義(多摩美の場所)
#define LATITUDE 35.61129013687765
#define LONGITUDE 139.34929847717285

//————————————————————–
void testApp::setup(){
//iPhoneの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofSetLogLevel(OF_LOG_VERBOSE);
ofEnableAlphaBlending();

//load font for displaying info
//font.loadFont("verdana.ttf", 12);

//MapViewを開く
mapKit.open();

//最初に表示する位置と、拡大率(1000km x 1000km)を設定
mapKit.setRegionWithMeters(LATITUDE, LONGITUDE, 200, 200);

//マップに関するイベントのリスナーを追加する
mapKit.addListener(this);

//ユーザの現在位置を表示(青い点で表示される)
mapKit.setShowUserLocation(true);

//マップの表示形式を設定
//通常の地図:OFXIPHONE_MAPKIT_MAP
//衛星画像:OFXIPHONE_MAPKIT_SATELLITE
//ハイブリット:OFXIPHONE_MAPKIT_HYRBID
mapKit.setType(OFXIPHONE_MAPKIT_MAP);

//OpenGLの表示を前面に
ofxiPhoneSendGLViewToFront();
//OpenGLの透明度を有効に
ofxiPhoneSetGLViewTransparent(true);
//OpenGLの表示部分のインタラクションを無しに
ofxiPhoneSetGLViewUserInteraction(false);
}

//————————————————————–
void testApp::update() {
if(mapKit.isOpen()) {
//現在の中心の緯度と経度を表示
ofxMapKitLocation centerLocation = mapKit.getCenterLocation();
log = "latitude:"+ofToString(centerLocation.latitude,5)+", longitude:"+ofToString(centerLocation.longitude,5);
}
}

//————————————————————–
void testApp::draw() {
if(mapKit.isOpen()) {
ofFill();
ofSetColor(0, 0, 0, 200);
ofRect(0, 0, ofGetWidth(), 20);
ofSetColor(255, 255, 255);
ofDrawBitmapString(log, 10, 10);

//中心位置に円を表示
ofNoFill();
ofSetLineWidth(2);
ofSetColor(255, 0, 0);
ofCircle(ofGetWidth()/2, ofGetHeight()/2, 5);
}
}

void testApp::regionWillChange(bool animated) {

}

void testApp::regionDidChange(bool animated) {

}

void testApp::willStartLoadingMap() {

}

void testApp::didFinishLoadingMap() {

}

void testApp::errorLoadingMap(string errorDescription) {

}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}

//————————————————————–
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]

ステップ3:地図上に図形を配置する

  • 緯度と経度を指定して、地図の上に図形を描いて配置していく
  • 地図を拡大/縮小したり、位置を移動しても、地図上の点の位置がずれていないところに注目

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhoneExtras.h"

class testApp : public ofxiPhoneApp, ofxiPhoneMapKitListener {

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);

//ofxiPhoneMapKitのインスタンス
//すべての地図に関する命令は、このオブジェクトを使用する
ofxiPhoneMapKit mapKit;

//ログ出力用文字列
string log;

//緯度、経度で位置を指定するための配列
ofxMapKitLocation mapLoc[9];

//地図に関するイベント
void regionWillChange(bool animated);
void regionDidChange(bool animated);
void willStartLoadingMap();
void didFinishLoadingMap();
void errorLoadingMap(string errorDescription);
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//表示する緯度と経度を定義(多摩美の場所)
#define LATITUDE 35.61127
#define LONGITUDE 139.34983

//————————————————————–
void testApp::setup(){
//iPhoneの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofSetLogLevel(OF_LOG_VERBOSE);
ofEnableAlphaBlending();

//緯度、経度で位置を指定
mapLoc[0].latitude = 35.61045;
mapLoc[0].longitude = 139.35108;

mapLoc[1].latitude = 35.61090;
mapLoc[1].longitude = 139.35029;

mapLoc[2].latitude = 35.61124;
mapLoc[2].longitude = 139.34923;

mapLoc[3].latitude = 35.61139;
mapLoc[3].longitude = 139.35041;

mapLoc[4].latitude = 35.61207;
mapLoc[4].longitude = 139.35048;

mapLoc[5].latitude = 35.61185;
mapLoc[5].longitude = 139.34979;

mapLoc[6].latitude = 35.61153;
mapLoc[6].longitude = 139.35120;

mapLoc[7].latitude = 35.61222;
mapLoc[7].longitude = 139.34878;

mapLoc[8].latitude = 35.61150;
mapLoc[8].longitude = 139.34828;

//MapViewを開く
mapKit.open();

//最初に表示する位置と、拡大率(300m x 300m)を設定
mapKit.setRegionWithMeters(LATITUDE, LONGITUDE, 300, 300);

//マップに関するイベントのリスナーを追加する
mapKit.addListener(this);

//ユーザの現在位置を表示(青い点で表示される)
mapKit.setShowUserLocation(true);

//マップの表示形式を設定
//通常の地図:OFXIPHONE_MAPKIT_MAP
//衛星画像:OFXIPHONE_MAPKIT_SATELLITE
//ハイブリット:OFXIPHONE_MAPKIT_HYRBID
mapKit.setType(OFXIPHONE_MAPKIT_MAP);

//OpenGLの表示を前面に
ofxiPhoneSendGLViewToFront();
//OpenGLの透明度を有効に
ofxiPhoneSetGLViewTransparent(true);
//OpenGLの表示部分のインタラクションを無しに
ofxiPhoneSetGLViewUserInteraction(false);
}

//————————————————————–
void testApp::update() {
if(mapKit.isOpen()) {
//現在の中心の緯度と経度を表示
ofxMapKitLocation centerLocation = mapKit.getCenterLocation();
log = "latitude:"+ofToString(centerLocation.latitude,5)+", longitude:"+ofToString(centerLocation.longitude,5);
}
}

//————————————————————–
void testApp::draw() {
if(mapKit.isOpen()) {
ofFill();
ofSetColor(0, 0, 0, 200);
ofRect(0, 0, ofGetWidth(), 20);
ofSetColor(255, 255, 255);
ofDrawBitmapString(log, 10, 10);

//中心位置に赤い円を表示
ofNoFill();
ofSetLineWidth(2);
ofSetColor(255, 0, 0);
ofCircle(ofGetWidth()/2, ofGetHeight()/2, 5);

//位置を指定した場所に青い円を表示
ofFill();
ofSetColor(0, 0, 255);
for (int i=0; i<9; i++) {
ofPoint loc = mapKit.getScreenCoordinatesForLocation(mapLoc[i].latitude, mapLoc[i].longitude);
ofCircle(loc.x, loc.y, 5);
}
}
}

void testApp::regionWillChange(bool animated) {

}

void testApp::regionDidChange(bool animated) {

}

void testApp::willStartLoadingMap() {

}

void testApp::didFinishLoadingMap() {

}

void testApp::errorLoadingMap(string errorDescription) {

}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
}

//————————————————————–
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]

サンプルファイルのダウンロード

今日の授業の全てのサンプルファイルは、以下のリンクよりダウンロードしてください


openFrameworks for iPhone:Addonをつかう


Addonについて

Addonとは

openFramewokrs v0.0061 for iPhone FAT版にインストールされているAddon

  • 他のプラットフォーム(Mac/Win/Linux)と共通のもの
    • ofxDirList – ディレクトリの項目の一覧を生成
    • ofxVectorGraphics – OpenFrameworksからPostscriptを生成し出力する
    • ofxVectorMath – ベクトルや、座標、行列の計算を行う
    • ofxXmlSettings – アプリケーションの設定をXML形式で保存、読込み
  • iPhone版固有のAddon
    • ofxiPhone – openFrameworksをiPhoneで作動させるためのコアな機能
    • ofxAccelerometer – iPhone/iPad版固有のAddon、iPhone/iPadの加速度センサーの値を取得
    • ofxMultiTouch – マルチタッチのインタフェイスを使用するための機能

Addonの追加方法

  • Addonは、フォルダ内のソース(src)、またもし存在すればライブラリ(libs)フォルダをプロジェクトに追加する
  • まず、Addonのフォルダごとプロジェクトに追加した後で、余計なものを取り除く(examples, install.xmlなど)
  • 複数のAddonが存在する際などは、プロジェクト内に「Addons」というグループを作成し、その中に追加していくとわかりやすい

Addonを使ってみる

物理シミュレーション – ofxBox2D

Box2Dとは

  • C++で書かれた、物理エンジン
  • 重力や反発力、摩擦、衝突判定といった物理計算を複雑な計算をすることなく利用できる
  • ActionScript、Java、C#、Pythonなどにも移植されている

ダウンロードとインストール

ofxBox2dをプロジェクトに追加

  • XCodeで「ファイル」→「新規プロジェクト」を選択して新規プロジェクトを作成
  • XCode画面の左側のコラム「グループとファイル」の欄の一番先頭にあるプロジェクト名の表示されたアイコンをコントロール+クリック、もしくは右クリック – 「追加」→「新規グループ」を選択
  • 追加されたグループのフォルダに「addons」という名前をつける
  • addonsフォルダをコントロール+クリック、もしくは右クリック – 「追加」→「既存のファイル」を選択
  • addonsフォルダから「ofxBox2d」フォルダを選択
  • 設定画面の設定はそのままで「追加」をクリック
  • ofxBox2dフォルダ内の「example」はフォルダごと削除して、「参照を削除」を選択


ofxBox2dフォルダの追加


アドオン追加の設定画面


余計なファイルは削除する

サンプルテンプレートをダウンロード

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
#include "ofxBox2d.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);

ofxBox2d box2d; //Box2Dのインスタンス
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone、iPadの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

ofBackground(0,0,0);

//Box2Dの基本設定
box2d.init(); //初期化
box2d.registerGrabbing(); //物体をつかめるように設定
box2d.setGravity(0, 1); //重力の設定(下方向に1)
box2d.createBounds(0, 0, ofGetWidth(), ofGetHeight()); //枠を追加
box2d.setFPS(15.0); //Box2Dの演算の更新頻度を設定
box2d.setIterations(5, 5); //インタラクションの精度を設定
}

//————————————————————–
void testApp::update(){
box2d.update(); //Box2Dの物理演算を実行
}

//————————————————————–
void testApp::draw(){

}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]

物理世界に物体を置いてみる

  • ofxBox2dCircle – 円形の物理法則を適用可能な物体
  • 生成した円は、vector(動的配列)に格納して管理してみる – circles
  • 画面をタッチすると、その座標をとりだして、円(ofxBox2dCircle)を生成し、vector circlesに追加する
  • testApp.mmのdrawメソッド内で、circlesに格納された全ての円(ofxBox2dCircle)を描画している


実行結果

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
#include "ofxBox2d.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);

ofxBox2d box2d; //Box2Dのインスタンス
vector <ofxBox2dCircle> circles; //円形の物体のインスタンス
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone、iPadの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

ofBackground(0,0,0);

//Box2Dの基本設定
box2d.init(); //初期化
box2d.registerGrabbing(); //物体をつかめるように設定
box2d.setGravity(0, 1); //重力の設定(下方向に1)
box2d.createBounds(0, 0, ofGetWidth(), ofGetHeight()); //枠を追加
box2d.setFPS(15.0); //Box2Dの演算の更新頻度を設定
box2d.setIterations(5, 5); //インタラクションの精度を設定
}

//————————————————————–
void testApp::update(){
box2d.update(); //Box2Dの物理演算を実行
}

//————————————————————–
void testApp::draw(){
//描画した円(ofxBox2dCircle)の数だけ、円を描画する
for(int i=0; i<circles.size(); i++) {
circles[i].draw();
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//画面をタッチすると新たに円(ofxBox2dCircle)を追加する
ofPoint pos; //タッチした座標を格納するための変数
pos.set(touch.x, touch.y); //タッチした場所を取得
ofxBox2dCircle c; //新規にofxBox2dCircleをインスタンス化
c.setPhysics(1.0, 0.8, 0.3); //物理特性を設定
//Box2Dの世界に追加
c.setup(box2d.getWorld(),
pos.x,
pos.y,
ofRandom(10, 30));
circles.push_back(c); //Vector、circlesに作成した円を追加
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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 / iPadの加速度センサーで、重力の向きと大きさを変化させる

– testApp.mm のupdateメソッドの中に、加速度センサーの値を参照するコードを追加する


実行結果 (iPhone)


iPadでの実行結果

testApp.h
[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"
#include "ofxBox2d.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);

ofxBox2d box2d; //Box2Dのインスタンス
vector <ofxBox2dCircle> circles; //円形の物体のインスタンス
};
[/code]

testApp.mm
[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
//iPhone、iPadの基本設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);

ofBackground(0,0,0);

//Box2Dの基本設定
box2d.init(); //初期化
box2d.registerGrabbing(); //物体をつかめるように設定
box2d.setGravity(0, 1); //重力の設定(下方向に1)
box2d.createBounds(0, 0, ofGetWidth(), ofGetHeight()); //枠を追加
box2d.setFPS(15.0); //Box2Dの演算の更新頻度を設定
box2d.setIterations(5, 5); //インタラクションの精度を設定
}

//————————————————————–
void testApp::update(){
box2d.update(); //Box2Dの物理演算を実行

//加速度センサーで重力を設定
ofPoint gravity = ofxAccelerometer.getForce();
gravity *= 5.0;
gravity.y *= -1.0;
box2d.setGravity(gravity);
}

//————————————————————–
void testApp::draw(){
//描画した円(ofxBox2dCircle)の数だけ、円を描画する
for(int i=0; i<circles.size(); i++) {
circles[i].draw();
}
}

//————————————————————–
void testApp::exit(){

}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){
//画面をタッチすると新たに円(ofxBox2dCircle)を追加する
ofPoint pos; //タッチした座標を格納するための変数
pos.set(touch.x, touch.y); //タッチした場所を取得
ofxBox2dCircle c; //新規にofxBox2dCircleをインスタンス化
c.setPhysics(1.0, 0.8, 0.3); //物理特性を設定
//Box2Dの世界に追加
c.setup(box2d.getWorld(),
pos.x,
pos.y,
ofRandom(10, 30));
circles.push_back(c); //Vector、circlesに作成した円を追加
}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
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]


openFrameworks + iPhoneで、オリジナルのカメラアプリを作る

今日の目標 – オリジナルのカメラアプリを作成する

  • iPhoneのカメラを使用して、オリジナルのカメラアプリを作成してみる
  • openFramworks for iPhoneを使用すると、簡単に内蔵カメラの画像を使用できる
  • 内蔵カメラから画像イメージを取得するには、ofxiPhoneImagePicker アドオンを使用する

カメラアプリ1:写真を撮影する

  • 内蔵カメラで写真を撮影し、撮影した写真を画像(ofImage)にコピーして表示する
  • 以降のカメラアプリの基本となる機能

testApp.h

[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//シミュレータを使用する際には、コメントアウトを外す
//#define _USE_SIMULATOR

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);

//カメラの画像を一時的に格納する領域
unsigned char * cameraPixels;
//カメラを使用するためのアドオン
ofxiPhoneImagePicker * camera;
//撮影した画像データ
ofImage photo;
//現在の状態を格納
//0:撮影待ち, 1:画像処理, 2:処理終了(待機)
int status;

};
[/code]

testApp.mm

[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
// iPhone用初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofEnableSmoothing();
ofSetCircleResolution(64);
ofEnableAlphaBlending();

//カメラ初期設定
cameraPixels = NULL;
camera = new ofxiPhoneImagePicker();
camera->setMaxDimension(480);

status = 0;
}

//————————————————————–
void testApp::update()
{
#ifndef _USE_SIMULATOR
//実機使用の場合
if(camera->imageUpdated){
//カメラのメモリ領域を確保
if (cameraPixels == NULL){
cameraPixels = new unsigned char [camera->width * camera->height*4];
}

//カメラの画像のままだと上下反転してるので、イメージの上下を反転
for (int i = 0; i < camera->height; i++){
memcpy(cameraPixels+(camera->height-i-1)*camera->width*4, camera->pixels+i*camera->width*4, camera->width*4);
}

//カメラから取得したイメージを、処理用のofImage(photo)にコピーする
photo.setFromPixels(cameraPixels, camera->width, camera->height, OF_IMAGE_COLOR_ALPHA);
camera->imageUpdated = false;
status = 1;
}
#endif
}

//————————————————————–
void testApp::draw()
{
if (status == 0) {
//撮影を促す画面を表示
ofSetColor(255, 255, 255);
ofDrawBitmapString("Double tap on the screen!!", 40, ofGetHeight()/2-5);
}

if(status == 1){
//撮影した画像を表示
photo.draw(0, 0);
}
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
#ifdef _USE_SIMULATOR
//シミュレータ使用の場合:画像をロード
photo.loadImage("images/photo.png");
photo.setImageType(OF_IMAGE_COLOR_ALPHA);
status = 1;
#else
//実機使用の場合:写真を新規に撮影
camera->openCamera();
#endif
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]


写真撮影を促す画面


カメラから取得された画像

カメラアプリ2:モザイクカメラ

  • 撮影した写真をモザイク状に加工する
  • 撮影した写真のピクセル情報を一定間隔でとりだして、取得したRGB情報をもとに四角形を描いている
  • 写真画像ののピクセル情報は、getPixel() 関数を用いて取り出している
  • 写真のイメージは、1ピクセルごとにRGBA(Red, Green, Blue, Alpha)の4つの情報が含まれている
  • ピクセルをスキャンしていく際には、4ピクセルを1単位として扱うように留意する

testApp.h

[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//シミュレータを使用する際には、コメントアウトを外す
//#define _USE_SIMULATOR

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);

//カメラの画像を一時的に格納する領域
unsigned char * cameraPixels;
//カメラを使用するためのアドオン
ofxiPhoneImagePicker * camera;
//撮影した画像データ
ofImage photo;
//現在の状態を格納、0:撮影待ち, 1:画像処理, 2:処理終了(待機)
int status;
};
[/code]

testApp.mm

[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
// iPhone用初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofEnableSmoothing();
ofSetCircleResolution(64);
ofEnableAlphaBlending();

//カメラ初期設定
cameraPixels = NULL;
camera = new ofxiPhoneImagePicker();
camera->setMaxDimension(480);

status = 0;
}

//————————————————————–
void testApp::update()
{
#ifndef _USE_SIMULATOR
//実機使用の場合
if(camera->imageUpdated){
//カメラのメモリ領域を確保
if (cameraPixels == NULL){
cameraPixels = new unsigned char [camera->width * camera->height*4];
}

//カメラの画像のままだと上下反転してるので、イメージの上下を反転
for (int i = 0; i < camera->height; i++){
memcpy(cameraPixels+(camera->height-i-1)*camera->width*4, camera->pixels+i*camera->width*4, camera->width*4);
}

//カメラから取得したイメージを、処理用のofImage(photo)にコピーする
photo.setFromPixels(cameraPixels, camera->width, camera->height, OF_IMAGE_COLOR_ALPHA);
camera->imageUpdated = false;
status = 1;
}
#endif
}

//————————————————————–
void testApp::draw()
{
if (status == 0) {
//撮影を促す画面を表示
ofSetColor(255, 255, 255);
ofDrawBitmapString("Double tap on the screen!!", 40, ofGetHeight()/2-5);
}

if(status == 1){
//撮影した画像を表示
photo.draw(0, 0);

//画像データのビットマップ情報を配列に格納
unsigned char * pixels = photo.getPixels();

//画像の幅と高さを所得
int w = photo.width;
int h = photo.height;

//スキャンする間隔
int skip = 20;

//モザイク化:等間隔にピクセルの色を検知し、四角形を描く
for (int j = 0; j < h; j+=skip){
for (int i = 0; i < w; i+=skip){
int valueR = pixels[j*4*w + i*4];
int valueG = pixels[j*4*w + i*4+1];
int valueB = pixels[j*4*w + i*4+2];
ofSetColor(valueR,valueG,valueB);
ofRect(i, j, skip, skip);
}
}
}
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
#ifdef _USE_SIMULATOR
//シミュレータ使用の場合:画像をロード
photo.loadImage("images/photo.png");
photo.setImageType(OF_IMAGE_COLOR_ALPHA);
status = 1;
#else
//実機使用の場合:写真を新規に撮影
camera->openCamera();
#endif
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]


モザイク化されたイメージ

カメラアプリ3:スキャンカメラ

  • モザイクの応用
  • ある高さ(Y座標)のピクセル情報のみとりだす
  • 全てのX座標のRGBAの値を取得して、縦に拡げてバーコード状に表示する
  • 取得する高さは、画面をタッチして変更できるようにする
  • 写真を指定したラインでスキャンするような効果を得ることができる

testApp.h

[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//シミュレータを使用する際には、コメントアウトを外す
//#define _USE_SIMULATOR

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);

//カメラの画像を一時的に格納する領域
unsigned char * cameraPixels;
//カメラを使用するためのアドオン
ofxiPhoneImagePicker * camera;
//撮影した画像データ
ofImage photo;
//現在の状態を格納、0:撮影待ち, 1:画像処理, 2:処理終了(待機)
int status;
//イメージをスキャンするY座標
int scanHeight;
};
[/code]

testApp.mm

[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
// iPhone用初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofEnableSmoothing();
ofSetCircleResolution(64);
ofEnableAlphaBlending();

//カメラ初期設定
cameraPixels = NULL;
camera = new ofxiPhoneImagePicker();
camera->setMaxDimension(480);

status = 0;
scanHeight = 0;
}

//————————————————————–
void testApp::update()
{
#ifndef _USE_SIMULATOR
//実機使用の場合
if(camera->imageUpdated){
//カメラのメモリ領域を確保
if (cameraPixels == NULL){
cameraPixels = new unsigned char [camera->width * camera->height*4];
}

//カメラの画像のままだと上下反転してるので、イメージの上下を反転
for (int i = 0; i < camera->height; i++){
memcpy(cameraPixels+(camera->height-i-1)*camera->width*4, camera->pixels+i*camera->width*4, camera->width*4);
}

//カメラから取得したイメージを、処理用のofImage(photo)にコピーする
photo.setFromPixels(cameraPixels, camera->width, camera->height, OF_IMAGE_COLOR_ALPHA);
camera->imageUpdated = false;
status = 1;
}
#endif
}

//————————————————————–
void testApp::draw()
{
if (status == 0) {
//撮影を促す画面を表示
ofSetColor(255, 255, 255);
ofDrawBitmapString("Double tap on the screen!!", 40, ofGetHeight()/2-5);
}

if(status == 1){
//撮影した画像を表示
photo.draw(0, 0);

//画像データのビットマップ情報を配列に格納
unsigned char * pixels = photo.getPixels();

//画像の幅と高さを所得
int w = photo.width;
int h = photo.height;

//モザイク化:等間隔にピクセルの色を検知し、四角形を描く
for (int i = 0; i < w; i++){
int valueR = pixels[scanHeight*4*w + i*4];
int valueG = pixels[scanHeight*4*w + i*4+1];
int valueB = pixels[scanHeight*4*w + i*4+2];
ofSetColor(valueR,valueG,valueB);
ofRect(i, 0, 1, h);
}

//今スキャンしている場所を表示
ofSetColor(255, 255, 255);
ofLine(0, scanHeight, ofGetWidth(), scanHeight);
}
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){
//画面をドラッグした場所で、スキャンする高さを決定
scanHeight = touch.y;
}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
#ifdef _USE_SIMULATOR
//シミュレータ使用の場合:画像をロード
photo.loadImage("images/photo.png");
photo.setImageType(OF_IMAGE_COLOR_ALPHA);
status = 1;
#else
//実機使用の場合:写真を新規に撮影
camera->openCamera();
#endif
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]


写真をスキャン

カメラアプリ4:ピクセレイトカメラ(グレイスケール版)

  • 写真イメージのピクセル情報を解析
  • 一定間隔ごとに写真のRGB別のレベル(明るさ)を取得して、その平均値をとる
  • その値で半径を変化させながら円を描いていく
  • モノクロで写真を印刷したようなドットによる濃淡の表現になる

testApp.h

[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//シミュレータを使用する際には、コメントアウトを外す
//#define _USE_SIMULATOR

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);

//カメラの画像を一時的に格納する領域
unsigned char * cameraPixels;
//カメラを使用するためのアドオン
ofxiPhoneImagePicker * camera;
//撮影した画像データ
ofImage photo;
//現在の状態を格納、0:撮影待ち, 1:画像処理, 2:処理終了(待機)
int status;
};
[/code]

testApp.mm

[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
// iPhone用初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofEnableSmoothing();
ofSetCircleResolution(64);
ofEnableAlphaBlending();

//カメラ初期設定
cameraPixels = NULL;
camera = new ofxiPhoneImagePicker();
camera->setMaxDimension(480);

status = 0;
}

//————————————————————–
void testApp::update()
{
#ifndef _USE_SIMULATOR
//実機使用の場合
if(camera->imageUpdated){
//カメラのメモリ領域を確保
if (cameraPixels == NULL){
cameraPixels = new unsigned char [camera->width * camera->height*4];
}

//イメージの上下を反転
for (int i = 0; i < camera->height; i++){
memcpy(cameraPixels+(camera->height-i-1)*camera->width*4, camera->pixels+i*camera->width*4, camera->width*4);
}

//カメラから取得したイメージを、処理用のofImage(photo)にコピーする
photo.setFromPixels(cameraPixels, camera->width, camera->height, OF_IMAGE_COLOR_ALPHA);
camera->imageUpdated = false;
status = 1;
}
#endif
}

//————————————————————–
void testApp::draw()
{
if (status == 0) {
//撮影を促す画面を表示
ofSetColor(255, 255, 255);
ofDrawBitmapString("Double tap on the screen!!", 40, ofGetHeight()/2-5);
}

if(status == 1){
//画像データのビットマップ情報を配列に格納
unsigned char * pixels = photo.getPixels();

//画像の幅と高さを所得
int w = photo.width;
int h = photo.height;

//ピクセレイトの半径を設定
int r = 12;

//画像を等間隔にスキャン
for (int j = 0; j < h; j+=r){
for (int i = 0; i < w; i+=r){
//ピクセルのRGBの値を取得
//RGBAの順番で並んでいるので、4ピクセルずつ
int valueR = pixels[j*4*w + i*4];
int valueG = pixels[j*4*w + i*4+1];
int valueB = pixels[j*4*w + i*4+2];

//RGBの値の平均値を算出
float value = r*(valueR+valueG+valueB)/2.0/255.0;

//取得したRGB値をもとに、円を描画
//取得したピクセルの明るさを、円の半径に対応させている
ofSetColor(255,255,255,100);
ofCircle(i, j, value);
}
}
}
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){
}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
#ifdef _USE_SIMULATOR
//シミュレータ使用の場合:画像をロード
photo.loadImage("images/photo.png");
photo.setImageType(OF_IMAGE_COLOR_ALPHA);
status = 1;
#else
//実機使用の場合:写真を新規に撮影
camera->openCamera();
#endif
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]


グレースケールでのピクセレイト

カメラアプリ5:ピクセレイトカメラ(カラー版)

  • ピクセレイトのカラー版
  • RGB別々に円を描いて、重ねていく
  • 描画する際の色の合成を、加算合成に変更するところがポイント
  • OpenGLの命令を直接使用する – glEnable(GL_BLEND); と glBlendFunc(GL_SRC_ALPHA, GL_ONE); で実現可能
  • カラー写真を印刷したようなドットによる濃淡の表現になる

testApp.h

[code language=”cpp”]
#pragma once

#include "ofMain.h"
#include "ofxiPhone.h"
#include "ofxiPhoneExtras.h"

//シミュレータを使用する際には、コメントアウトを外す
//#define _USE_SIMULATOR

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);

//カメラの画像を一時的に格納する領域
unsigned char * cameraPixels;
//カメラを使用するためのアドオン
ofxiPhoneImagePicker * camera;
//撮影した画像データ
ofImage photo;
//現在の状態を格納、0:撮影待ち, 1:画像処理, 2:処理終了(待機)
int status;
};
[/code]

testApp.mm

[code language=”cpp”]
#include "testApp.h"

//————————————————————–
void testApp::setup(){
// iPhone用初期設定
ofRegisterTouchEvents(this);
ofxAccelerometer.setup();
ofxiPhoneAlerts.addListener(this);
ofEnableSmoothing();
ofSetCircleResolution(64);

//カメラ初期設定
cameraPixels = NULL;
camera = new ofxiPhoneImagePicker();
camera->setMaxDimension(480);

status = 0;
}

//————————————————————–
void testApp::update()
{
#ifndef _USE_SIMULATOR
if(camera->imageUpdated){
//カメラのメモリ領域を確保
if (cameraPixels == NULL){
cameraPixels = new unsigned char [camera->width * camera->height*4];
}

//イメージの上下を反転
for (int i = 0; i < camera->height; i++){
memcpy(cameraPixels+(camera->height-i-1)*camera->width*4, camera->pixels+i*camera->width*4, camera->width*4);
}

//カメラから取得したイメージを、処理用のofImage(photo)にコピーする
photo.setFromPixels(cameraPixels, camera->width, camera->height, OF_IMAGE_COLOR_ALPHA);
camera->imageUpdated = false;
status = 1;
}
#endif
}

//————————————————————–
void testApp::draw()
{
if (status == 0) {
//撮影を促す画面を表示
ofSetColor(255, 255, 255);
ofDrawBitmapString("Double tap on the screen!!", 40, ofGetHeight()/2-5);
}

if(status == 1){
//背景の更新を終了
ofSetBackgroundAuto(false);
//画面の描画を加算合成に
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);

//画像データのビットマップ情報を配列に格納
unsigned char * pixels = photo.getPixels();

//画像の幅と高さを所得
int w = photo.width;
int h = photo.height;

//ピクセレイトの半径を設定
int r = 12;

//画像を8ピクセル間隔でスキャン
for (int j = 0; j < h; j+=r){
for (int i = 0; i < w; i+=r){

//ピクセルのRGBの値を取得
int valueR = pixels[j*4*w + i*4];
int valueG = pixels[j*4*w + i*4+1];
int valueB = pixels[j*4*w + i*4+2];

//取得したRGB値をもとに、円を描画
//取得したピクセルの明るさを、円の半径に対応させている
ofSetColor(255, 0, 0, 63);
ofCircle(i, j, r*valueR/255.0*2.0);
ofSetColor(0, 255, 0, 63);
ofCircle(i, j, r*valueG/255.0*2.0);
ofSetColor(0, 0, 255, 63);
ofCircle(i, j, r*valueB/255.0*2.0);
}
}

//ステイタスを変更し、描画は1度だけに
status = 2;
}
}

//————————————————————–
void testApp::exit() {
}

//————————————————————–
void testApp::touchDown(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchMoved(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchUp(ofTouchEventArgs &touch){

}

//————————————————————–
void testApp::touchDoubleTap(ofTouchEventArgs &touch){
#ifdef _USE_SIMULATOR
//シミュレータ使用の場合:画像をロード
photo.loadImage("images/photo.png");
photo.setImageType(OF_IMAGE_COLOR_ALPHA);
status = 1;
#else
//実機使用の場合:写真を新規に撮影
camera->openCamera();
#endif
}

//————————————————————–
void testApp::lostFocus() {
}

//————————————————————–
void testApp::gotFocus() {
}

//————————————————————–
void testApp::gotMemoryWarning() {
}

//————————————————————–
void testApp::deviceOrientationChanged(int newOrientation){
}
[/code]


カラーでのピクセレイト

サンプルファイルのダウンロード

今回の授業でとりあげた全てのサンプルは下記よりダウンロードすることが可能です。


openFrameworks + iPhone マルチタッチイベントの取得、音アプリを作る

サンプルファイルのダウンロード

サンプルファイルは以下のリンクよりダウンロードしてください。

マルチタッチイベントの取得

マルチタッチの情報が取得できるイベント

定義 機能
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を使うと、こうした「音のおもちゃ」が簡単に作れる!!


Bloom


SounDrop


Rain

  • openFrameworks for iPhoneで音を鳴らすには – OpenALを使用する
  • OpenAL – クロスプラットフォームのオーディオAPI
  • 3次元定位オーディオを効率よく表現するように設計されている
  • OpenGLとの相性が良い
  • openFrameworksで、OpenALを利用するプロジェクトには、ofxALSoundPlayerアドオンのファイルが入っている必要がある
  • 「グループとファイル」の「addons」を右クリックして、「追加」→「既存のファイル」を選択
  • ofxALSoundPlayerのフォルダを追加する
  • [oFのフォルダ]/apps/iPhoneSpecificExamples/OpenAlExample/src/ofxALSoundPlayer


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

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]


完成!!