Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

jerrywickey

macrumors member
Original poster
Apr 16, 2009
81
0
Key West
One more question, and I believe, I can finish my first IPhone app. This one is about functions in Objective C. What???? functions???? in OOPs?

I understand some native system functions slipping through from C++ for convenience, but anyway....

In System Sound Services Reference, AudioToolbox/AudioToolbox.h, declared in AudioServices.h, defines among other functions these four that follow.

Code:
/* Creates the system sound object pointed to by outSystemSoundID.
 */
OSStatus AudioServicesCreateSystemSoundID (
   CFURLRef       inFileURL,
   SystemSoundID  *outSystemSoundID
);


/* Plays the sound inSystemSoundID
 * of course we would want to cause (SystemSoundID) inSystemSoundID = outSystemSoundID
 */
void AudioServicesPlaySystemSound (
   SystemSoundID inSystemSoundID
);

/* Registers  (AudioServicesSystemSoundCompletionProc) inCompletionRoutine        
 * as a callback function that is invoked when the specified system sound 
 * finishes playing.
 */
OSStatus AudioServicesAddSystemSoundCompletion (
   SystemSoundID                           inSystemSoundID,
   CFRunLoopRef                            inRunLoop,
   CFStringRef                             inRunLoopMode,
   AudioServicesSystemSoundCompletionProc  inCompletionRoutine,
   void                                    *inClientData
);

/* If you named your function MyAudioServicesSystemSoundCompletionProc, you would declare it like this:
 * This "function" is invoked when the sound is finished playing.
 */
void MyAudioServicesSystemSoundCompletionProc (
   SystemSoundID  ssID,
   void           *clientData
);

My question is how do I generate the ( AudioServicesSystemSoundCompletionProc ) inCompletionRoutine? What type is it? Is it a pointer? Does it matter, if there is a method which returns it? If so, what is this method? or where would I look to find it? I couldn't find anything in the docs about it.

I am pretty darn sure this function doesn't return the function reference needed for the call back.

And where in my code, do I place such a function declaration when I figure out what it is?

I guess I just place my code responding to the call back inside the function and then throw away what ever my function returns when Audio Services calls it? Or perhaps the function could return nothing... (void)?

Thanks for any help.

Jerry
 
This is tough if you don't have a lot of C; buy once you get some example code, it's a snap. Here's an example of the callback function; mine just releases the sound object, but you could start another sound, or whatever.

Code:
//put me in your .m file, with your methods.
static void completionCallback (SystemSoundID  mySSID, void* myself) {
	//NSLog(@"completion Callbak");
	AudioServicesRemoveSystemSoundCompletion (mySSID);
	
	[(SoundEffect*)myself release];
}

To set up the callback, do this. Note that I pass a poniter to the current object into the callback function; you could pass whatever pointer your callback needs.
Code:
AudioServicesAddSystemSoundCompletion (_soundID, NULL, NULL, completionCallback, (void*) self);

AudioServicesPlaySystemSound(_soundID);
 
Thank you very much for your help.

This all makes sense, but the compiler complains about one thing and I really don't under stand why. Here's the problem: (full code follows below)

Code:
OSStatus AudioServicesCreateSystemSoundID( myfileURL, *newPlayer );

syntax error before "*" token

OR

Code:
OSStatus AudioServicesCreateSystemSoundID( myfileURL, newPlayer );
warning: parameter names (without types) in function declaration


The compile fails anyway as the compiler can't find the AudioServices newPlayer construct.

1) I don't understand why I would have to show that newPlayer is a pointer in the first place? I declared it as such in the .h file

Code:
SystemSoundID *newPlayer;

as a pointer to the data which will identify the sound player construct to the audio services functions. But the compiler won't let me use only "newPlayer". It complains unless I use "*newPlayer" Why must I use the * prefix? Do functions operate differently? Do they see * as part of the name?

2) More importantly, If I use *newPlayer the AudioServices add function doesn't see the myfileURL, parameter.

What am I doing wrong?

Your example code is great, but understanding what is happening is more important to me.

I am sure, your answer will help me better understand pointers as well as the use of functions in Obj C.

Thank you

Jerry

Code:
// file testViewController.h

#import <UIKit/UIKit.h>
#import "oporate.h"
#import <AudioToolbox/AudioToolbox.h>

@interface testViewController : UIViewController {
	
...more code...
	
	SystemSoundID *newPlayer;
}

...more code...

-(IBAction) soundbutton:(id) sender;

@end

Code:
// file testViewController.m

#import "testViewController.h"

static void completionCallback (SystemSoundID newPlayer, void* myself) {
	
	AudioServicesRemoveSystemSoundCompletion (newPlayer);
	
        // my code
	[oporate setrem];
}

@implementation testViewController

...more code...

-(IBAction) soundbutton:(id) sender{
	
	NSString *mysoundFilePath = [[NSBundle mainBundle] pathForResource: @"AA" ofType: @"aiff"];
	NSURL *myfileURL = [[NSURL alloc] initFileURLWithPath: mysoundFilePath];
	
	//OSStatus AudioServicesCreateSystemSoundID( myfileURL, newPlayer );
        //OR
	OSStatus AudioServicesCreateSystemSoundID( myfileURL, *newPlayer );
		
	[myfileURL release];
	
	AudioServicesPlaySystemSound(*newPlayer);
	
	AudioServicesAddSystemSoundCompletion(*newPlayer, NULL, NULL, completionCallback, (void*) self);
}
		
...more code...

@end
 
I think I got it.

myfileURL is a NSURL type while the AudioServices is looking for CFURL.

The parameter before the * token is a NSURL which is meaningless to AudioServices.

I am currently trying to find CFURL in the docs. Any help?

Am I on the right track?

Jerry

jnic,

that makes sence.

If something is a pointer to a data construct, then we would want to use the data to which it points.

I tried declaring *newPlayer as a pointer to a SystemSoundID in the .h and then using &newPlayer as the parameter in the audio function in .m but the compiler gives me the exact same error.

I am looking up all the syntax now.

It seems that all the docs want to explain pointers and indexes and the concepts, but no one actually just puts the damn syntax in a list and nails it down. I don't need the concepts, I understand them. I need the syntax.

Thanks. Any further help, perhaps with a primer on syntax would be great.

jerry
 
Thank you very much J,

Jerry

Code:
        NSString *mysoundFilePath = [[NSBundle mainBundle] pathForResource: @"AA" ofType: @"aiff"];
	NSURL *myfileURL = [[NSURL alloc] initFileURLWithPath: mysoundFilePath];
		
	 AudioServicesCreateSystemSoundID(  &myfileURL, &newPlayer   );
		
	[myfileURL release];
	
	AudioServicesPlaySystemSound(&newPlayer);
	
	AudioServicesAddSystemSoundCompletion(&newPlayer, NULL, NULL, completionCallback, (void*) self);

still makes the compiler bark incompatable pointer type on all three function statements, while

Code:
        NSString *mysoundFilePath = [[NSBundle mainBundle] pathForResource: @"AA" ofType: @"aiff"];
	NSURL *myfileURL = [[NSURL alloc] initFileURLWithPath: mysoundFilePath];
	
	AudioServicesCreateSystemSoundID(  myfileURL, &newPlayer   );
		
	[myfileURL release];
	
	AudioServicesPlaySystemSound(*newPlayer);
	
	AudioServicesAddSystemSoundCompletion(*newPlayer, NULL, NULL, completionCallback, (void*) self);

makes no such incompatible error for SoundCompletion or Play functions while the Create function still gives me incompatable pointer.

Is it the NSURL vs. CFURL after all?

Jerry

To clarify the pointer * and & information:

Code:
NSString *pointerToCharacterStringData;

pointerToCharacterStringData = @"test character string";

[someUnimportantClassInstance someUnimportantMethod: pointerToCharacterStringData];  

int unimportant = someFunctionWhichTakesAStringInputParameter ( &pointToCharcacterStringData );

Are these all correct?

Does Obj C pointer syntax just get thrown away when we use a function?

Or is C pointer syntax abrogated when using Obj C statements?
 
According to the docs, AudioServicesCreateSystemSoundID's method signature is:

Code:
OSStatus AudioServicesCreateSystemSoundID (
   CFURLRef       inFileURL,
   SystemSoundID  *outSystemSoundID
);

So:

Code:
AudioServicesCreateSystemSoundID(&myfileURL, &newPlayer);

ought to be:

Code:
AudioServicesCreateSystemSoundID(myfileURL, &newPlayer);

Likewise, AudioServicesPlaySystemSound is:

Code:
void AudioServicesPlaySystemSound (
   SystemSoundID inSystemSoundID
);

So:

Code:
AudioServicesPlaySystemSound(*newPlayer);

should be:

Code:
AudioServicesPlaySystemSound(newPlayer);

etc.
 
Pointers are done exactly the same way in C, Objective C, and assembly language. Consider them as address registers. Objective C allows you to name a pointer when used as a message parameter, but then stuffs them into ordinary C subroutine parameters under the hood. Most strings are passed around by either pointers, or handles (pointers to pointers), to either the first character (C strings), or to some opaque data structure containing more information about the string (NSStrings).

All of the C string pointer stuff can be found in a basic beginning C textbook. Try your local library.
 
First

is there an IPhone SDK class whose methods provide audio capabilities?


firewood,

That is exactly what I understand pointers to be as well. As such, I used the syntax jnic just suggested. It did not work.

I thought, perhaps, Obj C implements some sort of unusual syntax.
I played around with the syntax, but jnic just posted the exact thing I had already tried and now tried again and it did not work.

I get "passing incompatable pointer type" errors using exactly what I thought first and what jnic confirms.

I am thinking it is what I suggested in post. The pointer type would be wrong, if the data to which it pointed was not what the function expected. Is that not correct?

I think I got it.

myfileURL is a NSURL type while the AudioServices is looking for CFURL.

The parameter before the * token is a NSURL which is meaningless to AudioServices.

I am currently trying to find CFURL in the docs. Any help?

Am I on the right track?

Jerry

Sorry to be a bother, but where in the docs can I find CFURL? Or is there something about this I am missing?

I am still looking for CFURL. Again I find that CFURL.... are a bunch of functions. Can I just define a bunch of functions in Obj C and just use them any time I want peppered through out my code. If so, I will forget about objects and methods. Functions are much less finicky. Just kidding of course, but can anyone suggest a good manual on the use and syntax of functions in obj C.

BTW Apples The Objective-C 2.0 Programming Language reference doesn't even mention the word function.

Is there a better reference for Mac Obj C?

Or is there an IPhone SDK class whose methods provide audio capabilities?

Jerry
 
Sorry to be a bother, but where in the docs can I find CFURL? Or is there something about this I am missing?

I am still looking for CFURL.

Jerry
CFURL Reference

CFURL is “toll-free bridged” with its Cocoa Foundation counterpart, NSURL. This means that the Core Foundation type is interchangeable in function or method calls with the bridged Foundation object. In other words, in a method where you see an NSURL * parameter, you can pass in a CFURLRef, and in a function where you see a CFURLRef parameter, you can pass in an NSURL instance. This also applies to concrete subclasses of NSURL. See Integrating Carbon and Cocoa in Your Application for more information on toll-free bridging.
 
Yeah.

that is where I was reading.

But if your qoute
CFURL is “toll-free bridged” ... where you see a CFURLRef parameter, you can pass in an NSURL instance ....
is true, then myfileURL was never the issue. The &newPlayer was. Again but using the & syntax which explicitly brings up the data pointed to rather than the pointer itself and which is required by functions did not work either.

The easiest way to deal with this is to find audio capabilities that are available through methods rather than trying to figure out how to cram functions into Obj C.

Do you know of any Classes that evoke sound?

Jerry
 
This is the code I use for creating the sound:

Code:
NSURL *aFileURL = [NSURL fileURLWithPath:path isDirectory:NO];
SystemSoundID aSoundID;            

if (aFileURL != nil)  {
     OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)aFileURL, &aSoundID);
     }

You must declare a SystemSoundID (not just a pointer - you need an actual chunk of memory to be allocated) and then pass the address where that chunk is stored (&aSoundID). The function is going to copy the actual ID into that chunk of memory; that's why the function needs the address.

I can vouch that it actually works.
 
Do you know of any Classes that evoke sound?

There are at least 4 or 5 different sets of sound APIs, depending on the level at which you want to work.

If you were used to doing hard-real-time buffer management in your ASM days, then look at the Audio Queue code in SpeakHere or the Audio Unit Remote IO code in the AurioTouch examples. There are also some simpler system sound classes, and a game sound engine example in one of the other sample applications.
 
dejo's SysSound link got it done.

It was the NSURL vs CFURL problem like I figured.

Sure would be nice if there were a nice neat list of useful classes.

Also It sure would be nice if Obj C picked methods or functions and stuck with it. SysSound simply objectifies functions so that the rest of the software can [mySound play]; it.

Now let's see if I am smart enough to add the call back stuff to it.

Jerry
 
Also It sure would be nice if Obj C picked methods or functions and stuck with it.

Remember that Obj C is merely a macro wrapper (and an interpreter vectoring the subroutine calls at runtime). You can turn any C function into a method/message if you don't mind slowing it down. (What you get in exchange is names on the parameters, reverse type checking on the first parameter, and the ability to modify the function to be called at runtime, or to "fork" its code during development.)

I've written lots of wrappers to turn functions into methods/messages, as well as vice versa, to support calling into/out of legacy C code in conjunction with Apple's iPhone sample UIKit code.
 
firewood,

Thanks, I noticed the sound APIs you mentioned.

I picked the one that seems to pose the least syntax frills and which provides a call back when the sound is finished playing.

I still write assembly code, I just don't do it commercially now. The concepts are identical. The syntax is so different. I am sure you are aware that it is a misconception that object oriented programming introduced redirection.

I even wrote self altering code. That represents redirection on a scale only ever so slightly touched in objective languages with dynamic allocation of object instances.

Its the syntax that's killin' me.

Code:
int i ;    // i is a label for memory locations which can contain an integer value
int j ;
j = 2;    // the memory locations which j labels now contains 2
int *k;   // k is a lable for memory locations which can contain the location of other memory which can contain an integer value
k = &j;   // the memory locations which k labels now contains the location of memory which contains the integer value 2 and which is labeled by j 
i = *k;   // the memory locations which i labels now contains 2
i = k;    // the memory locations which i labels now contains the location of the memory contains 2 and which j labels

We refer to the object constructed inside the memory labeled by k as *k so that i can be assigned the value 2, but below the label myFraction which is a label for memory locations which can contain the location to other memory locations which can contain the data constructions which make up the class Fraction is used in the next line as if we were refering instead to the address of the memory locations which contain the data constructions which make up the class Fraction.


Code:
Fraction *myFraction = [[Fraction alloc] init];
[myFraction someMethod];

Literally, we are saying "send someMethod to a memory location not to the data constructs and the methods found there to which it points, but rather send it to the memory locations themselves and see what they want to do with it.

It is the Obj C syntax engine which makes the correction for us. But clearly, programmers used to writing in this way must do so with out really thinking about it.

I am used to labeling everything and thinking about it. I am not used to the compiler screwing with me and having to be familiar with all of its inconsistencies.

Such as:

Code:
soundFileURLRef = CFBundleCopyResourceURL (mainBundle,CFSTR ("TA"),CFSTR ("aiff"),NULL);
AudioServicesCreateSystemSoundID (soundFileURLRef,&theSoundFile);

Not to mention the fact that functions seem to be all over the place, defying class scope among other things.

Obj languages restrictions on scope and inheritance are attempts to reign in errant programmers who can't keep track of their labels.

It seems, however, that in our effort to ease ourselves of the burden of documenting our software, we have instead simply traded it for the equally onerous burdens of compiler restrictions plus adherance to capricious syntax. To top it off, we still have to document our software.

What a deal!!?? Huh???

By The Way, I got it all to work. I now have all my programming "tools" together for the app. I am about to write the app. That is the fun part. Not to say I won't get stuck on some new syntax thing that comes up. Also I have a few syntax questions. Is there a good manual that covers that?

Code:
void label         // what exactly do these make the compiler do?
void *label        //  and what exactly do they construct?
void* label
(void) label
(void) *label
(void*) label

Thanks for your help.

Jerry
 
Code:
Fraction *myFraction = [[Fraction alloc] init];
[myFraction someMethod];

Literally, we are saying "send someMethod to a memory location not to the data constructs and the methods found there to which it points, but rather send it to the memory locations themselves and see what they want to do with it.

I prefer to think of it as something simpler: just calling a subroutine named "someMethod" with the first parameter being the address of a memory array named "myFraction".

Any other parameters go on the other side of the subroutine call, and all but the second parameter get an extra label.

If there are one, several, or no subroutines named "someMethod" scattered throughout the program, then the last so-named subroutine in the chain of definitions for the class "Fraction" is the one hunted down and actually called.

It's all mostly just JSR's and LOAD indirect's.

y
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.