Problème avec un graph audio, le render fonctionne mais je n'ai pas le son!

HerveHerve Membre
juin 2014 modifié dans API UIKit #1

Bonjour,


 


Je crée un AudioUnit avec un RenderCallback. La fonction RenderCallback est bien appelée et génère les nombres désirés (vérification console) mais je n'ai pas le son. Pour un synthé, c'est embêtant!...


 


Sous MacOS, je créais un AUGraph avec des AUNode. D'après ce que j'ai pu lire sur Internet, j'ai fait cela :



NSLog(@SetAu);//appelé
NewAUGraph (&_graph);//non utilisé, mais je dois avoir tord!
AudioUnit defaultOutputUnit;//le synthé

//int enableIO = 1;

AudioComponentDescription cd;
cd.componentType = kAudioUnitType_Output;
cd.componentSubType = kAudioUnitSubType_RemoteIO;
cd.componentManufacturer = kAudioUnitManufacturer_Apple;
cd.componentFlags = 0;
cd.componentFlagsMask = 0;

AudioComponent comp = AudioComponentFindNext(NULL, &cd);
NSAssert(comp, @Can't find default output);
AudioComponentInstanceNew(comp, &defaultOutputUnit);

AURenderCallbackStruct input;
input.inputProc = MyAURenderCallback;//ma fonction RenderCallback
input.inputProcRefCon = (__bridge void *)(self);

AudioUnitSetProperty (defaultOutputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&input,
sizeof(input));

//AUGraphSetNodeInputCallback (_graph, _synthNode, 2, &input );

AudioStreamBasicDescription format = {
.mSampleRate = 44100.0,
.mBytesPerPacket = sizeof(int),
.mFramesPerPacket = 1,
.mBytesPerFrame = sizeof(int),
.mChannelsPerFrame = 2,
.mBitsPerChannel = 8 * sizeof(int),
.mReserved = 0,
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kAudioFormatFlagIsNonInterleaved//kAudioFormatFlagsAudioUnitCanonical,
//j'ai essayé les deux...
};

AudioUnitSetProperty(defaultOutputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&format,
sizeof(AudioStreamBasicDescription));
AudioUnitInitialize(defaultOutputUnit);

/*** 3 ***/
AudioOutputUnitStart (defaultOutputUnit);
NSLog(@SetAu post AudioOutputUnitStart);//est bien appelé

Selon vous, qu'est-ce que j'ai oublié? 


Réponses

  • HerveHerve Membre

    Je reviens vers vous parce que je ne vois pas encore la solution.


    En adaptant la méthode du livre "Learning Core Audio", j'ai fait ceci :



    AudioComponentDescription cd = {0};
    cd.componentType = kAudioUnitType_Output;
    cd.componentSubType = kAudioUnitSubType_RemoteIO;
    cd.componentManufacturer = kAudioUnitManufacturer_Apple;
    cd.componentFlags = 0;
    cd.componentFlagsMask = 0;

    AudioComponent comp = AudioComponentFindNext (NULL, &cd);
    if (comp == NULL) {
    printf ("can't get output unit");
    exit (-1);
    }
    AudioComponentInstanceNew(comp, &defaultOutputUnit);

    // register render callback
    input.inputProc = MyAURenderCallback;
    input.inputProcRefCon = (__bridge void *)(self); //sous MacOS, on met "self" directement,
    //mais cela marche, les méthodes de la classe sont bien appelées.

    AudioUnitSetProperty(defaultOutputUnit,
    kAudioUnitProperty_SetRenderCallback,
    kAudioUnitScope_Input,
    0,
    &input,
    sizeof(input));

    //ajouté par rapport à  la méthode du livre.
    //Le renderCallback ne marche que si ceci est ajouté, sinon il est ignoré
    AudioStreamBasicDescription format = {
    .mSampleRate = 44100.0,
    .mBytesPerPacket = sizeof(int),
    .mFramesPerPacket = 1,
    .mBytesPerFrame = sizeof(int), //??? ce doit être ça...
    .mChannelsPerFrame = 2, //2 pour avoir les deux canaux, sinon le out right ne marche pas.
    .mBitsPerChannel = 8 * sizeof(int),
    .mReserved = 0,
    .mFormatID = kAudioFormatLinearPCM, //bien sûr!
    .mFormatFlags = kAudioFormatFlagsAudioUnitCanonical, //le générique semble t-il.
    };

    AudioUnitSetProperty(defaultOutputUnit,
    kAudioUnitProperty_StreamFormat,
    kAudioUnitScope_Input,
    0,
    &format,
    sizeof(AudioStreamBasicDescription));
    //fin de l'ajout

    // initialize unit
    AudioUnitInitialize(defaultOutputUnit);

    AudioOutputUnitStart(defaultOutputUnit);

    Remarque : le problème vient peut-être de la définition de l'"AudioComponentDescription cd". Si je fais comme dans le livre :


    cd.componentType = kAudioUnitType_Output;


    cela ne marche pas alors que cela fonctionne très bien sous MacOS. (Le compilateur corrige en mettant kAudioUnitSubType_GenericOutput


    pour iOS, cela ne marche pas mieux!   :'(  )


    Il me faut faire 


    cd.componentSubType = kAudioUnitSubType_RemoteIO;


    Alors la fonction RenderCallback est appelée, mais le son ne sort pas (testé aussi avec l'iPad maintenant que j'ai souscrit au programme développeur iOS. Là  c'est le "pompon"! Cela a coincé le son de l'iPad (plus de son du tout pour l'ensemble des applis, j'ai dû l'éteindre et le rallumer...   ??? )


     


    Quelqu'un saurait comment régler correctement la sortie audio? Merci par avance!   ::) 


     


    remarque : Les valeurs produites par mon "Render" oscillent entre -1.0 et 1.0, parfois un peu plus, comme pour MacOS.


  • CéroceCéroce Membre, Modérateur
    juin 2014 modifié #3

    remarque : Les valeurs produites par mon "Render" oscillent entre -1.0 et 1.0, parfois un peu plus, comme pour MacOS.

    Je peux me tromper, mais il me semble qu'iOS n'accepte que les échantillons sur 16 bits non signés... Je dis ça de mémoire.
    D'ailleurs, ton code n'est pas cohérent avec une valeur flottante. Avec un float, tu as 32 bits/échantillon.

    Désolé, mais je n'ai pas mon code sous la main pour comparer au tien.
  • HerveHerve Membre
    juin 2014 modifié #4

    Merci Céroce. Je pense que le problème vient aussi de mon Render qui fonctionne bien sous MacOS mais pas là . 


     


    Je viens en effet d'essayer le générateur du livre (un oscillateur produisant une sinusoà¯de), "j'ai le son". Je vous dérange peut-être pour rien, le AUgraph est peut-être bon...


     


    Par contre j'ai un gros problème de saturation. Le sineOut est compris entre -1.0 et 1.0, cela sature beaucoup sur le simulateur. Ce qui est plus bizarre encore est que le volume ne baisse pas si je divise la valeur de sortie par un grand nombre. Normalement 



    Float32 outOScillo, out, volume;

    out = outOscillo*volume;//avec volume compris entre 0 et 1.0

    permet de contrôler le volume. Pas là !!


     


    Il me semble effectivement avoir lu que iOS code avec des int l'audio et non avec des float. Si quelqu'un a l'info??


     


    Je vous tiens au courant pour le reste. Merci.


  • HerveHerve Membre
    juin 2014 modifié #5

    Je confirme : j'ai un gros problème de saturation (énorme même!!) Mais j'ai le son.


    Sous MacOS, je faisais :



    AudioManager* def = inRefCon;
    AudioUnitSampleType *outL;
    AudioUnitSampleType *outR;
    outL = ioData->mBuffers[0].mData;
    outR = ioData->mBuffers[1].mData;

    for (int i = 0; i < inNumberFrames; i++){
    //calculs du synthé

    *outL++ = outGlobalL;
    *outR++ = outGlobalR;
    }

    Là , il m'a fallu faire :



    Float32 *outL; //Et oui, pas d'AudioSampleType, structure bien commode pourtant...
    Float32 *outR;
    outL = (Float32*)ioData->mBuffers[0].mData;
    outR = (Float32*)ioData->mBuffers[1].mData;

    //la boucle avec en sortie :

    outL[i] = outGlobalL * [def volume];
    outR[i] = outGlobalR * [def volume];
    }

    J'ai le son, mais le contrôle de volume est sans effet, et cela sature énormément.


     


    C'est étonnant que le "paquet de nombres" que sont les AudioUnitSampleType ne veulent pas fonctionner!!


  • CéroceCéroce Membre, Modérateur
    juin 2014 modifié #6
    Vraiment, regarde ta configuration. Là , tu lui dis que tes échantillons sont des entiers sur 16 bits, comment veux-tu que ça fonctionne si tu génères des floats ?
  • HerveHerve Membre

    Le problème est "par là " en effet. AudioSampleType qui renvoie à  un "SInt32" fait que je n'entends plus le son (même en multipliant ou divisant la valeur de sortie), tandis que "Float32" (qui est d'ailleurs une valeur pour l'audio dans CoreAudio, un autre "AudioSampleType" en fait) produit le son mais hyper saturé...


     


    Ah là  là !!


  • HerveHerve Membre

    Par "acquis de conscience", étant donné que un int sur 16 bits doit donner 65536 valeurs, j'ai essayé avec des "AudioSampleType", en multipliant le Float de sortie par différentes valeurs,  jusqu'à  30000 (genre out = floorf(leFloat)). Soit c'est le silence (le out ne fait que des 0), soit c'est toujours bruyant.


     


    Bon, résumons le problème (qui a changé par rapport à  l'intitulé...) Il me faut des SInt16 en sortie (iOS travaille avec cela) alors que mon code produit des Float32 (comme sous MacOS). Quelqu'un aurait-il la formule???


     


    Merci par avance!


  • CéroceCéroce Membre, Modérateur
    juin 2014 modifié #9
    Un Int16 contient des nombres allant de -2^15 à  2^15-1, soit -32768 à  +32767.
    Multiplie ton float par 32767 et tu as ta valeur sur 16 bits signés. (Il existe une constante SInt16Max, ou un nom comme ça).
  • HerveHerve Membre
    juin 2014 modifié #10

    Bonjour Céroce, et merci pour ta réponse (je réponds tardivement, j'ai eu autre chose à  faire ces derniers jours...)


     


    En fait, d'après le livre d'Adamson/Avila, les méthodes de iOS et MacOS sont tout de même très différentes. Je suis en train d'adapter leur code source, on est loin d'une simple conversion Float32>SInt16. Le problème est très au delà . Ce n'est pas la même architecture, tout simplement... 


     


    Modif : 


     


    problème en passe d'être résolu, le problème venait aussi du ASBD, que j'ai eu beaucoup de mal à  régler correctement.


     


     


     


    Merci beaucoup.


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