i'm using this code to detect blow.
but i cant get the blow. i got voice.
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.3 target: self selector: #selector(levelTimerCallback:) userInfo: nil repeats: YES];
} else
NSLog(#"error %#",[error description]);
But got voice not blow.
You kind of have to play with the low pass results. Try this:
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
//NSLog(#"%f", lowPassResults);
if (lowPassResults > 0.55)
NSLog(#"Mic blow detected");
}
Related
I can record with the setup below - it works first time, but then when I try again the file is always 8192 bytes, i.e. not a correct recording.
-(void) startRecording
{
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 11025.0f], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithInt: 2], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityLow], AVEncoderAudioQualityKey,
nil];
NSString *filenameBasedOnTime = [[NSDate date] description];
if (_recordedFileURL) _recordedFileURL = nil;
_recordedFileURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingString:filenameBasedOnTime]];
NSError* error;
if (_audioRecorder) _audioRecorder = nil;
_audioRecorder = [[AVAudioRecorder alloc] initWithURL:_recordedFileURL settings:settings error:&error];
_audioRecorder.delegate = self;
if (error)
{
return;
}
[_audioRecorder prepareToRecord];
_audioRecorder.meteringEnabled = YES;
[_audioRecorder record];
}
-(void) stopRecord
{
[_audioRecorder stop];
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag
{
[self saveRecording];
}
-(void) saveRecording
{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:_recordedFileURL.relativeString]];
NSLog(#"Recording data size = %i", [data length]);
}
It is called inside a UIPopoverController if that helps...
Since found out that the problem was I was missing
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:NULL];
From here iPhone SDK: AVAudioRecorder will not record after calling [AVPlayer play]
I am working on an app which is related to the recipes.In this app there is a section where user can blow air through the mic and can change the image as well the content on it by using animation transition CurlDown.I am able to detect the blow by using the following code,
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target: self selector: #selector(levelTimerCallback:) userInfo:nil repeats:YES];
}
else{
// NSLog([error description]);
}
image =[[UIImageView alloc] init];
image.image =[UIImage imageNamed:#"Recipie.png"];
image.frame =CGRectMake(50, 100, 150, 200);
[self.view addSubview:image];
}
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
// NSLog(#"Average input: %f Peak input: %f Low pass results: %f", [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults);
if (lowPassResults >0.055 )
{
NSLog(#"Mic blow detected");
[self changeFrame];
}
}
-(void)changeFrame
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:image cache:NO];
[UIView commitAnimations];
}
But my problem is,when i blow first time through the mic then image animated 5 to 7 times and when i blow second time then images animates 9 to 10 times,i want this animation single times on every blow detection.
Please suggest me how can i do this using this code or it will be better for me if somebody can share the code for this section.
I suspect the problem comes from the fact that you are calling levelTimerCallback each second. So, when a blow come in, for the whole duration of the blow your callback will make the image change.
A workaround to this would be using a BOOL flag:
#property (nonatomic) BOOL blowDetected;
In levelTimerCallback, you keep track of when a blow is detected and when it ends and you do change images only for new blows:
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
if (lowPassResults > 0.055)
{
NSLog(#"Blow detected with power: %f", lowPassResults);
if (!self.blowDetected) {
self.blowDetected = YES;
NSLog(#"Mic blow detected");
[self changeFrame];
}
} else {
NSLog(#"Blow not detected with residual power: %f", lowPassResults);
self.blowDetected = NO;
}
}
This should prevent multiple image changes for the same blow...
Now, this will work fine when between a blow and the next one you wait enough time so that the power currently detected by the mic decreases below the 0.055 threshold. This means that any blow occurring before that will be ignored.
To improve this, instead of simply filtering the signal, we could simply try and detect when the filtered value increases; so I would suggest the following implementation:
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
double currentLowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
if (currentLowPassResults > 0.055)
{
NSLog(#"Blow detected with power: %f", lowPassResults);
if (!self.blowDetected || currentLowPassResult > K * lowPassResults) {
self.blowDetected = YES;
NSLog(#"Mic blow detected");
[self changeFrame];
}
} else {
NSLog(#"Blow not detected with residual power: %f", lowPassResults);
self.blowDetected = NO;
}
lowPassResult = currentLowPassResults;
}
You could find an optimal value for K by doing some tests.
In the latter implementation:
when a blow is first detected, we change the image and go into mode "wait for blow to extinguish" (self.blowDetected == YES);
in mode "wait for blow to extinguish", we do not change images, unless we detect a new blow, characterized by the fact that we have a recording power significantly larger than the current level.
Use return as you get first lowpass results >0.55
I have solve the issue have a look.
-(void)readyToBlow1 {
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: #selector(levelTimerCallback1:) userInfo: nil repeats: YES];
}
else
NSLog(#"%#",[error description]);
}
- (void)levelTimerCallback1:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
//NSLog(#"lowPassResults= %f",lowPassResults);
if (lowPassResults > 0.55)
{
lowPassResults = 0.0;
[self invalidateTimers];
NextPhase *objNextView =[[NextPhase alloc]init];
[UIView transitionFromView:self.view
toView:objNextView.view
duration:2.0
options:UIViewAnimationOptionTransitionCurlUp
completion:^(BOOL finished) {
}
];
[self.navigationController pushViewController:objNextView animated:NO];
**return;**
}
}
I am trying to run the following code on my device with no success. Although the code works perfectly on Simulator. I have been following this tutorial. It simply crash on device.
http://mobileorchard.com/tutorial-detecting-when-a-user-blows-into-the-mic/
Code is:
#interface MicBlowViewController : UIViewController {
AVAudioRecorder *recorder;
NSTimer *levelTimer;
double lowPassResults;
}
- (void)levelTimerCallback:(NSTimer *)timer;
#end
.m file :
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder)
{
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 3
target: self
selector: #selector(levelTimerCallback:)
userInfo: nil
repeats: YES];
}
else
NSLog(#"%#", [error description]);
}
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
if (lowPassResults < 0.95)
NSLog(#"Mic blow detected");
}
Add those two lines of code after [recorder prepareToRecord ]
[recorder prepareToRecord];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
This question already has an answer here:
How to measure noise or sound and displays in dB(A) in iphone?
(1 answer)
Closed 9 years ago.
I have an audio recorder and I was wondering if anyone has a code to show a audio meter (the bar that most of audio recorders have which shows the level of input audio).
Apple's SpeakHere example code includes a LevelView class which seems to be exactly what you are looking for.
Heres an example that calculates output and prints it:
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"]; // Your audio save path
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: #selector(levelTimerCallback:) userInfo: nil repeats: YES];
}
}
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
NSLog(#"%f",(lowPassResults*100.0f));
}
Depending on the lowPassResults you can animate a view accordingly.
I am trying to detect when the user is blowing into the mic of an iPhone. Right now I am using the SCListener class from Stephen Celis to call
if ([[SCListener sharedListener] peakPower] > 0.99)
in an NSTimer. However, this returns true sometimes when I'm not blowing. Anyone have any sample code to check if the user is blowing into the mic?
I would recommend low-pass filtering the power signal first. There is always going to be some amount of transient noise that will mess with instantaneous readings; low-pass filtering helps mitigate that. A nice and easy low-pass filter would be something like this:
// Make this a global variable, or a member of your class:
double micPower = 0.0;
// Tweak this value to your liking (must be between 0 and 1)
const double ALPHA = 0.05;
// Do this every 'tick' of your application (e.g. every 1/30 of a second)
double instantaneousPower = [[SCListener sharedListener] peakPower];
// This is the key line in computing the low-pass filtered value
micPower = ALPHA * instantaneousPower + (1.0 - ALPHA) * micPower;
if(micPower > THRESHOLD) // 0.99, in your example
// User is blowing on the microphone
when run on iPhone, you should add the following code after [recorder prepareToRecorder]
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
Use return as lowPassResults is bigger than 0.55. This is working fine:
-(void)readyToBlow1 { NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: #selector(levelTimerCallback1:) userInfo: nil repeats: YES];
} else
NSLog(#"%#",[error description]);
}
-(void)levelTimerCallback1:(NSTimer *)timer { [recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
double lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
if (lowPassResults > 0.55) {
lowPassResults = 0.0;
[self invalidateTimers];
NextPhase *objNextView =[[NextPhase alloc]init];
[UIView transitionFromView:self.view
toView:objNextView.view
duration:2.0
options:UIViewAnimationOptionTransitionCurlUp
completion:^(BOOL finished) {}
];
[self.navigationController pushViewController:objNextView animated:NO];
**return;**
}
}
http://mobileorchard.com/tutorial-detecting-when-a-user-blows-into-the-mic/
this tutorial works fine with simulator but its not working in iphone there is no response from iphone mic
Try this It is working fine for me. Thanks #jinhua liao
- (void)viewDidLoad {
[super viewDidLoad];
lowPassResults = 0.0;
[self readyToBlow1];
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: #selector(levelTimerCallback:) userInfo: nil repeats: YES];
} else
NSLog([error description]);
}
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0]));
lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults;
NSLog(#"lowpassResult is %f",lowPassResults);
if (lowPassResults > 0.95){
NSLog(#"Mic blow detected");
[levelTimer invalidate];
}
}