cocoa playing an mp3
Asked Answered
L

6

13

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.

Launalaunce answered 18/7, 2010 at 17:51 Comment(3)
Sorry, are you developing for iOS or Mac?Architect
Yes, sorry, forgot to clarify: AVAudioPlayer won't work: i'm developing for OSXLaunalaunce
As of Mac OS X 10.7 Lion (possibly even 10.6.8?) AVFoundation works! Hence, AVAudioPlayer.. See answer below..Nepali
N
41

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.

Nepali answered 12/4, 2012 at 14:7 Comment(3)
How do you test to know if you are able to use this?Overthrow
What do you mean? Go through the steps explained, and make sure you add an MP3 file to your resources. Then, add a button (action) that will call [audioPlayer play]Nepali
The method URLWithString always returned nil for me. Using [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"myFile" ofType:@"mp3"]]; instead fixed the problem.Kultur
J
5

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

Johnsonjohnsonese answered 18/7, 2010 at 18:29 Comment(0)
N
1

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.

Naphthyl answered 18/7, 2010 at 19:16 Comment(0)
T
1
#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
Tun answered 18/9, 2015 at 15:26 Comment(0)
R
0

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.

Restrain answered 18/7, 2010 at 18:47 Comment(7)
I've also seen examples with QTKit without any views, but i'm not sure if this is a good way to do it, since i haven't found how to seek a file or maybe even add some effects later.Launalaunce
I'm not sure what you mean by "seek a file".Restrain
Well, in simpler terms, go to some specific position and continue playing from there.Launalaunce
Oh, OK... when using QTMovieView, you can use QTMovie methods such as setCurrentTime: on the associated QTMovie.Restrain
Thanks. Would it be possible to add some audio effects to QTMovie later? Like reverb, equalizer etc.? Or is it only possible for CoreAudio?Launalaunce
I can't swear that it can't be done, but I don't recall seeing anything about using audio effects on a QTMovie.Restrain
@JWWalker, I know that you wrote your answer back in 2010, but now, in 2016, I believe tht QTMoviewView is deprecated.Indecorum
F
0
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.
        }
    }
    
    
}
Foilsman answered 9/12, 2020 at 22:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.