Skip to content

Commit

Permalink
SGAudioPlayer: Support for changing pitch.
Browse files Browse the repository at this point in the history
  • Loading branch information
libobjc committed Dec 26, 2019
1 parent 97b181e commit 59bcf46
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 15 deletions.
5 changes: 5 additions & 0 deletions SGPlayer/Classes/Core/SGAudio/SGAudioPlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
*/
@property (nonatomic) float rate;

/**
* Pitch.
*/
@property (nonatomic) float pitch;

/**
* Volume.
*/
Expand Down
60 changes: 46 additions & 14 deletions SGPlayer/Classes/Core/SGAudio/SGAudioPlayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ @interface SGAudioPlayer ()
AudioUnit _timePitchUnit;
}

@property (nonatomic, readonly) BOOL needsTimePitchNode;

@end

@implementation SGAudioPlayer
Expand Down Expand Up @@ -121,9 +123,18 @@ - (void)setup
AUGraphSetNodeInputCallback(_graph, _mixerNode, 0, &inputCallbackStruct);
AudioUnitAddRenderNotify(_outputUnit, outputCallback, (__bridge void *)self);

[self setRate:1];
[self setVolume:1];
AudioUnitParameterID mixerParam;
#if SGPLATFORM_TARGET_OS_MAC
mixerParam = kStereoMixerParam_Volume;
#elif SGPLATFORM_TARGET_OS_IPHONE_OR_TV
mixerParam = kMultiChannelMixerParam_Volume;
#endif
AudioUnitGetParameter(_mixerUnit, mixerParam, kAudioUnitScope_Input, 0, &_volume);
AudioUnitGetParameter(_timePitchUnit, kNewTimePitchParam_Rate, kAudioUnitScope_Global, 0, &_rate);
AudioUnitGetParameter(_timePitchUnit, kNewTimePitchParam_Pitch, kAudioUnitScope_Global, 0, &_pitch);

[self setAsbd:asbd];
[self reconnectTimePitchNodeForce:YES];

AUGraphInitialize(_graph);
}
Expand Down Expand Up @@ -154,6 +165,24 @@ - (void)disconnectNodeInput:(AUNode)sourceNode destNode:(AUNode)destNode
}
}

- (void)reconnectTimePitchNodeForce:(BOOL)force
{
BOOL needsTimePitchNode = (_rate != 1.0) || (_pitch != 0.0);
if (_needsTimePitchNode != needsTimePitchNode || force) {
_needsTimePitchNode = needsTimePitchNode;
if (needsTimePitchNode) {
[self disconnectNodeInput:_mixerNode destNode:_outputNode];
AUGraphConnectNodeInput(_graph, _mixerNode, 0, _timePitchNode, 0);
AUGraphConnectNodeInput(_graph, _timePitchNode, 0, _outputNode, 0);
} else {
[self disconnectNodeInput:_mixerNode destNode:_timePitchNode];
[self disconnectNodeInput:_timePitchNode destNode:_outputNode];
AUGraphConnectNodeInput(_graph, _mixerNode, 0, _outputNode, 0);
}
AUGraphUpdate(_graph, NULL);
}
}

#pragma mark - Interface

- (void)play
Expand Down Expand Up @@ -188,6 +217,9 @@ - (BOOL)isPlaying

- (void)setVolume:(float)volume
{
if (_volume == volume) {
return;
}
AudioUnitParameterID param;
#if SGPLATFORM_TARGET_OS_MAC
param = kStereoMixerParam_Volume;
Expand All @@ -205,19 +237,19 @@ - (void)setRate:(float)rate
return;
}
if (AudioUnitSetParameter(_timePitchUnit, kNewTimePitchParam_Rate, kAudioUnitScope_Global, 0, rate, 0) == noErr) {
if (_rate == 1.0 || rate == 1.0) {
if (rate == 1.0) {
[self disconnectNodeInput:_mixerNode destNode:_timePitchNode];
[self disconnectNodeInput:_timePitchNode destNode:_outputNode];
AUGraphConnectNodeInput(_graph, _mixerNode, 0, _outputNode, 0);
} else {
[self disconnectNodeInput:_mixerNode destNode:_outputNode];
AUGraphConnectNodeInput(_graph, _mixerNode, 0, _timePitchNode, 0);
AUGraphConnectNodeInput(_graph, _timePitchNode, 0, _outputNode, 0);
}
AUGraphUpdate(_graph, NULL);
}
_rate = rate;
[self reconnectTimePitchNodeForce:NO];
}
}

- (void)setPitch:(float)pitch
{
if (_pitch == pitch) {
return;
}
if (AudioUnitSetParameter(_timePitchUnit, kNewTimePitchParam_Pitch, kAudioUnitScope_Global, 0, pitch, 0) == noErr) {
_pitch = pitch;
[self reconnectTimePitchNodeForce:NO];
}
}

Expand Down
9 changes: 8 additions & 1 deletion SGPlayer/Classes/Core/SGRenderer/SGAudioRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@
*/
+ (SGAudioDescriptor *)supportedAudioDescriptor;

/*!
@property pitch
@abstract
Indicates the current pitch.
*/
@property (nonatomic) Float64 pitch;

/*!
@property volume
@abstract
Indicates the current audio volume.
Indicates the current volume.
*/
@property (nonatomic) Float64 volume;

Expand Down
25 changes: 25 additions & 0 deletions SGPlayer/Classes/Core/SGRenderer/SGAudioRenderer.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ @interface SGAudioRenderer () <SGAudioPlayerDelegate>
@implementation SGAudioRenderer

@synthesize rate = _rate;
@synthesize pitch = _pitch;
@synthesize volume = _volume;
@synthesize delegate = _delegate;
@synthesize descriptor = _descriptor;
Expand All @@ -57,6 +58,7 @@ - (instancetype)initWithClock:(SGClock *)clock
if (self = [super init]) {
self->_clock = clock;
self->_rate = 1.0;
self->_pitch = 0.0;
self->_volume = 1.0;
self->_lock = [[NSLock alloc] init];
self->_capacity = SGCapacityCreate();
Expand Down Expand Up @@ -123,6 +125,28 @@ - (Float64)rate
return ret;
}

- (void)setPitch:(Float64)pitch
{
SGLockCondEXE11(self->_lock, ^BOOL {
return self->_pitch != pitch;
}, ^SGBlock {
self->_pitch = pitch;
return nil;
}, ^BOOL(SGBlock block) {
self->_player.pitch = pitch;
return YES;
});
}

- (Float64)pitch
{
__block Float64 ret = 0.0f;
SGLockEXE00(self->_lock, ^{
ret = self->_pitch;
});
return ret;
}

- (void)setVolume:(Float64)volume
{
SGLockCondEXE11(self->_lock, ^BOOL {
Expand Down Expand Up @@ -164,6 +188,7 @@ - (BOOL)open
self->_player = [[SGAudioPlayer alloc] init];
self->_player.delegate = self;
self->_player.rate = self->_rate;
self->_player.pitch = self->_pitch;
self->_player.volume = self->_volume;
return [self setState:SGRenderableStatePaused];
}, nil);
Expand Down

0 comments on commit 59bcf46

Please sign in to comment.