Change OpenEars pitch dynamically (on the fly) - ios

I have an iOS app that reads text using the OpenEars API. I am using the latest version (1.2.5). I can not figure out how to change the pitch while the words are being read ("on the fly"). I created a slider to control the pitch. A delegate is fired as the slider is changed. In the delegate function, the FliteController target_mean is changed. The intent was to have the pitch change as soon as the target_mean value was changed. My code is as follows:
-(void)sayTheMessage:(NSString *)message {
// if there is nothing there, don't try to say anything
if (message == nil)
return;
[self.oeeo setDelegate:self];
// we are going to say what is in the label...
#try {
// set the pitch, etc...
self.flite.target_mean = pitchValue; // Change the pitch
self.flite.target_stddev = varienceValue; // Change the variance
self.flite.duration_stretch = speedValue; // Change the speed
// finally say it!
[self.flite say:message withVoice:self.slt];
}
#catch (NSException *exception) {
if ([delegate respondsToSelector:#selector(messageError)])
[delegate messageError];
}
#finally {
}
}
-(void)changePitch:(float)pitch {
if ((pitch >= 0) && (pitch <= 2)) {
// save the new pitch internally
pitchValue = pitch;
// change the pitch of the current speaking....
self.flite.target_mean = pitchValue;
}
}
Any ideas?

OpenEars developer here. You can't change the pitch on the fly with FliteController since the pitch is set before speech is processed.

Related

Saving ARSCNView snapshot in didUpdateFrame method causes camera to freeze

I am creating video in ARKit during session. When I press record button, camera freezes. I have written code in didUpdateFrame delegate that causes the problem. There I save scene.snapshot in an array. Also when i create video from these images, app crashes with following message in debugger:
Message from debugger: Terminated due to memory issue
-(void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame
{
if (_recordButton.state == UIControlStateSelected)
{
currentState = Recording;
[self saveImage];
}
else if (previousState == Recording)
{
NSLog(#"Stop recording");
currentState = NotRecording;
recordTime = NULL;
self.nextButton.enabled=YES;
}
//update recording state per frame update
previousState = currentState;
}
-(void)saveImage
{
UIImage *image = self.sceneView.snapshot;
[self.bufferArray addObject:image];
image = nil;
}
Do not use ARSCNView.snapshot with implementing ARSessionDelegate.didUpdateFrame. I had same issue and solution was do not implement ARSessionDelegate.didUpdateFrame. I have used CADisplayLink with ARSCNView.snapshot and it works well.
I also tried to use ARFrame.capturedImage, but it has not contain AR objects at all. ARSCNView.snapshot contains them.

BOOL gives different result in if statement at update:(CFTimeInterval)currentTime method

I have two scenes - DifficultScene and GameScene. In DifficultScene I have three buttons - easy, medium and hard. I use a global variable Bool to keep track of the current difficulty level. When I try easy mode everything works fine, but when I try medium or hard, bool is changing every second, jumping from hard to medium and easy, making game unplayable. My question is - how can I fix it? Here are code were it happens:
GamesScene.m
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
extern BOOL isEasyMode;
extern BOOL isMediumMode;
extern BOOL isHardMode;
if ((isEasyMode = YES)) {
NSLog(#"easy");
[self computer];
}
if ((isMediumMode = YES)) {
NSLog(#"medium");
[self computerMedium];
}
if ((isHardMode = YES)) {
NSLog(#"hard");
[self computerHard];
}
[self scoreCount];
}
(if more code is needed, i will post it)
I think your update method calls periodically as per timer so it will get called continuously if it so then. Thats why it is happening i think and another major thing is you should use == for comparison. you are using (isEasyMode = YES) that means you are assigning YES to isEasyMode.
So replce all if statement like if ((isEasyMode = YES)) with if (isEasyMode == YES).
Update :
if statement should like,
if (isEasyMode == YES) {
NSLog(#"easy");
[self computer];
}
Hope this will help :)

Detect level of input audio?

I have an application which requires to use the microphone for recording user voice. I'm trying to make a speech to text.
I'm work with SpeechKit.framework and below is my code used:
-(void)starRecording{
self.voiceSearch = [[SKRecognizer alloc] initWithType:SKSearchRecognizerType
detection:SKShortEndOfSpeechDetection
language:[[USER_DEFAULT valueForKey:LANGUAGE_SPEECH_DIC] valueForKey:#"record"]
delegate:self];
}
- (void)recognizer:(SKRecognizer *)recognizer didFinishWithResults:(SKRecognition *)results {
long numOfResults = [results.results count];
if (numOfResults > 0) {
// update the text of text field with best result from SpeechKit
self.recordString = [results firstResult];
[self sendChatWithMediaType:#"messageCall" MediaUrl:#"" ContactDetail:#"{}" LocationDetail:#"{}"];
[self.voiceSearch stopRecording];
}
if (self.voiceSearch) {
[self.voiceSearch cancel];
}
[self starRecording];
}
That makes the SKRecognizer to be always open and that thing reduce the application performance.
I want to start the SKRecognizer when the microphone is detecting input audio.
I have a method for that? A method which is called when the microphone have input sound for me or a method which is always returning the level of audio detected?
Thank you!
You need to use the SpeechKit class to set up the audio.
Look here for details;
http://www.raywenderlich.com/60870/building-ios-app-like-siri
This project shows how to detect audio threshold;
github.com/picciano/iOS-Audio-Recoginzer

CMMotionManager: Device Calibration does not work on a real device

I've a strange behavior with CMMotionManager. I try to calibrate the position of my device to enable my App to support multiple device orientations.
When I debug my App on a real device (not in Simulator), everything is working fine.
When I run the same App without debugging, the calibration does not work.
Here's my code:
static CMMotionManager* _motionManager;
static CMAttitude* _referenceAttitude;
// Returns a vector with the current orientation values
// At the first call a reference orientation is saved to ensure the motion detection works for multiple device positions
+(GLKVector3)getMotionVectorWithLowPass{
// Motion
CMAttitude *attitude = self.getMotionManager.deviceMotion.attitude;
if (_referenceAttitude==nil) {
// Cache Start Orientation
_referenceAttitude = [_motionManager.deviceMotion.attitude copy];
} else {
// Use start orientation to calibrate
[attitude multiplyByInverseOfAttitude:_referenceAttitude];
NSLog(#"roll: %f", attitude.roll);
}
return [self lowPassWithVector: GLKVector3Make(attitude.pitch,attitude.roll,attitude.yaw)];
}
+(CMMotionManager*)getMotionManager {
if (_motionManager==nil) {
_motionManager=[[CMMotionManager alloc]init];
_motionManager.deviceMotionUpdateInterval=0.25;
[_motionManager startDeviceMotionUpdates];
}
return _motionManager;
}
I've found a solution. The issue was caused due the different timing behavior between debug and non debug mode. CMMotionManager needs a little time for initializing, before it returns correct values. The solution was to postpone the calibration for 0.25 seconds.
This code works:
+(GLKVector3)getMotionVectorWithLowPass{
// Motion
CMAttitude *attitude = self.getMotionManager.deviceMotion.attitude;
if (_referenceAttitude==nil) {
// Cache Start Orientation
// NEW:
[self performSelector:#selector(calibrate) withObject:nil afterDelay:0.25];
} else {
// Use start orientation to calibrate
[attitude multiplyByInverseOfAttitude:_referenceAttitude];
NSLog(#"roll: %f", attitude.roll);
}
return [self lowPassWithVector: GLKVector3Make(attitude.pitch,attitude.roll,attitude.yaw)];
}
// NEW:
+(void)calibrate
_referenceAttitude = [self.getMotionManager.deviceMotion.attitude copy]
}

Returning an enum ivar causes EXC_BAD_ACCESS

I'm writing a game where a MainGameplay class keeps track of whose turn it is by setting an ivar to an enum value:
typedef enum {
GAME_NOT_STARTED,
PLAYER_1_TO_MOVE,
PLAYER_2_TO_MOVE
} WhoseTurnIsIt;
Then the GameBoard class checks whether a move attempt is valid, and calls either turnEnded:(WhoseTurnIsIt)turn or reportTurnFailure:(WhoseTurnIsIt)turn in MainGameplay.m.
I get EXC_BAD_ACCESS as soon as I try to access this returned value back in MainGameplay, in the receiving methods. Seems like I should retain something, but you can't retain an enum. In the debugger the values are there, so I don't understand what's being accessed improperly.
This is the code doing the calling in GameBoard:
-(void)buttonPressed:(id)sender {
CCArray *kids = [[[CCDirector sharedDirector] runningScene] children];
if (!mainScene) { // mainScene is an ivar on each the GameBoard's buttons.
for (CCScene *s in kids) {
// this looks crazy because the "main" scene is actually a controlling layer that has as a child the main gameplay layer:
if ([s isKindOfClass:[ControlLayer class]]) {
self->mainScene = (MainGameplay *)((ControlLayer *) s).gameLayer;
}
}
}
if (MOVE_NO_ERROR == [self checkMove:mainScene.turn]) {
[self setMove:mainScene.turn];
[mainScene turnEnded:mainScene.turn]; // This line and the next are the ones causing the EXC_BAD_ACCESS
} else [mainScene reportTurnFailure:mainScene.turn]; // This line too.
}
EDIT Functions in mainScene being called go like this:
-(void) reportTurnFailure:(WhoseTurnIsIt)_turn {
NSLog(#"MainScene still valid"); // This line works fine
NSLog(#"Bzzzzzt. Player %#, try again", _turn); // This line crashes BUT _turn shows up with a proper value in the debugger.
}
_turn is not an object, but the %# format specifier says that the argument is an object. Use %i instead.
-(void) reportTurnFailure:(WhoseTurnIsIt)_turn {
NSLog(#"MainScene still valid"); // This line works fine
NSLog(#"Bzzzzzt. Player %i, try again", _turn); // This line crashes BUT _turn shows up with a proper value in the debugger.
}

Resources