Cocoa: Simple audio recording - objective-c

I'm trying to implement some simple audio recording functionality in my application and I can't quite figure out to do it. I've been pointed to this example, but I can't get it to run in XCode, and it appears to be written in C++.
What I need to be able to do is record audio to a file, and then be able to get the current timestamp of the recording whilst recording. I would appreciate any help with this. Thanks!

You can record and play audio using the AVFoundation framework. Firstly you will need to implement this within your .h file and add a framework or library's within your xcode project settings like so:
After adding into your project settings import AVFoundation into your .h file like so:
#import <AVFoundation/AVFoundation.h>
Now Implement your delegates within your .h file:
#interface ViewController : UIViewController <AVAudioRecorderDelegate, AVAudioPlayerDelegate>
After this declare your AVAudioRecorder and AVAudioPlayer in your .h file like so:
#interface ViewController () {
AVAudioRecorder *recorder;
AVAudioPlayer *player;
IBOutlet UIButton *stopButton;
IBOutlet UIButton *playButton ;
}
- (IBAction)recordPauseTapped:(id)sender;
- (IBAction)stopTapped:(id)sender;
- (IBAction)playTapped:(id)sender;
Now set up everything in the -(Void)ViewDidLoad{} :
- (void)viewDidLoad
{
[super viewDidLoad];
// Disable Stop/Play button when application launches
[stopButton setEnabled:NO];
[playButton setEnabled:NO];
// Set the audio file
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemo.m4a",
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
// Define the recorder setting
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
// Initiate and prepare the recorder
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
}
Now Implement the recording Button Like so...
- (IBAction)recordPauseTapped:(id)sender {
// Stop the audio player before recording
if (player.playing) {
[player stop];
}
if (!recorder.recording) {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
// Start recording
[recorder record];
[recordPauseButton setTitle:#"Pause" forState:UIControlStateNormal];
} else {
// Pause recording
[recorder pause];
[recordPauseButton setTitle:#"Record" forState:UIControlStateNormal];
}
[stopButton setEnabled:YES];
[playButton setEnabled:NO];
}
Now Implement the StopButton IBAction:
- (IBAction)stopTapped:(id)sender {
[recorder stop];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setActive:NO error:nil];
}
Next Implement the playTapped IBAction like so:
- (IBAction)playTapped:(id)sender {
if (!recorder.recording){
player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
[player setDelegate:self];
[player play];
}
}
Lastly Implement the required AVPlayer Delegate by doing this:
- (IBAction)playTapped:(id)sender {
if (!recorder.recording){
player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
[player setDelegate:self];
[player play];
}
}
And that's it! The Finished Product should look something like this...
For more info take a look at These Links:
Link1
Link2
Link3
Documentation Links:
Link 1
Hope This Helps.

The above mentioned AVFoundation framework is iOS only. Dealing with audio on OS X is quite painful in the beginning. CoreAudio, while it is one of the best components I worked with, does require some time spent learning and understanding. You may want to consider for exampel using https://github.com/syedhali/EZAudio for your task.

Related

How do assign a type of file to my app on Mac

I try to assign a file type to my application.
In Info.plist I add:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>type</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>icon</string>
<key>CFBundleTypeName</key>
<string>My Project</string>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>LSTypeIsPackage</key>
<false/>
</dict>
</array>
In Main.mm:
....
-(BOOL) application:(NSApplication *)sender openFile:(NSString *)filename {
NSLog(#"Opened by file");
return YES;
}
#end
int main(int argc, char* argv[]) {
[NSApplication sharedApplication];
[[[[Window alloc] init] autorelease] makeMainWindow];
[NSApp run];
return 0;
}
But when I try double click on the my file type, The app only open with the warn: could not be opened, MyApp cannot open file in format. Also the message from NSLog is not called at all.
There are several issues with the code you posted but I was able to get the desired behavior with a few modifications.
I assume this is your window interface and implementation:
#interface Window : NSWindow <NSApplicationDelegate>
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
#end
#implementation Window
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
NSLog(#"Opened by file");
return YES;
}
#end
This is extremely odd to be using a window object as an application delegate. Normally, you have a controller object that owns and manages the window and also acts as the application's delegate.
In any case, it's still possible to get... well, functional behavior by changing the main() function to the following:
int main(int argc, const char * argv[]) {
[NSApplication sharedApplication];
Window *window = [[[Window alloc] init] autorelease];
NSApp.delegate = window;
[window makeKeyAndOrderFront:nil];
[NSApp run];
return 0;
}
There are two notable changes. First, your problem was that you didn't set the window instance to be the application delegate. Second, IIRC, you should never call -makeMainWindow directly; rather, that method exists so that you can override it if you wish. If you want to display the window on screen, you call -makeKeyAndOrderFront:.
Opening a file should display the logged line in console (if you're using Xcode 12.5.1, resize the log window if needed to workaround the display bug).
Under manual reference counting, I believe this would leak memory, since no autorelease pool is created, but I didn't see any of the usual warnings in console. Anyway, while this code works, it results in a fairly undesirable scenario. There is no main menu in the app so to quit it you have to use the Dock. The window created is also tiny and has no resizing capabilities, etc.
EDIT: An example project is at https://github.com/NSGod/OpenFile.
The following subclass of NSWindow should allow you to save a file with a unique ‘.jaf’ extension and then reopen the file into the app by double clicking on it. The info.plist is not as critical as I initially thought; I did not alter the one created by Xcode. Most important for this non-Document based app seems to be the calling of NSApplicationDelegate method -(BOOL) application: openFile. The NSApplicationDelegate was added to the NSWindow subclass instead of having a separate AppDelegate as is usually the case. When working correctly you should hear a beep when this method is called after a .jaf file is double-clicked; I couldn’t find the NSLog output. To run the demo in Xcode first create an objc project and delete everything in the ‘main.m’ file and copy/paste the following source code into it. Delete the pre-supplied AppDelegate class to avoid duplicate symbols. In the entitlements set the App Sandbox to NO and set read-only to zero. After the JAF app has been made, use it to save a file to your desktop with the ‘.jaf’ extension. Then make a copy of the app (shown in the Finder) and copy/paste it into the Applications folder. The next step is critical; right click on the file that you just made and use either Get Info or Open With to set the file to always open with your newly made app. At this point you should be able to double click on the xxxx.jaf file and have it open into your app with an audible beep.
#import <Cocoa/Cocoa.h>
#interface Window : NSWindow <NSApplicationDelegate> {
NSTextView *txtView;
}
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag;
-(void) buildMenu;
-(void) openAction;
-(void) saveAction;
#end
#implementation Window
#define _wndW 700
#define _wndH 550
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
NSLog(#"This comes from JAF : filename = %#.",filename);
NSBeep(); // Listen for this.
NSError *error;
NSURL *url = [NSURL fileURLWithPath:filename];
NSString *fileStr = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (!fileStr) {
NSLog(#"Unable to open file %#", error);
} else {
[txtView setString:fileStr];
}
return YES;
}
-(void) buildMenu {
// **** Menu Bar **** //
NSMenu *menubar = [NSMenu new];
[NSApp setMainMenu:menubar];
// **** App Menu **** //
NSMenuItem *appMenuItem = [NSMenuItem new];
NSMenu *appMenu = [NSMenu new];
[appMenu addItemWithTitle: #"Quit" action:#selector(terminate:) keyEquivalent:#"q"];
[appMenuItem setSubmenu:appMenu];
[menubar addItem:appMenuItem];
}
-(void) openAction {
NSOpenPanel *op = [NSOpenPanel openPanel];
[op setAllowedFileTypes:[NSArray arrayWithObjects: #"jaf", #"txt", nil]];
[op beginSheetModalForWindow: self completionHandler: ^(NSInteger returnCode) {
if (returnCode == NSModalResponseOK) {
NSURL *url = [op URL];
NSError *error;
NSString *fileStr = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (!fileStr) {
NSLog(#"Unable to open file %#", error);
} else {
[self->txtView setString:fileStr];
}
}
}];
}
-(void) saveAction {
NSSavePanel *sp = [NSSavePanel savePanel];
[sp setTitle:#"Save contents to file"];
[sp setAllowedFileTypes:[NSArray arrayWithObjects: #"jaf", nil]];
[sp setNameFieldStringValue: #".jaf"];
[sp beginSheetModalForWindow: self completionHandler: ^(NSInteger returnCode) {
if (returnCode == NSModalResponseOK) {
NSURL *url = [sp URL];
NSString *viewStr = [[self->txtView textStorage] string];
NSError *err;
BOOL fileSaved = [viewStr writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:&err];
if (!fileSaved) { NSLog(#"Unable to save file due to error: %#", err);}
}
}];
}
- (instancetype)initWithContentRect:(NSRect)contentRect styleMask:(NSWindowStyleMask)style backing:(NSBackingStoreType)backingStoreType defer:(BOOL)flag {
self = [super initWithContentRect:NSMakeRect(0, 0, _wndW, _wndH) styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable backing:NSBackingStoreBuffered defer:NO];
[self setTitle: #"Test window"];
[self center];
[self makeKeyAndOrderFront: nil];
// ****** NSTextView with Scroll ****** //
NSScrollView *scrlView = [[NSScrollView alloc] initWithFrame:NSMakeRect( 10, 10, _wndW - 20, _wndH - 80 )];
[[self contentView] addSubview:scrlView];
[scrlView setHasVerticalScroller: YES];
[scrlView setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
txtView = [[NSTextView alloc] initWithFrame:NSMakeRect( 0, 0, _wndW - 20, _wndH - 80 )];
[scrlView setDocumentView: txtView];
// **** Open Button **** //
NSButton *openBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, _wndH - 50, 95, 30 )];
[openBtn setBezelStyle:NSBezelStyleRounded ];
[openBtn setTitle: #"Open"];
[openBtn setAutoresizingMask: NSViewMinYMargin];
[openBtn setAction: #selector (openAction)];
[[self contentView] addSubview: openBtn];
// **** Save Button **** //
NSButton *saveBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 130, _wndH - 50, 95, 30 )];
[saveBtn setBezelStyle:NSBezelStyleRounded ];
[saveBtn setTitle: #"Save"];
[saveBtn setAutoresizingMask: NSViewMinYMargin];
[saveBtn setAction: #selector (saveAction)];
[[self contentView] addSubview: saveBtn];
return self;
}
- (BOOL)windowShouldClose:(id)sender {
[NSApp terminate:sender];
return YES;
}
#end
int main() {
NSApplication *application = [NSApplication sharedApplication];
Window *window = [[Window alloc]init];
[window buildMenu];
[application setDelegate:window];
[application activateIgnoringOtherApps:YES];
[NSApp run];
return 0;
}

NSSound stop function

Thanks for the help.
This activates basic playback of referenced file:
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ping" ofType:#"aiff"] byReference:NO];
[sound play];
What's the proper way to terminate playback? No luck implementing the following:
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ping" ofType:#"aiff"] byReference:NO];
if([sound isPlaying]) {
[sound stop];
Thanks for the assistance.
From the couple code snippets you included in your question, it looks like you are doing this:
// create new sound object
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ping" ofType:#"aiff"] byReference:NO];
// start it playing
[sound play];
and then you create another new sound object:
// create new sound object
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ping" ofType:#"aiff"] byReference:NO];
// this cannot be true - you just created the sound object
if([sound isPlaying]) {
[sound stop];
}
Try this very simple example (just add Play and Stop buttons to a view controller and connect them):
#import "ViewController.h"
#interface ViewController() {
NSSound *sound;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// instantiate sound object with file from bundle
sound = [[NSSound alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"1162" ofType:#"aiff"] byReference:NO];
}
- (IBAction)playClicked:(id)sender {
if (sound) {
[sound play];
}
}
- (IBAction)stopClicked:(id)sender {
if (sound && [sound isPlaying]) {
[sound stop];
}
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
}
#end

How to record video from iPhone camera in iOS 9 objective c?

hello I need to build app that record video from iPhone camera.
I search in the net and not found notting that works in iOS 9.
I get this code from this git project :
https://github.com/versluis/Video-Recorder
This code open camera but not allow Me to take a video.
- (IBAction)recordButton:(id)sender {
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
UIImagePickerController *picker = [[UIImagePickerController alloc]init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
picker.allowsEditing = NO;
NSArray *mediaTypes = [[NSArray alloc]initWithObjects:(NSString *)kUTTypeMovie, nil];
picker.mediaTypes = mediaTypes;
[self presentViewController:picker animated:YES completion:nil];
} else {
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:nil message:#"I'm afraid there's no camera on this device!" delegate:nil cancelButtonTitle:#"Dang!" otherButtonTitles:nil, nil];
[alertView show];
}
}
- (IBAction)playbackButton:(id)sender {
// pick a video from the documents directory
NSURL *video = [self grabFileURL:#"video.mov"];
// create a movie player view controller
MPMoviePlayerViewController * controller = [[MPMoviePlayerViewController alloc]initWithContentURL:video];
[controller.moviePlayer prepareToPlay];
[controller.moviePlayer play];
// and present it
[self presentMoviePlayerViewControllerAnimated:controller];
}
#pragma mark - Delegate Methods
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
// user hit cancel
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
// grab our movie URL
NSURL *chosenMovie = [info objectForKey:UIImagePickerControllerMediaURL];
// save it to the documents directory
NSURL *fileURL = [self grabFileURL:#"video.mov"];
NSData *movieData = [NSData dataWithContentsOfURL:chosenMovie];
[movieData writeToURL:fileURL atomically:YES];
// save it to the Camera Roll
UISaveVideoAtPathToSavedPhotosAlbum([chosenMovie path], nil, nil, nil);
// and dismiss the picker
[self dismissViewControllerAnimated:YES completion:nil];
}
- (NSURL*)grabFileURL:(NSString *)fileName {
// find Documents directory
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
// append a file name to it
documentsURL = [documentsURL URLByAppendingPathComponent:fileName];
return documentsURL;
}
Ray gave pretty good tutorial about this. Hope it helped.

How to change video url for MPMoviePlayerViewController?

I am developing for iOS 6 using Xcode 4.6.1 (Target is iPad)
I am trying to change the video URL when the user swipes the screen.
This is my ViewController.m file:
#import "ViewController.h"
#interface experiencesViewController () {
MPMoviePlayerViewController *playerViewController;
MPMoviePlayerController *player;
}
#end
...
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSString *url = [[NSBundle mainBundle] pathForResource:"video" ofType:#"mp4"];
playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL fileURLWithPath:url]];
player = [playerViewController moviePlayer];
[player setMovieSourceType:MPMovieSourceTypeFile];
player.fullscreen = YES;
[player play];
...
}
...
Now, I want to change the video on a swipe event. I tried doing this:
- (IBAction)didSwipeLeft:(UITapGestureRecognizer *)recognizer {
NSLog(#"Left");
player.movieSourceType = MPMovieSourceTypeFile;
player.contentURL = [NSURL URLWithString:#"video2.mp4"];
[player prepareToPlay];
[player play];
}
However, this doesn't work. The video stops playing and nothing happens after that. Any help would be highly appreciated.
Thanks :)
remove the [player play] because the video is not yet ready to play.

cocoa playing an mp3

Is there an easy way to load, play and control an mp3 file from cocoa? Tried googling it, but, as all things apple, i get messy results and have no idea where to start. As i understand, there's and NSSound, but it has lots of limitations and then there's CoreAudio, but it's very difficult. So can someone point me in a right direction with this? Thanks.
Use AVFoundation! According to apple, it has been integrated with Mac OS X Lion (I think), so.. Here is how to play mp3 painlessly:
1- link the AVFoundation Framework.
2- import it wherever you want to play your awesome mp3
#import <AVFoundation/AVFoundation.h>
3- Add an audioPlayer instance variable to play the sound (That's how I like to do it, at least)
#interface WCMainWindow : ... {
...
AVAudioPlayer* audioPlayer;
}
4- In you init, make sure you initialize your audioPlayer:
NSString* path = [[NSBundle mainBundle] pathForResource:#"myFile" ofType:#"mp3"];
NSURL* file = [NSURL fileURLWithPath:path];
// thanks #gebirgsbaerbel
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
[audioPlayer prepareToPlay];
5- Play your awesome Mp3!!
if ([audioPlayer isPlaying]) {
[audioPlayer pause];
} else {
[audioPlayer play];
}
Finally, credit goes to this guy.
I've written a framework in C++ that might help: http://github.com/sbooth/SFBAudioEngine
It supports multiple audio formats and has a fairly benign API and comes with a Cocoa sample.
If you're not interested in third-party frameworks, your bet would probably be to use an AudioQueue to take care of the playback. To do this, you'd probably use AudioFile to decode the MP3 and AudioQueue for the playback. Apple has an example at http://developer.apple.com/mac/library/samplecode/AudioQueueTools/Introduction/Intro.html
Use NSSound.
You didn't specify what you mean by “lots of limitations”, so I don't know why this won't work for you. Note that it has a lot fewer limitations since Leopard; you can now play to any device, for example.
#import <Cocoa/Cocoa.h>
#import <QTKit/QTKit.h>
#interface SoundPlayer : NSObject {
NSSound *sound;
IBOutlet NSWindow *window;
IBOutlet NSSlider *progress;
BOOL loop;
}
- (IBAction)open: (id)sender;
- (IBAction)setLoop: (id)sender;
- (IBAction)play: (id)sender;
- (IBAction)stop: (id)sender;
- (IBAction)takeCurrentTimeFrom: (id)sender;
#end
#import "SoundPlayer.h"
#implementation SoundPlayer
- (IBAction)open: (id)sender
{
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel runModalForTypes: [NSArray arrayWithObjects: #"aiff", #"mp3", #"m4a", nil]];
[sound release];
sound = [[QTMovie movieWithFile: [openPanel filename]
error: NULL] retain];
[sound setAttribute: [NSNumber numberWithBool: loop]
forKey: QTMovieLoopsAttribute];
[window setTitle: [[openPanel filename] lastPathComponent]];
}
- (IBAction)setLoop: (id)sender
{
loop = ([sender state] == NSOnState);
[sound setAttribute: [NSNumber numberWithBool: loop]
forKey: QTMovieLoopsAttribute];
}
- (IBAction)play: (id)sender
{
NSTimeInterval duration;
QTGetTimeInterval([sound duration], &duration);
[progress setMaxValue: duration];
[NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector: #selector(updateIndicator:)
userInfo: sound
repeats: YES];
[sound play];
}
- (void)updateIndicator: (NSTimer*)aTimer
{
QTMovie *playingSound = [aTimer userInfo];
if (!(sound == playingSound && ([sound rate] != 0)))
{
[aTimer invalidate];
return;
}
NSTimeInterval currentTime;
QTGetTimeInterval([sound currentTime], &currentTime);
[progress setDoubleValue: currentTime];
}
- (IBAction)stop: (id)sender
{
[sound stop];
}
- (IBAction)takeCurrentTimeFrom: (id)sender
{
[sound setCurrentTime: QTMakeTimeWithTimeInterval([sender doubleValue])];
}
#end
Besides NSSound, you could consider QTMovieView. It sounds odd, but you can have a hidden QTMovieView in your window and use it to play an MP3.
Added: QTMovieView is deprecated as of OS 10.9. So unless you need to support OS versions before 10.7 (when AVFoundation came to the Mac), you should probably not use this.
import Cocoa
import AVFoundation
class ViewController: NSViewController {
var audio = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
let play = Bundle.main.path(forResource: "A" , ofType: "mb3")
do{
audio = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: play!))
}
catch{
print(error)
}
}
#IBAction func button(_ sender: Any)
{
audio.play()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}