[Résolu] NSSound + Core Data = comportement étrange

berfisberfis Membre
avril 2015 modifié dans API AppKit #1

Bonjour,


 


L'une des entités de mon modèle possède un attribut optional, transformable "sound". Mon intention est d'y stocker des sons de taille modeste (quelques dizaine de K, pas de BLOB).


 


L'utilisateur définit ce son en faisant un drag&drop du fichier son sur un TextField (c'est provisoire, je vais réécrire une NSView plus explicite). Dans le delegate du TextField j'implémente ça:



// - (void) controlTextDidChange:(NSNotification *)obj
// {
NSTextField *textField = obj.object;
NSString *string = [textField stringValue];
NSFileManager *fm = [NSFileManager defaultManager];
if ([fm fileExistsAtPath:string])
{
NSSound *sound = [[NSSound alloc]initWithContentsOfFile:string byReference:NO];
Place *place = self.selectedObjects.lastObject;
[place setSound:[sound copy]];
}
else NSBeep();
}

J'ai pris les précautions suivantes une fois que le fichier est reconnu comme valide:


1. initWithContentsOfFile: byReference: prend le paramètre NO, qui est censé garantir que toutes les données du son sont chargées dans le NSSound.


2. je fais (peut-être inutilement) une copie de l'objet (NSSound se conforme aux protocoles de copy et de coding).


 


Je clique sur un bouton pour jouer le son: je l'entends. J'enregistre le document et là  les ennuis commencent.


 


Mon entité est vidée de son contenu: aucune valeur n'est enregistrée, pas seulement "sound", ce que je pourrais comprendre en cas d'erreur, mais toutes les autres aussi. Un peu comme si j'enregistrais un "fault"...


 


Et bien sûr pas la moindre erreur run-time.


 


Transformable fonctionne par défaut sans avoir besoin de réécrire un NSValueTransformer spécifique dans les cas suivants: NSAttributedString, NSImage, NSArray... mais peut-être pas NSSound?


 


J'écris donc un NSValueTransformer NSData <-> NSSound et je le référence dans le modèle. Aucune différence.


 


Je ne sais pas où se situe mon erreur: on dirait que NSSound ne garde que la référence en fait, car je peux jouer le son tant que le fichier d'origine existe. Si je l'élimine, il n'y a plus moyen.


 


J'ai même essayé une copydeep en archivant/désarchivant le son. Aucun changement.


 


Jusqu'à  présent, j'ai travaillé avec NSSound de la manière la plus simple: charger avec soundNamed, puis play/stop etc. sans le moindre souci. Mais là  j'essaie de stocker et je n'y arrive pas.


 


Note finale: je ne peux pas stocker par référence parce que le document va être déplacé, et il faut donc que les sons l'accompagnent.


 


Est-ce que quelqu'un a une idée de l'erreur? D'avance merci.


Réponses

  • CéroceCéroce Membre, Modérateur
    avril 2015 modifié #2

    Il est très peu probable que NSSound conserve les données sonores.


    Enregistre l'échantillon sous forme de data blob dans Core Data.


  • Merci Céroce.


     


    Mais là  je cale. Rien dans la doc Apple, rien sur Google.


     


    Personne ne semble avoir jamais eu besoin de ça. Des sons dans le bundle de l'application pour des jeux, dans les ressources système pour des alertes, dans la librairie pour ceux qui programment la 1843e version maison de iTunes...


     


    Aucune idée de la façon de récupérer l'échantillon sonore, rien sur sa sérialisation... encore moins sur le ValueTransformer à  écrire... j'ai vraiment l'impression de marcher sur Mars avec cette histoire. On se retourne et personne ne vous a suivi. Et les réserves d'oxygène baissent.


  • Joanna CarterJoanna Carter Membre, Modérateur
    avril 2015 modifié #4

    Si les fichiers son sont disponibles "sur disque", pourquoi pas stocker l'URL du fichier dans Core Data ?


  • Hello Joana,


     


    Les fichiers sons et images ne sont pas forcément disponibles "sur disque". Un utilisateur crée un document sur son ordinateur, définit les sons et expédie le tout en pièce jointe par mail. Que va entendre le destinataire?


     


    Les documents sont destinés à  être distribués. Une autre solution consisterait à  transformer le document en "bundle" et à  y stocker les sons, par copie de fichier. Mais je reste convaincu qu'il doit y avoir un moyen d'éviter le bundle (de toute façon j'aime pas).


     


    Peut-être lire le fichier son, stocker son contenu dans un NSData et ensuite dans l'attribut "sound" de mon entité? Ensuite, à  l'intérieur de l'application, recréer le NSSound avec ce data, et l'utiliser durant la durée de vie de l'application?


  • CéroceCéroce Membre, Modérateur

    Quand l'utilisateur choisit le fichier, tu crées une NSData à  partir du chemin ou de l'URL du fichier.


    Tu stockes la NSData dans ton entité Core Data.


    NSSound possède une méthode -initWithData:.


  • Ca ne marche pas. NSSound retourne NIL.


     


    Stockage dans le soundBytes de Core Data [attribute = "soundBytes" type = Binary Data] (ça marche):



    // - (void) controlTextDidChange:(NSNotification *)obj
    // {
    NSTextField *textField = obj.object;
    NSString *string = [textField stringValue];
    NSFileManager *fm = [NSFileManager defaultManager];
    if ([fm fileExistsAtPath:string])
    {
    NSData *soundBytes = [NSData dataWithContentsOfFile:string];
    SoundGuard *soundGuard = self.selectedObjects.lastObject;
    [soundGuard setSoundbytes:soundBytes];
    }
    else NSBeep();
    }

    Relecture:



    // - (IBAction)playSound:(id)sender
    // {
    SoundGuard *soundGuard = self.selectedObjects.lastObject;
    NSSound *sound = [[NSSound alloc] initWithData:soundGuard.soundbytes];
    NSLog(@sound:%@",sound); // RETURNS NIL
    [sound setLoops:soundGuard.continuous];
    [sound play];
    }
  • Joanna CarterJoanna Carter Membre, Modérateur

    Tu as bien sauvegardé  le Core Data ?


  • berfisberfis Membre
    avril 2015 modifié #9

    Oui, Joanna. Sauvegardé, fermé, réouvert: le NSData est bien là , toujours les mêmes 207 Kb (j'ai vérifié avec Core Data Editor).


  • Joanna CarterJoanna Carter Membre, Modérateur

    Donc, tu veux assigner la valeur de la propriété à  une variable NSData, afin que tu aurais pu la perdre en référence weak avant que tu l'assignes au NSSound ?


  • Zut, zut et zut. C'est le .mp3 qui fait problème. ça fonctionne parfaitement avec du .aiff et du .wav...


     


    Si c'est bien ça, je vais devoir filtrer les types de fichiers lors du drag&drop  <_<


  • CéroceCéroce Membre, Modérateur

    Ah oui, NSSound est très limité quant au formats autorisés.


    Il te reste la possibilité de jouer le son avec AVAudioPlayer (je sais que les mp3 fonctionnent, mais je crois que c'est n'est pas le cas pour d'autres, comme l'aifc).


  • Joanna CarterJoanna Carter Membre, Modérateur
    avril 2015 modifié #13
    Bravo berfis
  • Quel idiot je fais. J'ai testé avec le premier fichier qui m'est tombé sous la main (du mp3 donc) et il ne me serait pas venu à  l'idée que le problème venait de là .


     


    Du coup, l'attribut Core Data "Transformable" (sans NSValueTransformer) fonctionne parfaitement aussi...


     


    Bon, désolé du dérangement et merci à  vous deux, Joanna et Céroce !


  • Si tu stock du blob dans Core Data n'oublis pas d'activer la fonction de stockage dans un fichier secondaire du champs en question histoire de ne pas tuer tes perfs de recherche.


  • Salut Yoann,


     


    J'ai vu l'option mais je ne m'en suis jamais servi. Pour les raisons données plus haut, les BLOB éventuels devront se trouver dans le document.


     


    Maintenant j'ai vu qu'il y avait un moyen d'alléger l'empreinte mémoire et les performances générales: stocker le BLOB dans une entité à  part et établir une relation to-one avec elle, au lieu de le stocker dans un attribute: ça utilise au mieux le mécanisme de faulting.




  • Maintenant j'ai vu qu'il y avait un moyen d'alléger l'empreinte mémoire et les performances générales: stocker le BLOB dans une entité à  part et établir une relation to-one avec elle, au lieu de le stocker dans un attribute: ça utilise au mieux le mécanisme de faulting.




     


    ça c'est le principe de base de tout modèle de donnée. Faulting ou pas.


     


    À combiner au système de fichiers secondaire.

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