Core Audio について詳しくなりたい。
・参考にしているWebサイト
My Codex Leicester Mac, iOS サンプルや知識も充実しています
Objective-Audio こちらもサンプルが充実, 細かいデータの設定なども載っています
この2つのwebサイトは本当にすばらしいです。大変お世話になりました。
Apple Dev のサンプル - 正攻法で, Apple の Developer のサイトでサンプルをがんばって探す
Stack Overflow いつもおせわになっているプログラミング関係のQ&Aサイト
・書籍 iPhone Core Audio プログラミング やっと手に入りました。細かいところまで結構書いている有名な本です
Learning Core Audio 英語です。ちらっと読んでみましたが, 上の本の方が強力です
・資料
•ツール
Audacity フリーのオーディオソフト, Mac 版, Win版とある, 音声処理, 信号処理などかなり豊富な機能がついています。よくテストで使っていました。しかもオープンソース(C++)。ソースが読めます。信号処理の参考に使えるかも 。でもソースは結構読みづらいC++ です。
ここにサンプルを追加していきます。(編集中)
1. iOS 音声再生(AVAudioPlayer) (iOS, Mac OS X)
2. byte -> short -> byte そしてfloat(Objective-C) ( iOS, Mac OS X)
3. iOS 音声録音(AVAudioRecorder) ( iOS, Mac OS X)
4. NSError, OSStatus用のログをつくる (iOS, Mac OS X)
5. Audio Unitを使おう (iOS)
・仕事記・開発記
(編集中)
シンガポール在住のソフトウェア開発者です。なんだかんだでシンガも4年目突入。仕事もしくは趣味でやっていることをまとめています。 英語のブログは http://atmarkplant.com にあります
2013年4月6日土曜日
2013年3月9日土曜日
Objective-C から C++
iOSやMac OS アプリケーションを作っている時, 主要な部分をObjective-C で書き, C, C++ ライブラリや, 過去の資産のコードを使いたいというケースがあるはずです。
実は, C, C++ なんかのデバッグは, XCode でやればいいのではと最近思うようになりました(Eclipse + CDTよりも)
こういったケースでは, Objective-C のコードから, C, C++ を呼び出すわけです。Cは特に問題ありませんがC++ にはちょっとした工夫が必要です。
Objective-C は C です
これさえわかっていれば, 実はどうってことないわけですが...
さくっと解決策は, 2つです
1. extern C を使って, C 関数として呼び出す
2. Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う
ちょっとした例をあげながら確認していきましょう
・Objective-C から C を呼び出す
test.c(C source), test.h(C header), CWrapper.h(C header), CWrapper.m(Objective-C source)
というソースを用意しました
ex) test.c
#include "test.h"
#include<stdio.h>
void testFunc()
{
printf("Hello C\n");
}
ex)test.h
#ifndef AudoSamples_testc_h
#define AudoSamples_testc_h
void testFunc();
#endif
ex)CWrapper.h
#include "test.h"
@interface CWrapper : NSObject
+(void)callC;
@end
ex)CWrapper.m
#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
testFunc();
}
@end
How to use
[CWrapper callC];
このコードは問題なく動作します.
・Objective-CからC++を呼び出す
ex) testcp.cpp(C++ source), testcp.h(C++ header)
をさらに追加しました
ex) testcp.h
#ifdef __AudioSamples__File__
#define __AudioSamples__File__
void testCpp();
#endif
これを, C++ のヘッダーに変えましょう。XCode の、Inspector で変更します
ex) testcp.cpp
#include "testcp.h"
void testCpp()
{
std::cout << "Hello cpp" << std::endl;
}
先ほどの, CWapper.h を変更します
ex) CWapper.h
#include "test.h"
#include "testcp.h"
@interface CWrapper : NSObject
+(void)callC;
+(void)callCpp;
@end
先ほどの, CWrapper.mを変更します
ex) CWrapper.m
#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
testFunc();
}
+(void)callCpp
{
testCpp();
}
@end
このソースはコンパイルはできますが, リンクができません。
Apple Match-O Linker Error Undefined symbols for architecture i386:
といったように, C++ で作った関数 testCpp がないというのです, コンパイルできてるのに, みつからないだと...
実際 testcp.o というObject ファイルは生成されているようです。ですが中身が, C++ の関数になっているので うまくリンクできません。
UNIX コマンド nm で確認してみるとよくわかります
nm testcp.o
これはおいておいて, 解決策にまいりましょう
1. extern C を使って, C 関数として呼び出す
定義部分のところで, Cの関数として呼び出すように変更します
testcp.h を変更します
ex)
#ifdef __AudioSamples__File__
#define __AudioSamples__File__
#ifdef __cplusplus
#extern "C" {
#endif
void testCpp();
#ifdef __cplusplus
}
#endif
#endif
これで, Objective-C から, C++ を呼び出せるようになりました
2. Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う
こちらは, Objective-C++ というのを使って, Objective-CをC++ としてしまいます
例を変えて説明しましょう
ex) pure.cpp(C++), pure.h(C++), CpWrapper.h(C++), CpWrapper.mm(Objective-C++)
ex) pure.h
#ifndef __AudioSamples__pure__
#define __AudioSamples__pure__
void pureCpp();
#endif
実は, C, C++ なんかのデバッグは, XCode でやればいいのではと最近思うようになりました(Eclipse + CDTよりも)
こういったケースでは, Objective-C のコードから, C, C++ を呼び出すわけです。Cは特に問題ありませんがC++ にはちょっとした工夫が必要です。
Objective-C は C です
これさえわかっていれば, 実はどうってことないわけですが...
さくっと解決策は, 2つです
1. extern C を使って, C 関数として呼び出す
2. Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う
ちょっとした例をあげながら確認していきましょう
・Objective-C から C を呼び出す
test.c(C source), test.h(C header), CWrapper.h(C header), CWrapper.m(Objective-C source)
というソースを用意しました
ex) test.c
#include "test.h"
#include<stdio.h>
void testFunc()
{
printf("Hello C\n");
}
ex)test.h
#ifndef AudoSamples_testc_h
#define AudoSamples_testc_h
void testFunc();
#endif
ex)CWrapper.h
#include "test.h"
@interface CWrapper : NSObject
+(void)callC;
@end
ex)CWrapper.m
#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
testFunc();
}
@end
How to use
[CWrapper callC];
このコードは問題なく動作します.
・Objective-CからC++を呼び出す
ex) testcp.cpp(C++ source), testcp.h(C++ header)
をさらに追加しました
ex) testcp.h
#ifdef __AudioSamples__File__
#define __AudioSamples__File__
void testCpp();
#endif
これを, C++ のヘッダーに変えましょう。XCode の、Inspector で変更します
ex) testcp.cpp
#include "testcp.h"
void testCpp()
{
std::cout << "Hello cpp" << std::endl;
}
先ほどの, CWapper.h を変更します
ex) CWapper.h
#include "test.h"
#include "testcp.h"
@interface CWrapper : NSObject
+(void)callC;
+(void)callCpp;
@end
先ほどの, CWrapper.mを変更します
ex) CWrapper.m
#import "CWrapper.h"
@implementation CWrapper
+(void)callC
{
testFunc();
}
+(void)callCpp
{
testCpp();
}
@end
このソースはコンパイルはできますが, リンクができません。
Apple Match-O Linker Error Undefined symbols for architecture i386:
といったように, C++ で作った関数 testCpp がないというのです, コンパイルできてるのに, みつからないだと...
実際 testcp.o というObject ファイルは生成されているようです。ですが中身が, C++ の関数になっているので うまくリンクできません。
UNIX コマンド nm で確認してみるとよくわかります
nm testcp.o
これはおいておいて, 解決策にまいりましょう
1. extern C を使って, C 関数として呼び出す
定義部分のところで, Cの関数として呼び出すように変更します
testcp.h を変更します
ex)
#ifdef __AudioSamples__File__
#define __AudioSamples__File__
#ifdef __cplusplus
#extern "C" {
#endif
void testCpp();
#ifdef __cplusplus
}
#endif
#endif
これで, Objective-C から, C++ を呼び出せるようになりました
2. Objective-C++ (.mm) を使って, C++ のコードとしてObjective-Cを扱う
こちらは, Objective-C++ というのを使って, Objective-CをC++ としてしまいます
例を変えて説明しましょう
ex) pure.cpp(C++), pure.h(C++), CpWrapper.h(C++), CpWrapper.mm(Objective-C++)
ex) pure.h
#ifndef __AudioSamples__pure__
#define __AudioSamples__pure__
void pureCpp();
#endif
ex) pure.cpp
#include "pure.h"
#include <iostream>
void pureCpp()
{
std::cout << "I am CP9" << std::endl;
}
ex) CpWrapper.h
#import <Foundation/Foundation.h>
#include "pure.h"
@interface CpWrapper : NSObject
@end
ex) CpWrapper.mm
#import "CpWrapper.h"
@implementation CpWrapper
void pureCppCall()
{
pureCpp();
}
@end
2013年2月11日月曜日
Audio Unitを使おう(iOS)
まだまだ勉強がたりないです。さて, Audio Unitです。
Audio Unit というのは, Core Audio のオーディオ処理の機能を持つ1つの単位のこと。Input, Effect, Output などが Audio Unit になります。 詳しい説明は, 各所ありますのでこれくらいです。
Mac OS X と, iOS ではプログラムの書き方が違います。
Mac OS Xでは, こちら のサンプルが完璧です。
これを参考にさせていただきながら, iOSとどのように違うのか, やってみました。
My Codex Leister さんでも言及のとおり, iOSでは, kAudioUnitType_Generatorつまり, 入力を発生させるような Audio Unit がないような気がします。
Output, Effect あたりはできそうな気がします。
コンポーネントの違い
Mac OS X AudioUnit.framework ComponentDescription
iOS AudioToolbox.framework AudioComponentDescripton
iOSでは,
struct AudioComponentDescription
{
OSType componentType;
OSType componentSubStype;
OSType componentManufacturer;
UInt32 componentFlags;
UInt32 componentFlagsMask;
};
typedef struct AudioComponentDescription AudioComponentDescription;
を使って, AudioComponent を取り出します。
その違い以外は, ほぼ Mac OS Xと同じコードです。
iOS で, Audio Unit で sin波を発生させて聞いてみるサンプルです。
重要そうなところは太字もしくは赤字にしてみました。
•AudioUnitViewController.h
•AudioUnitViewController.m
Audio Unit というのは, Core Audio のオーディオ処理の機能を持つ1つの単位のこと。Input, Effect, Output などが Audio Unit になります。 詳しい説明は, 各所ありますのでこれくらいです。
Mac OS X と, iOS ではプログラムの書き方が違います。
Mac OS Xでは, こちら のサンプルが完璧です。
これを参考にさせていただきながら, iOSとどのように違うのか, やってみました。
My Codex Leister さんでも言及のとおり, iOSでは, kAudioUnitType_Generatorつまり, 入力を発生させるような Audio Unit がないような気がします。
Output, Effect あたりはできそうな気がします。
コンポーネントの違い
Mac OS X AudioUnit.framework ComponentDescription
iOS AudioToolbox.framework AudioComponentDescripton
iOSでは,
struct AudioComponentDescription
{
OSType componentType;
OSType componentSubStype;
OSType componentManufacturer;
UInt32 componentFlags;
UInt32 componentFlagsMask;
};
typedef struct AudioComponentDescription AudioComponentDescription;
を使って, AudioComponent を取り出します。
その違い以外は, ほぼ Mac OS Xと同じコードです。
iOS で, Audio Unit で sin波を発生させて聞いてみるサンプルです。
重要そうなところは太字もしくは赤字にしてみました。
•AudioUnitViewController.h
#import "ViewController.h"
#import <AudioToolbox/AudioToolbox.h>
#define kRate 44100
#define kFreq 440
@interface AudioUnitViewController : ViewController
@property (nonatomic)AudioUnit unit;
@property (nonatomic)float phase;
- (IBAction)startClick:(id)sender;
- (IBAction)stopClick:(id)sender;
@end
•AudioUnitViewController.m
#import "AudioUnitViewController.h"
@interface AudioUnitViewController ()
@end
@implementation AudioUnitViewController
@synthesize unit;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
OSStatus AuRenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
//NSLog(@"inNumberFrames: %ld", inNumberFrames);
//NSLog(@"Bufs %ld", ioData->mNumberBuffers);
AudioUnitViewController *controller = (__bridge AudioUnitViewController *)inRefCon;
float *buf = ioData->mBuffers[0].mData;
float freq = kFreq * 2 * M_PI / kRate;
for ( int i=0; i < inNumberFrames; i++ )
{
float wave = sin(controller.phase);
*buf++ = wave;
controller.phase += freq;
}
return noErr;
}
-(void)audioUnit
{
OSStatus status;
AudioComponentDescription cd;
cd.componentType = kAudioUnitType_Output;
cd.componentSubType = kAudioUnitSubType_RemoteIO;
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
cd.componentFlags = 0;
cd.componentFlagsMask = 0;
// Find compoent and create instance
AudioComponent comp = AudioComponentFindNext(NULL, &cd);
status = AudioComponentInstanceNew(comp, &unit);
// Set Callback
AURenderCallbackStruct input;
input.inputProc = AuRenderCallback;
input.inputProcRefCon = (__bridge void *)(self);
status = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &input, sizeof(input));
status = AudioUnitInitialize(unit);
status = AudioOutputUnitStart(unit);
self.phase = 0;
}
-(void)stop
{
AudioOutputUnitStop(unit);
}
- (IBAction)startClick:(id)sender
{
[self audioUnit];
}
- (IBAction)stopClick:(id)sender
{
[self stop];
}
@end
NSError, OSStatus用のログをつくる
こんにちは, Audio系のプログラミング絶賛継続中です。
Audio系のAPIを使っているとその戻り値もしくは, Error の詳細が
NSError, OSStatus として返ってくるケースが多いです。
このデータからできればエラーの詳細, プログラムを続けるかの可否, 独自のログメッセージなどが欲しいものです。というわけで少し作ってみました。
Audio系のAPIを使っているとその戻り値もしくは, Error の詳細が
NSError, OSStatus として返ってくるケースが多いです。
このデータからできればエラーの詳細, プログラムを続けるかの可否, 独自のログメッセージなどが欲しいものです。というわけで少し作ってみました。
+(BOOL)errorLog:(NSError *)error message:(NSString *)message
{
if ( error != nil )
{
NSLog(@"%@ : %@", message, [error localizedDescription]);
}
return error == nil;
}
+(BOOL)statusLog:(OSStatus)status message:(NSString *)message
{
if ( status != noErr )
{
NSLog(@"Error - %@ %ld", message, status);
}
return status == noErr;
}
NSErrorの場合エラーがなければnilを返します。 OSStatusの場合0(noErr) を返します。
そこで判定をいれてO.K.ならYES, だめならNOを返すようにつくりました。
エラーがある場合, NSError の場合, [error localizedDescription] でエラーの詳細がとれます。
OSStatus というのはSInt32のtypedefです。はいただの番号です。この番号からエラーを掘り出す訳ですが残念ながら, 詳細などを引っ張るには一覧などを参考にするしかありません。(しかもよくわからない)
2013年2月10日日曜日
iOS 音声録音(AVAudioRecorder)
・iOS, Mac でのオーディオ録音のためのObjective-C インタフェースを提供するAVAudioRecorderの使い方(Mac OS Xでも同じです)
※Mac OS Xの場合, 録音に利用するデバイスの選択はできません。(デフォルトになる)デバイスを選択する場合は, Audio Queue Service を利用します。iOSはマイク入力は1つです今のところ。
AVAudioRecorder を利用すると以下のようなことができるらしいです。
・録音
・長さ(duration)を決めて録音
・PauseとResume
・レベルで与えられた入力のオーディオレベルを取得する
・ファイルとして保存する
すこし調べてみて出来そうもなかったこと
・録音の入力(マイクの入力)音量の変更(iOS)
※ちなみにMac OS Xならできます
・サンプル : 録音してファイルとして保存, 再生もできます
※ちなみに, Simulator でも動作します。私はMac Book Pro を使っていますが, マイクついています。さらに仕事で, Mac を使っていますが, こちらもマイクがついています。マイクが付いていれば録音のテストをSimulator 上でもできます。
- RecordViewController.h
#import "ViewController.h"
#import <AudioToolbox/AudioToolbox.h>
@interface RecordViewController : ViewController
@property (nonatomic)AVAudioRecorder *recorder;
@property (nonatomic)AVAudioSession *session;
@property (nonatomic)AVAudioPlayer *player;
@property (weak, nonatomic) IBOutlet UIButton *recordButton;
- (IBAction)recordClick:(id)sender;
@property (weak, nonatomic) IBOutlet UIButton *playButton;
- (IBAction)playClick:(id)sender;
@end
AudioSessionと AVAudioRecorder, AVAudioPlayerを宣言しています。
ARC用です。
//
// RecordViewController.m
// AudioSamples
//
// Created by atmarkplant on 13/02/10.
// Copyright (c) 2013年 atmarkplant. All rights reserved.
//
#import "RecordViewController.h"
@interface RecordViewController ()
@end
- RecordViewController.m
@implementation RecordViewController
@synthesize session;
@synthesize recorder;
@synthesize player;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Helpers
-(NSMutableDictionary *)setAudioRecorder
{
NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];
[settings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[settings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[settings setValue:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
[settings setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[settings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[settings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
return settings;
}
-(void)recordFile
{
// Prepare recording(Audio session)
NSError *error = nil;
self.session = [AVAudioSession sharedInstance];
if ( session.inputAvailable ) // for iOS6 [session inputIsAvailable] iOS5
{
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
}
if ( error != nil )
{
NSLog(@"Error when preparing audio session :%@", [error localizedDescription]);
return;
}
[session setActive:YES error:&error];
if ( error != nil )
{
NSLog(@"Error when enabling audio session :%@", [error localizedDescription]);
return;
}
// File Path
NSString *dir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString *filePath = [dir stringByAppendingPathComponent:@"test.caf"];
NSURL *url = [NSURL fileURLWithPath:filePath];
// recorder = [[AVAudioRecorder alloc] initWithURL:url settings:nil error:&error];
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:[self setAudioRecorder] error:&error];
//recorder.meteringEnabled = YES;
if ( error != nil )
{
NSLog(@"Error when preparing audio recorder :%@", [error localizedDescription]);
return;
}
[recorder record];
}
-(void)stopRecord
{
if ( self.recorder != nil && self.recorder.isRecording )
{
[recorder stop];
self.recorder = nil;
}
}
-(void)playRecord
{
NSError *error = nil;
// File Path
NSString *dir = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];
NSString *filePath = [dir stringByAppendingPathComponent:@"test.caf"];
NSURL *url = [NSURL fileURLWithPath:filePath];
if ( [[NSFileManager defaultManager] fileExistsAtPath:[url path]] )
{
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if ( error != nil )
{
NSLog(@"Error %@", [error localizedDescription]);
}
[self.player prepareToPlay];
[self.player play];
}
}
- (IBAction)recordClick:(id)sender
{
if ( self.recorder != nil && self.recorder.isRecording )
{
[self stopRecord];
[self.recordButton setTitle:@"Record" forState:UIControlStateNormal];
}
else
{
[self recordFile];
[self.recordButton setTitle:@"..." forState:UIControlStateNormal];
}
}
- (IBAction)playClick:(id)sender
{
[self playRecord];
}
@end
重要な部分は太字になっています。
-(NSMutableDictionary *)setAudioRecorder
では, 保存形式を入れています。 settingsの部分で入れていますが, nilにするとdefault の設定になります。 辞書式に設定を入れていきます。ここで保存形式などを細かく指定できます。
-(void)recordFile
で, 実際の処理をしています。処理手順はこんな感じです。
1. AudioSession をつくる
2. マイク入力が可能かどうかの確認
3. ファイルパスの設定
4. AVAudioRecorder の作成
5. record 開始
※caf って何? ということですが, caf はApple のwrapper です。中身はこれだけではわかりません。PCMかもしれないですし, MP4かもしれません。動画いう.avi みたいなコーデックのラッパーみたいなものでしょうか。
2013年2月6日水曜日
byte -> short -> byte そしてfloat(Objective-C)
こんにちは信号処理とデバイスまわりでのデータ移動のために必要なものを実装しておきました。iOS, Mac OS で活用できると思います。
何に使うかといえば特に音声系です。
Byte : Low Level APIでの扱い
short(Int16) : 16bitのデータ, 音声系は16bit, 32b it系が多いのでしょうか
float : FFT等の信号処理のライブラリはfloat, doubleが多いのでこれらの変換も必要
これらの値をさくっと変換して計算に活用したいというのが今回の目的です
short はだいたいの処理系で16bitでしょうか。わかりやすくするためObjective-CのInt16を使いましょう。
もう少しByte, short について。 このプログラムは 2 byteのデータを1つのshort(Int16) に変換するものです
プログラムリスト
•Byte配列 -> short(Int16)
•short(Int16) -> Byte配列
•short(Int16) -> float
•float -> short(Int16)
•byte配列 -> short(Int16)
•short(Int16) -> byte配列
•short(Int16) -> float
•float -> short(Int16)
何に使うかといえば特に音声系です。
Byte : Low Level APIでの扱い
short(Int16) : 16bitのデータ, 音声系は16bit, 32b it系が多いのでしょうか
float : FFT等の信号処理のライブラリはfloat, doubleが多いのでこれらの変換も必要
これらの値をさくっと変換して計算に活用したいというのが今回の目的です
short はだいたいの処理系で16bitでしょうか。わかりやすくするためObjective-CのInt16を使いましょう。
もう少しByte, short について。 このプログラムは 2 byteのデータを1つのshort(Int16) に変換するものです
プログラムリスト
•Byte配列 -> short(Int16)
•short(Int16) -> Byte配列
•short(Int16) -> float
•float -> short(Int16)
•byte配列 -> short(Int16)
+(SInt16)convertByteToShort:(Byte *)bytes order:(BOOL)order
{
if ( order )
{
// Small address first
SInt16 res = (bytes[0] << 8) + bytes[1];
return res;
}
else
{
SInt16 res = (bytes[1] << 8) + bytes[0];
return res;
}
}
※エンディアン系の処理のためちょっと変則的なコードになっています
+(void)convert16ToByte:(SInt16)src bytes:(Byte *)bytes order:(BOOL)order
{
if ( order )
{
bytes[0] = (src & 0xFF00) >> 8;
bytes[1] = (src & 0xFF);
}
else
{
// Small address first
bytes[1] = (src & 0xFF00) >> 8;
bytes[0] = (src & 0xFF);
}
}
+(float)getNormarilize16Bit:(SInt16)signal
{
return (float)signal / (float)32768;
}
+(SInt16)restore16Bit:(float)signal
{
return (SInt16)(signal * 32768);
}
2012年7月1日日曜日
iOS ローカライズ
こんにちは, iOS の学習を着々と進めてまいりましたが, Android, Windows Phone と比べるとずいぶん手こずっています。
今回は, ローカライズです。普段, Webアプリも, スマフォアプリもEnglish を基準に開発していますが,
最終的には, 日本語版を作ります。 できれば他の言語でも出して, いろいろな方に使っていただけたら~。 ダウンロード数を増やしたい というのが本音です。
※先日, ColorDos というアプリを公開いたしました。無料ですので, よかったらダウンロードしてみてください。
ローカライズというのは
・ UI のローカライズ
・ 文字列(コード内)のローカライズ
もうひとつ アプリ名のローカライズというのがありますが, またの機会に。
UIのローカライズ
UIのローカライズですが, これは, Interface Buider で作成したUI , ボタンとか, ラベルとか 特に
動的にコードなどで変更しない, 部分のことを指します。
.xib でも, storyboard の場合でも方法はほぼ同じです。
とりあえず, UI を作っていきましょう。
UIを作成したのち, "View" -> "Utilities" -> "Show File Inspector" の順に選択します
すると, XCode の右側に "Localization" という項目が出てくるので, ここから言語を追加します。
そこから言語を追加します。
言語を追加すると, .xib, .storyboard のところに
・ .xib の場合
ViewController.xib(English)
ViewController.xib(Japanese)
・.storyboard の場合
MainStoryboard....board(English)
MainStoryboard....board(Japanese)
というように追加されます
それぞれが, その言語に対応したものになります。
ここで, それぞのUI の文字を変更すると, 実際に起動したときに言語に応じて, 表示が変わります
上が英語, 下が日本語( storyboard )
後でUI を修正する場合は, 先頭にある (言語名) なしのファイルを変更しましょう。これで, 他の言語ファイルにも UIの修正がいきわたります。
文字列(コード内)のローカライズ
こちらは, コードで取り出したり, 加工したものとかです。最終的には, UIに反映するでしょうが, 上と違い途中でコードから変更する場合です。
"New File" -> "iOS" -> "Resources" -> "Strings File" を選択しましょう
このファイルを Localizable.strings とでも名付けておいて, Supporting File の下にでも入れておきます。
先ほどの .xib や, storyboard と同様に, "Localization" という項目が出てくるので そこで, 言語を追加します。
Localizable.strings(English)
Localizable.strings(Japanese)
のように言語ファイルが追加されました。
このファイルに "key" = "value"; という形式で, 使いたいkey と value のセットを作ります。
例)
"Hello" = "こんにちは";
※ "" と ; を忘れないように
これをコードから取り出すには, NSLocalizedString を使います
NSString *message = NSLocalizedString("Hello", nil);
第一引数が key で, 第二引数は, コメントです(いらなければ nil で)
上のファイルに, key, value のセットを追加すれば複数の値が利用できます。
※どうやら, 言語ごとにstoryboard が増えるという, 厄介なことを解決してくれる術があるようです。
(コードで全部入れないといけない気もしますが... )
今回は, ローカライズです。普段, Webアプリも, スマフォアプリもEnglish を基準に開発していますが,
最終的には, 日本語版を作ります。 できれば他の言語でも出して, いろいろな方に使っていただけたら~。 ダウンロード数を増やしたい というのが本音です。
※先日, ColorDos というアプリを公開いたしました。無料ですので, よかったらダウンロードしてみてください。
ローカライズというのは
・ UI のローカライズ
・ 文字列(コード内)のローカライズ
もうひとつ アプリ名のローカライズというのがありますが, またの機会に。
UIのローカライズ
UIのローカライズですが, これは, Interface Buider で作成したUI , ボタンとか, ラベルとか 特に
動的にコードなどで変更しない, 部分のことを指します。
.xib でも, storyboard の場合でも方法はほぼ同じです。
とりあえず, UI を作っていきましょう。
UIを作成したのち, "View" -> "Utilities" -> "Show File Inspector" の順に選択します
すると, XCode の右側に "Localization" という項目が出てくるので, ここから言語を追加します。
そこから言語を追加します。
言語を追加すると, .xib, .storyboard のところに
・ .xib の場合
ViewController.xib(English)
ViewController.xib(Japanese)
・.storyboard の場合
MainStoryboard....board(English)
MainStoryboard....board(Japanese)
というように追加されます
それぞれが, その言語に対応したものになります。
ここで, それぞのUI の文字を変更すると, 実際に起動したときに言語に応じて, 表示が変わります
上が英語, 下が日本語( storyboard )
後でUI を修正する場合は, 先頭にある (言語名) なしのファイルを変更しましょう。これで, 他の言語ファイルにも UIの修正がいきわたります。
文字列(コード内)のローカライズ
こちらは, コードで取り出したり, 加工したものとかです。最終的には, UIに反映するでしょうが, 上と違い途中でコードから変更する場合です。
"New File" -> "iOS" -> "Resources" -> "Strings File" を選択しましょう
このファイルを Localizable.strings とでも名付けておいて, Supporting File の下にでも入れておきます。
先ほどの .xib や, storyboard と同様に, "Localization" という項目が出てくるので そこで, 言語を追加します。
Localizable.strings(English)
Localizable.strings(Japanese)
のように言語ファイルが追加されました。
このファイルに "key" = "value"; という形式で, 使いたいkey と value のセットを作ります。
例)
"Hello" = "こんにちは";
※ "" と ; を忘れないように
これをコードから取り出すには, NSLocalizedString を使います
NSString *message = NSLocalizedString("Hello", nil);
第一引数が key で, 第二引数は, コメントです(いらなければ nil で)
上のファイルに, key, value のセットを追加すれば複数の値が利用できます。
※どうやら, 言語ごとにstoryboard が増えるという, 厄介なことを解決してくれる術があるようです。
(コードで全部入れないといけない気もしますが... )
2012年6月21日木曜日
Objective-C, iPhoneアプリ NSLogでログを残す
Objective-C でCommand Line Tool を作成すると, 最初に表示されているのが
NSLog (@"Helllo World!");
iPhone アプリを作成しているときでも, 画面に関係なく, Console(Output)に出力ができるので, Debugに効果を発揮します
(Android でいうLog catとかにでてくるやつと同じなのかな)
使い方
NSLog("フォーマット", フォーマットの引数);
フォーマット + 引数の形は, printf とかと同様です。
NSLog (@"Helllo World!");
iPhone アプリを作成しているときでも, 画面に関係なく, Console(Output)に出力ができるので, Debugに効果を発揮します
(Android でいうLog catとかにでてくるやつと同じなのかな)
使い方
NSLog("フォーマット", フォーマットの引数);
フォーマット + 引数の形は, printf とかと同様です。
ex) 例
NSLog(@"Homuhomu");
int cnt = 3;
NSLog(@"It's a magica %lu", cnt);
こういうのも使え増す
__LINE__ 行番号
__PRETTY_FUNCTION__ NSLogを実行した関数名
__FILE__ ファイル名
・フォーマット
%@ 文字列
%d, %D, %i int
%u int
%lu int
%f, %e, %E, %g, %G double
2012年6月20日水曜日
Objective-C とりあえずコンソールアプリ
iOS のプログラミングを本格的に始めました。Objective-C の普通のプログラムから初めてiPhone のUIKitへ進むべく始めましたが, C言語からC++, Javaへ移ったときと同じくらいわからない衝撃がありました。
少しずつレベルアップを目指しつつ勉強用メモとして残しておきます。
まず Mac OS X のコンソールアプリケーションを作ってみる
(Objective-Cのクラスを利用する)
環境 : Mac OS X 10.7 Lion
XCode : 4.3
※ここでいきなりですが, Objective-Cには, GCがないといわれていましたが, OS X のいつごろからかついています。iOS は 5の段階ではまだないようです。
もうひとつ ARCというのがあります Automatic Release Connection というやつですが
変数を扱うときに, retain - release というセットをいれて, インスタンスの参照をカウントしていましたが -> これの説明は別の機会に。
iPhoneの開発本などを買って( ちょっと古いやつとか ) サンプルを入力してはい、Buildしようとしたら, [tmp release] で警告 dealloc なんてないぜとかいうのはこの ARCのおかげです。iOS5 から標準でこの ARCがついたみたいです。コンパイラ設定から外せますが。
早速コンソールアプリを作ってみましょう。
●まず Hello World!
XCode を開いて, "Create Project" -> Mac OS X -> Application -> Command Line Toolを 選択します。
いろいろ名前を入れるところがでてきます。
Product Name : いわゆるプロジェクトの名前 ここではConsoleTestとしました
Company Identifier : Javaでいうトップのnamespace 自分のURLとかを逆順に入れておく
私の場合 com.atmarkplant かな
Type : Foundation
チェックを入れる Use Automatic Reference Counting
このプロジェクトのフォルダを作成する場所を選びます。 別にどこでもいいです。
プロジェクトを作成すると, 早速 Hello World!のプログラムが完成しているようです。
main.m には すでにmain 関数が書いてあります。
左上にある Run という→のボタンを押すとBuild と実行です。
実行すると, 右下の方に実行結果が表示されます。これはNSLog の効果です。
プログラムはぱっと見た感じ Cです。ただのCです。 もちろんこのままC like に書き続けることもできます。
ですが, Objective-Cのクラスを書きます。
● クラスを書く
ConsoleTest フォルダを右クリック -> New File -> Mac OS X -> Objective-C Class
を選択します。名前は TestClass とでもしておきます。
2つのファイルが作成されました。
TestClass.m TestClass.h です。
クラスを作成するとこの 2つのファイルが作成されます。
TestClass.h : クラス定義用
TestClass.m : クラスの実装用
とざっくりいうとこんな感じです。今回は中身の説明はしません。
早速必要なことを書いていきます。
TestClass.h
TestClass.m
これを利用するため main.mを書き換えましょう。
release はいりません。だってARC がついているから。
これで実行すると, Mayuyu というのが表示されるはずです。
少しずつレベルアップを目指しつつ勉強用メモとして残しておきます。
まず Mac OS X のコンソールアプリケーションを作ってみる
(Objective-Cのクラスを利用する)
環境 : Mac OS X 10.7 Lion
XCode : 4.3
※ここでいきなりですが, Objective-Cには, GCがないといわれていましたが, OS X のいつごろからかついています。iOS は 5の段階ではまだないようです。
もうひとつ ARCというのがあります Automatic Release Connection というやつですが
変数を扱うときに, retain - release というセットをいれて, インスタンスの参照をカウントしていましたが -> これの説明は別の機会に。
iPhoneの開発本などを買って( ちょっと古いやつとか ) サンプルを入力してはい、Buildしようとしたら, [tmp release] で警告 dealloc なんてないぜとかいうのはこの ARCのおかげです。iOS5 から標準でこの ARCがついたみたいです。コンパイラ設定から外せますが。
早速コンソールアプリを作ってみましょう。
●まず Hello World!
XCode を開いて, "Create Project" -> Mac OS X -> Application -> Command Line Toolを 選択します。
いろいろ名前を入れるところがでてきます。
Product Name : いわゆるプロジェクトの名前 ここではConsoleTestとしました
Company Identifier : Javaでいうトップのnamespace 自分のURLとかを逆順に入れておく
私の場合 com.atmarkplant かな
Type : Foundation
チェックを入れる Use Automatic Reference Counting
このプロジェクトのフォルダを作成する場所を選びます。 別にどこでもいいです。
プロジェクトを作成すると, 早速 Hello World!のプログラムが完成しているようです。
main.m には すでにmain 関数が書いてあります。
左上にある Run という→のボタンを押すとBuild と実行です。
実行すると, 右下の方に実行結果が表示されます。これはNSLog の効果です。
プログラムはぱっと見た感じ Cです。ただのCです。 もちろんこのままC like に書き続けることもできます。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
@autoreleasepool {
NSLog(@"Hello World!");
}
return 0;
}
ですが, Objective-Cのクラスを書きます。
● クラスを書く
ConsoleTest フォルダを右クリック -> New File -> Mac OS X -> Objective-C Class
を選択します。名前は TestClass とでもしておきます。
2つのファイルが作成されました。
TestClass.m TestClass.h です。
クラスを作成するとこの 2つのファイルが作成されます。
TestClass.h : クラス定義用
TestClass.m : クラスの実装用
とざっくりいうとこんな感じです。今回は中身の説明はしません。
早速必要なことを書いていきます。
TestClass.h
#import <Foundation/Foundation.h>
@interface TestClass : NSObject
{
NSString *str;
int index;
BOOL testBool;
}
@property (nonatomic) NSString *str;
@property (readonly) int index;
@property BOOL testBool;
@end
TestClass.m
#import "TestClass.h"
@implementation TestClass
@synthesize str;
@synthesize index;
@synthesize testBool;
-(id)init
{
if ( self = [super init] )
{
str = [[NSString alloc]initWithString:@"Mayuyu"];
index = 2;
testBool = YES;
}
return self;
}
@end
これを利用するため main.mを書き換えましょう。
#import <Foundation/Foundation.h>
#import "TestClass.h"
int main(int argc, const char * argv[])
{
@autoreleasepool {
TestClass *tmp;
tmp = [[TestClass alloc] init];
NSLog(@"str %@", tmp.str);
// [tmp release];
}
return 0;
}
release はいりません。だってARC がついているから。
これで実行すると, Mayuyu というのが表示されるはずです。
登録:
投稿 (Atom)












