I am listing from the mic using AVAudioEngine by this code:
NSError *err2 = nil;
engine = [[AVAudioEngine alloc] init];
mainMixer = [engine mainMixerNode];
[mainMixer installTapOnBus:0 bufferSize:1024 format:[mainMixer outputFormatForBus:0] block:^(AVAudioPCMBuffer * _Nonnull buffer, AVAudioTime * _Nonnull when) {
[self normalize:buffer];
}];
[engine startAndReturnError:&err2];
Then as u see passing the buffer I get into a function called normalize:
-(void) normalize:(AVAudioPCMBuffer*) buffer{
float sum = 0;
NSMutableArray *values = [NSMutableArray new];
for (AVAudioFrameCount i = 0; i < buffer.frameLength; i++) {
[values addObject:#(buffer.floatChannelData[0][i])];
}
for (int i = 0 ; i< [values count]; i++){
if ([values[i] floatValue] != 0){
NSLog(#"%f", [values[i] floatValue]) ;
}
}
}
for now, I only want to print the values of floatChannelData.
The problem is that it is always printing 0. so the buffer has all values 0.
Why is this happening? shouldn't the values be changing with the change of voices received by the mic?
This solved it for me:
Go to your "Info.plist" file.
Right-click and click "Add Row".
Then, in the first column of the newly created row, find the key "Privacy - Microphone Usage Description" and add a suitable explanation of what you intend to do with the audio as the key's value (third column).
Now a dialog box will appear when you run your app asking for permission to access the microphone. Basically, you can't retrieve audio unless you have explicit permission from the user, even if you can technically talk to the audio device and start the audio engine.
Related
-(void)artworkImages{
NSArray *noOfSongs = [mySongsArray content];
for (int i=0; i<[noOfSongs count]; i++) {
NSDictionary *dic = [[NSDictionary alloc] init];
dic = [[mySongsArray arrangedObjects] objectAtIndex:i];
NSURL *url = [NSURL fileURLWithPath:[dic objectForKey:#"Path"]];
AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
for (NSString *format in [asset availableMetadataFormats]) {
for (AVMetadataItem *item in [asset metadataForFormat:format]) {
if (i>240 && i<250) {
NSBeginAlertSheet(#"Check the loop", #"Delete", nil, #"Cancel", window, self, #selector(alertEnd:returnCode:cInfo:), NULL, nil, #"format===%#,%d",format);
}
}
}
}
}
Above methods is working fine if I run the project by Code (X code), but getting issue if I run by build. I am importing songs from iTunes library.xml, after that I am storing into NSArrayController. Here in this method I am trying to fetch artwork images but if I run by build I am getting around 250 images out of 400.
Without the code of alertEnd:returnCode:cInfo: it's hard to tell, but it generally appears like something in that function is killing the for loop.
What exactly are you trying to achieve with:
if (i>240 && i<250)
Can you post the code for the 'alertEnd:returnCode:cInfo'. Also it would probably be easier to read if you used a __block for alert sheets. If the alertEnd:returnCode:cInfo isn't referred to more than once, I'd keep it as a block. If you reuse the code within alertEnd:returnCode:cInfo then promote it to it's own void/function.
some possibilities:
you are importing/reading a different "iTunes library.xml" file that was created with a smaller set of itunes files. and maybe that filename is set in the xcode arguments???
[noOfSongs count] has an inconsistent value, because objects are removed from noOfSongs
try :
NSInteger *cntSongs = [[mySongsArray content] count];
for (int i=0; i< cntSongs; i++) {
rather than the current:
NSArray *noOfSongs = [mySongsArray content];
for (int i=0; i<[noOfSongs count]; i++) {
mySongsArray is shadowed by another property of the same name. see -Wshadow.
I'm new to cocoa and I have an IKImageBrowserView and that's how I load images to it:
- (IBAction)loadImages:(id)sender
{
NSMutableArray *urls = [[NSMutableArray alloc]init];
int i = 1;
for (i=1; i<55; i++) {
NSString *photoNumber = [NSString stringWithFormat:#"%i", i];
NSMutableString *urlString = [[NSMutableString alloc] initWithString:#"Australia"];
[urlString appendString:photoNumber];
NSURL* url = [[NSBundle mainBundle] URLForImageResource:urlString];
[urls addObject:url];
}
[self addImagesWithPaths:urls];
}
- (void)addAnImageWithPath:(NSString *)path
{
myImageObject *p;
/* add a path to our temporary array */
p = [[myImageObject alloc] init];
[p setPath:path];
[_importedImages addObject:p];
}
- (void)addImagesWithPath:(NSString *)path recursive:(BOOL)recursive
{
NSInteger i, n;
BOOL dir;
[[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&dir];
if (dir)
{
NSArray *content = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil];
n = [content count];
// parse the directory content
for (i=0; i<n; i++)
{
if (recursive)
[self addImagesWithPath:[path stringByAppendingPathComponent:[content objectAtIndex:i]] recursive:YES];
else
[self addAnImageWithPath:[path stringByAppendingPathComponent:[content objectAtIndex:i]]];
}
}
else
{
[self addAnImageWithPath:path];
}
}
/* performed in an independant thread, parse all paths in "paths" and add these paths in our temporary array */
- (void)addImagesWithPaths:(NSArray *)urls
{
NSInteger i, n;
n = [urls count];
for ( i= 0; i < n; i++)
{
NSURL *url = [urls objectAtIndex:i];
[self addImagesWithPath:[url path] recursive:NO];
}
/* update the datasource in the main thread */
[self performSelectorOnMainThread:#selector(updateDatasource) withObject:nil waitUntilDone:YES];
}
Now my images are loaded by name - #"Australia". That's kind of inconvenient as your images need to have same name and a number. How do I load images with different names from the folder, which has been imported to xcode?
So at the moment I'm loading images by name Australia1, Australia2, Australia3, Australia4... and so on.
How do I load images from a bundle folder?
Your data source needs to return items to the image browser view that conform to the IKImageBrowserItem protocol. Your myImageObject class is a good place to start with that.
In that protocol, three methods are required:
imageUID: Returns a string that uniquely identifies this item (image).
imageRepresentationType: Returns a constant string that identifies how imageRepresentation represents the image.
imageRepresentation: Returns an object that represents the image.
For a start, I'd just use the path that you're already giving every myImageObject. You can use that as both the identifier string and the image representation.
Depending on what else you're doing in this app, you may find it advantageous later on, for memory and/or speed reasons, to load each image yourself. If, after profiling, you do come to that conclusion, you can load the image yourself as an NSImage or CGImage, change your representation type appropriately, and return the image as the representation.
As the data source, you'll return the number of items in your _importedImages array, and, when asked for the item at an index, return that item via objectAtIndex:.
More info:
The IKImageBrowserDataSource protocol reference
The IKImageBrowserItem protocol reference
I'm new to iOS programming and I am working on a easy project that lists holidays from a given city and gives users the ability to add those events to the iCal default calendar.
The issue is: how to check if there is already an event with same properties (title and start date for example) in the user's calendar. This could happen if the action button (used to add an event to iCal) is pressed more than once. In such a situation, I don't want two or more identical events being created in iCal.
I have tried to use NSPredicate but I am totally lost on how to get it sorted.
Any help would come be appreciated!
Thanks in advance.
Bellow is my event-adding code just to make things clear. In this case a user is adding multiple events from a list (all local holidays for example).
for (int i = 0; i<[allHolidayNames count]; ++i) {
// ------ EVENT MANIPULATION ------
EKEventStore *eventStore = [[EKEventStore alloc] init];
EKEvent *addEvent = [EKEvent eventWithEventStore:eventStore];
addEvent.title = [allHolidayNames objectAtIndex:i];
addEvent.startDate = [allHolidayDates objectAtIndex:i];
addEvent.allDay = YES;
[addEvent setCalendar:[eventStore defaultCalendarForNewEvents]];
[eventStore saveEvent:addEvent span:EKSpanThisEvent commit:YES error:nil];
}
Summary
At some point in your instance method (probably during the for loop) you will want to create an NSPredicate based on [allHolidayDates objectAtIndex:i] to return an array that you loop through to check if [allHolidayNames objectAtIndex:i] is present in the returned events.
Example code
for (int i = 0; i<[allHolidayNames count]; ++i) {
// ------ EVENT MANIPULATION ------
EKEventStore *eventStore = [[EKEventStore alloc] init];
NSPredicate *predicateForEventsOnHolidayDate = [eventStore predicateForEventsWithStartDate:[allHolidayDates objectAtIndex:i] endDate:[allHolidayDates objectAtIndex:i] calendars:nil]; // nil will search through all calendars
NSArray *eventsOnHolidayDate = [eventStore eventsMatchingPredicate:predicateForEventsOnHolidayDate]
BOOL eventExists = NO;
for (EKEvent *eventToCheck in eventsOnHolidayDate) {
if ([eventToCheck.title isEqualToString:[allHolidayNames objectAtIndex:i]]) {
eventExists = YES;
}
}
if (eventExists == NO) {
EKEvent *addEvent = [EKEvent eventWithEventStore:eventStore];
addEvent.title = [allHolidayNames objectAtIndex:i];
addEvent.startDate = [allHolidayDates objectAtIndex:i];
addEvent.allDay = YES;
[addEvent setCalendar:[eventStore defaultCalendarForNewEvents]];
[eventStore saveEvent:addEvent span:EKSpanThisEvent commit:YES error:nil];
}
}
Tips
To help visualise the data, especially the contents of arrays and objects, try using NSLog. This will output the contents of an object to the console to help you understand the data structures a bit better.
NSLog("eventsOnHolidayDate = %#",eventsOnHolidayDate);
Note that eventsMatchingPredicate will block the main thread whilst retrieving events. If your doing this multiple times in a row it could impact on the user experience. You should consider using enumerateEventsMatchingPredicate:usingBlock: (outside the scope of this question).
My app registers the callback once:
notificationAddressBook = ABAddressBookCreate();
ABAddressBookRegisterExternalChangeCallback(notificationAddressBook, MyAddressBookExternalChangeCallback, self);
Then in my callback:
void MyAddressBookExternalChangeCallback (ABAddressBookRef notifyAddressBook,CFDictionaryRef info,void *context)
{
NSLog(#"in MyAddressBook External Change Callback");
ABAddressBookRevert(notifyAddressBook);
CFArrayRef peopleRefs = ABAddressBookCopyArrayOfAllPeopleInSource(notifyAddressBook, kABSourceTypeLocal);
CFIndex count = CFArrayGetCount(peopleRefs);
NSMutableArray* people = [NSMutableArray arrayWithCapacity:count];
for (CFIndex i=0; i < count; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(peopleRefs, i);
ABRecordID id_ = ABRecordGetRecordID(ref);
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[context executionContext] recordId:id_ module:context] autorelease];
NSLog(#"name: %#", [person valueForKey:#"firstName"]);
NSLog(#"phone: %#", [person valueForKey:#"phone"]);
NSLog(#"modified: %#", [person valueForKey:#"modified"]);
[people addObject:person];
}
CFRelease(peopleRefs);
}
When adding a new contact, the event is triggered fine, and the data is up-to-date in the first addition and the second and third. The problem is with editing an existing contact's details.
The first time the event is triggered the data is correct to the last update (I changed the phone number of one contact in the iPhone contacts), then I switch to the app and get the latest update. Then I switch back to the address book, make another change, switch to my app and get another event. This time the data is stale, the latest changes are not reflected.
I tried releasing the ABAddressBookRef instance and call ABAddressBookCreate() again but it did not help either.
Any ideas?
Try to re-create ABAddressBookRef.
void MyAddressBookExternalChangeCallback (ABAddressBookRef notifyAddressBook,CFDictionaryRef info,void *context)
{
NSLog(#"in MyAddressBook External Change Callback");
//ABAddressBookRevert(notifyAddressBook);
notifyAddressBook = ABAddressBookCreate();
CFArrayRef peopleRefs = ABAddressBookCopyArrayOfAllPeopleInSource(notifyAddressBook, kABSourceTypeLocal);
CFIndex count = CFArrayGetCount(peopleRefs);
NSMutableArray* people = [NSMutableArray arrayWithCapacity:count];
for (CFIndex i=0; i < count; i++) {
ABRecordRef ref = CFArrayGetValueAtIndex(peopleRefs, i);
ABRecordID id_ = ABRecordGetRecordID(ref);
TiContactsPerson* person = [[[TiContactsPerson alloc] _initWithPageContext:[context executionContext] recordId:id_ module:context] autorelease];
NSLog(#"name: %#", [person valueForKey:#"firstName"]);
NSLog(#"phone: %#", [person valueForKey:#"phone"]);
NSLog(#"modified: %#", [person valueForKey:#"modified"]);
[people addObject:person];
}
CFRelease(peopleRefs);
}
I am not a Cocoa developer, but I have been dabbling in it to build some plugins for PhoneGap. This particular plugin method is either 1) crashing the app without saying why or 2) complaining about how I release/don't release an object. I have tried a ton of things on my end, including using an Enumerator instead of the for loop. If anyone can point me in the right direction, that would be awesome. I don't mind legwork:
- (void)getPreferences:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
NSUInteger argc = [arguments count];
NSString* jsCallback = nil;
if (argc > 0) {
jsCallback = [arguments objectAtIndex:0];
} else {
NSLog(#"Preferences.getPreferences: Missing 1st parameter.");
return;
}
NSDictionary *defaults = [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
NSMutableArray *keys = (NSMutableArray *) [options objectForKey:#"keys"];
NSMutableDictionary *values = [[NSMutableDictionary alloc] init];
NSUInteger ky = [keys count];
for (int i = 0; i < ky; i ++) {
#try {
[values setObject:[defaults objectForKey:[keys objectAtIndex:i]] forKey:[keys objectAtIndex:i]];
}
#catch (NSException * err) {
NSLog(#"Error %#", err);
}
}
[keys release];
NSString* jsString = [[NSString alloc] initWithFormat:#"%#(%#);", jsCallback, [values JSONRepresentation]];
[defaults release];
[values release];
[webView stringByEvaluatingJavaScriptFromString:jsString];
[jsString release];
}
Human version:
options contains a dictionary with a single key of "keys"
that key contains an array of strings (that are going to be used as keys for lookup)
I want to loop through that array and
For every value that exists in defaults for that key, copy it to values using the same key
Finally, I want to send that values back as JSON (This part was working when I just passed the entire defaults object in, so I think the JSON method is working)
From your code, it follows that you 'own' objects values and jsString (the ones you created with alloc), so you should release them and not any other.
You can read more on memory management here.
Is this the whole code? Also, what exactly error do you get?
Nikita is right, it looks as though you're overreleasing defaults, which would cause a crash later when the autorelease pool gets released. Also, if I understand what you're trying to do correctly, you could create the values dictionary with a single line of code:
NSDictionary *values = [defaultsDict dictionaryWithValuesForKeys:keys];