ホームページ開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでMIDIを鳴らす・録音する - 別稿

 実験用なので、現在再生中の音を録音するのみの機能です。
  1. Xojoで新規プロジェクトを作成
  2. Window1に、PushButton2個(Name:PushButton1、Name:PushButton2)を追加
  3. 以下をPushButton1にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      // 録音開始
      AVCaptureSession()
    End Sub
    
  4. 以下をPushButton2にペースト(できなければ、Sub - Endの間をActionイベントに記述)
    Sub Action() Handles Action
      // 録音停止
      Declare Sub stopRunning Lib "Cocoa" selector "stopRunning" (obj_id As Ptr)
      stopRunning(pSession)
    End Sub
    
  5. 以下をWindow1にペースト
    Protected Sub AVCaptureSession()
      Dim error As Ptr
      
      // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      
      Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr
      Declare Function init Lib "Cocoa" selector "init" (obj_id As Ptr) As Ptr
      
      // セッション初期化
      pSession = NSClassFromString("AVCaptureSession")
      pSession = init(alloc(pSession))
      
      // 入力デバイスを指定
      Dim device As Ptr = NSClassFromString("AVCaptureDevice")
      Declare Function deviceWithUniqueID Lib "Cocoa" selector "deviceWithUniqueID:" (class_id As Ptr, dev As CFStringRef) As Ptr
      device = deviceWithUniqueID(device, "SoundflowerEngine:0")  // Soundflowerを直接指定
      
      // 入力(入力デバイスを指定して初期化)
      Dim input As Ptr = NSClassFromString("AVCaptureDeviceInput")
      Declare Function deviceInputWithDevice Lib "Cocoa" selector "deviceInputWithDevice:error:" (obj_id As Ptr, dev As Ptr, byRef err As Ptr) As Ptr
      input = deviceInputWithDevice(input, device, error)
      Declare Function canAddInput Lib "Cocoa" selector "canAddInput:" (obj_id As Ptr, input As Ptr) As Boolean
      Declare Sub addInput Lib "Cocoa" selector "addInput:" (obj_id As Ptr, input As Ptr)
      Dim flgI As Boolean = canAddInput(pSession, input)
      if flgI then
        addInput(pSession, input)
      else
        msgBox "err in"
      end if
      
      // 出力
      Dim output As Ptr = NSClassFromString("AVCaptureAudioFileOutput")
      output = init(alloc(output))
      Declare Function canAddOutput Lib "Cocoa" selector "canAddOutput:" (obj_id As Ptr, output As Ptr) As Boolean
      Declare Sub addOutput Lib "Cocoa" selector "addOutput:" (obj_id As Ptr, output As Ptr)
      Dim flgO As Boolean = canAddOutput(pSession, output)
      if flgO then
        addOutput(pSession, output)
      else
        msgBox "err out"
      end if
      
      // セッションスタート
      Declare Sub startRunning Lib "Cocoa" selector "startRunning" (obj_id As Ptr)
      startRunning(pSession)
      
      // 出力ファイル(ここではAIFF形式)
      Dim f As FolderItem = SpecialFolder.Desktop.Child("test.aiff")
      Dim url As Ptr = NSClassFromString("NSURL")  // クラスメソッドなので、まずNSURLクラスを取得
      Declare Function fileURLWithPath Lib "Cocoa" Selector "fileURLWithPath:" (receiver As Ptr, path As CFStringRef) As Ptr
      url = fileURLWithPath(url, f.NativePath)
      
      // 録音開始
      Declare Sub startRecordingToOutputFileURL Lib "Cocoa" selector "startRecordingToOutputFileURL:outputFileType:recordingDelegate:" (obj_id As Ptr, url As Ptr, type As CFStringRef, delegat As Ptr)
      startRecordingToOutputFileURL(output, url, "public.aiff-audio", makeDelegate())  // delegateは必須(nilではダメ)
    End Sub
    
  6. 以下をWindow1にペースト(できなければプロパティに、名前:pSession、データ型:Ptr、を追加)
    Protected Property pSession as Ptr
    
  7. 以下をWindow1にペースト
    Protected Shared Sub didFinishRecording(id As Ptr, SEL As CString, output As Ptr, url As Ptr, connect As Ptr, err As Ptr)
      msgBox "didFinishRecording"
    End Sub
    
  8. 以下をWindow1にペースト
    Protected Shared Function makeDelegate() as Ptr
      // 既に作成済なら値を返す
      if delegateId <> nil then
        return delegateId
      end if
      
      // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。
      Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr
      Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr
      
      // Declare宣言
      Declare Function objc_allocateClassPair Lib "Cocoa" (superclass As Ptr, name As CString, extraBytes As Integer) as Ptr
      Declare Sub objc_registerClassPair Lib "Cocoa" (cls As Ptr)
      Declare Function class_addMethod Lib "Cocoa" (cls As Ptr, name As Ptr, imp As Ptr, types As CString) As Boolean
      
      // クラス名をmyClass1Delegate(名前は任意。少なくとも今回のケースでは参照されない。)、メタクラス名をNSObjectにして、生成
      Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSObject"), "myClass1Delegate", 0)
      // ランタイムに登録(参照を可能とするため)
      objc_registerClassPair newClassId
      if not class_addMethod (newClassId, NSSelectorFromString("captureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:"), AddressOf didFinishRecording, "@@:@@@@") then
        msgBox "error."
        return nil
      end if
      
      // 上記で生成したクラスのインスタンスを作成
      Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr
      Declare Function init Lib "Cocoa" selector "init" (obj_id As Ptr) As Ptr
      delegateId = init(alloc(newClassId))
      
      // インスタンスを返す
      return delegateId
    End Function
    
    (注:Delegateメソッドは他にもあるが、ここではcaptureOutput:didFinishRecordingToOutputFileAtURL:fromConnections:error:のみ実装。)
  9. 以下をWindow1にペースト(できなければ共有プロパティに、名前:delegateId、データ型:Ptr、を追加)
    Protected Shared Property delegateId as Ptr
    

[Home]  [MacSoft]  [Donation]  [History]  [Privacy Policy]  [Affiliate Policy]