DivideConcept.net

le blog de divide.

Carnet de notes de développement

En m’attaquant au développement de la 3eme version de SpectraLayers il y a pile-poil un an, j’ai décidé de tout reprendre à zéro, afin de repartir sur de meilleures bases tant en terme d’architecture que d’expérience utilisateur. SpectraLayers était ma première grosse application et j’ai improvisé en cours de route, ignorant certaines conventions et techniques pourtant courantes. Jusque là mes projets se limitaient pour la plupart à de la R&D d’algorithmes.
Je vais tacher d’énumérer ici tout ce que j’ai pu noter lors du développement de cette nouvelle version.

UX Design

Un des points faibles des deux premières versions était la courbe d’apprentissage bien plus longue que sur les autres soft d’édition. Les concepts de transfert de données direct d’un calque à l’autre et d’inversion de phase étaient loin d’être intuitifs, l’association de couleurs par rapport à des états un peu déroutant, la navigation perfectible, et la première version consommait beaucoup coté CPU (point quelque peu amélioré dans la version 2).

Tous ces éléments ont donc été remis complètement à plat, et l’idée maîtresse pour rendre le tout intuitif a été de s’inspirer le plus directement possible de tous les termes, apparences, actions, comportements et mises en page standards de l’ensemble des logiciels d’édition existants (aussi bien des éditeurs de texte, que d’image, de montage vidéo et audio) pour en tirer ce qui en faisait l’essence même. Puis penser l’intégration de tous ces concepts autour de l’édition spectrale multi-couches. Tous ces éléments constituent l’UX, l’eXpérience Utilisateur, concept qui va au delà de celui d’UI (Interface Utilisateur), même si les deux sont étroitement liés.

Quelques exemples de questions que je me suis posé:
-Quel est le raccourcis clavier standard sur chaque plateforme pour telle action ?
-Quels sont les outils/méthodes en vogue pour naviguer au sein d’un projet ?
-Que se passe t-il généralement lorsqu’on sélectionne quelque chose, et qu’on cherche à le déplacer directement ?
-Quelle est la dénomination la plus courante pour un outil qui fait ce genre de travail ? Et sa représentation ?
-Dans quel ordre ce type de processus est t-il généralement appliqué ?
-Quels éléments de l’interface sont superflus, et lesquels devraient être accessibles en priorité ?

sl3banner

Certaines questions se sont posés en amont, et le reste en cours de développement, au cas par cas, une fois confronté aux dilemmes. Il existe néanmoins quelques exceptions à cette règle, quand on pense apporter un réponse bien plus intuitive ou pratique que la pratique la plus répandue; mais dans ce cas, il faut s’assurer que cela semblera couler de source pour l’utilisateur.
Si il ne fallait retenir qu’une chose sur ce point, c’est que tout ce qui n’est pas l’innovation à proprement parler du projet doit absolument se conformer aux us et coutumes en rigueur dans son domaine. Dans le cas contraire il en résulte généralement un apprentissage plus long, avec le risque d’aboutir sur une incompréhension voire un rejet pur et simple par l’utilisateur.

Le choix des outils

Vient ensuite le choix des outils pour commencer la réalisation à proprement parler. Ce choix est extrêmement important, car il va conditionner la bonne conduite du projet jusqu’à son terme, et assurer sa pérennité ensuite. Et il n’est pas question d’en changer en cours de route (au risque de se retrouver avec les symptômes d’un Duke Nukem Forever). Il n’y a pas de réponse universelle : il faut faire en fonction de ses connaissances, de sa capacité d’adaptation, du type de projet, des plateformes ciblées, de la qualité de l’outil en lui même (ses fonctionnalités, sa stabilité, son suivis, sa documentation)… Bref prendre quelques jours pour bien étudier l’offre disponible, télécharger quelques outils pour voir comment ils se présentent sur le terrain, tout ça se fait aussi un peu au feeling.

Pour mon projet Qt s’est montré d’une richesse incroyable, très bien fournis en exemples et documentation, suivis par une grosse communauté et évolutif.
Sa dernière version (5.4) intègre le support High-DPI, Windows RT, et de nombreuses autres améliorations appréciables.
Coté compilateur je m’appuie sur VS2013 Express pour Windows, et XCode 5 sur Mac OS. L’ensemble est totalement gratuit d’utilisation, même pour des projets commerciaux.

Git, c’est fantastique

Believe it or not, mais jusque là tous mes projets étaient versionnés… avec des archives zip quotidiennes de la totalité du projet. J’étais conscient qu’il s’agissait d’une mauvaise pratique, mais c’était simple et j’avais un peu peur que la plupart des systèmes de versionning soient des usines à gaz.
Quelques jours de test avec Git ont suffit à me convaincre du contraire (merci les wefragés), la mise en place est très simple, ça peut s’utiliser offline et/ou online au choix, et un ou deux scripts simples peuvent en simplifier l’utilisation quotidienne encore plus qu’un archivage zip. Le gain de place est monstrueux par rapport à mon ancien système, même en archivant les binaires du projet (Git gère très bien les redondances au sein des binaires via sa compression interne, contrairement à une croyance répandue). Couplé à Github (pour les projets open source) ou Bitbucket (pour les projets fermés) c’est l’assurance de ne jamais perdre son projet.

Architecture : ce qui se conçoit bien s’énonce clairement…

Afin d’établir des fondations solides pour ce “nouveau” logiciel, je me suis appuyé sur l’excellent yEd, un éditeur de schémas très simple à prendre en main (et gratuit). Merci Darkstryder !
En quelques clics on peut rapidement définir des modules, les relier entre eux, modifier tout ça aisément en cours de réflexion et même demander au logiciel de tout réorganiser automatiquement au mieux.

yed

…Mais les mots pour le dire ne viennent qu’avec le temps.

Déterminer la structure prend du temps, mais ce qui prend certainement autant de temps est de trouver le nom juste pour chaque module. Décrire en un seul, maximum deux mots tout ce que chaque objet est censé faire, sans employer d’expression tarabiscotée est tout un art qui ne se plie pas à l’urgence. Autant tirer des traits entre des modules dont on connait le rôle peut se faire (relativement) rapidement, autant trouver leur description exacte et leur véritable lien ne se fait qu’avec le temps de la réflexion au fil des jours, voire des semaines. Mais quoi qu’il en soit, je recommanderai ici de garder les choses aussi simples que possible, partir dans des diagrammes UML complexes tel qu’enseigné en école d’ingénieur me semble complètement inutile, et au final une grosse perte de temps. La vraie réflexion n’arrive que lorsqu’on commence à coder et qu’on se rend alors compte de certaines réalités et de la véritable nature de chaque objet.

Pour mieux organiser l’ensemble, j’ai catégorisé chacun de mes modules selon l’une de ces cinq catégories, que je pense universelles:

-Les “primitives”: classes/structures très simples, ne contenant qu’une donnée unique (matrice, vecteur, zone rectangulaire…) et quelques opérations simples pour agir dessus et les combiner. Un header suffit à les définir intégralement.
-Les “entités”: classes contenant des données plus complexes (une piste audio par exemple, avec ses caractéristiques, ou des buffers de calcul complexes), et dont le nombre est variable pendant une session.
-Les “applicatives”: classes qui n’ont de sens qu’au sein de ce logiciel spécifiquement, et dont le nombre est généralement fixe au cours d’une session. Elles organisent tout le fonctionnement du programme et de l’interface en se servant des autres types de classes.
-Les “interfaces”: des classes dont l’unique but est d’être un intermédiaire de communication, entre classe d’un même programme, ou entre un programme et ses plugins par exemple. On dérive généralement de ces classes dans plusieurs classes entités ou applicatives.
-Les “utilitaires”: prend le plus souvent la forme de namespace que de classes, ne contiennent aucune données, ils ont un rôle purement moteur: ça peut être des opérations mathématiques, des routines qui prennent une info en entrée et en donne une autre en sortie, mais qui dans tous les cas n’ont aucun intérêt à stocker quelque état que ce soit.

Communication interne

Une fois la structure en place, il va falloir l’irriguer; c’est à dire faire communiquer les différentes classes entre-elles, pas n’importe comment ni dans n’importe quel ordre !
Il y a plusieurs écoles à ce niveau, pour ma part j’ai opté pour le système suivant, conseillé par skaven, qui m’a semblé à la fois élégant, robuste et sécurisé :

Pour l’irrigation générale de l’application, j’ai une classe d’interface IEvent qui se charge de passer tous les principaux évènements globaux (format de projet, liste des calques, mouvements de souris…) aux classes principales du projet (qui dérivent de IEvent). Libre à chaque classe de faire une copie locale de ces nouvelles informations, le tout se propage progressivement dans toute l’application, mais chaque objet s’auto-gère de manière indépendante et renvoit d’autres évènements si besoin (la classe IEvent gérant un système de queue). Avec ce système, je peux débrancher n’importe quel objet et l’application continuera de fonctionner (de manière incomplète bien sur). Pas de synchronisation à gérer.

Qt propose également un système Signal/Slot qui permet de connecter directement à la volée différents objets entre eux. J’ai réservé cet usage à la connection des objets Qt au reste de mon application, pour communiquer entre threads de manière asynchrone, et pour que certains objets enfants puissent communiquer certains changement d’état à leur parent sans connaissance préalable de leur parent.

Enfin l’accès direct aux méthodes a été réservé pour la communication avec les entités (voire définition plus haut), cas d’accès le plus fréquent. Pas de mise en place, pas de perte de temps niveau exécution.

Factoriser le code…

Une fois le travail de structuration, de catégorisation et d’irrigation bien définie, il va falloir factoriser un maximum de code. Pour la clarté, la concision (on code plus vite et on maintient ce code plus facilement) et (en partie) pour l’optimisation. Mais encore une fois pas n’importe quoi, n’importe comment, ni n’importe où… Sous peine d’obtenir l’effet inverse. Il faut bien identifier les taches, les objets ou les bouts de code qui sont susceptibles de se répéter de nombreuses fois au moment de l’écriture de l’application, et dans ses futurs développements.
Quelques techniques C++ pour pousser la factorisation:

-L’héritage/Le polymorphisme/héritage multiple: grande force du C++, mais à utiliser avec précaution (il ne s’agit pas d’empiler les niveaux d’héritages au risque de rendre le code incompréhensible), son utilisation judicieuse peut créer d’élégantes structures aux possibilités décuplées. Savoir comment ou sur quoi l’utiliser sera à déterminer en amont en même temps que la structure générale du programme et de la classification des objets.

-Les macros: on y pense pas forcément, mais on peut factoriser et simplifier énormément de code répétitif via les macros. Certes, cela à l’effet pervers de cacher le code réel, mais ça peut s’avérer être de redoutables outils pour créer presque un nouveau language propre à l’application. Bien identifier les quelques blocs de codes qui vont se répéter énormément au cours de l’application, et bien trier entre ceux qui relèvent d’une nouvelle fonction et ceux qui relèvent de la macro.

Le framework Qt fait un large usage de ces deux concepts, et c’est en partie ce qui fait son élégance. Cette approche a permit de grandement réduire la complexité du code de SpectraLayers 3 vs SpectraLayers 2, et malgré le plus grand nombre de features le nombre de lignes de code reste similaire; il est répartie sur beaucoup plus d’objets spécifiques. Le nombre de commentaires a également été divisé par deux, ce que j’attribue au fait que le code est naturellement plus facile à suivre.

graph
text(statistiques SourceMonitor)

…Et factoriser les calculs

L’optimisation de la vitesse d’exécution d’un programme ne repose pas que sur la concision des algorithmes qui le composent; avec le recul je me suis aperçu que l’exploitation optimale des techniques et contraintes hardware et la vérification minutieuse de la vitesse d’exécution de chaque élément de la chaîne logicielle comptait tout autant.

Ainsi, il ne suffit pas de lancer aléatoirement plein de threads de calculs divers pour exploiter au mieux les cœurs d’un CPU. La meilleure technique (et le gain est réellement notable) est de subdiviser au maximum les calculs en sous-calculs indépendant, jusqu’à obtenir de petites unités qui prennent très peu de temps d’exécution (par rapport à l’ensemble de la tâche), lancer autant de threads “exécuteurs” que de cœurs sur le CPU, et assigner cette liste de micro-calculs à ces threads qui vont tourner en permanence. Je compare ces micro-calculs à des grains de sable qui vont remplir de manière optimale la capacité d’exécution de chaque cœur CPU. Il faut également savoir qu’arrêter et relancer un thread est coûteux, il vaut mieux donc avoir des threads dédiés prêt à prendre une tache dès que nécessaire.

Toujours dans l’idée d’exploiter au mieux les capacités des CPU, il ne faut pas négliger les instructions vectorielles, car depuis le lancement du Pentium MMX celles-ci n’ont pas arrêté d’évoluer en parallèle de la montée en puissance et en cœurs. Les instructions vectorielles sont comme autant de sous-cœurs par cœur, capables d’effectuer en parallèle et de manière synchronisés plusieurs opérations élémentaires.
Ainsi, si le MMX se limitait à 2 opérations sur des nombres entier (int32), le SSE a apporté 4 opérations sur des nombres flottants (float32), l’AVX double ça, et le future AVX-512 le redouble encore.
Du coup une application correctement optimisée pour les derniers CPUs est capable d’effectuer 8 coeurs x 8 composants par vecteur = 64 opérations en parallèle !
Même si le gain réel n’atteint pas 64, il reste néanmoins important par rapport à un algorithme non pensée multi-thread/vectoriel. Un facteur à ne pas négliger donc.

Pour en finir avec les CPU, un point sur le gain réel entre 32bits et 64bits : si il est vrai que certaines opérations sont légèrement plus optimisés en 64bits qu’en 32bits, car bâtis sur un jeu d’instruction plus moderne, le gain est néanmoins difficilement mesurable (toutes les opérations ne sont pas systématiquement plus rapides, et un calcul est un ensemble d’opérations très divers). En revanche, pouvoir s’affranchir de la barrière mémoire 32bit offre des possibilités d’architecture nouvelles et bien plus optimisés en terme de vitesse d’accès. Des opérations qui devaient se limiter à des buffers de tailles bien délimités sous peine de crash peuvent maintenant demander allègrement toute la place qu’elles désirent, et à charge de l’OS de répartir au mieux en fonction des capacités hardware réelles. Des concepts comme le mapping mémoire de fichiers (faire correspondre le contenu d’un fichier à un emplacement mémoire) prend alors tout son sens, puisque même les gros fichiers pourront trouver leur équivalent en RAM dans la plupart des cas, accélérant ainsi d’autant plus la vitesse de traitement des données.

Quand au GPU, si son utilisation semble évidente dans le contexte d’un jeu vidéo, c’est bien moins souvent le cas dans un cadre professionnel (en dehors des logiciels de 3D, et bien que cela se généralise petit à petit au sein des applications de montage et de traitement d’image). Ainsi dans le domaine de l’audio, l’utilisation des GPU est quasi-inexistante. Mais au vu de la particularité de mon application (éditeur spectral multi-couches tridimensionnel) il me semblait essentiel de l’intégrer dans les optimisations. Il a fallut alors composer en connaissance de cause du marché, peu fournis en GPU “gamer”, en ne posant qu’un pré-requis OpenGL 3 (ce que toutes les machines sont heureusement capables de fournir maintenant), et l’utiliser uniquement là où il s’avère le plus efficace, c’est à dire en tant qu’accélérateur graphique 2D/3D.

Enfin, last but not least, il est important de penser la chaîne d’exécution d’un calcul dans son ensemble, de ce qui l’a déclenché jusqu’à l’affichage du résultat final. On a tendance à se focaliser sur le calcul lui-même mais en réalité c’est l’ensemble de la chaîne qui compte, et en particulier son maillon le plus faible. Si un calcul est très rapidement exécuté mais que le composant qui envois les ordres ou qui affichera le résultat n’est pas prévu pour un rafraîchissement aussi rapide, c’est toute la chaîne qui est impacté !
Ainsi, j’ai déjà vu une simple boite de texte standard ralentir l’ensemble de mon programme. Pour les mêmes raisons, j’ai désactivé d’emblée le vertical refresh de mon application, et l’affichage de certains éléments ne sont que partiellement recalculés.

L’ensemble de ces optimisations a conduit à un boost perf de x5 entre SL2 et SL3:
bench

Une touche de modernisme

Les outils et le hardware évoluant constamment, il est important de continuer à s’adapter aux changements. Voici quelques points que j’ai pu intégrer en codant la nouvelle version:

-Auto-vectorization: les compilateurs de VS2013 et XCode 5 sont maintenant capables d’auto-vectoriser certains calculs (voir le point sur l’optimisation plus haut). Même si en pratique il vaut mieux vectoriser les calculs cruciaux soit-même en connaissance de cause, il est appréciable de pouvoir laisser la main au compilateur sur les tâches annexes.

-C++11: là aussi une nouveauté apportée par VS2013/XCode 5, quelques facilités sont très appréciables, en particulier les fonctions lambdas (aussi appelés fonctions anonymes), qui permettent d’optimiser grandement son code pour des micro-tâches temporaires. Elles se marient particulièrement bien avec le système de signal de Qt.
La possibilité d’utiliser des <> imbriqués et de déclarer des listes directement à l’initialisation sont aussi des détails qui m’ont simplifié le boulot et rendu le code plus élégant.

-Le support High-DPI et Touch: Il s’agit la d’évolutions hardwares quasi-simultanés, qui en plus du marché mobile trouvent écho aussi bien sur Mac (Rétina, TrackPad) que sur Windows (High-DPI, Touchscreen). Le support High-DPI devient de plus en plus indispensable, à minima pour s’assurer que le logiciel est bien compatible (c’est à dire que l’OS se charge bien d’upscaler correctement l’application, au risque de se retrouver avec des fenêtres et icônes minuscules, le programme considérent que le device pixel ratio est toujous de 1), au mieux pour en profiter au maximum avec des graphismes haute-résolution. Quand au support touch, il apporte un plus indéniable pour naviguer au sein d’un projet, le contrôle étant beaucoup plus intuitif et précis.

Quality Assurance

Étape finale du développement, indispensable dès que le logiciel fait une certaine taille ou doit être utilisé dans des environnements/situations critiques. Le récent scandale des sorties Ubisoft est clairement le résultat d’une défaillance à cette étape (sans doute plus du à la direction qui a décidé de passer outre qu’à l’incompétence des testeurs et ingénieurs, ceci dit).
Le QA ne se limite d’ailleurs pas à la recherche de bugs, il peut également apporter des suggestions sur des comportements qui peuvent sembler étrange ou peu intuitifs.
L’expérience m’a néanmoins montré que le seul département QA ne peut trouver tous les bugs, ils ont leurs techniques pour en débusquer (beaucoup), mais multiplier les sources de test externes permet aussi d’avoir autant de regards neufs avec autant de configurations exotiques. Je rajoute donc généralement quelques testeurs supplémentaires externes en plus de l’équipe de base.
Allouer environ un mois à cette étape pour avoir assez de recul semble indispensable, quelle que soit la qualité du code il survient toujours quelque chose à cette étape, et ce jusqu’à la dernière minute. Foutue loi de Murphy.
Quoi qu’il en soit, le travail abattus à ce moment là est autant de travail de support en moins une fois le logiciel sortie.

Release

La version 3 vient de sortir aujourd’hui, ceux qui ont connus les versions 1 et 2 pourront donc se faire une idée par eux-même. Je suis plutôt content du résultat final, et j’espère que le logiciel est maintenant plus abordable d’utilisation :)

SpectraLayers Pro 3

20 commentaires pour “Carnet de notes de développement”

  1. Darkstryder dit :

    Excellent article, tant dans le fond que la forme !

  2. Nioub dit :

    Champagne !

    Article très instructif.

  3. MrHelmut dit :

    Bien ouej’ pour la release ! Article bien intéressant. :)

    Je me suis aussi passé de versionning pendant longtemps. Avec des petits projets et des équipes de 2 à 3 personnes, on s’est largement contenté d’un sync google drive. Les projets et les plateformes se multipliant, j’ai fini par tout mettre sur Git sur un serveur privé avec raid redondant (histoire d’échappé aux EULA des services d’hosting de code ou fichiers). Avec l’intégration Git de Visual Studio 2013, c’est un vrai bonheur.

  4. epsylon dit :

    “Pouce vert” pour cet article et félicitations pour la release !

  5. Sir_carma dit :

    GG mon pote !

  6. neFAST dit :

    Super article, tu peux détailler la charge de boulot et les avantages qu’a représenté le passage à Qt5 ?
    Quant à VS Express, quelles sont les limitations par rapport à la version payante ? Il n’y a rien de vital qui manque ?

  7. Gama dit :

    Félicitations ! Je me demande encore comment t’as fait pour les premières versions, honnêtement.

    J’ai plein de questions sur ton process :
    Comment tu faisais pour le multi-plateforme, t’avais un système de build automatique ? Tu faisais tout à la main avec des va-et-vient ?
    T’as utilisé un profiler particulier ?
    À quand les ondelettes ?!

    neFAST: La version Express n’a pas de plugin, c’est tout.

  8. divide dit :

    Merci !

    @neFAST: En réalité le passage à Qt 5.x s’est fait avec SL2, et ça s’est fait sans trop de difficulté. J’ai du changer des trucs, mais pas tant que ça. Le portage de Qt 5.0 vers Qt 5.2 et Qt 5.4 a été encore plus aisé. La nouvelle classe QOpenGLWidget m’a beaucoup aidé.
    Par rapport à VS Express, tous les trucs vitaux sont présents comme le souligne Gama, MS a enfin rajouté le compilateur 64bit (depuis VS Express 2012) et la license est utilisable même sur des projets commerciaux. Quand à l’IDE VS en réalité je ne le vois jamais, tout mon projet est géré sous Qt Creator (l’IDE multiplateforme de Qt), qui fait appel au compilateur de VS.

    @Gama: Je me demande aussi.
    Tout mon projet est géré sous Windows, car en réalité… je n’ai pas de mac chez moi.
    J’ai par contre des images virtuelles OSX, que j’invoque pour tester et compiler les builds mac. Mais 90% du temps, je suis sous Windows. Pas de profiler, par contre j’ai un partenariat avec Intel, qui me fournit des machines et leur expertise niveau perfs (pour que SL tourne au mieux sur le hardware Intel).
    SL a une approche dynamique de la résolution spectrale (fenêtrage changeable à la volée) donc les ondelettes ne sont pas aussi importantes dans ce contexte qu’elle peuvent l’être sur des analyses statiques… enfin, je crois !

  9. Gama dit :

    Merci pour les détails ! Plus de précisions sur les VM OSX ? Ça m’intéresserait énormément, j’avais eu des gros problèmes de stabilité pour développer sous Mac sans Mac.

    Je vais peut-être en profiter pour faire du lobbying à mon taf pour avoir une licence, tiens…

  10. MrHelmut dit :

    Si c’est juste pour s’en servir comme compilateur C/C++, VS Express est, a priori, largement suffisant.
    La version complète de l’IDE a beaucoup de fonctionnalités en plus en terme d’ergonomie et d’intégration avec d’autres soft (avoir la liste des commits et contributeurs git relatifs à une ligne de code sur un simple hover, ca a quelque chose de magique). Les debuggeur et profiler sont beaucoup mieux (la version express ne permet même pas de faire des arrêts conditionnels et je crois que le profiler n’est même pas présent).
    La différence de fonctionnalités est surtout notable vis-à-vis de tout ce qui touche à .Net (hors C/C++ donc).

    Je suis aussi curieux pour les VM OSX. ^^ J’ai du prendre un Mac Mini rien que pour faire les builds Mac/iOS. On m’a toujours dit qu’XCode chouinait en VM (surtout pour le déploiement iOS).

  11. Nioub dit :

    Gama a dit :
    À quand les ondelettes ?!

    Quand on applique la transformée de Fourier sur un signal audio, on obtient une représentation de ce signal dans une base différente : on passe de l’amplitude par unité de temps à la puissance répartie par fréquence. Un utilisateur peut comprendre cette représentation et la manipuler, c’est la base même de SpectraLayers.
    Par contre, la transformée par ondelettes obtient une représentation dans une autre base qui n’est pas intelligible pour l’utilisateur. C’est mieux que Fourier pour compresser, mais pas pour manipuler la représentation audio.
    Donc je doute que SpectraLayers proposera les ondelettes, à moins d’une avancée scientifique majeure.

  12. skaven dit :

    Nice!
    Beau boulot! Et je suis content d’y avoir participé un tout petit peu :D

  13. divide dit :

    Concernant les VM OSX elles émulent assez fidèlement un vrai OSX, aucun problème pour utiliser XCode (bien que comme dans le cas de VS, je ne l’utilise que pour son compilateur). Les seules restrictions sont:
    -vitesse d’exécution un peu plus lente (mais pas rédhibitoire, il est tout a fait possible de coder normalement sur une VM).
    -pas de support hardware de l’OpenGL (OSX switch sur la version software).
    -pas possibilité (à ma connaissance) de tester correctement des spécificités hardware Apple (genre trackpad, magic mouse).
    -Yosemite (OSX 10.10) a encore du mal a être émulé a bonne vitesse.
    Je passe par VMWare, il faut juste bien penser à avoir assez de RAM et d’espace disque libre pour que la machine puisse prendre ses aises.

  14. ecaheti dit :

    Tu es magique, félicitations !

  15. Conradson dit :

    Merci pour ce retour d’expérience.

  16. jiminy-billy-bob dit :

    Super intéressant, comme d’hab.

    Et bravo pour la v3 ! :)

  17. eilgin dit :

    Bravo pour la qualité pro. du logiciel !
    Et dire que tu es le seul dév., je suis impressionné.

  18. Nomys_Tempar dit :

    Très intéressant, et qui confirme des tas de trucs qu’on expérimente avec un collègue développeur.

    Toujours pas de version gnu/linux ? Je veux bien tester les build si c’est ça le problème…

  19. divide dit :

    Toujours pas de version gnu/linux, mais c’est une histoire de marché: ceux qui achètent des softs audio pro sont majoritairement sur Mac et Windows.
    Après comme je commence à étudier d’autres pistes plus scientifiques, qui sait…

  20. Nomys_Tempar dit :

    Je croise les doigts alors :)

Laisser un commentaire

Si vous avez un compte sur WeFrag, connectez-vous pour publier un commentaire.

Vous pouvez, entre autres, utiliser les tags XHTML suivant :
<a href="" title="">...</a>,<b>...</b>,<blockquote cite="">...</blockquote>,<code>...</code>,<i>...</i>