6. 入力装置からの入力

本体に搭載されているデジタルボタン、スライドパッド、タッチパネル、加速度センサー、ジャイロセンサー、マイク、カメラなどの入力装置からの入力は、それぞれ対応するライブラリとクラスによって簡単にアプリケーションに取り込むことができます。

6.1. デバイスを利用するライブラリについて

アプリケーションから本体に搭載されている各種入力装置などのデバイスにアクセスするには、CTR-SDK で提供されるライブラリを使用しなければなりません。デバイスを利用するライブラリの多くは、関数呼び出しの返り値に nn::Result クラスが返されます。

関数呼び出しとその処理が成功したかどうかは、nn::Result クラスの IsSuccess() または IsFailure() を呼び出して判定します。IsSuccess()true を返した場合は成功、false を返した場合は失敗です。IsFailure() はその逆で、true を返した場合は失敗、false を返した場合は成功です。

nn::Result クラスにはエラーの重要度や概要、エラーの発生したモジュールの情報が記録されています。処理結果の成否判定に加え、これらの詳細な情報から発生したエラーへの対処方法を決定しなければならない場合もあります。

6.2. HID ライブラリ

HID ライブラリでは、デジタルボタン(十字ボタン、A/B/X/Y/L/R ボタン、START ボタン)、スライドパッド、タッチパネル、加速度センサー、ジャイロセンサー、デバッグパッド、拡張スライドパッドからの入力を扱うことができます。

HID ライブラリの初期化は nn::hid::Initialize() を呼び出して行います。初期化関数を重複して呼び出した場合は、何も行わずにエラーを返します。

ライブラリの初期化後、各デバイスの入力は対応するクラスを介して取得することができます。デバイスの種類によって、入力のサンプリングが開始されるタイミングやサンプリング周期が異なります。サンプリングの終了タイミングは、加速度センサーとジャイロセンサーは生成したクラスを破棄したとき、拡張スライドパッドは nn::hid::ExtraPad::StopSampling() を呼び出したとき、そのほかは HID ライブラリを終了したときです。

補足:

SNAKE に搭載されている C スティック、ZL ボタン、ZR ボタンは CTR に拡張スライドパッドを常時装着された状態と同じように処理することができます。その際、C スティックはスライドパッド(R)に対応し、ZL ボタンと ZR ボタンはそのまま ZL ボタンと ZR ボタンに対応します。

C スティックについての情報および拡張スライドパッドとの相違点については「6.2.7. C スティック」を参照してください。

表 6-1. 入力の種類と扱うクラス、サンプリング周期の一覧

種類

入力を扱うクラス

サンプリング開始の契機

周期

デジタルボタンとスライドパッド

nn::hid::PadReader

HID ライブラリの初期化

4 ms

タッチパネル

nn::hid::TouchPanelReader

HID ライブラリの初期化

4 ms

加速度センサー

nn::hid::AccelerometerReader

Reader クラスの生成

平均 10 ms

ジャイロセンサー

nn::hid::GyroscopeReader

Reader クラスの生成

平均 10 ms

デバッグパッド

nn::hid::DebugPadReader

HID ライブラリの初期化(接続していた場合)

16 ms

拡張スライドパッド

nn::hid::ExtraPadReader

ExtraPad クラスの StartSampling()

8 ~ 32 ms

C スティック、ZL / ZR ボタン nn::hid::ExtraPadReader ExtraPad クラスの StartSampling() 8 ~ 32 ms
補足:

SNAKE に搭載されている C スティック、ZL ボタン、ZR ボタンに対して、ライブラリではサンプリング周期を 8~32 ms の間で設定することができますが、ハードウェアに設定可能なサンプリング周期である 10~21 ms の間で設定することを推奨します。

HID ライブラリの使用を終了するときは nn::hid::Finalize() を呼び出してください。なお、nn::hid::ExtraPadReader クラスを使用している場合は、先に nn::hid::ExtraPad::Finalize() を呼び出さなければなりません。

6.2.1. デジタルボタンとスライドパッド

nn::hid::PadReader クラスの Read() または ReadLatest() を呼び出すことで、デジタルボタンとスライドパッドの入力を nn::hid::PadStatus 構造体に取得することができます。Read() はサンプリング結果を新しい順に取得することができますが、取得したサンプリング結果は再度取得することはできません。そのため、サンプリング周期よりも早い周期で呼び出したときはサンプリング結果を取得することができません。一方、ReadLatest() は常に最新のサンプリング結果だけを取得することができます。サンプリング結果は再度取得することができますので、サンプリング周期よりも早い周期で呼び出したときでもサンプリング結果を取得することができます。

nn::hid::PadStatus 構造体の hold メンバにはサンプリング時に押されているボタンが、trigger メンバにはサンプリング時に押されたボタンが、release メンバにはサンプリング時に離されたボタンがビットにマッピングされてそれぞれ記録されています。ReadLatest() では、triggerrelease の両メンバがその時点の状態で評価されますので、呼び出しと呼び出しの間の変化は考慮されません。スライドパッドの入力で十字ボタンの入力をエミュレーションしたビットもあります。スライドパッド自体の入力は stick メンバに 2 軸の座標値で記録されています。

表 6-2. ボタンと定義の対応

定義

対応するボタン

BUTTON_UP

十字ボタン(上)

BUTTON_DOWN

十字ボタン(下)

BUTTON_LEFT

十字ボタン(左)

BUTTON_RIGHT

十字ボタン(右)

BUTTON_A

A ボタン

BUTTON_B

B ボタン

BUTTON_X

X ボタン

BUTTON_Y

Y ボタン

BUTTON_L

L ボタン

BUTTON_R

R ボタン

BUTTON_START

START ボタンまたは SELECT ボタン(通常動作時)

BUTTON_SELECT_FOR_DEBUGGING

SELECT ボタン(デバッグ用途のみ)

BUTTON_EMULATION_UP

スライドパッドによる十字ボタン(上)のエミュレーション入力

BUTTON_EMULATION_DOWN

スライドパッドによる十字ボタン(下)のエミュレーション入力

BUTTON_EMULATION_LEFT

スライドパッドによる十字ボタン(左)のエミュレーション入力

BUTTON_EMULATION_RIGHT

スライドパッドによる十字ボタン(右)のエミュレーション入力

nn::hid::EnableSelectButton()nn::hid::DisableSelectButton() で SELECT ボタンのサンプリングの有効 / 無効を切り替えることができます。

コード 6-1. SELECT ボタンのサンプリングの有効 / 無効の切り替え
bool nn::hid::EnableSelectButton();
void nn::hid::DisableSelectButton();

SELECT ボタンのサンプリングを有効に切り替えることができたときに、EnableSelectButton()true を返します。デバッグモードに設定されていない場合は必ず false を返し、有効になりません。SELECT ボタンのサンプリングが有効になると、BUTTON_SELECT_FOR_DEBUGGING を返すようになり、START ボタンとの押し分けが可能になります。

スライドパッドは触れていない状態でも座標値を返します。そのため、nn::hid::PadReader クラスの SetStickClamp()SetStickClampMode() を呼び出して、入力に適切な遊びとクランプの方法を設定してください。クランプの方法には円形クランプ(STICK_CLAMP_MODE_CIRCLE)と十字形クランプ(STICK_CLAMP_MODE_CROSS)、最小クランプ(STICK_CLAMP_MODE_MINIMUM)の 3 種類を用意しています。現在のスライドパッドのクランプ方法は GetStickClampMode() で、クランプで使用する値は GetStickClamp() で、それぞれ取得することができます。デフォルトのクランプ方法には円形クランプが設定されています。 スライドパッドからの入力座標を(x, y)、原点からの距離を d、クランプの下限値と上限値を min と max、クランプ後の座標を(x', y')、原点からの距離を d' とすると、それぞれ以下のように座標をクランプします。

円形クランプ

d <= min

(x', y') = (0, 0)

min < d < max

(x', y') = ((d - min) / d * x, (d - min) / d * y)

d > max

(x', y') = ((max - min) / d * x, (max - min) / d * y)

十字形クランプ

x < 0

(x', y') = (x + min, y) ただし、x + min は 0 以上にならない

x >= 0

(x', y') = (x - min, y) ただし、x - min は 0 以下にならない

y < 0

(x', y') = (x, y + min) ただし、y + min は 0 以上にならない

y >= 0

(x', y') = (x, y - min) ただし、y - min は 0 以下にならない

d' > (max - min)

(x', y') = ((max - min) / d' * x', (max - min) / d' * y')

最小クランプ

最小クランプは円形クランプと十字形クランプを組み合わせたクランプ方法です。内側(最小値)のクランプは、ともに下限値に設定された円形クランプと十字形クランプそれぞれでクランプされる領域が小さな方(同じ入力座標でクランプされない方)を適用します。外側(最大値)のクランプは円形クランプと同じ方法で行われます。

スライドパッドの入力に対してクランプ後の座標が変化する範囲を図示すると、図 6-1 のようになります。

図 6-1. 円形クランプと十字形クランプの有効入力範囲

min max STICK_CLAMP_MODE_CIRCLE STICK_CLAMP_MODE_CROSS STICK_CLAMP_MODE_MINIMUM min(CROSS) min(CIRCLE)

STICK_CLAMP_MODE_CROSS の x, y 軸近辺は x, y どちらかの座標(x 軸近辺なら x 座標)のみが変化します。

1 つの座標軸に注目して入力座標と出力座標をグラフにすると、どのクランプ方法でも以下のようになります。

図 6-2. 入力座標と出力座標の関係

 max-min min max input output -max -min min-max

どのクランプ方法でも、min までは 0、max 以上は ±(max - min) を出力し、min と max の間は 0 から ±(max - min) へと入力に比例して出力されます。

クランプ後に取り得る座標はどの方法でも (max - min) を半径とする円になりますが、どのような入力が必要なのかで採用する方法を決定することができます。STICK_CLAMP_MODE_CIRCLE は原点と入力座標の角度が保持されますので、細かく方向を指定する用途に向いています。STICK_CLAMP_MODE_CROSS は x, y 軸近辺で片方の座標のみが出力されますので、メニューを選択するときのように軸方向の入力を重視する用途に向いています。

スライドパッドの座標値の正規化

nn::hid::PadReader クラスの NormalizeStick() は、Read() または ReadLatest() で取得したスライドパッドの座標値を (max - min) を 1.0 とする -1.0 ~ +1.0 の範囲で、f32 型の浮動小数点数に正規化します。

NormalizeStickWithScale() は、感度調節機能を付加したスライドパッドの座標値の正規化を行います。感度の調節は、SetNormalizeStickScaleSetting() で設定された scale(デフォルトは 1.5)と threshold(デフォルトは 141)をもとに行われます。正規化後の値は、threshold 未満ならば (1/scale) 倍になり、threshold 以上ならば徐々に ±1.0 へと近づきます。この機能によって、スライドパッドの可動範囲が scale 倍あるように振る舞うことになります。

スライドパッドの十字ボタンエミュレーション

スライドパッドの入力で十字ボタンをエミュレーションしたビット(BUTTON_EMULATION_*)は、下限値を 40、上限値を 145 に設定した円形クランプを適用したあとの座標値が原点から見てどの方向にあるのかで判定されます。SetStickClamp() および SetStickClampMode() による設定は影響しません。x, y 軸の正負それぞれに上下左右を割り振り、軸を中心に 120 度の範囲に座標があれば対応するビットが ON となります。そのため、範囲が重なる 30 度の部分は斜め方向の入力と判定されます。

図 6-3. BUTTON_EMULATION_ の判定範囲*

DOWN LEFT RIGHT UP X Y 30° 120° 60°

6.2.1.1. スライドパッドのハードウェア特性

3DS に搭載されているスライドパッドは、抵抗板と接触しているシャフトとキートップの接合部分に遊びがある構造のため、ゲームキューブや Wii のコントローラに搭載されているアナログスティックに比べて、入力方向の反転に対する応答に若干の遅れが発生します。

図 6-4. スライドパッドの構造による反転入力への応答の遅れ

抵抗板 シャフト キートップ 抵抗板 右方向へ動かすと、シャフトは左側に寄ります。 そこから左方向へ動かしても、シャフトの位置がすぐには変化しません。 スライドパッドの動き 検知された動き 時間の流れ

また、スライドパッドを同じ位置に移動させたときに、その移動経路によって得られる値が異なる可能性(経路依存性)があります。この経路依存性もスライドパッドの構造が原因で発生しています。

例えば、左端から中央寄りの経路をたどった場合はシャフトが左寄りになるために –X 方向寄りの値が得られる傾向があり、右端から中央寄りの経路をたどった場合はシャフトが右寄りになるために +X 方向寄りの値が得られる傾向があります。この傾向は上下(±Y)方向にも当てはまります。

図 6-5. スライドパッドの経路依存性

抵抗板 シャフトは左側に寄ります。 シャフトは右側に寄ります。 左側から中央寄りの経路 右側から中央寄りの経路 Y X 入力される値(イメージ) スライドパッドの移動経路

アプリケーションは、入力値に対しての判定閾値に余裕を持たせるなど、この経路依存性に考慮した対応を行うことを推奨します。

6.2.2. タッチパネル

nn::hid::TouchPanelReader クラスの Read() または ReadLatest() を呼び出すことで、タッチパネルの入力を nn::hid::TouchPanelStatus 構造体に取得することができます。Read() はサンプリング結果を新しい順に取得することができますが、取得したサンプリング結果は再度取得することはできません。そのため、サンプリング周期よりも早い周期で呼び出したときはサンプリング結果を取得することができません。一方、ReadLatest() は常に最新のサンプリング結果だけを取得することができます。サンプリング結果は再度取得することができますので、サンプリング周期よりも早い周期で呼び出したときでもサンプリング結果を取得することができます。

nn::hid::TouchPanelStatus 構造体の x、y メンバには、(下画面を手前にしたときの)LCD の左上隅を原点とするタッチパネルの入力座標がドット単位で記録されています。GX ライブラリでの LCD の座標とは座標軸が異なる点には注意が必要です。また、接触の難しい外周部の 5 ドットはクランプされた座標値で返されますので、実際に返される座標値は x が 5 ~ 314、y が 5 ~ 234 の範囲となります。

コード 6-2. タッチパネルの入力座標を LCD の座標に変換するコード例
x = nn::gx::DISPLAY1_WIDTH - touchPanel.y;
y = nn::gx::DISPLAY1_HEIGHT - touchPanel.x;

touch メンバにはタッチパネルにタッチペンが接触しているかどうかが記録されています。このメンバが 0 ならばタッチペンは接触しておらず、1 ならば接触しています。

6.2.3. 加速度センサー

nn::hid::AccelerometerReader クラスの Read() または ReadLatest() を呼び出すことで、加速度センサーの入力を nn::hid::AccelerometerStatus 構造体に取得することができます。Read() はサンプリング結果を新しい順に取得することができますが、取得したサンプリング結果は再度取得することはできません。そのため、サンプリング周期よりも早い周期で呼び出したときはサンプリング結果を取得することができません。一方、ReadLatest() は常に最新のサンプリング結果だけを取得することができます。サンプリング結果は再度取得することができますので、サンプリング周期よりも早い周期で呼び出したときでもサンプリング結果を取得することができます。

加速度センサーの電源は、AccelerometerReader クラスのインスタンスが作成されたときにオンになり、インスタンスが破棄されたときにオフになります。そのため、加速度センサーを使用するシーンの間だけインスタンスを作成する実装はバッテリーの節約には有効です。ただし、毎フレーム呼び出される関数でインスタンスの作成と破棄を繰り返すような実装は、頻繁に電源のオンとオフを切り替えるため、無駄な電力の消費や予期せぬ誤動作の一因となります。

nn::hid::AccelerometerStatus 構造体の xyz メンバには加速度センサーの 3 軸の入力が記録されています。十字ボタンの右から左への方向が x 軸の正方向、下 LCD の画面に垂直で下から上への方向が y 軸の正方向、十字ボタンの下から上への方向が z 軸の正方向です。3 軸の入力はそのままでは加速度を示す値ではありませんので、nn::hid::AccelerometerReader クラスの ConvertToAcceleration() で加速度(単位:G)に変換してからアプリケーションで利用してください。

図 6-6. 加速度センサーの 3 軸の方向

+x +y +z

加速度センサーのゼロ点に最大で、経年変化により 0.05 G、温度特性により 0.08 G の計 0.13 G のズレが生じる可能性があります。アプリケーションで加速度センサーを利用する場合は、このゼロ点のズレを考慮した仕様にしてください。経年変化によるズレはキャリブレーションによりほぼ解消することができますが、温度特性によるズレはキャリブレーションを行っても短時間で再び生じることがあります。0.08 G のズレは、角度にしておよそ 5 度の傾きに相当します。この精度以上の繊細な動きを検知する場合は、ユーザーが違和感を感じたときに、すぐキャリブレーションを行えるようにするなどの配慮をしてください。

補足:

HOME メニュー表示中に Y ボタンと B ボタンを 3 秒間押し続けることで、加速度センサーのキャリブレーションを行うことができます。

また、感度には最大で ± 8 % のズレが生じる可能性があります。ゼロ点のズレによるオフセットも加味して、入力の最大値には測定可能範囲の限界値(約 1.8 G)を 10 % 軽減した値(約 1.62 G)を使用し、この値以上の入力をトリガにするような設計にはしないでください。

注意:

加速度センサーの出力値には ±0.02 G の静止ノイズが重畳します。スピーカーからサウンドを出力している場合は、さらにスピーカーから伝わる振動が ±0.05 G のノイズとして重畳します。そのため、微小な加速度を検知する際には、これらのノイズによる影響を考慮する必要があります。

振動ノイズは 1kHz 帯付近で最大となり、再生音量を調節することで影響を小さくすることができます。

nn::hid::AccelerometerReader クラスの SetSensitivity() を呼び出すことで入力の遊びと検出感度を設定することができ、GetSensitivity() を呼び出すことでそれらの設定を取得することができます。どちらの設定も 0 ~ MAX_OF_ACCELEROMETER_SENESITIVITY の範囲で指定し、デフォルトでは遊びが 0、検出感度が MAX_OF_ACCELEROMETER_SENESITIVITY が指定されています。検出感度に 0 を指定すると 0 しか返さなくなります。MAX_OF_ACCELEROMETER_SENESITIVITY を指定すると、デバイスで検出した値そのままを返します。

加速度センサーからの入力値を 3 軸の座標値として見たとき、軸ごとに加速度の変化量が入力の遊び以下であれば遊びの範囲と判定します。遊びの範囲内での出力値は 0 になり、出力値の変化はまったくありません。

遊びを play として、加速度センサーからの入力値と出力値の関係をグラフにすると以下のようになります。この遊びの設定は、手ブレなどの小さな変位による誤検知を軽減するために使用します。

図 6-7. 遊びの設定による入力値と出力値の関係

Output Play Input

nn::hid::AccelerometerReader クラスでは、検出感度と遊びを適用後の出力値に対してオフセットによる修正を行ったあと、軸回転による回転処理を行うことができます。なお、出力値の軸回転は任意の傾きを加速度センサーに与えることに利用できます。

コード 6-3. 加速度センサーの出力値のオフセット
class nn::hid::AccelerometerReader
{
    void EnableOffset();
    void DisableOffset();
    bool IsEnableOffset() const;
    void SetOffset(s16 x, s16 y,s16 z);
    void GetOffset(s16* pX, s16* pY, s16* pZ) const;
    void ResetOffset();
}

出力値へのオフセット修正は、EnableOffset() で有効(デフォルト)に、DisableOffset() で無効にすることができます。現設定が有効か無効かは IsEnableOffset() の返り値が true であるかどうかで判断することができます。オフセット修正が有効になっている場合、設定されたオフセット値の各成分が出力値の各成分から減算されます。

オフセット値の設定は SetOffset() で行います。各軸のオフセットを値で指定することができます。オフセット値の各成分は加速度(単位: G)ではなく、変換前のサンプリング値で指定することに注意してください。現設定の取得は GetOffset() で行います。オフセット値を初期値(すべての成分が 0)に戻すには ResetOffset() を呼び出してください。

補足:

SetOffsetFromBaseStatus() は CTR-SDK から削除されました。

注意:

オフセット値の設定を加速度センサーのキャリブレーションを行う目的で使用しないでください。

コード 6-4. 加速度センサーの軸回転
class nn::hid::AccelerometerReader
{
    void EnableAxisRotation();
    void DisableAxisRotation();
    bool IsEnableAxisRotation() const;
    void SetAxisRotationMatrix(const nn::math::MTX34 mtx);
    void GetAxisRotationMatrix(nn::math::MTX34* pMtx) const;
    void ResetAxisRotationMatrix();
}

出力値の軸回転は、EnableAxisRotation() で有効に、DisableAxisRotation() で無効(デフォルト)にすることができます。現設定が有効か無効かは IsEnableAxisRotation() の返り値が true であるかどうかで判断することができます。軸回転が有効になっている場合、設定された回転行列による回転処理が出力値に対して行われます。

回転行列(3x4 行列)は、SetAxisRotationMatrix() で設定、GetAxisRotationMatrix() で現設定の取得、ResetAxisRotationMatrix() で単位行列(軸回転なし)に戻すことができます。

出力値へのオフセット修正と軸回転の 2 つを有効にしたときは、オフセット修正を適用後に軸回転が適用されます。

注意:

軸回転の設定を加速度センサーのキャリブレーションを行う目的で使用しないでください。

6.2.3.1. アプリケーション独自のキャリブレーションを実装する場合の注意点

注意:

アプリケーション独自のキャリブレーションを実装することは禁止となりました。

6.2.4. ジャイロセンサー

nn::hid::GyroscopeReader クラスの Read() または ReadLatest() を呼び出すことで、ジャイロセンサーの入力を nn::hid::GyroscopeStatus 構造体に取得することができます。Read() はサンプリング結果を新しい順に取得することができますが、取得したサンプリング結果は再度取得することはできません。そのため、サンプリング周期よりも早い周期で呼び出したときはサンプリング結果を取得することができません。一方、ReadLatest() は常に最新のサンプリング結果だけを取得することができます。サンプリング結果は再度取得することができますので、サンプリング周期よりも早い周期で呼び出したときでもサンプリング結果を取得することができます。

ジャイロセンサーの電源は、GyroscopeReader クラスのインスタンスが作成されたときにオンになり、インスタンスが破棄されたときにオフになります。そのため、ジャイロセンサーを使用するシーンの間だけインスタンスを作成する実装はバッテリーの節約には有効です。ただし、毎フレーム呼び出される関数でインスタンスの作成と破棄を繰り返すような実装は、頻繁に電源のオンとオフの切り替えるため、無駄な電力の消費や予期せぬ誤動作の一因となります。

nn::hid::GyroscopeStatus 構造体の speedangledirection メンバにはジャイロセンサーの角速度、回転角、三次元姿勢が記録されています。角速度と回転角は 3 次元のベクトルで、x 成分にピッチ方向、y 成分にヨー方向、z 成分にロール方向の値が記録されています。角速度は 360 dps を 1.0 とする値、回転角は 360 度を 1.0 とする値です。下 LCD 画面の長辺を軸に手前側を持ち上げて回転させる方向がピッチの正方向、中央を軸に水平に時計回りで回転させる方向がヨーの正方向、短辺を軸に十字ボタン側を持ち上げて回転させる方向がロールの正方向です。

図 6-8. ジャイロセンサーの 3 要素

Yaw(+y) Pitch(+x) Roll(+z)

角速度の感度には最大で ± 8 % のズレが生じる可能性があります。ゼロ点のズレによるオフセットも加味して、入力の最大値には測定可能範囲の限界値(約 1800 dps)を 10 % 軽減した値(約 1620 dps)を使用し、この値以上の入力をトリガにするような設計にはしないでください。

三次元姿勢は 3x3 行列で記録されています。三次元姿勢は角速度を元に計算されており、計算時に参照する角速度の倍率を nn::hid::GyroscopeReader::SetDirectionMagnification() で変更することができます。倍率に 1.0 を指定した場合は、検出された角速度をそのままを計算に使用します。倍率に 2.0 を指定した場合は、検出された角速度を 2 倍して計算に使用します。

nn::hid::GyroscopeReader クラスは静止状態を検知し、ゼロ点オフセットの自動キャリブレーション(ゼロ点ドリフトの補正)を行っています。補正処理の設定はすべての方向に一様に適用されます。

コード 6-5. ジャイロセンサーのゼロ点ドリフトの補正
class nn::hid::GyroscopeReader
{
    void EnableZeroDrift();
    void DisableZeroDrift();
    bool IsEnableZeroDrift() const;
    f32 GetZeroDriftEffect() const;
    void ResetZeroDriftMode();
    void SetZeroDriftMode(const nn::hid::ZeroDriftMode& mode);
    void GetZeroDriftMode(nn::hid::ZeroDriftMode& mode) const;
}

ゼロ点ドリフトの補正は、EnableZeroDrift() で有効(デフォルト)に、DisableZeroDrift() で無効にすることができます。補正の有効・無効は IsEnableZeroDrift() の返り値が true であるかどうかで確認することができます。補正処理の働き具合は GetZeroDriftEffect() の返り値で確認することができます。補正が無効の場合は負の値が返りますが、有効の場合は 0 以上の値が返ります。0 は補正が行われなかった(動きを検知した)ことを示し、1.0 に近づくほど安定している(動きが少ない)ことを示します。

ゼロ点ドリフトの補正モードによって補正が行われる変動値の幅が異なり、本体が安定していると判断される角速度の幅が変化します。ゼロ点ドリフトの補正モードは、SetZeroDriftMode() で設定、GetZeroDriftMode() で現設定の取得、ResetZeroDriftMode() で初期値(GYROSCOPE_ZERODRIFT_STANDARD)に戻すことができます。

表 6-3. ジャイロセンサーのゼロ点ドリフトの補正モード

定義

説明

GYROSCOPE_ZERODRIFT_LOOSE

補正する変動幅が広くなり、等速運動を検知しない場合があります。

GYROSCOPE_ZERODRIFT_STANDARD

標準的な補正を行います。(デフォルト)

GYROSCOPE_ZERODRIFT_TIGHT

補正する変動幅が狭くなり、緩やかな動きを検知することができます。

ゼロ点ドリフトの補正を無効にした場合、ゼロ点のオフセットに最大で 50 dps のズレが生じることがあります。極めてゆっくりとした動きを検知するために無効に設定した場合は、このズレの発生に十分留意してください。

補足:

GYROSCOPE_ZERODRIFT_LOOSE 以外では静止状態でも補正処理の効きが悪くなる場合がありますので、本体を動かさないと思われるシーンでは GYROSCOPE_ZERODRIFT_LOOSE による補正を掛け、使用時に元の補正モードに戻すなどの実装を推奨します。

ゼロ点の遊び補正を設定することで、角速度の小さな変動に反応させないようにすることができます。ゼロ点の遊び補正の設定はすべての方向に一様に適用されます。

コード 6-6. ジャイロセンサーのゼロ点の遊び補正
class nn::hid::GyroscopeReader
{
    void EnableZeroPlay();
    void DisableZeroPlay();
    bool IsEnableZeroPlay() const;
    f32 GetZeroPlayEffect() const;
    void SetZeroPlayParam(f32 radius);
    void GetZeroPlayParam(f32& radius) const;
    void ResetZeroPlayParam();
}

ゼロ点の遊び補正は、EnableZeroPlay() で有効に、DisableZeroPlay() で無効(デフォルト)にすることができます。遊び補正の有効・無効は IsEnableZeroPlay() の返り値が true であるかどうかで確認することができます。遊び補正のかかり具合は GetZeroPlayEffect() の返り値で確認することができます。遊び補正が無効の場合は負の値が返りますが、有効の場合は 0 以上の値が返ります。角速度が設定された遊びの値に近くなるほど返り値は 0 に近づき、0 の場合は遊びによる補正が行われなかったことを示します。

遊び補正で 0 となる角速度の絶対値は、SetZeroPlayParam() で設定、GetZeroPlayParam() で現設定の取得、ResetZeroPlayParam() で初期値(0.005)に戻すことができます。絶対値は 360 dps を 1.0 とする値で設定します。

ゼロ点に関する 2 つの機能が有効である場合は、先にゼロ点ドリフトの補正が行われ、次に遊びによる補正が行われます。

nn::hid::GyroscopeReader クラスでは、ゼロ点ドリフトの補正と遊び補正を適用後の角速度に対して、軸回転による回転処理を行うことができます。静止時の出力値をもとに回転行列を計算することで、アプリケーションにジャイロセンサーのキャリブレーションを実装することができます。ほかにも、出力値の軸回転は任意の傾きをジャイロセンサーに与えることに利用できます。

コード 6-7. ジャイロセンサーの軸回転
class nn::hid::GyroscopeReader
{
    void EnableAxisRotation();
    void DisableAxisRotation();
    bool IsEnableAxisRotation() const;
    void SetAxisRotationMatrix(const nn::math::MTX34 mtx);
    void GetAxisRotationMatrix(nn::math::MTX34* pMtx) const;
    void ResetAxisRotationMatrix();
}

角速度の軸回転は、EnableAxisRotation() で有効に、DisableAxisRotation() で無効(デフォルト)にすることができます。現設定が有効か無効かは IsEnableAxisRotation() の返り値が true であるかどうかで判断することができます。軸回転が有効になっている場合、設定された回転行列による回転処理が角速度に対して行われます。

回転行列(3x4 行列)は、SetAxisRotationMatrix() で設定、GetAxisRotationMatrix() で現設定の取得、ResetAxisRotationMatrix() で単位行列(軸回転なし)に戻すことができます。

nn::hid::GyroscopeReader クラスは加速度センサーの入力値を利用して、ジャイロセンサーの三次元姿勢の補正を行っています。そのためジャイロセンサーを使用するときは、加速度センサーも使用することになります。コンストラクタで引数 pAccelerometerReaderNULL を渡した(オーバーロードの呼び出した)場合は、デフォルト設定の nn::hid::AccelerometerReader クラスのインスタンスを内部で生成して利用します。入力の遊びや検出感度を変更したい場合は、設定を変更した nn::hid::AccelerometerReader クラスのインスタンスへのポインタを渡してください。

コード 6-8. 加速度による三次元姿勢の補正
class nn::hid::GyroscopeReader
{
    GyroscopeReader(nn::hid::AccelerometerReader* pAccelerometerReader = NULL, 
                    nn::hid::Gyroscope& gyroscope = nn::hid::GetGyroscope());

    void EnableAccRevise();
    void DisableAccRevise();
    bool IsEnableAccRevise() const;
    f32 GetAccReviseEffect() const;
    void SetAccReviseParam(f32 revise_pw, f32 revise_range);
    void GetAccReviseParam(f32& revise_pw, f32& revise_range) const;
    void ResetAccReviseParam();
}

加速度による補正は、EnableAccRevise() で有効(デフォルト)に、DisableAccRevise() で無効にすることができます。補正が有効か無効かは IsEnableAccRevise() の返り値が true であるかどうかで確認することができます。補正のかかり具合は GetAccReviseEffect() の返り値で確認することができます。補正が無効の場合は常に 0 が返りますが、有効の場合は 0 以上の値が返ります。返り値が 1.0 に近づくほど三次元姿勢(GyroscopeStatus.direction)の方向を加速度の方向に近づくように補正したことを示します。

加速度による補正のパラメータ(重みと有効範囲)は、SetAccReviseParam() で設定、GetAccReviseParam() で現設定の取得、ResetAccReviseParam() で初期値(重み 0.03、有効範囲 0.4)に戻すことができます。revise_pw には加速度の重みを 0.0 ~ 1.0 の範囲の値で指定します。値が大きいほど急激な補正がかかります。revise_range には補正に使用する加速度の範囲(1.0 を中心に±revise_range)を指定します。例えば、0.4 を指定した場合は 0.6 G ~ 1.4 G の範囲ならば補正計算に加速度を使用します。補正のパラメータはすべての方向に一様に適用されます。

加速度による補正が有効な状態でジャイロセンサーに角速度の軸回転を適用する場合は、ジャイロセンサーと加速度センサーの軸回転で適用する回転行列には同じ行列を指定してください。コンストラクタでデフォルト設定のインスタンスを利用している場合はライブラリ内で同じ行列となるように調整していますが、独自設定のインスタンスを利用している場合は注意が必要です。異なる行列が指定された場合は、加速度の補正が不適切に働く可能性があります。

6.2.5. デバッグパッド(デバッグ専用コントロールパッド)

nn::hid::DebugPadReader クラスの Read() または ReadLatest() を呼び出すことで、デバッグパッドのデジタルボタンと 2 本のアナログスティックの入力を nn::hid::DebugPadStatus 構造体に取得することができます。Read() はサンプリング結果を新しい順に取得することができますが、取得したサンプリング結果は再度取得することはできません。そのため、サンプリング周期(16 ms)よりも早い周期で呼び出したときはサンプリング結果を取得することができません。一方、ReadLatest() は常に最新のサンプリング結果だけを取得することができます。サンプリング結果は再度取得することができますので、サンプリング周期よりも早い周期で呼び出したときでもサンプリング結果を取得することができます。

nn::hid::DebugPadStatus 構造体の hold メンバにはサンプリング時に押されているボタンが、trigger メンバにはサンプリング時に押されたボタンが、release メンバにはサンプリング時に離されたボタンがビットにマッピングされてそれぞれ記録されています。ReadLatest() では、triggerrelease の両メンバがその時点の状態で評価されますので、呼び出しと呼び出しの間の変化は考慮されません。leftStickX, leftStickY メンバには左アナログスティックの x 軸と y 軸、rightStickX, rightStickY メンバには右アナログスティックの x 軸と y 軸の値が -1.0 ~ +1.0 の範囲で記録されています。

アナログスティックのクランプ方法は SetStickClampMode() で設定、GetStickClampMode() で現在の設定の取得を行うことができます。左右のアナログスティックに対して、個別に設定することはできません。クランプの方法には、遊びのある円形クランプ(STICK_CLAMP_MODE_CIRCLE_WITH_PLAY)と遊びのない円形クランプ(STICK_CLAMP_MODE_CIRCLE_WITHOUT_PLAY)の 2 種類があります。

表 6-4. デバッグパッドのデジタルボタンと定義の対応

定義

対応するボタン

DEBUG_PAD_BUTTON_UP

十字ボタン(上)

DEBUG_PAD_BUTTON_DOWN

十字ボタン(下)

DEBUG_PAD_BUTTON_LEFT

十字ボタン(左)

DEBUG_PAD_BUTTON_RIGHT

十字ボタン(右)

DEBUG_PAD_BUTTON_A

A ボタン

DEBUG_PAD_BUTTON_B

B ボタン

DEBUG_PAD_BUTTON_X

X ボタン

DEBUG_PAD_BUTTON_Y

Y ボタン

DEBUG_PAD_TRIGGER_L

L トリガー

DEBUG_PAD_TRIGGER_R

R トリガー

DEBUG_PAD_TRIGGER_ZL

ZL トリガー

DEBUG_PAD_TRIGGER_ZR

ZR トリガー

DEBUG_PAD_BUTTON_PLUS

+(プラス)ボタン

DEBUG_PAD_BUTTON_MINUS

-(マイナス)ボタン

DEBUG_PAD_BUTTON_HOME

HOME ボタン

6.2.6. 拡張スライドパッド

拡張スライドパッドは CTR に装着して使用する周辺機器です。主な特徴は、CTR 本体に搭載されている入力装置に加え、拡張スライドパッドに搭載されたスライドパッド(以下スライドパッド(R)と表記し、本体に搭載されたものはスライドパッドと表記する)とデジタルボタン(ZL/ZR ボタン)が使用できる点です。

拡張スライドパッドに搭載されている入力装置からの入力は、赤外線通信により CTR 本体へ送信されます。サンプリング周期として指定可能な値は、1 ms 間隔で 8 ms から 32 ms までの範囲です。具体的な値の設定方法については、「6.2.6.4. サンプリングの開始と状態取得」を参照してください。

補足:

アプリケーションで拡張スライドパッドを利用する際の処理フローについては、「付録:拡張スライドパッドを利用する場合のフロー図」を参照してください。

SNAKE に搭載されている C スティック、ZL ボタン、ZR ボタンの詳細、拡張スライドパッドとの相違点については、「6.2.7. C スティック」を参照してください。

注意:

CTR では、赤外線通信を用いて拡張スライドパッドと通信します。
アプリケーションから拡張スライドパッドを使用する際、赤外線通信を利用する他の機能を使用中ならば、その機能を先に終了させてください。

赤外線通信は以下の機能で利用されています。

  • 本体間赤外線通信
  • NFP ( CTR のみ)

6.2.6.1. ハードウェアの内部ステート

拡張スライドパッドのハードウェアの内部ステートとしては、CTR との通信が可能な「アクティブ状態」と、一切の通信を行わない「スタンバイ状態」の 2 種類のステートしかありません。

表 6-5. ハードウェアの内部ステート

内部ステート

説明

アクティブ状態

CTR との通信が可能な状態です。この状態でなければ、CTR との接続ができません。

電池の挿入直後はこの状態になります。

スタンバイ状態

CTR との通信を一切行わない状態です。未使用時の電池消費を最小限に抑え、電池を長持ちさせます。

ボタン入力や赤外線通信が行われていない状態が 5 分間続くと、この状態になります。拡張スライドパッドのデジタルボタン(ZL、ZR、R)のいずれかを押すことで、アクティブ状態に復帰します。

補足:

拡張スライドパッドには内部ステートを示すインジケータが存在しません。また、ライブラリから内部ステートを取得することもできません。

6.2.6.2. ソフトウェアの内部ステート

ソフトウェア(ライブラリ)の内部ステートは以下のように遷移します。

図 6-9. ソフトウェアの内部ステート遷移図(拡張スライドパッド)

NO_CONNECTION CONNECTED STOPPED StartSampling() StopSampling() 外的要因による切断 スリープ状態への移行 内部ステート 明示的な状態遷移 自動的な状態遷移

以下のように、内部ステートは拡張スライドパッドとの接続状態を示しています。

表 6-6. ソフトウェアの内部ステート

内部ステート

説明

NO_CONNECTION

拡張スライドパッドとの接続が確立していない状態です。

初期化直後も同じ内部ステートです。

CONNECTED

拡張スライドパッドとの接続が確立され、サンプリングが行われている状態です。

STOPPED

確立していた拡張スライドパッドとの接続が、外的要因(電池の消耗、本体からの離脱など)によって切断されている状態です。

CTR 本体がスリープ状態に移行したときも、この内部ステートに遷移します。

内部ステートを示す定義は、nn::hid::ExtraPad::ConnectionState 列挙子に「CONNECTION_STATE_*」で定義されています。

6.2.6.3. 初期化

拡張スライドパッドからの入力のサンプリングを開始する前に、nn::hid::ExtraPad クラスの初期化関数を呼び出す必要があります。

コード 6-9. 拡張スライドパッドの初期化に使用する関数
static void nn::hid::ExtraPad::Initialize(
                void* workingMemory,
                size_t workingMemorySize);

workingMemory には、赤外線通信のためのバッファを指定します。指定するバッファは、サイズが nn::hid::CTR::ExtraPad::WORKING_MEMORY_SIZE ( 12288 Byte )、先頭アドレスのアライメントが nn::hid::CTR::ExtraPad::WORKING_MEMORY_ALIGNMENT ( 4096 Byte ) でなければなりません。また、デバイスメモリから確保したバッファは使用できません

初期化が完了した時点で nn::hid::ExtraPadReader クラスを使用することができるようになります。

6.2.6.4. サンプリングの開始と状態取得

サンプリングの開始と状態取得には、以下の関数を使用します。

コード 6-10. サンプリングの開始と状態取得に使用する関数
class nn::hid::ExtraPad
{
    static nn::Result StartSampling(s32 samplingThreadPriority, s32 period);
    static ConnectionState GetConnectionState();
    static bool IsSampling();
}

拡張スライドパッドのサンプリングは nn::hid::ExtraPad::StartSampling() の呼び出しで行います。初期化が完了する前に呼び出すとエラー(nn::hid::MakeResultNotInitialized() と同値)が返されます。この関数の処理には、拡張スライドパッドとの接続に成功した場合は 50 ~ 200 ms、失敗した場合は最大 100 ms かかります。

samplingThreadPriority には、サンプリング用のスレッドのスレッド優先度を指定します。指定可能な値の範囲は 0~31 です。優先度が高い(0 に近い)ほど、安定したサンプリングが期待できます。

period には、サンプリング周期を 1 ミリ秒単位で指定します。指定可能な値の範囲は 8~32 です。

サンプリングを開始する際に、アプリケーションのリソースを消費してサンプリング用のスレッド(スレッド優先度は samplingThreadPriority で指定された値)が作成されます。このスレッドは period で指定したサンプリング周期で拡張スライドパッドからのサンプリングデータの受信処理を行い、約 1 秒ごとに拡張スライドパッドとの通信を持続するための送信処理を行います。サンプリング周期が高いほど単位時間あたりの処理量が大きくなり、周期の長さにほぼ反比例してアプリコア、システムコアの負荷が大きくなります。そのため、負荷の軽減を目的とする場合、サンプリング周期を下げることが最も有効となります。

注意:

ほかの処理における負荷が非常に高く、それがサンプリングスレッドの動作周期に影響を与えるほどである場合、入力の遅延や拡張スライドパッドの切断が発生する可能性があります。

拡張スライドパッドがアクティブ状態でなければサンプリングを開始することができません。ライブラリからはアクティブ状態であるかどうかを判断することができませんので、StartSampling() が拡張スライドパッドが見つからないという返り値(nn::hid::MakeResultNoConnection() と同値)を返したときは、ユーザーに拡張スライドパッドのデジタルボタン(R/ZR/ZL)のいずれかの入力を促すなどして、アクティブ状態に復帰させてから再接続を行ってください。

なお、接続状態で StartSampling() を呼び出すと、一度切断処理を行ってから接続処理が行われます。

補足:

拡張スライドパッドの常時検出のために、1 秒間に 1 回の頻度で StartSampling() を呼び出した場合の負荷は 32 ms 周期でサンプリングする処理よりも小さいことがわかっています。

nn::hid::ExtraPad::GetConnectionState() は、拡張スライドパッドとの接続状態を内部ステートで返します。外的要因などで切断され、CONNECTION_STATE_STOPPED が返されたときは、切断処理を行ってから再接続を行ってください。

nn::hid::ExtraPad::IsSampling() は、サンプリング中かどうかを返します。true を返したときはサンプリングが行われていますので、nn::hid::ExtraPadReader クラスで取得した nn::hid::ExtraPadStatus 構造体には拡張スライドパッドの入力が反映されています。true を返したときは内部ステートも接続状態(CONNECTED)であることが保証されていますが、接続処理や切断処理の途中などで、内部ステートが接続状態であっても false を返す可能性があることに注意してください。

補足:

拡張スライドパッドのサンプリングが開始されると nn::hid::PadReader クラスは使用できなくなりますが、拡張スライドパッドが接続されていなくても、nn::hid::ExtraPadReader クラスで取得した nn::hid::ExtraPadStatus 構造体には本体のデジタルボタンやスライドパッドからの入力が反映されています。

そのため、拡張スライドパッドに対応するアプリケーションは nn::hid::ExtraPadReader クラスと nn::hid::ExtraPadStatus 構造体を使用し、接続状態によって使用するクラスや構造体を切り替える必要はありません。

6.2.6.5. サンプリングの終了

サンプリングを終了するには、nn::hid::ExtraPad::StopSampling() を呼び出します。

コード 6-11. サンプリングの終了に使用する関数
static nn::Result nn::hid::ExtraPad::StopSampling();

切断処理に成功すると、サンプリング用のスレッドが破棄され、内部ステートが未接続状態(NO_CONNECTION)になります。この関数は、初期化されていない状態で呼び出されない限り、必ず処理に成功します。

6.2.6.6. サンプリング結果の取得

サンプリング結果は、nn::hid::ExtraPadReader クラスの Read() または ReadLatest() で取得する nn::hid::ExtraPadStatus 構造体に反映されます。Read() はサンプリング結果を新しい順に取得することができますが、取得したサンプリング結果は再度取得することはできません。そのため、サンプリング周期よりも早い周期で呼び出したときはサンプリング結果を取得することができません。一方、ReadLatest() は常に最新のサンプリング結果だけを取得することができます。サンプリング結果は再度取得することができますので、サンプリング周期よりも早い周期で呼び出したときでもサンプリング結果を取得することができます。

コード 6-12. nn::hid::ExtraPadStatus 構造体
struct nn::hid::ExtraPadStatus {
    AnalogStickStatus stick;
    AnalogStickStatus extraStick;
    bit32 hold;
    bit32 trigger;
    bit32 release;
    u8    batteryLevel;
    bool  isConnected;
    NN_PADDING2;
};

stick には、nn::hid::PadStatus 構造体と同じく、本体側のスライドパッドの入力が反映されます。

extraStick には、拡張スライドパッドのスライドパッド(R)の入力が反映されます。

holdtriggerrelease メンバは nn::hid::PadStatus 構造体と同じですが、以下のボタンが追加されます。

表 6-7. 拡張スライドパッドで追加されるボタン

定義

対応するボタン

BUTTON_ZL

拡張スライドパッドの ZL ボタン

BUTTON_ZR

拡張スライドパッドの ZR ボタン

BUTTON_EMULATION_R_UP

スライドパッド(R)による十字ボタン 上のエミュレーション入力

BUTTON_EMULATION_R_DOWN

スライドパッド(R)による十字ボタン 下のエミュレーション入力

BUTTON_EMULATION_R_LEFT

スライドパッド(R)による十字ボタン 左のエミュレーション入力

BUTTON_EMULATION_R_RIGHT

スライドパッド(R)による十字ボタン 右のエミュレーション入力

補足:

拡張スライドパッドの装着時に R ボタンの押下が困難になるため、拡張スライドパッドにも R ボタンが実装されています。ただし、押下された R ボタンが本体のものなのか拡張スライドパッドのものなのかはアプリケーションから判別することができません。

拡張スライドパッドのサンプリングが行われていない状態では、nn::hid::ExtraPadReader クラスは 4 ms のサンプリング周期で nn::hid::ExtraPadStatus 構造体に本体側の入力を反映しています。しかし、拡張スライドパッドのサンプリングが行われている状態では、本体側の入力のサンプリング周期も、nn::hid::ExtraPad::StartSampling() で指定したサンプリング周期(8~32 ms)になります。

batteryLevel には、拡張スライドパッドの電池残量が 0 または 1 の 2値で格納されます。0 が返されるようになってからでも、1 日程度の連続動作が可能です。

注意:

直前まで電池残量に 1 を返していても、一定以上消耗している電池を抜き差しすると、拡張スライドパッドが再起動しない可能性があります。電池の抜き差し後に通信不可能になった場合は、新しい電池に交換してください。なお、この現象は電池の抜き差し時にのみ発生します。電池を入れたまま使用している場合は、電池残量が 0 になるまで動作します。

isConnected には、サンプリング中かどうかをライブラリ内で調べた結果が格納されます。

補足:

拡張スライドパッドの入力がアプリケーションによって取得できる状態になるまでの所要時間(入力遅延)は、アプリケーションのほかの処理が十分小さい場合で、約 2 ms ~(2 ms + サンプリング周期)になります。ユーザーの入力を拡張スライドパッドが取得するまでに 0 ~サンプリング周期の時間がかかり、そのあとの通信と CTR 側での処理に約 2 ms がかかります。

6.2.6.7. スライドパッドのクランプ処理

本体側のスライドパッドのクランプ処理で使用する関数は、nn::hid::PadReader クラスのメンバ関数と同じ関数名で定義されています。また、その動作も同じです。

スライドパッド(R)のクランプ処理で使用する関数は、以下のように関数名の「Stick」が「ExtraStick」になっていること以外、本体側のスライドパッドと同様の設定を個別に行うことができます。

コード 6-13. スライドパッド(R)のクランプ処理に使用する関数
class nn::hid::ExtraPadReader
{
    void SetExtraStickClamp(s16 min, s16 max);
    void GetExtraStickClamp(s16* pMin, s16* pMax) const;
    StickClampMode GetExtraStickClampMode() const;
    void SetExtraStickClampMode(StickClampMode mode);
    f32 NormalizeExtraStick(s16 x);
    void NormalizeExtraStickWithScale(
            f32* normalized_x, f32* normalized_y, s16 x, s16 y);
    void SetNormalizeExtraStickScaleSettings(f32 scale, s16 threshold);
    void GetNormalizeExtraStickScaleSettings(f32* scale, s16* threshold) const;
}

6.2.6.8. イベント通知

接続状態の変化とサンプリング完了を通知するイベント(nn::os::LightEvent クラス)を登録することができます。

コード 6-14. イベント通知に使用する関数
class nn::hid::ExtraPad
{
    static void RegisterConnectionEvent(nn::os::LightEvent* pLightEvent);
    static void UnregisterConnectionEvent();
    static void RegisterSamplingEvent(nn::os::LightEvent* pLightEvent);
    static void UnregisterSamplingEvent();
}

「~ConnectionEvent()」が接続状態の変化を、「~SamplingEvent()」がサンプリング完了を通知するイベントの登録と登録解除を行う関数です。イベントを登録すると、サンプリング用のスレッドの処理がわずかに増加します。

接続状態の変化を通知するイベントを登録したときの処理負荷は無視できるほどわずかです。しかし、サンプリング完了を通知するイベントを登録すると、サンプリング周期ごとに処理が行われるため、CPU の処理に負荷がかかります。そのため、イベント通知を使用しないアプリケーションは、これらの関数を使用しないことを推奨します。

なお、接続状態の変化は nn::hid::ExtraPad クラスの GetConnectionState()IsSampling()nn::hid::ExtraPadStatus 構造体の isConnected メンバの変化でも判断できます。

6.2.6.9. 補正アプレット

拡張スライドパッドのスライドパッド(R)の操作感覚を補正するため、「拡張スライドパッド補正アプレット」というライブラリアプレットが用意されています。拡張スライドパッドに対応するアプリケーションは、拡張スライドパッド補正アプレットを呼び出すシーンを用意するなど、ガイドラインの指示に従ってください。

拡張スライドパッド補正アプレットについては、「12.1.7. 拡張スライドパッド補正アプレット」を参照してください。

6.2.6.10. スライドパッドとスライドパッド(R)の相違点

スライドパッドおよびスライドパッド(R)からサンプリングされた入力座標は、キートップを意図的に動かしていない場合でも電気的揺らぎなどにより変化することがあります。スライドパッドとスライドパッド(R)とでは、キートップの位置を完全に固定した場合の値の変化量およびその確率が以下のように異なります。特に、スライドパッド(R)は値が変化する確率が高くなっていることに注意してください。

表 6-8. スライドパッドおよびスライドパッド(R)の入力座標の変化の確率

変化量

スライドパッド
X 座標

スライドパッド
Y 座標

スライドパッド(R)
X 座標

スライドパッド(R)
Y 座標

-3

0.000006 %

0.000006 %

0.002 %

0.001 %

-2

0.000178 %

0.000178 %

0.349 %

0.352 %

-1

0.003541 %

0.003541 %

3.485 %

3.273 %

±0

99.949837 %

99.949837 %

92.326 %

92.743 %

+1

0.003541 %

0.003541 %

3.491 %

3.285 %

+2

0.000178 %

0.000178 %

0.346 %

0.345 %

+3

0.000006 %

0.000006 %

0.002 %

0.001 %

単位時間内に値が変化する確率は

単位時間内に取得したサンプリングデータの数 × 上記表の確率

となります。

キートップから指を離し、キートップが中央に位置している場合、値は 0 から変化することはありません。これは、値の変化量を加味してもクランプの下限値を超えることがないためです。

6.2.7. C スティック

SNAKE に搭載されている C スティックは、ライブラリ上では拡張スライドパッドに搭載されているスライドパッド(R)と区別することなく利用することができますが、ハードウェアが異なります。そのため、ハードウェア特性の違いなどを考慮する必要があります。

6.2.7.1. C スティックのハードウェア特性

SNAKE に搭載されている C スティックは、樹脂製の軸状部品に加えられた荷重によって生じるわずかな変形(ひずみ)を検知し、変形の大きさを電圧変化の大小で読み取るアナログ入力装置です。

軸部分にかかる荷重によって C スティックからの出力値が定まるため、以下の点に留意する必要があります。

  • ユーザーの力の強さによっては、最大値を入力し続けることが困難である可能性がある。
  • 一定以上の荷重がかかると C スティックからの出力値が変動しない(出力値が飽和する)ポイントがある。
  • C スティックを真上から強く押し込んだ場合、C スティックからの出力値が不定となる。
  • 物理的に X ボタンとの距離が近いため、X ボタンを強い力で長押しすると C スティックからの出力値が変動する可能性がある。

また、個々の本体に搭載されるデバイスには性能にばらつきがあるため、以下の点にも留意する必要があります。

  • 感度の個体差が分解能に影響する。
最大値を入力するために必要な荷重による影響

C スティックで検知可能な荷重範囲は、最大値が約 240 gf となっています。そのため、ユーザーによっては最大荷重をかけ続けることが困難になる可能性があります。

なお、最小荷重の値はクランプ方式および入力方向により異なり、C スティックで検知可能な荷重範囲をまとめると以下のようになります。

表 6-9. C スティックで検知可能な荷重範囲
クランプ方式 検知可能な最少荷重 検知可能な最大荷重
上下左右の 4 方向 斜め 45 度方向
円形(min=40, max=145) 約 68 gf 約 72 gf 約 240 gf
十字(min=36, max=145) 約 63 gf 約 90 gf
最小(min=40, max=145) 約 63 gf 約 72 gf
出力値が飽和することによる影響

C スティックに対して過大な荷重がかかった場合、一定の荷重を超えると、それ以上の大きな荷重をかけても C スティックからの出力値が変動しなくなります。これを「出力値の飽和」と呼びます。

C スティックへの入力は、独立した 2 軸(x 軸と y 軸)で取得しています。両軸ともに出力値が飽和する状況下では、ユーザーによる C スティックの操作の変化を検知できなくなります。

たとえば、大きく円を描くように力を込めて C スティックを動かすと、C スティックの入力軸と SNAKE 本体の上下左右方向が一致している場合では、下図のように C スティックの入力軸から見て±45 度にある 4 方向に C スティックからの出力値が変動しない区間が発生します。

図 6-10. 出力値の飽和(C スティックの入力軸が SNAKE 本体の上下左右方向と一致している場合)

x y X Y この区間では一定の値が出力される

オレンジ色の XY 軸は SNAKE 本体の上下左右方向、黒色の xy 軸は C スティックの入力軸を示し、オレンジ色の円は入力荷重、薄い灰色部分(中央)が C スティックのデバイスから得られる未加工の出力値が取り得る範囲、濃い灰色部分が両軸ともに出力値が変動しない範囲です。なお、図解のために実際よりも変動しない範囲を大きく描いています。

C スティックの入力軸は SNAKE 本体の上下左右方向から 45 度回転させた状態で配置されており、上記のような症状による、ユーザーから見た違和感を低減させています。

図 6-11. 出力値の飽和(C スティックの入力軸が SNAKE 本体の上下左右方向から 45 度回転している場合)

x y X Y この区間では一定の値が出力される

上記の入力軸の回転はシステムによって吸収されるため、アプリケーションはライブラリから取得した C スティックの入力に回転を加える必要はありません。

真上から強く押し込んだ場合の挙動

軸部分が変形するため、以下の症状が発生する可能性があります。

  • 上下左右方向に入力が加えられていない状態でも、C スティックからの出力値が変動する。
  • ユーザーが入力した方向と異なる方向への入力として処理される。
X ボタンを長押しすることによる影響

X ボタンにかなりの荷重をかけたときに、C スティックを操作していないにもかかわらず、C スティックからの出力値が変動することがあります。この現象は、X ボタンを強く押すことでボタン周りの本体表面が変形し、その影響で C スティックの軸部分まで変形することが原因で発生します。

この現象は X ボタンを連打するケースでは発生せず、X ボタンを長押しするケースでもかなりの荷重をかけなければ発生しません。また、開発機および Newニンテンドー3DS でこの現象を発生させるには、Newニンテンドー3DS LL で発生させるよりも強い力で長押しする必要があります。

なお、この現象による C スティックからの出力値の変動範囲は、実用上考えられる範囲で、以下のようになっています。

表 6-10. X ボタンの長押しによる C スティックからの出力値の変動範囲
クランプ方式 X 軸 Y 軸
円形(min=40, max=145) 0~10 0~-35
十字(min=36, max=145) 0 0~-38
最小(min=40, max=145) 0~10 0~-37
感度の個体差による分解能への影響

C スティックの感度には個体差があり、この個体差を吸収するために、生産工程でキャリブレーションを行っています。このキャリブレーションにより、キャリブレーション後の分解能が低い個体と高い個体が存在することになります。

個体差やクランプモードで変わりますが、クランプされたあとの C スティックからの出力値には、範囲内のすべての値が出力されるわけではありません。分解能が高い個体であっても連続して値が変化するとは限らず、分解能が低い個体はその傾向が顕著になります。ただし、中点および最外周については出力されることが保証されています。

そのため、出力値をごく狭い範囲に収めることを求めるような実装や滑らかな値変化を期待した判定を行うことは推奨しません。

以下の図は、分解能が最も低い個体で円形クランプをかけた際の出力値の分布と、推奨しないごく狭い範囲の例を図示したものです。オレンジ色の範囲がアプリケーションで使用可能な値の範囲、黒い点が実際に出力される値です。隣接する黒い点が連続した値であることは保証されていないことに注意してください。なお、左の緑の円は C スティックからの出力値をベクトル長に換算した値で判定する範囲が狭い場合、右の青い四角は C スティックからの出力値そのままで判定する範囲が狭い場合です。つまり、入力方向によっては求められるベクトル長を満たす点が存在しない可能性や、その範囲内の値を出力する点が存在しない可能性があるということです。

図 6-12. C スティックからの出力値の分布とごく狭い範囲の指定例(円形クランプ、分解能が最も低い個体を想定した場合)

6.2.7.2. 拡張スライドパッドとの相違点

HID ライブラリで SNAKE の C スティックへの入力を利用する場合、以下の点で拡張スライドパッドとは仕様や挙動に違いがあります。

  • 設定可能なサンプリング周期が異なる。
  • 外的要因による切断が発生しない。
  • スリープ復帰時の挙動が異なる。
  • 拡張スライドパッド補正アプレットでは中点補正および感度補正が行われない。
設定可能なサンプリング周期が異なる

SNAKE の C スティック、ZL ボタン、ZR ボタンに対して、ハードウェア的に設定可能なサンプリング周期は 10~21 ms です。

nn::hid::ExtraPad::StartSampling() では 8~32 ms の範囲で設定可能ですが、ライブラリ内で 10 ms 以下は 10 ms、21 ms 以上は 21 ms としてハードウェアからサンプリングし、関数で設定された周期でデータを返します。

そのため、ハードウェアのサンプリング周期に合わせて 10~21 ms の範囲でサンプリング周期を設定することを推奨します。

外的要因による切断が発生しない

赤外線通信によって接続されていた拡張スライドパッドでは外的要因(取り外しや電池切れ)による切断が発生しましたが、SNAKE の C スティック、ZL ボタン、ZR ボタンは本体に搭載されていますので、外的要因によって nn::hid::ExtraPad::GetConnectionState()nn::hid::ExtraPad::CONNECTION_STATE_STOPPED を返すことはありません。

電池切れがないため、サンプリングを行っている間は nn::hid::ExtraPadStatus 構造体の batteryLevel には常に 1 が設定されます。

スリープ復帰時の挙動が異なる

nn::hid::ExtraPad::StopSampling() を呼び出さずにスリープ状態に遷移した場合、拡張スライドパッドと C スティックでは、以下のように挙動が異なります。

  • 拡張スライドパッド
    スリープによって赤外線通信が停止することにより、スリープから復帰直後のサンプリングリクエストが失敗するためにサンプリングループを抜け、ライブラリは拡張スライドパッドが停止したとみなします。ただし、内部ステートの変化は赤外線通信の状態に依存するため、停止したことを検出する前の内部ステートは安定しません。
    具体的には、nn::hid::ExtraPad::GetConnectionState() はおおむね CONNECTION_STATE_STOPPED を返しますが、タイミングによっては CONNECTION_STATE_CONNECTED を返します。
  • C スティック
    スリープから復帰直後もサンプリングリクエストが成功し、接続状態を維持したままになります。
    具体的には、nn::hid::ExtraPad::GetConnectionState() は常に CONNECTION_STATE_CONNECTED を返します。

また、nn::hid::ExtraPad::IsSampling() が返す値は内部ステートによって変化するため、nn::hid::ExtraPad::IsSampling() も同様のタイミングで値が変化します。

この挙動への対応として、スリープ状態に遷移する前に nn::hid::ExtraPad::StopSampling() を呼び出してサンプリングを停止することを推奨します。nn::hid::ExtraPad::StopSampling() を呼び出していた場合は、スリープから復帰した際に nn::hid::ExtraPad::StartSampling() でサンプリングを再開してください。アプリケーションに制御が戻る前にスリープ状態に遷移する可能性がある、HOMEメニュー、ライブラリアプレットの呼び出し前後も同様に対応することを推奨します。

拡張スライドパッド補正アプレットでは中点補正および感度補正が行われない

CTR で拡張スライドパッド補正アプレットを呼び出した場合と異なり、SNAKE でアプレットを呼び出した場合は C スティックの動作を確認するモードとなり、C スティックの中点補正を行う方法がメッセージによってユーザーに案内されます。

これは、以下のタイミングで C スティックの中点補正が自動的に行われるためです。

  • 電源投入時
    C スティックを入力状態にしたまま電源が投入されると正常に補正されません。そのような場合でも、後述のスリープ復帰時の補正で正常な補正を行うことができます。
  • スリープ復帰時
    蓋を閉じた状態では物理的に C スティックの操作を行うことができないため、C スティックを入力状態にしたままスリープ操作が行われることはまずありません。そのため、この補正が行われた場合は正常な補正が行われたとみなすことができます。
  • サンプリング中(ユーザーによる操作が行われていない間)
    C スティックからの出力値がクランプの下限値以下の状態で行われる補正のため、アプリケーションでこの補正の影響を考慮する必要はありません。
注意:

スリープ復帰時の中点補正はスリープから復帰したことをトリガーに行われます。そのため、アプリケーションでスリープを拒否すると蓋を開けても中点補正が行われません。なお、補正アプレットで表示されるメッセージでは、ユーザーに蓋を閉じてスリープすることを促します。

たとえば、以下のような理由でスリープを拒否するアプリケーションでは、スリープを拒否している間は中点補正を行えなくなることに注意してください。

  • 蓋を閉じても通信を切断したくない
  • サウンドモードで蓋を閉じたときに、ヘッドホンが接続されていたらスリープしない

6.3. MIC ライブラリ

MIC ライブラリでは、自動サンプリングによるマイクからの音声入力を扱うことができます。

MIC ライブラリの初期化は、nn::mic::Initialize() を呼び出して行います。この関数の処理が成功した時点でマイクの使用は可能となりますが、アプリケーションでマイクのサンプリングを行うには、サンプリング結果を格納するバッファの確保やマイクアンプのゲイン設定、マイク電源の制御など、サンプリングのための準備が必要です。

6.3.1. バッファの確保

サンプリング結果を格納するバッファはアプリケーションで確保してください。バッファは先頭アドレスが nn::mic::BUFFER_ALIGNMENT ( 4096 Byte ) アライメント、サイズが nn::mic::BUFFER_UNITSIZE ( 4096 ) の倍数で、デバイスメモリ以外から確保しなければなりません。確保したバッファは、nn::mic::SetBuffer() で MIC ライブラリに渡します。バッファの終端部分の 4 Byte には、管理用のメモリ領域が確保されるため、実際にサンプリング結果が格納に使用されるバッファのサイズは、指定のサイズから管理用のメモリ領域のサイズを差し引いたものとなります。サンプリング結果の格納に使用されるバッファのサイズは、nn::mic::GetSamplingBufferSize() を呼び出して取得することもできます。

バッファが確保されている状態で、nn::mic::SetBuffer() を呼び出した場合はエラーとなります。バッファを確保しなおす場合は、先に nn::mic::ResetBuffer() でバッファを呼び出してから nn::mic::SetBuffer() を呼び出してください。

6.3.2. マイクアンプのゲイン設定

マイクアンプのゲイン(増幅率)設定は、マイクからの入力音声をどれくらいの倍率で増幅するかの設定です。

ゲインの取得と設定は nn::mic::GetAmpGain()nn::mic::SetAmpGain() の呼び出しで行います。ゲインは 0 ~ 119 の範囲の値で 0.5 dB 刻みに設定することができ、0 が 10.5 dB(約 3.4 倍)、119 が 70.0 dB(約 3162 倍)に対応しています。NITRO でマイクアンプのゲインに設定可能だった 4 段階の倍率は以下の表のように、ゲインの設定値に変換して使用することができます。

表 6-11. NITRO で設定可能だった倍率とゲインの設定値

倍率

dB

ゲインの設定値

20 倍

26.0

31

40 倍

32.0

43

80 倍

38.0

55

160 倍

44.0

67

マイクアンプのゲイン設定は、ライブラリの初期化時に AMP_GAIN_DEFAULT_VALUE に設定されています。

6.3.3. マイク電源の制御

マイク電源(マイクアンプの電源)の制御は nn::mic::SetAmp() の呼び出しで行います。引数に true を渡して呼び出すことでマイク電源が ON になります。マイク電源を ON にした直後とスリープ状態から復帰した直後はマイクからの入力が安定しないため、1 秒間のサンプリング結果が強制的に無音となります。

現在の設定を取得するには nn::mic::GetAmp() を呼び出してください。

6.3.4. サンプリングの開始

ここまでの処理によってマイクのサンプリングを開始する準備は整いました。nn::mic::StartSampling() の呼び出しでマイクのサンプリングを開始することができ、サンプリングは自動で行われます。

コード 6-15. マイクサンプリングの開始
nn::Result nn::mic::StartSampling(
        nn::mic::SamplingType type, nn::mic::SamplingRate rate, s32 offset, 
        size_t size, bool loop);

type には取得するデータの種別を指定します。データの種別は以下の 4 種類から選択することができ、ビット幅と符号の有無などに違いがあります。

表 6-12. マイクサンプリングデータの種別

type

ビット幅

符号の有無

サンプリング値の範囲

無音を示すサンプリング値

SAMPLING_TYPE_8BIT

8

なし

0 ~ 255

128

SAMPLING_TYPE_16BIT

16

なし

0 ~ 65535

32768

SAMPLING_TYPE_SIGNED_8BIT

8

あり

-128 ~ 127

0

SAMPLING_TYPE_SIGNED_16BIT

16

あり

-32768 ~ 32767

0

rate にはサンプリングレート(周波数)を指定します。サンプリングレートは以下の 4 種類から選択することができます。

表 6-13. マイクのサンプリングレート

rate

サンプリングレート

SAMPLING_RATE_32730

32.73 kHz(32728.498046875 Hz)

SAMPLING_RATE_16360

16.36 kHz(16364.2490234375 Hz)

SAMPLING_RATE_10910

10.91 kHz(10909.4993489583 Hz)

SAMPLING_RATE_8180

8.18 kHz(8182.12451171875 Hz)

offset にはサンプリングデータの格納開始位置(バッファの先頭からのオフセット)を指定します。0 以上、 nn::mic::OUTPUT_OFFSET_ALIGNMENT ( 2 Byte ) のアライメントで指定しなければなりません。

size には 1 回のサンプリングで格納するサンプリング結果のバイト数を nn::mic::CTR::OUTPUT_UNITSIZE ( 2 ) の倍数で指定します。(offset + size)がバッファ確保時に指定したサイズ以下になるように指定しなければなりません。

loop には size で指定したバイト数分のサンプリング結果を格納したときに、サンプリングを継続するのか、停止するのかを指定します。true を指定した場合はサンプリングを継続し、バッファをリングバッファ(offset から size バイトの領域)のように扱います。

サンプリング中に nn::mic::StartSampling() を呼び出した場合は、サンプリングを中止してから新たなサンプリングを開始します。蓋が閉じられた状態で呼び出した場合は nn::mic::ResultShellClose を返し、サンプリングは開始されません。サンプリング中に蓋が閉じられると、自動的にサンプリングを停止し、開けられたときに再開します。

nn::mic::AdjustSampling() を呼び出すことでサンプリング中にサンプリングレートを変更することができます。サンプリングレートを変更すると、現在の格納位置から変更後のサンプリングデータを続けて格納します。

nn::mic::IsSampling() を呼び出すことでサンプリング中かどうかを取得できます。しかし、サンプリング中かどうかをデバイスに直接問い合わせるため処理が重く、毎フレーム呼び出すような処理には適していません。

nn::mic::SetLowPassFilter() の引数 enabletrue を渡して呼び出すことで、マイク入力にカット周波数がサンプリングレートの 45 % のローパスフィルタを適用することができます。デフォルトの設定は false(適用しない)です。ただし、サンプリングレートに SAMPLING_RATE_32730 を指定してサンプリングしたデータは、オリジナルデータにローパスフィルタが適用済みのため、この関数でローパスフィルタを適用しても効果はありません。

6.3.4.1. サウンド処理との同期

サウンド処理を行っている DSP とマイク処理を行っているプロセッサは別のデバイスですので、完全に同期させることができません。ただし、ズレの補正を行うことで同期に近い状態にすることは可能です。

タイマーのズレに関しては、一定時間ごとにマイクのサンプリング数と経過時間やサウンドの再生時間とのズレを計算して補正を行なってください。また、サンプリング周波数のズレについては、Voice::SetPitch() で調整して補正を行ってください。

6.3.5. サンプリング結果の取得

nn::mic::GetLastSamplingAddress() の呼び出しで、最新のサンプリング結果が格納されたアドレスを取得することができます。

nn::mic::GetBufferFullEvent() の呼び出しで取得することのできる nn::os::Event クラスのインスタンスは、バッファにこれ以上のサンプリング結果を格納することができなくなったときにシグナル状態になる手動リセットイベントです。このイベントは offset の位置から size で指定されたバイト数のサンプリング結果を格納したときにシグナル状態となり、ClearSignal() で解除されるまでシグナル状態を維持します。

入力として得られる値の範囲には本体によって個体差があり、サンプリング種別ごとの入力値の保証範囲は、TYPE_*_GUARANTEED_INPUT_MIN(MAX) で定義されています。マイク入力の判定に、入力保証範囲外の値を期待するような実装はしないでください。

表 6-14. サンプリング種別ごとのマイク入力値の保証範囲

サンプリング種別

下限値

上限値

SAMPLING_TYPE_8BIT

27

228

SAMPLING_TYPE_16BIT

7105

58415

SAMPLING_TYPE_SIGNED_8BIT

-101

100

SAMPLING_TYPE_SIGNED_16BIT

-25663

25647

デフォルトでは、上記の保証範囲内の値になるように、マイクの入力値はクランプ処理されています。より広い入力範囲を必要とする場合は、nn::mic::SetClamp() でクランプ処理を無効に設定することができますが、保証範囲外の入力値が取得できない可能性があることに注意してください。

6.3.5.1. マイク入力あり判定禁止領域

nn::mic::GetForbiddenArea() にマイクアンプのゲイン設定とサンプリング種別を渡し、マイク入力ありと判定してはいけないサンプリング結果の下限値と上限値を取得してください。取得した下限値から上限値の間の値となったサンプリング結果をマイク入力ありと判定しないでください。取得可能な値を表 6-15 に示します。

表 6-15. マイク入力あり判定禁止領域」の中で薄い灰色で示してある、ゲインが 68 以上(44.5 dB 以上)の場合は、本体スピーカーの出力音や各種ボタンの操作音、タッチパネル操作音、その他の外部からの雑音などの影響が、マイク入力に対して顕著に表れます。そのため、ゲインが 68 以上の場合は、振幅レベルによるマイク入力あり/なしの判定に使用するには不適切です。さらに、濃い灰色で示してある、ゲインが 104 以上(62.5 dB 以上)の場合は、ノイズ成分がマイク入力の範囲全域に現れるため、マイク入力が不正であってもかまわない場面でのみ使用するようにしてください。

表 6-15. マイク入力あり判定禁止領域

サンプリング種別

ゲイン

dB

マイク入力あり判定禁止領域(ノイズ成分)

SAMPLING_TYPE_8BIT

0 ~ 31

10.5 ~ 26.0

125 ~ 131

32 ~ 43

26.5 ~ 32.0

123 ~ 133

44 ~ 55

32.5 ~ 38.0

119 ~ 137

56 ~ 67

38.5 ~ 44.0

112 ~ 144

68 ~ 80

44.5 ~ 50.5

96 ~ 160

81 ~ 91

51.0 ~ 56.0

77 ~ 179

92 ~ 103

56.5 ~ 62.0

18 ~ 238

104 ~ 119

62.5 ~ 70.0

0 ~ 255

SAMPLING_TYPE_16BIT

0 ~ 31

10.5 ~ 26.0

32000 ~ 33536

32 ~ 43

26.5 ~ 32.0

31488 ~ 34048

44 ~ 55

32.5 ~ 38.0

30464 ~ 35072

56 ~ 67

38.5 ~ 44.0

28672 ~ 36864

68 ~ 80

44.5 ~ 50.5

24576 ~ 40960

81 ~ 91

51.0 ~ 56.0

19712 ~ 45824

92 ~ 103

56.5 ~ 62.0

4608 ~ 60928

104 ~ 119

62.5 ~ 70.0

0 ~ 65535

SAMPLING_TYPE_SIGNED_8BIT

0 ~ 31

10.5 ~ 26.0

- 3 ~ + 3

32 ~ 43

26.5 ~ 32.0

- 5 ~ + 5

44 ~ 55

32.5 ~ 38.0

- 9 ~ + 9

56 ~ 67

38.5 ~ 44.0

- 16 ~ + 16

68 ~ 80

44.5 ~ 50.5

- 32 ~ + 32

81 ~ 91

51.0 ~ 56.0

- 51 ~ + 51

92 ~ 103

56.5 ~ 62.0

- 110 ~ + 110

104 ~ 119

62.5 ~ 70.0

- 128 ~ + 127

SAMPLING_TYPE_SIGNED_16BIT

0 ~ 31

10.5 ~ 26.0

- 768 ~ + 768

32 ~ 43

26.5 ~ 32.0

- 1280 ~ + 1280

44 ~ 55

32.5 ~ 38.0

- 2304 ~ + 2304

56 ~ 67

38.5 ~ 44.0

- 4096 ~ + 4096

68 ~ 80

44.5 ~ 50.5

- 8192 ~ + 8192

81 ~ 91

51.0 ~ 56.0

- 13056 ~ + 13056

92 ~ 103

56.5 ~ 62.0

- 28160 ~ + 28160

104 ~ 119

62.5 ~ 70.0

- 32768 ~ + 32767

6.3.6. サンプリングの停止

開始されているサンプリングの停止は、nn::mic::StopSampling() の呼び出しで行います。この関数の呼び出しではサンプリングが停止するだけで、マイクの電源は OFF になりません。

6.3.7. MIC ライブラリの終了

アプリケーションの終了時など、マイク入力の使用を終了する場合は、サンプリングを停止したあとに以下の手順で終了処理を行ってください。

  1. nn::mic::SetAmp()false を渡して呼び出し、マイクの電源を OFF にします。
  2. nn::mic::ResetBuffer() を呼び出し、確保していたバッファを解放します。
  3. nn::mic::Finalize() を呼び出して MIC ライブラリを終了させます。

時間を空けてサンプリングを行う場合、1. の処理のみを行ってマイクの電源を OFF にし、バッテリーの消費を抑えることができます。

マイクアンプのゲイン設定は、ライブラリの終了時に AMP_GAIN_DEFAULT_VALUE に設定されます。

6.4. CAMERA ライブラリ、Y2R ライブラリ

CAMERA ライブラリでは、本体に搭載されているカメラを扱うことができます。カメラでキャプチャされた画像は YUV フォーマットでしか取得することができません。RGB フォーマットへの変換には、GPU のネイティブフォーマットへの変換にも対応している YUVtoRGB 回路の使用をお勧めします。YUVtoRGB 回路の扱いには Y2R ライブラリを利用してください。

6.4.1. 初期化

CAMERA ライブラリは nn::camera::Initialize() を、Y2R ライブラリは nn::y2r::Initialize() を呼び出すことで初期化が行われます。カメラも YUVtoRGB 回路も、これら初期化関数の呼び出しだけでは、まだ利用することができません。それぞれの設定やデータの送受信のための準備などが必要となります。

6.4.2. 撮影環境の設定

撮影環境に関して設定可能な項目について説明します。設定に使用する関数の呼び出しには対象とするカメラを指定する必要があり、以下の設定値から指定します。

表 6-16. 対象となるカメラの指定

設定値

対象となるカメラ

SELECT_NONE

カメラ指定なし。スタンバイ状態の設定などに使用します。

SELECT_OUT1

外側カメラ(R)。

SELECT_IN1

内側カメラ。

SELECT_IN1_OUT1

外側カメラ(R)と内側カメラ。

SELECT_OUT2

外側カメラ(L)。

SELECT_OUT1_OUT2

外側カメラ(R)と外側カメラ(L)。

SELECT_IN1_OUT2

外側カメラ(L)と内側カメラ。

SELECT_ALL

すべてのカメラ。外側カメラ(R)、外側カメラ(L)、内側カメラの 3 つ。

SELECT_OUT1_OUT2 を設定したときは特にステレオカメラと呼び、2 つのカメラで取得したキャプチャ画像を立体視表示に利用することができます。その際は、2 つのカメラの撮影環境がなるべく同じになるように設定してください。

補足:

ステレオカメラを利用した立体視表示やキャリブレーションの方法については、「3DS プログラミングマニュアル - グラフィックス応用編」を参照してください。

注意:

撮影環境の設定をキャプチャ中に行うと、キャプチャ画像がずれてしまう可能性がありますので、キャプチャを一時的に停止した状態で設定を行ってください。

SELECT_ALL によるカメラの指定は、外側のカメラが 1 つであったときと現在とでは対象となるカメラが異なることに注意してください。

カメラの再起動処理中に撮影環境の設定が行われると、ライブラリ内で処理が長時間ブロックされることがありますので注意してください。

カメラが撮影して得られる画像データには、カメラ個体のばらつき、環境光によるばらつき、被写体自体の色のばらつきを含むことになります。たとえば、カメラ個体のばらつきには画角、解像度、色再現性、回転、ディストーション等を含みます。そのため、同じアングル、同じカメラ設定で撮影して得られる画像は、本体ごとに異なります。

解像度

カメラがキャプチャするイメージの解像度を nn::camera::SetSize() の呼び出しで設定することができます。解像度はトリミングされる前のイメージサイズで、設定可能な解像度には以下のものがあります。

表 6-17. 解像度

設定値

解像度

説明

SIZE_VGA

640 x 480

VGA

SIZE_QVGA

320 x 240

QVGA

SIZE_QQVGA

160 x 120

QQVGA

SIZE_CIF

352 x 288

CIF(アスペクト比 11: 9)

SIZE_QCIF

176 x 144

QCIF(アスペクト比 11: 9)

SIZE_DS_LCD

256 x 192

DS の LCD の解像度

SIZE_DS_LCDx4

512 x 384

DS の LCD の解像度を幅、高さともに 2 倍にした解像度

SIZE_CTR_TOP_LCD

400 x 240

3DS の上 LCD の解像度

SIZE_CTR_BOTTOM_LCD

320 x 240

3DS の下 LCD の解像度。QVGA と同じです

SIZE_CIFSIZE_QCIFSIZE_CTR_TOP_LCD でキャプチャした画像は、4 : 3 でキャプチャした画像の左右が切られた形で取得することになります。

nn::camera::SetDetailSize() を呼び出すことで、上記以外の解像度を設定することができます。出力画像の幅と高さ、元画像(VGA サイズ)から切り出す領域(クロップ領域)を指定することで、任意の解像度でキャプチャ画像を取得することができます。必ずクロップ領域の幅と高さが出力画像以上になるように指定してください。トリミングを行わない場合は出力画像の幅と高さを乗じた値が 128 の倍数でなければなりません。また、互換性維持のため、必ず引数 cropX0 は偶数かつ、cropX1 - cropX0 + 1 が 4 の倍数になるように指定してください。

ステレオカメラを利用して立体視表示をするときは、2 つのカメラの解像度を同じ解像度に設定してください。

鮮明度

カメラの鮮明度を nn::camera::SetSharpness() の呼び出しで設定することができます。設定可能な鮮明度は -4 ~ +5 の範囲です。

露光

カメラの露光を nn::camera::SetExposure() の呼び出しで設定することができます。設定可能な露出量は -5 ~ +5 の範囲です。

自動露出機能は nn::camera::SetAutoExposure() の呼び出しで有効・無効を制御することができます。カメラ起動直後は露出値が不安定になるため、自動露出機能を有効にしておくことを推奨しています。現在の設定は nn::camera::IsAutoExposure() の呼び出しで取得することができます。自動露出機能が無効に設定されていても、nn::camera::SetExposure() で露出を設定すると有効に切り替わることに注意してください。

nn::camera::SetAutoExposureWindow() を呼び出すことで、自動露出機能による露出の自動計算の基準となる領域を設定することができます。領域はキャプチャ画像の最大サイズである VGA(640 × 480)内の部分領域として指定し、開始座標と幅、高さは以下の範囲内で変更することができます。また、表の右端 3 列はそれぞれ、内側カメラ、外側カメラ(R)、外側カメラ(L)の初期設定値です。

表 6-18. 露出の基準領域の指定

引数

設定

設定値の範囲

IN1

OUT1

OUT2

startX

開始座標(横方向)

0 ~ 600(40 ピクセル単位)

80

0

0

startY

開始座標(縦方向)

0 ~ 450(30 ピクセル単位)

60

0

0

width

40 ~ 640(40 ピクセル単位)startX との和が 640 以内

480

640

640

height

高さ

30 ~ 480(30 ピクセル単位)staryY との和が 480 以内

360

480

480

フレームレート

1 秒間にキャプチャする画像の枚数(fps)を nn::camera::SetFrameRate() の呼び出しで設定することができます。設定可能なフレームレートには以下のものがあります。ステレオカメラを利用するときは、2 つのカメラに対して同じ固定フレームレートを設定してください。

表 6-19. フレームレート

設定値

フレームレート

FRAME_RATE_15

15 fps 固定

FRAME_RATE_15_TO_5

明るさに応じて 15 fps から 5 fps の間で自動的に変化

FRAME_RATE_15_TO_2

明るさに応じて 15 fps から 2 fps の間で自動的に変化

FRAME_RATE_10

10 fps 固定

FRAME_RATE_8_5

8.5 fps 固定

FRAME_RATE_5

5 fps 固定

FRAME_RATE_20

20 fps 固定

FRAME_RATE_20_TO_5

明るさに応じて 20 fps から 5 fps の間で自動的に変化

FRAME_RATE_30

30 fps 固定

FRAME_RATE_30_TO_5

明るさに応じて 30 fps から 5 fps の間で自動的に変化

FRAME_RATE_15_TO_10

明るさに応じて 15 fps から 10 fps の間で自動的に変化

FRAME_RATE_20_TO_10

明るさに応じて 20 fps から 10 fps の間で自動的に変化

FRAME_RATE_30_TO_10

明るさに応じて 30 fps から 10 fps の間で自動的に変化

ホワイトバランス

ホワイトバランスを nn::camera::SetWhiteBalance() の呼び出しで設定することができます。設定可能なホワイトバランスには以下のものがあります。

表 6-20. ホワイトバランス

設定値

エイリアス指定

説明

WHITE_BALANCE_AUTO

WHITE_BALANCE_NORMAL

オートホワイトバランス

WHITE_BALANCE_3200K

WHITE_BALANCE_TUNGSTEN

タングステン光(白熱電球)

WHITE_BALANCE_4150K

WHITE_BALANCE_WHITE_FLUORESCENT_LIGHT

白色蛍光灯

WHITE_BALANCE_5200K

WHITE_BALANCE_DAYLIGHT

太陽光

WHITE_BALANCE_6000K

WHITE_BALANCE_CLOUDY

くもり

WHITE_BALANCE_HORIZON

夕焼け

WHITE_BALANCE_7000K

WHITE_BALANCE_SHADE

日陰

自動調整機能は、nn::camera::SetWhiteBalance() でホワイトバランスを WHITE_BALANCE_AUTO に設定すると有効になり、それ以外に設定すると無効になることに注意してください。

WHITE_BALANCE_AUTO で設定されるホワイトバランスのまま、自動調整機能の有効・無効だけを制御したい場合は nn::camera::SetAutoWhiteBalance() を使用してください。WHITE_BALANCE_AUTO 以外が設定されている場合、nn::camera::SetAutoWhiteBalance() を使用することはできません。自動調整機能の現在の設定は nn::camera::IsAutoWhiteBalance() の呼び出しで取得することができます。

nn::camera::SetAutoWhiteBalanceWindow() を呼び出すことで、ホワイトバランスの自動調節機能によるホワイトバランスの自動計算の基準となる領域を設定することができます。領域はキャプチャ画像の最大サイズである VGA(640 × 480)内の部分領域として指定し、開始座標と幅、高さは以下の範囲内で変更することができます。また、表の右端 3 列はそれぞれ、内側カメラ、外側カメラ(R)、外側カメラ(L)の初期設定値です。

表 6-21. ホワイトバランスの基準領域の指定

引数

設定

設定値の範囲

IN1

OUT1

OUT2

startX

開始座標(横方向)

0 ~ 600(40 ピクセル単位)

0

0

0

startY

開始座標(縦方向)

0 ~ 450(30 ピクセル単位)

0

0

0

width

40 ~ 640(40 ピクセル単位)startX との和が 640 以内

640

640

640

height

高さ

30 ~ 480(30 ピクセル単位)staryY との和が 480 以内

480

480

480

補足:

入力画像に変化が少ない場合やコントラストが少ない画像(無地の壁など)の場合は、ホワイトバランスの自動調整機能の働きが弱くなることがあります。

撮影モード

被写体に合わせて、撮影モードを nn::camera::SetPhotoMode() の呼び出しで設定することができます。設定可能な撮影モードには以下のものがあります。

表 6-22. 撮影モード

設定値

撮影モード

説明

PHOTO_MODE_NORMAL

補正なし

カメラの設定は補正されません。

PHOTO_MODE_PORTRAIT

ポートレートモード

人物の撮影に向いた設定です。

PHOTO_MODE_LANDSCAPE

風景モード

風景の撮影に向いた設定です。

PHOTO_MODE_NIGHTVIEW

暗視モード

暗所での撮影に向いた設定です。

PHOTO_MODE_LETTER

文字モード

QR コードや文字の撮影に向いた設定です。

撮影モードを変更すると、下表のようにコントラストやゲイン、鮮明度、露光、ホワイトバランスが上書きされるほか、外側カメラと内側カメラの露出の基準領域が変更されます。「全体」の設定は開始座標が (0, 0)、幅と高さが 640 と 480 です。「中心」の設定は開始座標が (80, 60)、幅と高さが 480 と 360 です。

表 6-23. 撮影モードで調整される撮影環境

撮影モード

コントラスト

ゲイン

鮮明度

露光

ホワイトバランス

外側
カメラ

内側
カメラ

補正なし

NORMAL

通常

0

0

NORMAL

全体

中心

ポートレートモード

LOW

通常

-2

0

NORMAL

中心

中心

風景モード

NORMAL

通常

+1

0

DAYLIGHT

全体

中心

暗視モード

NORMAL

最大

-1

+2

NORMAL

全体

中心

文字モード

HIGH

通常

+2

+2

NORMAL

全体

中心

反転処理

出力画像に適用される反転処理を nn::camera::FlipImage() の呼び出しで設定することができます。設定可能な反転処理には以下のものがあります。

表 6-24. 反転処理

設定値

適用される反転処理

FLIP_NONE

反転処理なし

FLIP_HORIZONTAL

左右反転

FLIP_VERTICAL

上下反転

FLIP_REVERSE

180 度回転(上下、左右ともに反転した状態)

エフェクト

出力画像に適用される特殊効果(エフェクト)を nn::camera::SetEffect() の呼び出しで設定することができます。設定可能なエフェクトには以下のものがあります。

表 6-25. エフェクト

設定値

エフェクト

EFFECT_NONE

特殊効果なし

EFFECT_MONO

モノクロ調

EFFECT_SEPIA

セピア調(黄土色)

EFFECT_NEGATIVE

ネガポジ反転

EFFECT_NEGAFILM

フィルム調のネガポジ反転。EFFECT_NEGATIVE の U と V の順番を入れ替えています

EFFECT_SEPIA01

セピア調(赤褐色)

エフェクトを適用した上でほかの設定を変更すると、エフェクトの効果が変わります。セピア調に設定した上で鮮明度を下げれば印象が柔らかくなり、フィルム調のネガポジ反転に設定した上でホワイトバランスの色温度を上げれば赤みを強調することができます。

コントラスト

コントラスト(ガンマカーブ)を nn::camera::SetContrast() の呼び出しで設定することができます。設定可能なコントラストには以下のものがあります。

表 6-26. コントラスト

設定値

コントラスト

CONTRAST_PATTERN_nn は 01 ~ 11)

コントラストのパターン No.n

CONTRAST_HIGH

デフォルトよりもコントラスト比が高くなる設定(パターン No.7)

CONTRAST_NORMAL

デフォルトの設定(パターン No.6)

CONTRAST_LOW

デフォルトよりもコントラスト比が低くなる設定(パターン No.5)

レンズ補正

レンズ補正とは、光量の差によって画像の中心と周辺の明るさに差が出てしまう現象(周辺光量低下)への対策として、画像の周辺の明るさを補正して中心の明るさに近づける処理のことです。レンズ補正は nn::camera::SetLensCorrection() の呼び出しで設定することができます。設定可能なレンズ補正の値には以下のものがあります。

表 6-27. レンズ補正

設定値

レンズ補正

LENS_CORRECTION_OFF

レンズ補正の設定を無効にします

LENS_CORRECTION_ON_70

レンズ補正を 70 に設定します

LENS_CORRECTION_ON_90

レンズ補正を 90 に設定します

LENS_CORRECTION_DARK

デフォルトよりも画像の周辺が暗くなる設定(LENS_CORRECTION_OFF

LENS_CORRECTION_NORMAL

デフォルトの設定(LENS_CORRECTION_ON_70

LENS_CORRECTION_BRIGHT

デフォルトよりも画像の周辺が明るくなる(LENS_CORRECTION_ON_90

コンテキスト

コンテキストを利用すると、複数の撮影環境の設定をまとめて切り替えることができます。コンテキストの切り替えは、nn::camera::SwitchContext() を呼び出して行います。コンテキストはカメラごとに A と B の 2 つ(計 6 パターン)があり、外側カメラがコンテキスト A、内側カメラがコンテキスト B のように独立して設定することができます。

コンテキストによって切り替えられる撮影環境は、解像度、反転処理、エフェクトの 3 項目です。

ノイズフィルタ

画面の明るさが明から暗またはその逆に変化したとき、カメラモジュールはノイズフィルタ機能によって自動的にキャプチャ画像のノイズを除去します。この機能が有効になっていると、ステレオカメラ使用時に片方のカメラのキャプチャ画像だけがぼやけて見える状況になることがあります。それを防ぐために nn::camera::SetNoiseFilter() の引数 onfalse を渡して呼び出して、ノイズフィルタを無効にしてください。ontrue を渡した場合は有効になります。どのカメラも、デフォルトでノイズフィルタが有効に設定されています。

撮影環境の一括設定

撮影環境を一括して変更する関数が用意されています。

nn::camera::SetPackageParameterWithoutContext() は、コンテキスト指定のない撮影環境すべて(解像度、反転処理、エフェクト以外)を一括して設定することができます。

nn::camera::SetPackageParameterWithContext() は、コンテキスト指定のある撮影環境すべて(解像度、反転処理、エフェクト)を一括して設定することができます。

6.4.3. キャプチャの設定

カメラがキャプチャした画像は数ラインずつ FIFO に書き込まれ、アプリケーションは用意したバッファに YUV フォーマットのデータを受け取ります。アプリケーションは次に、受け取ったデータを YUVtoRGB 回路に送信し、RGB フォーマットに変換されたデータを受け取ります。この一連のデータの流れを図にすると以下のようになります。

図 6-13. キャプチャされたデータの流れ

Camera FIFO(10KByte) YUVtoRGB Output Buffer Buffer(YUV) Buffer(RGB) CameraModule CapturedImage Hardware Application nn::camera::SetReceiving() nn::y2r::SetSendingYuv() Data Transfer nn::y2r::SetReceiving()

ここでは、YUV フォーマットのキャプチャ画像をアプリケーションのバッファに受け取るまでに必要な設定について説明します。

ポートについて

ステレオカメラのように 2 つのカメラを同時に使用できるようになり、キャプチャした画像を取得するときに、どのカメラから画像を取得するのかを指定しなければならなくなりました。3 つあるカメラのうち、内側カメラと外側カメラ(R)が 1 つのポートに接続されており、外側カメラ(L)は単独で別のポートに接続されています。

キャプチャの設定を行う関数のほとんどがポートの指定を必要とし、そのポートの指定には以下の列挙子を使用します。

表 6-28. ポートの指定

列挙子

説明

PORT_NONE

ポートを指定しません。

PORT_CAM1

内側カメラと外側カメラ(R)が接続されているポートを指定します。

PORT_CAM2

外側カメラ(L)が接続されているポートを指定します。

PORT_BOTH

両方のポートを指定します。

トリミング

トリミングは、キャプチャ画像の一部を切り取ってアプリケーションが必要とするサイズにする処理です。カメラの解像度と必要なキャプチャ画像のサイズが異なる場合に使用します。

トリミングは nn::camera::SetTrimming() の呼び出しで有効・無効を制御することができます。トリミングを有効にすると、nn::camera::SetTrimmingParams() または nn::camera::SetTrimmingParamsCenter() でトリミングの範囲を設定することができます。トリミングが有効であるかどうかは nn::camera::IsTrimming() の呼び出しで判定することができ、現在のトリミング範囲は nn::camera::GetTrimmingParams() の呼び出しで取得することができます。

注意:

トリミングの設定はキャプチャの開始前に行ってください。

トリミングの位置と範囲を nn::camera::SetTrimmingParams() で設定する場合は、トリミング開始位置(x1, y1)とトリミング終了位置(x2, y2)を指定します。(x1, y1)はトリミングの範囲に含まれますが、(x2, y2)は含まれません。これらの設定値には以下の制限があります。

  • トリミング開始位置の座標 x1 と y1 は偶数でなければなりません。
  • x1 < x2, y1 < y2 を満たさなければなりません。
  • トリミング後の画像の幅(x2 - x1)と(y2 - y1)は偶数でなければなりません。
  • トリミング後の画像の幅と高さを乗じた値が 128 の倍数でなければなりません。

nn::camera::SetTrimmingParamsCenter() で設定する場合は、トリミングサイズの幅(trimWidth)と高さ(trimHeight)、カメラ解像度の幅(camWidth)と高さ(camHeight)を指定し、キャプチャ画像の中心を基準にトリミングを行います。この設定から計算される(x1, y1)と(x2, y2)は以下のコードで表すことができます。計算後の位置が nn::camera::SetTrimmingParams() での制限にかからないように注意してください。

コード 6-16. 中心を基準にしたトリミング設定の位置計算
x1 = (camWidth - trimWidth) / 2;
y1 = (camHeight - trimHeight) / 2;
x2 = x1 + trimWidth;
y2 = y1 + trimHeight;

バッファに転送されるキャプチャ画像のサイズはトリミング後のサイズです。トリミング後のサイズが同じであれば、カメラの解像度が異なる場合でも転送にかかるコストは変わりません。ただし、高い解像度でキャプチャした画像に対してトリミングを行うと、視野角の違いによって映る範囲が狭まってしまいます。

転送バイト(ライン)数

カメラでキャプチャした画像は、ハードウェア上の FIFO に分割して格納され、数回の転送でアプリケーションが用意したバッファに書き込まれます。FIFO の容量は 10 KByte と決まっています。また、一回の転送で転送されるバイト数には、以下の条件があります。

  • 一回の転送バイト数は 256 Byte の整数倍でなければなりません。
  • 一回の転送バイト数は 10 KByte(10240 Byte)以下でなければなりません。
  • 総転送バイト数は一回の転送バイト数の整数倍でなければなりません。

総転送バイト数はトリミング後の画像の幅と高さに 1 ピクセルあたりのバイト数である 2 を乗じた値です。

一回の転送で転送されるバイト数をライン数で設定するには、nn::camera::SetTransferLines() を呼び出します。nn::camera::GetMaxLines() で返されるライン数は、そのまま一回の転送で転送されるライン数として設定することができますが、上記の条件を満たすライン数が見つからなければ関数内で停止しますので注意してください。nn::camera::SetDetailSize() で任意の解像度を設定しているなど、ライン数で設定することができないときは、nn::camera::SetTransferBytes() を呼び出して一回の転送で転送されるバイト数を設定してください。nn::camera::GetMaxBytes() で返されるバイト数は、そのまま一回の転送で転送されるバイト数として設定することができますが、幅と高さに 1 ピクセルあたりのバイト数である 2 を乗じた値が 256 の整数倍でなければ関数内で停止しますので注意してください。

注意:

転送バイト(ライン)数の設定はキャプチャの開始前に行ってください。バッファエラー回避のため、GetMaxLines()GetMaxBytes() は FIFO の容量を 5 KByte とみなして計算します。

現在の設定は nn::camera::GetTransferBytes() の呼び出しで取得することができます。

受信バッファ

1 フレームのキャプチャ画像を受信するために必要なバッファのサイズは nn::camera::GetFrameBytes() で取得することができます。バッファの先頭アドレスのアライメントは 4 Byte ですが、64 Byte 未満のアライメントでは転送速度が落ちる可能性があります。デバイスメモリ上に確保したバッファのみ指定可能です。

6.4.4. キャプチャの開始

転送とキャプチャの開始前に nn::camera::Activate() を呼び出してキャプチャに使用するカメラを起動します。同じポートに接続されている、内側カメラと外側カメラ(R)を同時に起動することはできません。別のポートに接続されている外側カメラ(L)は、内側カメラまたは外側カメラ(R)のどちらかと同時に起動することができます。

カメラの起動を確認してから、nn::camera::SetReceiving() を呼び出して転送を開始し、nn::camera::StartCapture() を呼び出してキャプチャを開始してください。

コード 6-17. nn::camera::SetReceiving()
void nn::camera::SetReceiving(nn::os::Event* pEvent, void* pDst, 
        nn::camera::Port port, size_t imageSize, s16 transferUnit);

pEvent には転送完了の通知を受け取るイベントを指定します。pDst には受信バッファの先頭アドレスを nn::camera::BUFFER_ALIGNMENT ( 4 Byte ) アライメントで指定します。port にはポートを指定します。imageSize には 1 フレームのキャプチャ画像のバイトサイズ(受信バッファのサイズ)を指定してください。transferUnit には nn::camera::GetTransferBytes() で返される一回の転送で転送されるデータのバイトサイズを指定してください。

nn::camera::IsFinishedReceiving() の呼び出しで、1 フレーム分のキャプチャ画像の転送が終了したかどうかを取得することができます。

FIFO への書き込みエラーなど、キャプチャの途中でエラーが発生したかどうかを確認するには、 nn::camera::GetBufferErrorInterruptEvent() で取得することのできるエラーイベントがシグナル状態になっていないかをチェックしてください。エラーイベントはバッファエラーが発生したときにシグナル状態になる、nn::os::Event クラスの自動リセットイベントです。また、このエラーイベントはカメラの誤作動による再起動処理が発生したときにもシグナル状態となります。エラーから復帰するには、転送、キャプチャの順に再開してください。

nn::camera::IsBusy() の呼び出しでキャプチャ画像を取り込んでいる最中であるかどうかを取得することができます。また nn::camera::GetVsyncInterruptEvent() では、カメラの VSYNC 割り込みの発生でシグナル状態となるイベントを取得することができます。カメラの VSYNC に同期した処理や、フレーム転送が行われていない期間に撮影環境を変更する処理などに利用することができます。

ステレオカメラを利用して立体視表示をするときなどに、カメラの VSYNC 割り込みのタイミングを同期させたい場合は nn::camera::SynchronizeVsyncTiming() を呼び出してください。この関数は 2 つのカメラの VSYNC 割り込みのタイミングが同期するように試みます。同期した状態を継続させる処理ではありませんので、ズレが生じた場合には再び呼び出す必要があります。また、カメラを一度スタンバイ状態にしてから復帰させるため、関数を呼び出した直後の 4 フレームの画像は極端に暗くなることがあります。2 つのカメラの設定を同じにしていても、それぞれのカメラからキャプチャ画像が送出されるタイミングにはズレがあります。また、同じ設定、固定フレームレートで撮影していても、nn::camera::Activate() を呼び出してカメラを起動したときや撮影環境の設定を変更したときは VSYNC 割り込みのタイミングに大きなズレが生じることがあります。

キャプチャ画像(YUV4:2:2 フォーマット)は、以下のデータの並びで出力されます。

+ 0 Byte

+ 1 Byte

+ 2 Byte

+ 3 Byte

Y (n)

U (n)

Y (n + 1)

V (n)

6.4.5. YUVtoRGB 回路の設定

YUVtoRGB 回路は YUV フォーマットのデータをハードウェアで RGB フォーマットに変換することができます。また、GPU のネイティブフォーマットであるブロックフォーマットでの出力機能も備えています。しかし、YUVtoRGB 回路は 1 つしか搭載されていませんので、ステレオカメラなどで複数のカメラからのキャプチャ画像を変換するときには、排他処理などで複数の変換要求が同時に発生しないようにしなければなりません。

ここでは、YUVtoRGB 回路による変換に関係する設定項目を説明します。

入力フォーマット

入力する YUV データのフォーマットは nn::y2r::SetInputFormat() を呼び出して設定します。現在の設定は nn::y2r::GetInputFormat() で取得することができます。入力可能なフォーマットには以下のものがあります。

表 6-29. 入力フォーマット

設定値

フォーマット

INPUT_YUV422_INDIV_8

YUV4:2:2 の Y、U、V を個別に 8 bit で入力します

INPUT_YUV420_INDIV_8

YUV4:2:0 の Y、U を個別に 8 bit で入力します

INPUT_YUV422_INDIV_16

YUV4:2:2 の Y、U、V を個別に 16 bit(要パディング)で入力します

INPUT_YUV420_INDIV_16

YUV4:2:0 の Y、U を個別に 16 bit(要パディング)で入力します

INPUT_YUV422_BATCH

YUV4:2:2 の Y、U、V をまとめて 32 bit で入力します

それぞれのデータ形式は以下のようになっています。

YUV4:2:2/YUV4:2:0 個別入力(8 bit)

成分

+ 0 Byte

+ 1 Byte

+ 2 Byte

+ 3 Byte

Y

Y(n)

Y (n + 1)

Y (n + 2)

Y (n + 3)

U

U (n)

U (n + 1)

U (n + 2)

U (n + 3)

V

V (n)

V (n + 1)

V (n + 2)

V (n + 3)

YUV4:2:2/YUV4:2:0 個別入力(16 bit padding)

成分

+ 0 Byte

+ 1 Byte

+ 2 Byte

+ 3 Byte

Y

Y (n)

padding

Y (n + 1)

padding

U

U (n)

padding

U (n + 1)

padding

V

V (n)

padding

V (n + 1)

padding

YUV4:2:2 一括入力

成分

+ 0 Byte

+ 1 Byte

+ 2 Byte

+ 3 Byte

YUV

Y (n)

U (n)

Y (n + 1)

V (n)

カメラのキャプチャ画像は YUV 一括のフォーマットでのみ取得することができますので、ほとんどの場合、キャプチャ画像の変換時には INPUT_YUV422_BATCH を指定することになります。

1 ラインの幅と入力ライン数

変換するデータ(入力データ)の 1 ラインの幅は nn::y2r::SetInputLineWidth() で設定します。現在の設定は nn::y2r::GetInputLineWidth() で取得することができます。1 ラインの幅は 1024 までの 8 の倍数でなければなりません。

入力ライン数は nn::y2r::SetInputLines() で設定します。現在の設定は nn::y2r::GetInputLines() で取得することができます。

出力フォーマット

YUVtoRGB 回路で変換されたデータは出力バッファに格納されます。出力されるデータのフォーマット設定は nn::y2r::SetOutputFormat() を呼び出して行います。現在の設定は nn::y2r::GetOutputFormat() で取得することができます。出力フォーマットには以下のフォーマットを指定することができます。

表 6-30. 出力フォーマット

設定値

フォーマット

OUTPUT_RGB_32

32 bit RGB(RGBA8888)

OUTPUT_RGB_24

24 bit RGB(RGB888)

OUTPUT_RGB_16_555

16 bit RGB(RGBA5551)

OUTPUT_RGB_16_565

16 bit RGB(RGB565)

それぞれのデータ形式は以下のようになっています。

32 bit RGB(OUTPUT_RGB_32

+0 Byte +1 Byte +2 Byte +3 Byte A [7 : 0] B (n) G (n) R (n)

24 bit RGB(OUTPUT_RGB_24

+0 Byte +1 Byte +2 Byte R (n) G (n) B (n)

16 bit RGB(OUTPUT_RGB_16_555

+0 Byte +1 Byte +2 Byte +3 Byte 5 bit 5 bit 5 bit 1 bit 5 bit 5 bit 5 bit 1 bit R (n) G (n) B (n) A [7] R (n + 1) G (n + 1) B (n + 1) A [7]

16 bit RGB(OUTPUT_RGB_16_565

+0 Byte +1 Byte +2 Byte +3 Byte 5 bit 6 bit 5 bit 5 bit 6 bit 5 bit R (n) G (n) B (n) R (n + 1) G (n + 1) B (n + 1)

アルファ成分が出力されるフォーマットの場合、nn::y2r::SetAlpha() の呼び出しで設定されたアルファ値が使用されます。設定されたアルファ値は、OUTPUT_RGB_32 のフォーマットでは 0 ~ 7 bit が、OUTPUT_RGB_16_555 のフォーマットでは 7 bit 目が使用されます。現在のアルファ値は nn::y2r::GetAlpha() の呼び出しで取得することができます。

ブロックアライメント

出力バッファに格納されるデータの並び(ブロックアライメント)は nn::y2r::SetBlockAlignment() を呼び出して行います。現在の設定は nn::y2r::GetBlockAlignment() で取得することができます。ブロックアライメントには以下のものを指定することができます。

表 6-31. ブロックアライメント

設定値

ブロックアライメント

BLOCK_LINE

水平ラインフォーマット。通常のリニアフォーマットです。出力フォーマットが 24 bit RGB または 32 bit RGB の場合、バイトオーダーの関係で、そのままでは OpenGL 標準フォーマットのテクスチャとして利用することができません。

BLOCK_8_BY_8

8x8 ブロックフォーマット。GPU のネイティブフォーマットであるブロックフォーマットと同じデータの並びです。ネイティブフォーマットのテクスチャイメージとして使用することができます。

注意:

BLOCK_8_BY_8 を指定した場合は、入力イメージの高さ(縦のライン数)も 8 の倍数でなければなりません。

出力バッファ

1 フレームの出力データを受信するために必要なバッファのサイズは nn::y2r::GetOutputImageSize() で取得することができます。バッファの先頭アドレスのアライメントは 4 Byte ですが、64 Byte 未満のアライメントでは転送速度が落ちる可能性があります。デバイスメモリ上に確保したバッファのみ指定可能です。

変換係数

YUV フォーマットから RGB フォーマットへの変換に使用する係数を標準的な変換係数から選択します。変換係数の設定は、nn::y2r::SetStandardCoefficient() の呼び出しで行うことができます。

カメラから出力された画像を変換するための変換係数には、カメラモジュールが将来的に変更される可能性を考慮し、nn::camera::GetSuitableY2rStandardCoefficient() で取得した変換係数のタイプを選択してください。

標準的な変換係数のタイプには以下の 4 つがあります。

表 6-32. 標準的な変換係数のタイプ

設定値

変換係数のタイプ(値の範囲)

COEFFICIENT_ITU_R_BT_601

ITU-R BT.601(0 ≦ Y, U, V ≦ 255)

COEFFICIENT_ITU_R_BT_709

ITU-R BT.709(0 ≦ Y, U, V ≦ 255)

COEFFICIENT_ITU_R_BT_601_SCALING

ITU-R BT.601(16 ≦ Y ≦ 235, 16 ≦ U, V ≦ 240)

COEFFICIENT_ITU_R_BT_709_SCALING

ITU-R BT.709(16 ≦ Y ≦ 235, 16 ≦ U, V ≦ 240)

回転

フォーマット変換の際に回転を適用することができます。nn::y2r::SetRotation() で回転の角度を指定することができ、nn::y2r::GetRotaion() で現在の回転角度を取得することができます。回転なしを含めると、指定可能な回転角度は以下の 4 つです。

表 6-33. 回転角度

設定値

回転角度

ROTATION_NONE

回転なし

ROTATION_CLOCKWISE_90

時計回りに 90 度

ROTATION_CLOCKWISE_180

180 度

ROTATION_CLOCKWISE_270

時計回りに 270 度(反時計回りに 90 度)

回転が適用されると、変換後のデータは正しいイメージデータの並びではありません。そのため、アプリケーションは 1 フレームのデータを受信したあと、データの並びを修正しなければなりません。

補足:

今後、転送時に正しいデータの並びで出力されるように修正される可能性があります。

図 6-14. ブロックアライメントと回転による出力データの並びの違い

ROTATION_NONE ROTATION_CLOCKWISE_90 ROTATION_CLOCKWISE_180 ROTATION_CLOCKWISE_270 Output Buffer BLOCK_LINE BLOCK_8_BY_8

一括設定

nn::y2r::SetPackageParameter() で YUVtoRGB 回路の設定を一括して変更することができます。設定の一括取得は nn::y2r::GetPackageParameter() で行うことができます。

6.4.6. フォーマット変換の開始

フォーマットの変換はデータの送受信と平行して行われるため、変換の開始までにデータ送受信の準備を行わなければなりません。

入力データの送信準備は、YUV 一括が nn::y2r::SetSendingYuv()、Y のみが nn::y2r::SetSendingY()、U のみが nn::y2r::SetSendingU()、V のみが nn::y2r::SetSendingV() で行われます。引数には入力データが格納されているバッファ(デバイスメモリ上に確保したバッファのみ指定可能です)と、転送データの総サイズと 1 ライン分の入力データのサイズをバイト単位で指定します。総サイズが 1 ライン分のサイズの整数倍でなければならないことに注意してください。また、いずれの関数でも 1 ライン分の入力データが転送されたときに加算されるオフセット値(transferStride)を指定することができます。

出力データの受信準備は nn::y2r::SetReceiving() で行います。引数には出力データを格納するバッファ(VRAM 上のバッファは指定できません。デバイスメモリ上に確保したバッファのみ指定可能です。また nn::y2r::BUFFER_ALIGNMENT ( 4 Byte ) アライメントが必要です。)と、受信データの総サイズと受信データの 1 回分の転送サイズをバイト単位で指定します。パフォーマンスを上げるために、転送サイズには 8 ライン分の出力データのサイズを指定することを推奨します。受信データの総サイズに指定する値は nn::y2r::GetOutputImageSize() で取得することができます。8 ライン分のデータサイズに指定する値には、nn::y2r::GetOutputFormatBytes() で取得した 1 ピクセルのバイトサイズと 1 ラインの幅とを乗算した値に 8 を乗算した値を指定します。また、1 回の転送ごとに加算されるオフセット値(transferStride)を指定することができます。1 ラインごとにオフセットを加えたい場合は、1 回分の転送サイズに 1 ライン分の出力データのサイズを指定してください。

データ送受信の準備を行うタイミングとしては、nn::camera::IsFinishedReceiving() もしくは nn::camera::SetReceiving() で指定したイベントのシグナル状態でキャプチャ画像の受信が終了したことを確認した直後の、入力データが確定した時点が最適です。ただし、nn::y2r::IsBusyConversion() でフォーマット変換中でないことを確認してからデータ送受信の準備を行ってください。

データ送受信の準備が整ったあとは nn::y2r::StartConversion() でフォーマット変換を開始することができます。フォーマット変換の開始と同時にデータの送受信も開始されます。キャプチャ処理中のエラーの発生などで、フォーマット変換を強制的に停止しなければならないときは nn::y2r::StopConversion() を呼び出してください。

フォーマット変換中であるかどうかは nn::y2r::IsBusyConversion() で取得することができます。入力データの送信が完了しているかどうかは、YUV 一括が nn::y2r::IsFinishedSendingYuv()、Y のみが nn::y2r::IsFinishedSendingY()、U のみが nn::y2r::IsFinishedSendingU()、V のみが nn::y2r::IsFinishedSendingV() で取得することができます。出力データの受信が完了しているかどうかは、nn::y2r::IsFinishedReceiving() で取得することができます。

1 フレーム分のフォーマット変換およびデータの送受信が終了しているかどうかは、上記の関数を組み合わせて判断することもできますが、データ転送完了時に発生する割り込みの通知を nn::y2r::GetTransferEndEvent() で取得したイベントクラス(自動リセットイベント)で受け取ることで判断することもできます。イベントクラスを取得する前に nn::y2r::SetTransferEndInterrupt() による割り込み通知の許可(デフォルトは許可された状態です)が必要です。現在、通知が許可されているかどうかは nn::y2r::GetTransferEndInterrupt() で取得することができます。

発生することはまれですが、カメラと YUVtoRGB 回路を同時に使用しているときに、カメラのデータ転送中にバッファエラーが発生すると、その復帰処理で nn::camera::SetReceiving() の処理と、YUVtoRGB 回路のデータ転送処理の特定のタイミングと重なったときに nn::y2r::GetTransferEndEvent() で取得した転送完了イベントがシグナル状態にならず、nn::y2r::IsBusyConversion()true を返さなくなるハードウェアの不具合があります。そのため転送完了イベントのシグナル状態を待つときには、必ずタイムアウト時間を指定するようにしてください。

タイムアウト時間には変換にかかる時間よりも長い時間を指定します。変換にかかる時間は入力画像のサイズと出力フォーマットに依存し、VGA 画像を 16 bit RGB で出力する場合はおよそ 13 msec、VGA 画像を 24 bit RGB で出力する場合はおよそ 16 msec です。

なお、この不具合が発生したときは nn::y2r::StopConversion() を呼び出して、変換を強制終了してください。YUVtoRGB 回路が再度使用できるようになります。

不具合の発生確率はカメラのバッファエラーの頻度に比例しますので、バッファエラーが起こりづらい条件でカメラを使用してください。バッファエラーが頻発する場合は、カメラのフレームレートを下げるなどの対応をしてください。また、nn::camera::SetReceiving() を呼び出すスレッドの優先度は高めに設定してください。

6.4.7. シャッター音の再生

スピーカー音量が 0 でもシャッター音を強制的に再生し、カメラランプ(LED)の一時消灯を行います。

補足:

SNAKE および FTR にはカメラランプが搭載されていません。

コード 6-18. シャッター音の再生
nn::Result nn::camera::PlayShutterSound(nn::camera::ShutterSoundType type);

type にはシャッター音の種類を以下から選択して指定します。

表 6-34. シャッター音の種類

設定値

シャッター音の種類

SHUTTER_SOUND_TYPE_NORMAL

通常のシャッター音

SHUTTER_SOUND_TYPE_MOVIE

動画撮影を開始するときに鳴らす音

SHUTTER_SOUND_TYPE_MOVIE_END

動画撮影を終了するときに鳴らす音

6.4.8. キャプチャの終了

キャプチャの終了処理は以下の手順で行ってください。下記の手順で終了処理を行わなければ、HOME メニュー上でサウンドのノイズが発生する可能性があります。

  1. nn::y2r::StopConversion() を呼び出してフォーマット変換を停止します。
  2. nn::camera::StopCapture() を呼び出してキャプチャを停止します。
  3. nn::camera::Activate(SELECT_NONE) で全カメラをスタンバイ状態にします。
  4. nn::camera::Finalize()nn::y2r::Finalize() を呼び出して CAMERA ライブラリと Y2R ライブラリを終了させます。

6.4.9. スリープへの対応

初期化時を含め、蓋が閉じられた状態で CAMERA ライブラリや Y2R ライブラリの関数を呼び出すと、蓋が閉じられていることを示す nn::camera::ResultIsSleepingnn::y2r::ResultIsSleeping)が返されます。この返り値は蓋が閉じられていれば、スリープ状態でなくても返されることに注意してください。

カメラはスリープとは関係なく、本体の蓋が閉じられることにより動作が停止するようになっています。キャプチャ中に蓋が閉じられた場合、蓋が開けられたタイミングでキャプチャが再開されますが、蓋が閉じられたときに、ライブラリ内部で nn::camera::Activate(SELECT_NONE) と同等の処理が行われるため、キャプチャを再開したときに Activate() によるカメラ起動直後の画像が不安定な期間が存在することに注意してください。また、蓋閉じのタイミングによっては、IsBusy() が常に true を返す状態になる可能性があります。この状態は蓋開け時に解除されますが、蓋閉じからスリープに移行する処理を実装する際は、IsBusy() によるポーリングをしないように注意してください。

Y2R ライブラリによる RGB 変換の最中にスリープに移行すると、変換は強制的に終了されますが、スリープから復帰したときに再開されません。そのため、スリープに対応する場合、変換中(IsBusyConversion()true を返すとき、あるいは GetTransferEndEvent() で取得したイベントを待っている最中)はスリープに移行せず、変換の完了を確認してからスリープに移行するように実装してください。特に、GetTransferEndEvent() で取得したイベントを待っている最中にスリープに移行すると、スリープから復帰したあとはイベントがシグナル状態にならないことに注意してください。

6.4.10. 簡易カメラ機能との競合

アプリケーションがカメラを利用しているときに HOME メニューを表示した場合、L ボタンとは R ボタンの同時押しで起動する簡易カメラ機能はカメラが使用中であるというダイアログを表示して起動をキャンセルします。

カメラが使用中であるかどうかは CAMERA ライブラリと Y2R ライブラリのいずれかが初期化されているかどうかで判断されます。そのため、カメラを使用するアプリケーションが起動時にライブラリの初期化を行っている場合、カメラを使用していない場面で HOME メニューを表示したときでもカメラが使用中であると判断されてしまいます。また、ムービーの再生など、YUV 画像を RGB 画像に変換するために Y2R ライブラリのみを使用している場合でも、カメラを使用していると見なされて簡易カメラ機能の起動がキャンセルされます。

なるべく、カメラや YUVtoRGB 回路を使用する場面の前後で初期化と終了処理を行い、使用していないときは CAMERA ライブラリや Y2R ライブラリが初期化したままにならないようにしてください。