ラベル objective-c の投稿を表示しています。 すべての投稿を表示
ラベル objective-c の投稿を表示しています。 すべての投稿を表示

2013年5月5日日曜日

[iOS]iOSのGUIをopenFrameworksのプロジェクトに追加する際の画面サイズの注意

openFrameworksでiPhoneアプリを開発していると、iOS標準のGUIを追加する方法で悩まされるかもしれません。

でもちょっと調べれば解決策がネット上にありました。
こちらのサイトにinterface builderを使ってGUIを追加する方法が記載されています。

ただしここで注意が必要なのはこの方法をただ適用しただけでは、iPhone4S以下向け3.5inchディスプレイとiPhone5向け4inchディスプレイの共存ができないことです。
iPhone5用に作成したviewを適用しようとするとiPhone4S以下では画面が下にはみ出してしまいます。
これはaddSubViewで追加したviewControllerのviewサイズがディスプレイのサイズによって自動で変換されないためです。

じゃあどうすればいいかというと、addSubViewでiOSのGUIを追加する直前でviewのサイズを変更してください。


      
   //iPhoneの画面サイズの取得
   CGSize addViewSize = CGSizeMake(ofGetWidth(), ofGetHeight());
        
   //iOSGUIのviewサイズをiPhoneの画像サイズに変換
   CGRect addViewRect = [xibViewController.view frame];
   addViewRect.size.width = addViewSize.width;
   addViewRect.size.height = addViewSize.height;
   [xibViewController.view setFrame:addViewRect];        
        
   //openFrameworksに追加
   [ofxiPhoneGetUIWindow() addSubview:xibViewController.view];

これでiPhone4S以下にもiPhone5にも対応できると思います。

2013年2月22日金曜日

[iOS]バックグラウンドで音楽を再生させつづける方法

音楽系アプリを開発していてバックグラウンドでも音楽を鳴らし続ける方法につまづいたのでメモ。

やり方は簡単でソースコードを2カ所修正するだけ。

1. info.plistファイルを修正する
[Required background modes]を追加し、Item 0のValueを[App plays audio]にする。



2. アプリ起動時の初期化関数内に次のコードを挿入する。

        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];

たったこれだけでバックグラウンドでも音楽を再生することが可能です。

2013年2月18日月曜日

iPhoneのミュージックライブラリ内の曲をopenALで使用する方法

最近はopenFrameworksを用いてiPhoneアプリを創作しています。

音楽とインタラクションをテーマにしたアプリを作成していたところ、iPhoneのミュージックライブラリ内の曲を編集するようにする方法につまづいたため記録しておきます。

AVAudioPlayerでは複数曲の再生や音楽データの加工に対応していません。このため、openALを用いて音楽データを扱います。
ところが、openALではm4aやmp3のファイルに対応していないためcafファイルに変換して書き出す必要があります。

やりかたはこのサイトを参考にして実装しました。

基本的にはMPMediaPickerControllerで選択した曲に対して、AVAssetReaderとAVAssetWriterを用いてcaf形式に変換してます。

書き出したcaf形式の音楽データをopenALのインスタンスから読み込めば音楽データの加工できます。

ちなみに書き出す際のチャンネルは1つにしておかなければ距離に応じた音の減衰ができないので気をつけてください。
ここに数時間とられました。。。

// iPodの曲目のピッカーを表示
-(IBAction)showMediaPicker:(id)sender
{
    MPMediaPickerController *picker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeMusic];
    [picker setDelegate: self];
    [picker setAllowsPickingMultipleItems: NO];
    picker.prompt = NSLocalizedString (@"Add songs to play", "Prompt in media item picker");

    // pickerをModalViewに表示
    [self presentModalViewController: picker animated: YES];
    [picker release];
}



//選択した曲に対して処理を行う
- (void)mediaPicker:(MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection
{
    MPMediaItem *item = [mediaItemCollection.items lastObject];
    
    NSLog(@"export succeeded?:%@", [self exportItem:item]? @"YES": @"NO");
    
    [self dismissModalViewControllerAnimated:YES];
}

//cafファイルに変換してファイルの書き出し
- (BOOL)exportItem:(MPMediaItem *)item
{   
    NSError *error = nil;
    
    NSDictionary *audioSetting = [NSDictionary dictionaryWithObjectsAndKeys:
                                  [NSNumber numberWithFloat:44100.0],AVSampleRateKey,
                                  [NSNumber numberWithInt:1],AVNumberOfChannelsKey, //チャネルを1にしておかないと音の減衰ができない
                                  [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
                                  [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
                                  [NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
                                  [NSNumber numberWithBool:0], AVLinearPCMIsBigEndianKey,
                                  [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
                                  [NSData data], AVChannelLayoutKey, nil];
    
    //読み込み側のセットアップ
    NSURL *url = [item valueForProperty:MPMediaItemPropertyAssetURL];
    AVURLAsset *URLAsset = [AVURLAsset URLAssetWithURL:url options:nil];
    if (!URLAsset) return NO;
    
    AVAssetReader *assetReader = [AVAssetReader assetReaderWithAsset:URLAsset error:&error];
    if (error) return NO;
    
    NSArray *tracks = [URLAsset tracksWithMediaType:AVMediaTypeAudio];
    if (![tracks count]) return NO;
    
    AVAssetReaderAudioMixOutput *audioMixOutput = [AVAssetReaderAudioMixOutput
                                                   assetReaderAudioMixOutputWithAudioTracks:tracks
                                                   audioSettings:audioSetting];
    
    if (![assetReader canAddOutput:audioMixOutput]) return NO;
    
    [assetReader addOutput:audioMixOutput];
    
    if (![assetReader startReading]) return NO;
    
    
    //書き込み側のセットアップ
    NSString *title = [item valueForProperty:MPMediaItemPropertyTitle];
    NSArray *docDirs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDir = [docDirs objectAtIndex:0];
    NSString *outPath = [[docDir stringByAppendingPathComponent:@"music1"]
                         stringByAppendingPathExtension:@"caf"];
    
    NSURL *outURL = [NSURL fileURLWithPath:outPath];
    AVAssetWriter *assetWriter = [AVAssetWriter assetWriterWithURL:outURL
                                                        fileType:AVFileTypeCoreAudioFormat
                                                             error:&error];
    //ファイルが存在している場合は削除する
    NSFileManager *manager = [NSFileManager defaultManager];
    if([manager fileExistsAtPath:outPath]){
        [manager removeItemAtPath:outPath error:&error];
    }
    
    if (error) return NO;
    
    AVAssetWriterInput *assetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio
                                                                              outputSettings:audioSetting];
    assetWriterInput.expectsMediaDataInRealTime = NO;
    
    if (![assetWriter canAddInput:assetWriterInput]) return NO;
    
    [assetWriter addInput:assetWriterInput];
    
    if (![assetWriter startWriting]) return NO;
    
    
    
    //コピー処理
    [assetReader retain];
    [assetWriter retain];
    
    [assetWriter startSessionAtSourceTime:kCMTimeZero];
    
    dispatch_queue_t queue = dispatch_queue_create("assetWriterQueue", NULL);
        
    //書き込み処理
    [assetWriterInput requestMediaDataWhenReadyOnQueue:queue usingBlock:^{
        
        NSLog(@"start");
        
        while (1){
            if ([assetWriterInput isReadyForMoreMediaData]) {
            
                CMSampleBufferRef sampleBuffer = [audioMixOutput copyNextSampleBuffer];
                
                if (sampleBuffer) {
                    [assetWriterInput appendSampleBuffer:sampleBuffer];
                    CFRelease(sampleBuffer);
                }
                else {
                    [assetWriterInput markAsFinished];
                    break;
                }
            }
        }
        
        [assetWriter finishWriting];
        [assetReader release];
        [assetWriter release];
        
        NSLog(@"finish");
                
    }];
    
    dispatch_release(queue);
    
    return YES;
}

2013年1月23日水曜日

iPhoneでXMLファイルからデータを取得する

サーバーからデータ取得してiPhoneで使用したい場合はXML形式で読み込むようにしています。
このやり方が正しいのかイマイチわからないのが1人で作業するとこの難しさだと感じてます。
だれか正攻法教えてください。

まずはサーバー側ではPHPでXML形式のデータを作成。

createXML.php
&lt?php
include_once "DatabaseClass.php";

if(!empty($_POST)){  
 $database = new Database;
 
 $table = "user_name";
 $email = $_POST['email'];
 $password = $_POST['password'];
 
 $select = sprintf('SELECT id, name, picture FROM %s WHERE email="%s" AND password="%s"',
      mysql_real_escape_string($table),
      mysql_real_escape_string($email),
      mysql_real_escape_string($password));
           
 $row = $database->array_select($select);

 if($row != NULL){
  $xml = "\n";
     
  $xml.= '';
  $xml.="\n";
     
   foreach($row as $value){
    $xml.="\n";
    $id=$value["id"];
    $xml.="\t$id\n";
    $name=$value["name"];
    $xml.="\t$name\n";
    $pict=$value["picture"];
    $xml.="\t$pict\n";
    $xml.="\n";
   }//foreach
     
   $xml.="\n";
   echo $xml; 
 } //if($row != NULL)
 
 $database->close();
}


?>

iPhoneからはPOSTメソッドでデータを送信し、返り値をNSXMLParserオブジェクトに代入してデータを取得する。

XMLParseAppDelegate.m
- (void)loadData{   
    NSURL *url = [[NSURL alloc]initWithString:@"http://localhost:8888/createXML.php"];
 
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
    
    // MethodにPOSTを指定する。
    request.HTTPMethod = @"POST";
    
    NSString *email    = @"momo@momochibi.com";
    NSString *password = @"momo";
    
    NSString *body = [NSString stringWithFormat:@"email=%@&password=%@",email,password];
    
    request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];

    //XML形式のデータを取得   
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 
    NSXMLParser *parser = [[NSXMLParser alloc]initWithData:returnData];
  [parser setDelegate:self];
    [parser parse];
}

// XMLのパース開始
- (void)parserDidStartDocument:(NSXMLParser *)parser {
 // 初期化処理
 //statuses = [NSMutableArray array];
    
    members = [NSMutableArray array];
    membersPicture = [NSMutableArray array];
    
    inIdElement   = NO;
    inNameElement = NO;
    inPictElement = NO;
    
}

// XMLのパース終了
- (void)parserDidEndDocument:(NSXMLParser *)parser {
 // 取得したデータを出力する
 for (NSString *member in members) {
  NSLog(@"%@", member);
 }
}

// 要素の開始タグを読み込み
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
 if ([elementName isEqualToString:@"id"]) {
  // nameタグの中に入った
  inIdElement = YES;
        ID = [NSMutableString string];
 }
    
    if ([elementName isEqualToString:@"name"]){
        inNameElement =YES;
        name = [NSMutableString string];
    
    }
    
    if( [elementName isEqualToString:@"pict"] ){
        inPictElement = YES;
        pict = [NSMutableString string];
    }
    
}

// 要素の閉じタグを読み込み
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
 if ([elementName isEqualToString:@"member"]) {
  // memberタグが終わるタイミングで、membersにメンバーを追加する
  NSString *s = [NSString stringWithFormat:@"%@: %@ : %@", ID, name, pict];
  [members addObject:s];
        
        NSString *ps = [NSString stringWithFormat:@"%@",pict];
        [membersPicture addObject:ps];
 } else if ([elementName isEqualToString:@"id"]) {
  // idタグから出た!
  inIdElement = NO;
 } else if ([elementName isEqualToString:@"name"]) {
  // nameタグから出た!
  inNameElement = NO;
 } else if ([elementName isEqualToString:@"pict"]) {
        
        inPictElement = NO;
    }
}

// テキストデータ読み込み
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
 // テキストデータは複数回に分けて呼び出されることがある
 if (inIdElement) {
  [ID appendString:string];
 }
    else if (inNameElement) {
  [name appendString:string];
 }
    else if (inPictElement){
        [pict appendString:string];
    }

}
XMLParseAppDelegate.h
#import &ltoundation/Foundation.h&gt

@interface XMLParseAppDelegate : NSObject&ltUIApplicationDelegate, NSXMLParserDelegate&gt
{
 
    NSMutableArray *members;
    BOOL inIdElement;
    BOOL inNameElement;
    BOOL inPictElement;
    NSMutableString *name;
    NSMutableString *ID;
    NSMutableString *pict;
}

- (void)loadData;


@end
こんな感じでデータをiPhoneからデータベースに接続して データを取得したりしてます。

iPhoneでPOSTメソッドによるデータを取得する方法

iPhoneではGETメソッドでデータをやり取りするのは簡単だけど、 POSTメソッドでやりとりする場合少しめんどくさい。

GETでデータを送信する場合はURLに入れればいいだけでできる。

NSString *s = [NSString stringWithFormat:@"http://localhost:8888/index.php?table_name=products&query_type=select"];    
NSURL  *url = [NSURL URLWithString:s];

POSTメソッドの場合はリクエストをNSMutableURLRequestで宣言する。
その後、POSTメソッドで送る内容をリクエストのHTTPBodyに代入することで可能となる。
    NSURL *url = [[NSURL alloc]initWithString:@"http://localhost:8888/dbconnect/POSTMethodFromiOS.php"];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
    
    // MethodにPOSTを指定する。
    request.HTTPMethod = @"POST";
    
    NSString *email    = @"momo@momochibi.com";
    NSString *password = @"momo";
    
    NSString *body = [NSString stringWithFormat:@"email=%@&password=%@",email,password];
    
    request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];

POSTメソッドでサーバにデータを送る場合は、何かしらの処理をした結果を取得したいと思う。
僕はXML形式に処理されたデータを変換し、そのデータを取得するようにしている。