[résolu] comment sauvegarder en Cocoa une structure C et la rappeler en C++?

HerveHerve Membre
janvier 2012 modifié dans API AppKit #1
Bonjour,

J'avance bien dans mon apprentissage Core Audio. Je fais en ce moment une appli qui envoie des structures C vers le Audio Unit : cela permet d'envoyer des valeurs plus nombreuses permettant un travail de synthèse sonore plus poussé qu'avec les seuls AU paramètres. Quand il y a un seul son, mon programme envoie de Cocoa à  AU une structure C (contenant des tableaux d'autres structures d'ailleurs.) Tout marche bien, super!

Mon idée serait maintenant, lorsque j'utilise mon AU, non pas avec mon appli mais depuis un Host (Garage band par exemple : il est super ce petit host, très sympa!!) appeler les sons du synthé par MIDI Program Change.

Mon idée serait alors :
un son = une structure C
tous les sons rappelables = tableau de ces structures. (ou structure contenant un tableau de ...)
Lorsque j'appelle un MIDI Program Change, le AU copie la structure correspondante comme paramètres.

Il faudrait :
- en Cocoa, écrire ce fichier. Je l'ai fait avec NSData (un NSMutable Array de NSData de type :
[data addObject:[NSNumber numberWithInt:mesProgrammes.lesPatchs[t].typePatch]];


Je voudrais rappeler ce tableau de structures à  l'initialisation du AU. Mais C++ ne connaà®t pas les NSMutable Array.

Auriez-vous une idée? Communiquer via le HD (et non plus directement, ça je sais le faire) des structures C de Cocoa à  C++?

Par ailleurs, est-ce que quelqu'un saurait m'expliquer la valeur d'un truc comme :
cc16[0] = 0xB0

Que veut dire le "x" en particuliers? J'ai vu plusieurs encodages qui "ressemblent", mais après? Ici, cela "veut dire" que on va envoyer un message MIDI CC.

Réponses

  • mpergandmpergand Membre
    08:45 modifié #2
    dans 1325533579:

    Par ailleurs, est-ce que quelqu'un saurait m'expliquer la valeur d'un truc comme :
    cc16[0] = 0xB0
    

    Que veut dire le "x" en particuliers? J'ai vu plusieurs encodages qui "ressemblent", mais après? Ici, cela "veut dire" que on va envoyer un message MIDI CC.


    0x signifie héxadécimal
    0xB0=176

    Pour le tableau de structure, j'ai du mal à  évaluer ton problème, tu peux avoir ce tableau en mémoire quelque part et passer l'adresse de ce tableau aux AudioUnits.

  • CéroceCéroce Membre, Modérateur
    janvier 2012 modifié #3
    J'ai commencé à  répondre dans le sens de mpergand, en me rendant compte que ça ne fonctionnerait probablement pas.
    En effet l'AU (en C++) et l'IHM (en ObjC) tournent dans des processus séparés, alors on ne peut pas passer facilement des données par un simple échange de buffer, puisque leurs espaces mémoire sont différents.

    Ceci dit, ils échangent déjà  des données: en effet, quand on déplace un curseur dans l'IHM, ça modifie bien les paramètres de l'AU. Je ne rappelle plus comment cela fonctionne (on passe un CFDictionary ?), mais tu pourrais utiliser le même principe.

    Pour le Program Change, il s'agit d'un message MIDI comme les autres (comme Key On, Key Off), alors il suffit de l'interpréter dans l'AU.
  • HerveHerve Membre
    08:45 modifié #4
    Merci Céroce et mpergand pour vos réponses, c'est très sympa.

    Pour l'hexadécimal, c'est le "x" que je ne comprends pas. Mais en te lisant, mpergand, et en considérant que B0 fait 11*16, soit 176, je devine que ce "0x" ne sert à  rien sinon à  dire que c'est de l'hexadécimal, non???

    Merci Céroce aussi pour tes éclaircissements. Une solution pourrait être (le but étant d'appeler ce tableau créé préalablement par l'appli sur le HD depuis le AU lorsqu'il est hébergé dans le host) d'utiliser l'interface Cocoa du Audio Unit (qui peut être différente de celle de l'appli, pas de problème là  dessus) et coder dedans l'appel du ficher qui serait ensuite renvoyé vers le AU (l'envoi de structures C de Cocoa à  AU (C++) marche très très bien, c'est très puissant et très commode).

    A défaut...

    Tant que j'y suis, il y a une structure que je ne comprends pas : ce n'est pas une structure, ni une fonction, cela sert à  appeler la valeur tempo du host dans le AU :
    /*!<br />	@typedef		HostCallback_GetBeatAndTempo<br />	@abstract		Retrieve information about the current beat and/or tempo<br />	@discussion		If the host app has set this callback, then the audio unit can use this to get the current beat and tempo as they relate to the first sample in the render buffer. The audio unit can call this callback only from within the audio unit render call (otherwise the host is unable to provide information accurately to the audio unit as the information obtained is relate to the current AudioUnitRender call). If the host cannot provide the requested information, it will return kAudioUnitErr_CannotDoInCurrentContext.<br />	<br />			The AudioUnit can provide NULL for any of the requested parameters (except for inHostUserData) if it is not interested in that particular piece of information<br /><br />	@param			inHostUserData			Must be provided by the audio unit when it makes this call. It is the client data provided by the host when it set the HostCallbacks property<br />	@param			outCurrentBeat			The current beat, where 0 is the first beat. Tempo is defined as the number of whole-number (integer) beat values (as indicated by the outCurrentBeat field) per minute.<br />	@param			outCurrentTempo			The current tempo<br />*/<br />typedef OSStatus (*HostCallback_GetBeatAndTempo) (void		*inHostUserData, <br />										Float64	&nbsp; &nbsp; &nbsp; &nbsp; *outCurrentBeat, <br />										Float64	&nbsp; &nbsp; &nbsp; &nbsp; *outCurrentTempo);
    


    Apparemment, utiliser cela suppose que le AU reçoit déjà  un "HostCallback_GetBeatAndTempo". Auriez-vous une idée de comment faire marcher cela? En fait, je ne sais même pas ce que c'est en C++ ce truc là ... Il me faudrait récupérer dans mes calculs le "*outCurrentTempo".

    Merci encore pour vos conseils.
  • mpergandmpergand Membre
    janvier 2012 modifié #5
    dans 1325595632:

    Pour l'hexadécimal, c'est le "x" que je ne comprends pas. Mais en te lisant, mpergand, et en considérant que B0 fait 11*16, soit 176, je devine que ce "0x" ne sert à  rien sinon à  dire que c'est de l'hexadécimal, non???



    C'est les conventions d'écriture du C, on peut entrer une valeur en décimal, hexa ou octal:
    <br />int decVal=256;<br />int hexVal=0x100;<br />int octVal=0400;<br /><br />printf(&quot;decimal %d %d %d&#092;n&quot;,decVal,hexVal,octVal);<br />printf(&quot;hexa %x %x %x&#092;n&quot;,decVal,hexVal,octVal);<br />printf(&quot;octal %o %o %o&#092;n&quot;,decVal,hexVal,octVal);<br /><br />résultats:<br />decimal 256 256 256<br />hexa 100 100 100<br />octal 400 400 400<br />
    


    typedef OSStatus (*HostCallback_GetBeatAndTempo) (void		*inHostUserData, <br />										Float64	&nbsp; &nbsp; &nbsp; &nbsp; *outCurrentBeat, <br />										Float64	&nbsp; &nbsp; &nbsp; &nbsp; *outCurrentTempo);
    


    C'est un pointeur de fonction.
  • CéroceCéroce Membre, Modérateur
    08:45 modifié #6
    dans 1325595632:

    Tant que j'y suis, il y a une structure que je ne comprends pas : ce n'est pas une structure, ni une fonction, cela sert à  appeler la valeur tempo du host dans le AU :
    <br />typedef OSStatus (*HostCallback_GetBeatAndTempo) (void		*inHostUserData, <br />										Float64	&nbsp; &nbsp; &nbsp; &nbsp; *outCurrentBeat, <br />										Float64	&nbsp; &nbsp; &nbsp; &nbsp; *outCurrentTempo);
    



    Ceci est le typage d'une fonction.
    En gros, ça dit que les fonctions de type "HostCallback_GetBeatAndTempo" prennent tels paramètres en entrée et renvoient un OSStatus.
    On est ici dans le cas typique, puisque ça sert souvent à  passer un pointeur sur une fonction de callback (c'est à  dire qui sera appelée sur un événement précis).

    De fait, il doit exister une fonction du genre:
    void SetGetBeatAndTempoCallback(HostCallback_GetBeatAndTempo callback);
    


    Pour fixer la callback, on écrit:
    SetGetBeatAndTempoCallback(maFonction);<br /><br />OSStatus maFonction(void *inHostUserData, Float64 *outCurrentBeat, Float64 *outCurrentTempo)<br />{<br /> // le code qui récupère les infos<br />}
    
  • HerveHerve Membre
    08:45 modifié #7
    Merci Céroce pour tes explications.

    Je comprends un peu, et j'ai cherché une fonction du type proposé.

    J'ai trouvé pour l'instant ceci :
    HostCallback_GetBeatAndTempo<br />When called by the system, provides beat and tempo information to an audio unit from a host application.<br /><br />typedef OSStatus (*HostCallback_GetBeatAndTempo) (<br />&nbsp;  void&nbsp; &nbsp; &nbsp; *inHostUserData,<br />&nbsp;  Float64&nbsp;  *outCurrentBeat,<br />&nbsp;  Float64&nbsp;  *outCurrentTempo<br />);<br />If you named your callback function MyHostCallback_GetBeatAndTempo, you would declare it like this:<br /><br />OSStatus MyHostCallback_GetBeatAndTempo (<br />&nbsp;  void&nbsp; &nbsp; &nbsp; *inHostUserData,<br />&nbsp;  Float64&nbsp;  *outCurrentBeat,<br />&nbsp;  Float64&nbsp;  *outCurrentTempo<br />);
    


    ce qui correspond à  ce que tu dis, mais pour l'instant je n'arrive pas à  la faire marcher.

    J'ai aussi trouvé cela :
    // These calls can be used to call a Host&#039;s Callbacks. The method returns -1 if the host<br />	// hasn&#039;t supplied the callback. Any other result is returned by the host.<br />	// As in the API contract, for a parameter&#039;s value, you specify a pointer<br />	// to that data type. Specify NULL for a parameter that you are not interested<br />	// as this can save work in the host.<br /><br />	/*! @method CallHostBeatAndTempo */<br />	OSStatus	CallHostBeatAndTempo (Float64				*outCurrentBeat,&nbsp; <br />										Float64				*outCurrentTempo)<br />	{<br />		return (mHostCallbackInfo.beatAndTempoProc <br />						? (*mHostCallbackInfo.beatAndTempoProc) (mHostCallbackInfo.hostUserData, <br />																	outCurrentBeat, <br />																	outCurrentTempo)<br />						: -1);<br />	}
    


    Mais les changements de tempo dans garageBand ne donnent rien (pour l'instant, je fais juste un printf("tempo appelé %e", outCurrentTempo))

    Bon, je cherche encore!

    En fait, j'ai dû dériver les méthodes
    HandleControlChange(	UInt8 	inChannel,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UInt8 	inController,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UInt8 	inValue,<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UInt32	inStartFrame)
    

    pour pouvoir utiliser les contrôles MIDI. Cela doit être la même chose avec le tempo.

    Merci mpergand pour les explications. Cela me servira à  écrire dans le host les données MIDI.
  • HerveHerve Membre
    08:45 modifié #8
    Bonjour,

    J'ai presque résolu le problème des appels de sons par MIDI. Ceci marche très bien :
    void DazibaoAU::ecrisPgMIDIPreferes(){<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; int h_fic ;<br />&nbsp; &nbsp; h_fic = open (&quot;/Users/hervenoury/Documents/preferedMIDIBankSound.dat&quot;, O_CREAT | O_TRUNC | O_WRONLY);<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; write (h_fic, &amp;mesProgrammes, sizeof (ProgrammesMIDI));<br />&nbsp; &nbsp; close (h_fic);<br />}<br /><br />void DazibaoAU::chargePgMIDIPreferes(){<br />&nbsp; &nbsp; int h_fic ;<br />&nbsp; &nbsp; h_fic = open (&quot;/Users/hervenoury/Documents/preferedMIDIBankSound.dat&quot;, O_RDONLY);<br />&nbsp; &nbsp; if (h_fic == -1){<br />&nbsp; &nbsp; &nbsp; &nbsp; return;<br />&nbsp; &nbsp; }<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; else{<br />&nbsp; &nbsp; &nbsp; &nbsp; ProgrammesMIDI pg;<br />&nbsp; &nbsp; &nbsp; &nbsp; read (h_fic, &amp;pg, sizeof (ProgrammesMIDI));<br />&nbsp; &nbsp; &nbsp; &nbsp; close (h_fic);<br />&nbsp; &nbsp; &nbsp; &nbsp; chargeLesProgrammes(pg);<br />&nbsp; &nbsp; }<br />}
    


    Lorsque le host charge le plug, il charge le fichier à  l'adresse indiquée avec.

    Mon problème est que je ne peux pas laisser l'adresse du fichier ainsi car elle est à  mon nom. Celle-ci ne pourra pas être modifiée par l'utilisateur une fois le programme diffusé. J'ai essayé les adresses /Library et /Library/Preferences mais rien n'est écrit dedans. L'OS bloque apparemment, et interdit à  mon plug l'accès aux bibliothèques.

    Sinon, si j'écris ce fichier dans Document, je crois me souvenir qu'au lieu de mettre mon nom entre /Users et /Documents, je peux le remplacer par un nom générique, mais je ne me souviens plus lequel. Quelqu'un ici s'en souviendrait? je n'arrive pas à  retrouver un exemple que je crois avoir vu une fois...

    Merci!

    (pas encore trouvé la bonne fonction pour le tempo, mais je vais reprendre cela maintenant)
  • CéroceCéroce Membre, Modérateur
    08:45 modifié #9
    Veux-tu absolument passer par un fichier ?

    Tu peux le créer dans le dossier temporaire de l'utilisateur. Sous Cocoa, utilise la fonction [tt]NSString * NSTemporaryDirectory (void);[/tt]
    (Par contre, en C++, je ne sais pas trop, quoiqu'on qu'on peut obtenir le chemin grâce aux variables d'environnement).
  • HerveHerve Membre
    08:45 modifié #10
    Merci Céroce, merci de me répondre encore.

    En fait, l'idée est que le Audio Unit charge une banque de sons "préférée" dans le host sans passer par un menu d'ouverture. Avec Cocoa en fait, le fichier n'est appelé que si ouvre l'interface utilisateur. En appelant un fichier C/C++ depuis la méthode d'initialisation du AU cela marche mieux : les sons sont dispo de suite. Je pense que c'est indispensable.

    Normalement, le host se souvient des positions des paramètres, mais un son avec mon synthé, ce sont des centaines de paramètres, d'où l'utilisation de structures C. D'où le chargement de ces structures C sans devoir passer par l'interface utilisateur ou l'appli : on n'a plus pour rejouer son morceau qu'à  écrire le bon MIDI programme change en début de morceau et c'est calé (lorsqu'on travaille souvent sur son morceau, c'est indispensable)

    Là , je viens d'essayer ceci :
    /Applications/DazibaoEdition.app/Contents/preferedMIDIBankSound.dat
    

    Le fichier est écrit, mais pas lu!!

    pareil avec
    /Applications
    
    , et là  je n'ose pas, franchement, c'est mettre le bazar!

    Il me faudrait un nom de fichier accessible par tout utilisateur que l'OS ne bloque pas en fait.
  • CéroceCéroce Membre, Modérateur
    08:45 modifié #11
    OK, je comprends mieux pourquoi tu veux passer par un fichier.

    Par contre, on ne peut pas écrire n'importe où, et Apple va ajouter de plus en plus de restrictions à  ce niveau (renseigne-toi à  propos du Mac App Store et du "Sandbox").

    Je pense que dans ton cas, la place naturelle est dans Application Support:
    ~/Library/Application Support/DazibaoEdition/
  • HerveHerve Membre
    janvier 2012 modifié #12
    Oui, mais cette bibliothèque a l'air très protégée. Je pense qu'il faudrait déjà  créer dedans le dossier concernant mon appli. Puis écrire dedans l'archive C++. Tout ceci est appelé depuis une interface Cocoa, sauf l'écriture du fichier final qui est faite depuis l'AU.

    Autrement
    /Users/Shared/preferedMIDIBankSound.dat
    fonctionne aussi. Mais en vrac comme cela je ne sais pas si c'est "légal" dans le MAS
  • CéroceCéroce Membre, Modérateur
    08:45 modifié #13
    Tu as le droit d'écrire dans ce répertoire, c'est même fait exprès (et oui, il faut créer le répertoire dans Application Support).
  • mpergandmpergand Membre
    08:45 modifié #14
    Exemple de recherche du support folder

    <br />#import &lt;Foundation/Foundation.h&gt;<br /><br />#define MAXPATH 300<br /><br />int main (int argc, const char * argv&#91;]) {<br />&nbsp; &nbsp; <br />	FSRef fRef;<br />	OSErr err;<br />	<br />	if((err=FSFindFolder(kUserDomain,kApplicationSupportFolderType,kCreateFolder,&amp;fRef))==noErr)<br />		{<br />		UInt8 path[MAXPATH];<br />		<br />		// On return, a pointer to the path. This path can be used by POSIX-style calls.<br />		if((err=FSRefMakePath (&amp;fRef,path,MAXPATH))==noErr)<br />			{<br />			printf(&quot;%s&#092;n&quot;,path);<br />			}<br /><br />		}<br />	return 0;<br />}<br /><br /><br />
    
  • AliGatorAliGator Membre, Modérateur
    08:45 modifié #15
    Oui ne surtout pas commencer à  s'amuser à  écrire des fichiers dans /Users/Shared ou dans des endroits bizarres comme ça.
    Le dossier "~/Library/Application Support" est fait pour tous ces fichiers de ce genre, et c'est la raison d'être de ce dossier (à  toi de créer un dossier dédié portant le nom de ton application dans ce dossier Application Support pour y mettre ton fichier .dat).

    C'est déjà  (1) la bonne pratique à  faire et à  suivre pour pas mettre des fichiers partout et n'importe où ailleurs à  des endroits pas faits pour. Y'a un dossier pour, autant l'utiliser (2) mais aussi un des seuls emplacements auxquels tu auras accès en écriture si tu distribues ton appli via le MacAppStore et doit donc suivre les restrictions sur les répertoires auxquels tu as accès et la Sandbox (justement fait pour éviter que tout le monde foute le dawa partout là  où c'est pas fait pour)
  • HerveHerve Membre
    08:45 modifié #16
    Bon OK! Je vais vous suivre. A vrai dire, c'est ce que je devinais...

    Merci à  tous, et en particulier à  mpergand pour les lignes de code. Je vais essayer tout cela. Je vous tiens au courant.

    Merci encore!
  • HerveHerve Membre
    janvier 2012 modifié #17
    Je rencontre un problème :
    Avec NSFileManager, je peux créer un dossier dans /Library, je peux créer le bon fichier dedans (il est écrit) mais ensuite son accès est bloqué. Le AU n'y a pas accès, lorsque je lis les infos du fichier, l'accès est interdit. (!!!  >:()

    Avec les différentes méthodes de NSFileManager, je sais récupérer les NSDictionary concernant les attributs du fichier, mais je ne vois pas quel paramètre je dois modifier. Ce sont :
    attributesOfItemForPath:
    2012-01-14 16:21:19.273 DazibaoEdition[571:60b] key 0 = NSFileOwnerAccountID, valeur = 0
    2012-01-14 16:21:19.273 DazibaoEdition[571:60b] key 1 = NSFileSystemFileNumber, valeur = 7512711
    2012-01-14 16:21:19.274 DazibaoEdition[571:60b] key 2 = NSFileExtensionHidden, valeur = 0
    2012-01-14 16:21:19.274 DazibaoEdition[571:60b] key 3 = NSFileSystemNumber, valeur = 234881026
    2012-01-14 16:21:19.275 DazibaoEdition[571:60b] key 4 = NSFileSize, valeur = 2244
    2012-01-14 16:21:19.276 DazibaoEdition[571:60b] key 5 = NSFileGroupOwnerAccountID, valeur = 0
    2012-01-14 16:21:19.276 DazibaoEdition[571:60b] key 6 = NSFileOwnerAccountName, valeur = root
    2012-01-14 16:21:19.277 DazibaoEdition[571:60b] key 7 = NSFileCreationDate, valeur = 2011-06-16 22:57:28 +0000
    2012-01-14 16:21:19.278 DazibaoEdition[571:60b] key 8 = NSFilePosixPermissions, valeur = 509
    2012-01-14 16:21:19.278 DazibaoEdition[571:60b] key 9 = NSFileType, valeur = NSFileTypeDirectory
    2012-01-14 16:21:19.279 DazibaoEdition[571:60b] key 10 = NSFileGroupOwnerAccountName, valeur = wheel
    2012-01-14 16:21:19.279 DazibaoEdition[571:60b] key 11 = NSFileReferenceCount, valeur = 66
    2012-01-14 16:21:19.280 DazibaoEdition[571:60b] key 12 = NSFileModificationDate, valeur = 2012-01-14 13:58:16 +0000

    Je pense qu'il faut modifier NSFilePosixPermissions, mais je ne trouve pas dans la doc la valeur à  lui donner.
    Quelqu'un ici saurait-il cela? Merci d'avance.

    En fait, plus exactement, si je crée manuellement depuis le finder le dossier, le fichier est écrit mais pas lu (accès totalement bloqué), mais en codant avec NSFileManager, rien ne s'écrit dans Library. Plus étonnant, si je crée un dossier avec NSFileManager dans Documents, les fichiers écrits dedans sont tout aussi inaccessibles. Le problème est donc bien l'autorisation d'accès aux fichiers que donne l'OS.
  • HerveHerve Membre
    08:45 modifié #18
    Autre solution, ceci :
    NSFileManager *fileCree;<br />&nbsp; &nbsp; NSString *cheminFichier = [NSHomeDirectory()stringByAppendingPathComponent:@&quot;/Library/DazibaoPrefences&quot;];<br />&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; NSLog(@&quot;fichier : %@&quot;,cheminFichier);<br />&nbsp; &nbsp; fileCree = [[NSFileManager alloc]init];<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; if([fileCree fileExistsAtPath:cheminFichier] == NO){<br />&nbsp; &nbsp; <br />&nbsp; &nbsp; &nbsp; &nbsp; [fileCree createDirectoryAtPath:cheminFichier <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; withIntermediateDirectories:YES <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  attributes:NULL<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; error:NULL];}<br />
    


    mais pour ma classe c++? CFString permet-il cela??

    J'ai vraiment l'art de me compliquer la vie parfois, mais bon...

    Si vous pouvez m'indiquer le bon document pour coder les autorisations d'accès, je suis preneur.
  • mpergandmpergand Membre
    janvier 2012 modifié #19
    <br />#import &lt;Foundation/Foundation.h&gt;<br /><br />#define AppName &quot;MonAppli&quot;<br /><br />Boolean createSupportFolder(CFStringRef folderName,FSRef* fRef);<br /><br />int main (int argc, const char * argv&#91;]) {<br />&nbsp; &nbsp; <br />	FSRef appFolderRef;<br />	// creation dossier dans SupportFolder<br />	//CFStringRef folderName=CFStringCreateWithCString (NULL,AppName,kCFStringEncodingASCII);<br />	CFStringRef folderName=CFSTR(AppName);&nbsp; // plus simple qu&#039;au-dessus !<br />	<br />	if(!createSupportFolder(folderName,&amp;appFolderRef))<br />		printf(&quot;folder not created !&#092;n&quot;);<br />	else<br />		printf(&quot;folder created&#092;n&quot;);<br />	<br />	CFRelease(folderName);<br />	<br />	return 0;<br />}<br /><br />Boolean createSupportFolder(CFStringRef folderName,FSRef* fRef)<br />{<br />	FSRef supportFolderRef;<br />	OSErr err;<br />	UniChar nameStr[80];<br />	CFIndex length=CFStringGetLength(folderName);<br />	<br />	// recherche/creation du support folder<br />	if((err=FSFindFolder(kUserDomain,kApplicationSupportFolderType,kCreateFolder,&amp;supportFolderRef))==noErr)<br />		{<br />		CFStringGetCharacters(folderName, CFRangeMake(0, length), nameStr);<br />		<br />		// existe-t-il déjà  ?<br />		if((err=FSMakeFSRefUnicode(&amp;supportFolderRef,length,nameStr,kTextEncodingUnknown,fRef))==noErr)<br />			return true;<br />			<br />		if((err=FSCreateDirectoryUnicode(&amp;supportFolderRef,length,nameStr,kFSCatInfoNone,NULL,fRef,NULL,NULL))==noErr)<br />			return true;<br />		}<br />			<br />	return false;<br />}<br /><br />
    


    Il y a un tuto pour créer/sauvegarder un Property list en  Core Foundation:
    http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFPropertyLists/CFPropertyLists.html#//apple_ref/doc/uid/10000130-SW1
  • HerveHerve Membre
    08:45 modifié #20
    Merci mpergand pour ta réponse. Je ne comprends pas bien ce code :
    Le code Cocoa
    NSString *cheminFichier = [NSHomeDirectory()stringByAppendingPathComponent:@&quot;/Library/DazibaoPrefences&quot;];<br />&nbsp; &nbsp;
    

    crée un dossier dans le répertoire utilisateur (de type Users/leNomUtilisateur/Library (ouDocuments)/leNomDuDossier.

    Je comprends pas quelle fonction fait ceci dans le code que tu me proposes.
    Ah là  là !! C'est dommage, c'est la seule chose qui manque à  mon appli, tout le reste marche maintenant. Le tempo obéit au Host sequencer en particulier (merci Ceroce de m'avoir bien aiguillé, il fallait employer les fonctions trouvées, mais dans la méthode render et non ailleurs)

    Par ailleurs ceci :
    [fileCree createDirectoryAtPath:cheminFichier <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; withIntermediateDirectories:YES <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  attributes:NULL&nbsp; //ceci ne va pas, il faut un NSDictionnary correct<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; error:NULL];<br />
    

    me crée un fichier dont l'accès est ensuite interdit. Je n'arrive pas à  trouver dans la doc ce qu'il faut modifier au NSDictionnary pour que le contenu du dossier soit ouvert.

    A last little help please?
  • AliGatorAliGator Membre, Modérateur
    janvier 2012 modifié #21
    Si tu crées un dossier dans [tt]/Library[/tt] (ou même dans [tt]~/Library[/tt]) comme dans ton cas directement [tt]~/Library/DaziboPreferences[/tt] :
    • C'est normal que tu n'aies pas les droits. La racine du dossier Library n'est pas faite pour ça.
    • Une appli qui fait ça et donc n'écrit pas ses fichiers de support au bon endroit c'est limite poubelle pour moi. C'est le meilleur moyen de (1) foutre le souk dans ton installation (2) avoir des problèmes de droits notamment après si tu crées des répertoires dans des répertoires où tu n'as pas les droits et qui vont prendre le umode du parent. Et puis ça respecte pas les conventions qui sont aussi là  pour avoir un système propre et bien rangé et pas le foutoir ;)
    • Si ton dossier s'appelle "DaziboPreferences" c'est sans doute qu'il contient des préférences ? S'il contient un fichier de préférences, c'est dans les [tt]NSUserDefaults[/tt] qu'il faut mettre ça (qui vont se loger tout seuls dans [tt]~/Library/Preferences[/tt], encore un dossier fait pour, mais que tu dois manipuler avec [tt]NSUserDefaults[/tt] en ObjC et [tt]CFPreferences[/tt] en C, qui se chargent de tout, y compris locks & co, donc ne pas manipuler les fichiers PLIST directement pour les prefs/userdefaults)
    • Si ton dossier contient des fichiers de support, genre des Units CoreAudio, des fichiers de son, etc... il doit aller dans un dossier "[tt]~/Library/Application Support/Dazibo[/tt]", avec juste le nom de ton appli donc "Dazibo" et pas un nom genre DaziboPreferences !


    Ca peut te paraà®tre du pinaillage ces histoires de nom et d'emplacement, mais ce sont les conventions de OSX. Et je pense que rien qu'en les respectant et mettant les fichiers au bon endroit tu t'enlèveras bien des soucis (de droits d'accès notamment), c'est aussi pour ça que je dis ça ;)
  • mpergandmpergand Membre
    08:45 modifié #22
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);<br />NSString* supportPath= [paths objectAtIndex:0];<br />NSString* appFolderPath=[supportPath stringByAppendingPathComponent:@&quot;Mon Appli&quot;];<br /><br />[[NSFileManager defaultManager] createDirectoryAtPath:appFolderPath attributes:nil];<br /><br />NSData* data=[NSData dataWithBytes:&quot;ok ?&quot; length:4];<br />NSString* filePath=[appFolderPath stringByAppendingPathComponent:@&quot;fichier.txt&quot;];<br />[[NSFileManager defaultManager] createFileAtPath:filePath contents:data attributes:nil];
    


    Crée "fichier.txt" dans le dossier "Mon Appli" dans "library/Application Support" de l'utilisateur.

    le fichier créé a les droits de l'utilisateur courant (tartampion (moi) lecture/écriture)

    Merci mpergand pour ta réponse. Je ne comprends pas bien ce code :
    Le code Cocoa
    Code: [Sélectionner]
    NSString *cheminFichier = [NSHomeDirectory()stringByAppendingPathComponent:@/Library/DazibaoPrefences];
       
    crée un dossier dans le répertoire utilisateur (de type Users/leNomUtilisateur/Library (ouDocuments)/leNomDuDossier.

    Je comprends pas quelle fonction fait ceci dans le code que tu me proposes.


    c'est Boolean createSupportFolder(CFStringRef folderName,FSRef* fRef)

    Ceci est un exemple de création du dossier support en CoreFoundation (puisque la biblio Cocoa n'est pas dispo).
  • HerveHerve Membre
    08:45 modifié #23
    Merci beaucoup AliGator et mpergand pour vos posts.
    J'ai cherché cet après-midi à  comprendre tout cela. Les préférences sont, un peu à  la manière des dictionnaires, ou de NSCoding, des associations Clef/Valeur. Est-ce qu'une structure C peut être considérée comme une valeur? A ce que j'ai compris, non. Je pensais sinon associer un URL à  la clef, puisque c'est permis, mais cela ne résout pas le problème me semble t-il.

    Voilà  où j'en suis ce soir, la suite demain...
  • CéroceCéroce Membre, Modérateur
    08:45 modifié #24
    dans 1326907336:

    Est-ce qu'une structure C peut être considérée comme une valeur?

    Non, mais tu pourrais imaginer prendre chaque champ de la structure.

    Les préférences ne sont pas faites pour ça, mais vraiment pour conserver les réglages de l'utilisateur.
    Un fichier dans "Application Support" est vraiment tout indiqué.
  • mpergandmpergand Membre
    08:45 modifié #25
    dans 1326907336:

    J'ai cherché cet après-midi à  comprendre tout cela. Les préférences sont, un peu à  la manière des dictionnaires, ou de NSCoding, des associations Clef/Valeur. Est-ce qu'une structure C peut être considérée comme une valeur? A ce que j'ai compris, non. Je pensais sinon associer un URL à  la clef, puisque c'est permis, mais cela ne résout pas le problème me semble t-il.


    c'est très confus tout ça  ???

    Revenons au problème initial: sauvegarder un tableau de structure dans un fichier:

    Exemple de structure:
    typedef struct<br />{<br />	char	name[10];<br />	UInt16	v1;<br />	UInt16	v2;<br />	char	n[5];<br />	SInt32	l1;<br />	UInt8	b1;<br />	SInt16	v3;<br />}Params;<br /><br />// initialisation du tableau<br />Params params&#91;]={<br />		{&quot;param1&quot;,1024,4096,&quot;ok1&quot;,-45000,255,-100},<br />		{&quot;param2&quot;,2024,4096,&quot;ok2&quot;,-45000,255,-200},<br />		{&quot;param3&quot;,3024,4096,&quot;ok3&quot;,-45000,255,-300}<br />	};<br />
    

    Il ne faut pas que cette structure contienne de pointeurs !

    Sauvegarde en Cococa:
    #define AppName @&quot;Mon Appli&quot;<br />#define FileName @&quot;Parametres.data&quot;<br /><br />NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);<br />NSString* supportPath= [paths objectAtIndex:0];<br />NSString* appFolderPath=[supportPath stringByAppendingPathComponent:AppName];<br />NSString* filePath=[appFolderPath stringByAppendingPathComponent:FileName];<br /><br />NSData* data=[NSData dataWithBytes:params length:sizeof(params)];<br />[data writeToFile:filePath atomically:YES];<br />
    


    Sauvegarde les données de la structure dans ~/Library/Application Support/Mon Appli/Parametres.data

    Pour les récupérer dans ton audio unit en C:
    <br />#include &lt;CoreFoundation/CoreFoundation.h&gt;<br />#include &lt;Carbon/Carbon.h&gt;<br /><br />Boolean createSupportFolder(CFStringRef folderName,FSRef* fRef);<br />Boolean makeFSRef(const FSRef parentRef,CFStringRef name,FSRef * fRef);<br /><br />#define AppName &quot;Mon Appli&quot;<br />#define FileName &quot;Parametres.data&quot;<br /><br />typedef struct<br />{<br />	char	name[10];<br />	UInt16	v1;<br />	UInt16	v2;<br />	char	n[5];<br />	SInt32	l1;<br />	UInt8	b1;<br />	SInt16	v3;<br />}Params;<br /><br />int main (int argc, const char * argv&#91;]) {<br /><br />	FSRef appFolderRef,fileRef;<br />	// récup du FSRef du dossier support<br />	if(!createSupportFolder(CFSTR(AppName),&amp;appFolderRef))<br />		return 1; // dossier non trouvé<br /><br />	if(!makeFSRef(appFolderRef,CFSTR(FileName),&amp;fileRef))<br />		return 2; // le fichier Parametres.data n&#039;existe pas<br />	<br />	// URL du fichier parametres.data<br />	CFURLRef paramsURLRef=CFURLCreateFromFSRef (NULL,&amp;fileRef);	<br />	CFDataRef dataRef;		<br /><br />	if(CFURLCreateDataAndPropertiesFromResource (NULL,paramsURLRef,&amp;dataRef,NULL,NULL,NULL))<br />		{<br />		int i,count=CFDataGetLength(dataRef)/sizeof(Params);<br />		Params* p=(Params*)malloc((size_t)CFDataGetLength(dataRef));<br />		memcpy(p,CFDataGetBytePtr(dataRef), CFDataGetLength(dataRef));<br />		<br />		for(i=0;i&lt;count;i++)<br />			printf(&quot;%s %d&#092;n&quot;,p[i].name,p[i].v1);<br />		<br />		CFRelease(dataRef);<br />		free(p);<br />		}<br />		<br />	CFRelease(paramsURLRef);<br />	<br />	return 0;<br /><br />}<br /><br />Boolean makeFSRef(const FSRef parentRef,CFStringRef name,FSRef * fRef)<br />{<br />	OSErr err;<br />	CFIndex length=CFStringGetLength(name);<br />	UniChar nameStr[length];<br />	<br />	CFStringGetCharacters(name, CFRangeMake(0, length), nameStr);<br />	<br />	err=FSMakeFSRefUnicode (&amp;parentRef,length,nameStr,kTextEncodingUnknown,fRef);<br />	<br />	if(err==noErr) <br />		return true;<br />		<br />	return false;<br />}<br /><br />// recherche création du support folder<br />Boolean createSupportFolder(CFStringRef folderName,FSRef* fRef)<br />{<br />	FSRef supportFolderRef;<br />	OSErr err;<br />	CFIndex length=CFStringGetLength(folderName);<br />	UniChar nameStr[length];<br />	<br />	// recherche/creation du support folder<br />	if((err=FSFindFolder(kUserDomain,kApplicationSupportFolderType,kCreateFolder,&amp;supportFolderRef))==noErr)<br />		{<br />		CFStringGetCharacters(folderName, CFRangeMake(0, length), nameStr);<br />		<br />		// existe-t-il déjà  ?<br />		if((err=FSMakeFSRefUnicode(&amp;supportFolderRef,length,nameStr,kTextEncodingUnknown,fRef))==noErr)<br />			return true;<br />			<br />		if((err=FSCreateDirectoryUnicode(&amp;supportFolderRef,length,nameStr,kFSCatInfoNone,NULL,fRef,NULL,NULL))==noErr)<br />			return true;<br />		}<br />			<br />	return false;<br />}<br /><br />
    


    qui affiche:
    param1 1024
    param2 2024
    param3 3024

    Les données du fichier sont bien récupérées !

    NB:
    faut créer un fichier .h avec la def de la struct et les #define:
    <br />#define AppName &quot;Mon Appli&quot;<br />#define FileName &quot;Parametres.data&quot;<br /><br />typedef struct<br />{<br />	char	name[10];<br />	UInt16	v1;<br />	UInt16	v2;<br />	char	n[5];<br />	SInt32	l1;<br />	UInt8	b1;<br />	SInt16	v3;<br />}Params;<br />
    
  • HerveHerve Membre
    08:45 modifié #26
    Bon, OK, j'oublie ma sauvegarde actuelle et je tente ce WE de faire ce que vous me proposez.

    Merci beaucoup, je vous tiens au courant.
  • HerveHerve Membre
    08:45 modifié #27
    Merci infiniment, et doublement merci en plus, mpergand :
    ton code est venu à  bout du problème!!

    (Comme d'habitude, j'ai commencé à  bricoler n'importe quoi à  partir de , et puis quand je suis revenu à  ton code, cela a marché impeccable. Ce que je peux m'énerver moi-même parfois...)

    Merci beaucoup, cette petite fonction ajoutée rendra de grands services aux musiciens qui utiliseront le synthé.

    Merci aussi à  toutes les autres personnes qui ont participé à  cette discussion. Je commence à  enregistrer des démos du truc, je vous ferai écouter.


Connectez-vous ou Inscrivez-vous pour répondre.