Difference between revisions of "macOS Audio Recorder"
m (→AVAudioRecorder: Minor update) |
(→Example Code: Added code example) |
||
Line 23: | Line 23: | ||
== Example Code == | == Example Code == | ||
− | + | {{Warning|This code compiles and creates the appropriate audio file, but until I get a microphone for my Mac mini the code should be considered "untested" :-)}} | |
+ | |||
+ | {{Note|Not every method in the AVAudioRecorder class has been implemented in the code below. Most methods have been implemented. Check the Apple documentation for the rest. The implemented methods are described in detail in the code below.}} | ||
+ | |||
+ | <syntaxhighlight lang="pascal"> | ||
+ | // | ||
+ | // Note: Free Pascal v3.3.1 (trunk), revision r42644, was used 6-Jan-2019 | ||
+ | // | ||
+ | |||
+ | unit unit1; | ||
+ | |||
+ | {$mode objfpc}{$H+} | ||
+ | {$modeswitch objectivec1} | ||
+ | {$linkframework AVFoundation} | ||
+ | |||
+ | interface | ||
+ | |||
+ | uses | ||
+ | ... | ||
+ | MacOSAll, | ||
+ | CocoaAll, | ||
+ | LCLType, | ||
+ | ... | ||
+ | |||
+ | type | ||
+ | |||
+ | { TForm1 } | ||
+ | |||
+ | AVAudioRecorder = objcclass external(NSObject) | ||
+ | public | ||
+ | {Initializes and returns an audio recorder. | ||
+ | url: File system location to record to. File type to record to is inferred | ||
+ | from the file extension included in this parameter’s value. | ||
+ | settings: Settings for the recording session. | ||
+ | outError: Returns, by-reference, a description of the error, if an error | ||
+ | occurs. Pass nil to ignore the error.} | ||
+ | function initWithURL_settings_error (url: NSURL; settings: NSDictionary; outError: NSErrorPtr):id; | ||
+ | message 'initWithURL:settings:error:'; | ||
+ | |||
+ | {Calling this method implicitly calls prepareToRecord(), which creates (or | ||
+ | erases) an audio file and prepares the system for recording.} | ||
+ | function avRecord: Boolean; message 'record'; | ||
+ | |||
+ | {Creates an audio file at the location specified by the url parameter in the | ||
+ | init() method. If a file already exists at that location, this method | ||
+ | overwrites it. The preparation invoked by this method takes place | ||
+ | automatically when you call record(). Use prepareToRecord when you want | ||
+ | recording to start as quickly as possible upon calling record().} | ||
+ | function prepareToRecord: Boolean; message 'prepareToRecord'; | ||
+ | |||
+ | {Pauses a recording. Call record() to resume recording.} | ||
+ | procedure pause; message 'pause'; | ||
+ | |||
+ | {Stops recording and closes the audio file.} | ||
+ | procedure stop; message 'stop'; | ||
+ | |||
+ | {Deletes a recorded audio file. The audio recorder must be stopped before | ||
+ | you call this method.} | ||
+ | function deleteRecording: Boolean; message 'deleteRecording'; | ||
+ | |||
+ | {A Boolean value that indicates whether the audio recorder is recording.} | ||
+ | function isRecording: Boolean; message 'isRecording'; | ||
+ | |||
+ | {Audio recorder settings are in effect only after you explicitly call the | ||
+ | prepareToRecord() method, or after you call it implicitly by starting | ||
+ | recording.} | ||
+ | function settings: NSDictionary; message 'settings'; | ||
+ | |||
+ | {The time, in seconds, since the beginning of the recording.} | ||
+ | function currentTime: NSTimeInterval; message 'currentTime'; | ||
+ | |||
+ | {By default, audio level metering is off for an audio recorder. Because | ||
+ | metering uses computing resources, turn it on only if you intend to use it.} | ||
+ | procedure setMeteringEnabled(newValue: ObjCBOOL); message 'setMeteringEnabled:'; | ||
+ | |||
+ | {A Boolean value that indicates whether audio-level metering is enabled.} | ||
+ | function isMeteringEnabled: ObjCBOOL; message 'isMeteringEnabled'; | ||
+ | |||
+ | {To obtain current audio power values, you must call this method before you | ||
+ | call averagePower(forChannel:) or peakPower(forChannel:).} | ||
+ | procedure updateMeters; message 'updateMeters'; | ||
+ | |||
+ | {The current peak power, in decibels, for the sound being recorded. A return | ||
+ | value of 0 dB indicates full scale, or maximum power; a return value of | ||
+ | -160 dB indicates minimum power (that is, near silence). If the signal | ||
+ | provided to the audio recorder exceeds ±full scale, then the return value | ||
+ | may exceed 0 (ie enter the positive range).} | ||
+ | function peakPowerForChannel (channelNumber: NSUInteger): single; message 'peakPowerForChannel:'; | ||
+ | |||
+ | {The current average power, in decibels, for the sound being recorded. A | ||
+ | return value of 0 dB indicates full scale, or maximum power; a return value | ||
+ | of -160 dB indicates minimum power (that is, near silence). If the signal | ||
+ | provided to the audio recorder exceeds ±full scale, then the return value | ||
+ | may exceed 0 (ie, it may enter the positive range).} | ||
+ | function averagePowerForChannel (channelNumber: NSUInteger): single; message 'averagePowerForChannel:'; | ||
+ | end; | ||
+ | |||
+ | TForm1 = class(TForm) | ||
+ | |||
+ | ... | ||
+ | |||
+ | private | ||
+ | |||
+ | public | ||
+ | |||
+ | end; | ||
+ | |||
+ | var | ||
+ | Form1: TForm1; | ||
+ | MyAudioRecorder : AVAudioRecorder = Nil; | ||
+ | |||
+ | |||
+ | implementation | ||
+ | |||
+ | {$R *.lfm} | ||
+ | |||
+ | ... | ||
+ | |||
+ | // Convert NSStrings function | ||
+ | function NSStringToString(ns: NSString): String; | ||
+ | var | ||
+ | pathStr: shortstring; | ||
+ | begin | ||
+ | CFStringGetPascalString(CFStringRef(ns),@pathStr,255,CFStringGetSystemEncoding()); | ||
+ | Result := pathStr; | ||
+ | end; | ||
+ | |||
+ | // Record audio to file | ||
+ | procedure RecordAudio(audioFileName : NSString); | ||
+ | var | ||
+ | path : NSString; | ||
+ | url : NSURL; | ||
+ | settings: NSDictionary; | ||
+ | err : NSError; | ||
+ | begin | ||
+ | path := NSTemporaryDirectory.stringByAppendingPathComponent(audioFileName); | ||
+ | url := NSURL.fileURLWithPath(path); | ||
+ | settings := Nil; | ||
+ | |||
+ | MyAudioRecorder := AVAudioRecorder.alloc.initWithURL_settings_error(url, settings, @err); | ||
+ | |||
+ | if Assigned(MyAudioRecorder) then | ||
+ | MyAudioRecorder.avrecord | ||
+ | else | ||
+ | NSLog(NSStr('Error in procedure RecordAudio(): %@'), err); | ||
+ | end; | ||
+ | |||
+ | ... | ||
+ | |||
+ | // Record audio - format mp4a inferred from filename | ||
+ | procedure TForm1.MenuItem27Click(Sender: TObject); | ||
+ | begin | ||
+ | RecordAudio(NSStr('testaudio.mp4a')); | ||
+ | end; | ||
+ | |||
+ | // Pause audio recording | ||
+ | procedure TForm1.MenuItem28Click(Sender: TObject); | ||
+ | begin | ||
+ | MyAudioRecorder.Pause; | ||
+ | end; | ||
+ | |||
+ | // Resume audio recording | ||
+ | procedure TForm1.MenuItem29Click(Sender: TObject); | ||
+ | begin | ||
+ | MyAudioRecorder.avRecord; | ||
+ | end; | ||
+ | |||
+ | // Stop audio recording and close file | ||
+ | procedure TForm1.MenuItem30Click(Sender: TObject); | ||
+ | begin | ||
+ | MyAudioRecorder.Stop; | ||
+ | end; | ||
+ | |||
+ | ... | ||
+ | |||
+ | finalization | ||
+ | |||
+ | If (Assigned (MyAudioRecorder)) then | ||
+ | begin | ||
+ | MyAudioRecorder.Release; | ||
+ | MyAudioRecorder := Nil; | ||
+ | end; | ||
+ | |||
+ | end. | ||
+ | |||
+ | </syntaxhighlight> | ||
== See also == | == See also == |
Revision as of 00:49, 6 January 2020
This article applies to macOS only.
See also: Multiplatform Programming Guide
Overview
The Apple AVFoundation framework combines four major technology areas that together encompass a wide range of tasks for capturing, processing, synthesising, controlling, importing and exporting audiovisual media on Apple platforms. It is available from macOS 10.7 (Lion). The framework provides essential services for working with time-based audiovisual media.
- To play sound files, you can use AVAudioPlayer.
- To record audio, you can use AVAudioRecorder.
AVAudioRecorder
The AVAudioRecorder class is intended to allow you to make audio recordings straight to a file with very little programming overhead. Using audio recorder, you can:
- Record until the user stops the recording;
- Record for a specified duration;
- Pause and resume a recording;
- Obtain input audio-level data that you can use to provide level metering.
In macOS, the audio comes from the system’s default audio input device as set by a user in System Preferences. To configure a recording, including options such as bit depth, bit rate, and sample rate conversion quality, configure the audio recorder’s settings dictionary.
Example Code
Warning: This code compiles and creates the appropriate audio file, but until I get a microphone for my Mac mini the code should be considered "untested" :-)
//
// Note: Free Pascal v3.3.1 (trunk), revision r42644, was used 6-Jan-2019
//
unit unit1;
{$mode objfpc}{$H+}
{$modeswitch objectivec1}
{$linkframework AVFoundation}
interface
uses
...
MacOSAll,
CocoaAll,
LCLType,
...
type
{ TForm1 }
AVAudioRecorder = objcclass external(NSObject)
public
{Initializes and returns an audio recorder.
url: File system location to record to. File type to record to is inferred
from the file extension included in this parameter’s value.
settings: Settings for the recording session.
outError: Returns, by-reference, a description of the error, if an error
occurs. Pass nil to ignore the error.}
function initWithURL_settings_error (url: NSURL; settings: NSDictionary; outError: NSErrorPtr):id;
message 'initWithURL:settings:error:';
{Calling this method implicitly calls prepareToRecord(), which creates (or
erases) an audio file and prepares the system for recording.}
function avRecord: Boolean; message 'record';
{Creates an audio file at the location specified by the url parameter in the
init() method. If a file already exists at that location, this method
overwrites it. The preparation invoked by this method takes place
automatically when you call record(). Use prepareToRecord when you want
recording to start as quickly as possible upon calling record().}
function prepareToRecord: Boolean; message 'prepareToRecord';
{Pauses a recording. Call record() to resume recording.}
procedure pause; message 'pause';
{Stops recording and closes the audio file.}
procedure stop; message 'stop';
{Deletes a recorded audio file. The audio recorder must be stopped before
you call this method.}
function deleteRecording: Boolean; message 'deleteRecording';
{A Boolean value that indicates whether the audio recorder is recording.}
function isRecording: Boolean; message 'isRecording';
{Audio recorder settings are in effect only after you explicitly call the
prepareToRecord() method, or after you call it implicitly by starting
recording.}
function settings: NSDictionary; message 'settings';
{The time, in seconds, since the beginning of the recording.}
function currentTime: NSTimeInterval; message 'currentTime';
{By default, audio level metering is off for an audio recorder. Because
metering uses computing resources, turn it on only if you intend to use it.}
procedure setMeteringEnabled(newValue: ObjCBOOL); message 'setMeteringEnabled:';
{A Boolean value that indicates whether audio-level metering is enabled.}
function isMeteringEnabled: ObjCBOOL; message 'isMeteringEnabled';
{To obtain current audio power values, you must call this method before you
call averagePower(forChannel:) or peakPower(forChannel:).}
procedure updateMeters; message 'updateMeters';
{The current peak power, in decibels, for the sound being recorded. A return
value of 0 dB indicates full scale, or maximum power; a return value of
-160 dB indicates minimum power (that is, near silence). If the signal
provided to the audio recorder exceeds ±full scale, then the return value
may exceed 0 (ie enter the positive range).}
function peakPowerForChannel (channelNumber: NSUInteger): single; message 'peakPowerForChannel:';
{The current average power, in decibels, for the sound being recorded. A
return value of 0 dB indicates full scale, or maximum power; a return value
of -160 dB indicates minimum power (that is, near silence). If the signal
provided to the audio recorder exceeds ±full scale, then the return value
may exceed 0 (ie, it may enter the positive range).}
function averagePowerForChannel (channelNumber: NSUInteger): single; message 'averagePowerForChannel:';
end;
TForm1 = class(TForm)
...
private
public
end;
var
Form1: TForm1;
MyAudioRecorder : AVAudioRecorder = Nil;
implementation
{$R *.lfm}
...
// Convert NSStrings function
function NSStringToString(ns: NSString): String;
var
pathStr: shortstring;
begin
CFStringGetPascalString(CFStringRef(ns),@pathStr,255,CFStringGetSystemEncoding());
Result := pathStr;
end;
// Record audio to file
procedure RecordAudio(audioFileName : NSString);
var
path : NSString;
url : NSURL;
settings: NSDictionary;
err : NSError;
begin
path := NSTemporaryDirectory.stringByAppendingPathComponent(audioFileName);
url := NSURL.fileURLWithPath(path);
settings := Nil;
MyAudioRecorder := AVAudioRecorder.alloc.initWithURL_settings_error(url, settings, @err);
if Assigned(MyAudioRecorder) then
MyAudioRecorder.avrecord
else
NSLog(NSStr('Error in procedure RecordAudio(): %@'), err);
end;
...
// Record audio - format mp4a inferred from filename
procedure TForm1.MenuItem27Click(Sender: TObject);
begin
RecordAudio(NSStr('testaudio.mp4a'));
end;
// Pause audio recording
procedure TForm1.MenuItem28Click(Sender: TObject);
begin
MyAudioRecorder.Pause;
end;
// Resume audio recording
procedure TForm1.MenuItem29Click(Sender: TObject);
begin
MyAudioRecorder.avRecord;
end;
// Stop audio recording and close file
procedure TForm1.MenuItem30Click(Sender: TObject);
begin
MyAudioRecorder.Stop;
end;
...
finalization
If (Assigned (MyAudioRecorder)) then
begin
MyAudioRecorder.Release;
MyAudioRecorder := Nil;
end;
end.