Pytanie Zapisz audio na dysk z urządzenia IO


Przepisanie tego pytania jest nieco bardziej udane.

Mój problem polega na tym, że nie mogę pomyślnie zapisać pliku audio na dysk ze zdalnego urządzenia IO.

Kroki, które podjąłem, były

Otwórz plik mp3 i wypakuj jego dźwięk do buforów. Skonfigurowałem asbd do użycia z moim wykresem w oparciu o właściwości wykresu. Ustawiam i uruchamiałem mój wykres, wygaszając wyodrębniony dźwięk, a dźwięk z powodzeniem wychodzi z głośnika!

Z czym mam problem to pobieranie próbek audio ze zdalnego wywołania zwrotnego IO i zapisywanie ich w pliku audio na dysku, dla którego używam ExtAudioFileWriteASync.

Plik audio jest zapisywany i nosi pewne podobieństwo do oryginalnego pliku mp3, ale brzmi bardzo zniekształcone.

Nie jestem pewien, czy problem jest

A) ExtAudioFileWriteAsync nie zapisuje próbek tak szybko, jak zapewnia je wywołanie zwrotne urządzenia io.

  • lub -

B) Skonfigurowałem ASBD na niewłaściwą refuelię. Chciałem zacząć od zapisania pliku WAV. Nie jestem pewien, czy opisałem to poprawnie w poniższej ASBD.

Po drugie nie jestem pewien, jaką wartość należy przekazać dla właściwości inChannelLayout podczas tworzenia pliku audio.

I w końcu jestem bardzo niepewny co do tego, jak używać do KExtAudioFileProperty_ClientDataFormat. Używałem mojego formatu strumieniowego stereo, ale bliższe przyjrzenie się dokumentom mówi, że musi to być pcm. Czy powinien to być ten sam format, co wyjście do zdalnego sterowania? A jeśli tak, to źle jest ustawić format wyjściowy zdalnej pamięci na stereostreamformat?

Zdaję sobie sprawę, że w tym pytaniu jest dużo i dużo, ale mam wiele niepewności, których nie mogę wyjaśnić sam.

ustaw format strumienia stereo

- (void) setupStereoStreamFormat
{

    size_t bytesPerSample = sizeof (AudioUnitSampleType);
    stereoStreamFormat.mFormatID          = kAudioFormatLinearPCM;
    stereoStreamFormat.mFormatFlags       = kAudioFormatFlagsAudioUnitCanonical;
    stereoStreamFormat.mBytesPerPacket    = bytesPerSample;
    stereoStreamFormat.mFramesPerPacket   = 1;
    stereoStreamFormat.mBytesPerFrame     = bytesPerSample;
    stereoStreamFormat.mChannelsPerFrame  = 2;                    // 2 indicates stereo
    stereoStreamFormat.mBitsPerChannel    = 8 * bytesPerSample;
    stereoStreamFormat.mSampleRate        = engineDescribtion.samplerate;

    NSLog (@"The stereo stereo format :");


}

konfiguruj oddzwanianie za pomocą strumienia stereo

AudioUnitSetProperty(engineDescribtion.masterChannelMixerUnit, 
                             kAudioUnitProperty_StreamFormat, 
                             kAudioUnitScope_Output, 
                             masterChannelMixerUnitloop, 
                             &stereoStreamFormat, 
                             sizeof(stereoStreamFormat));

        AudioUnitSetProperty(engineDescribtion.masterChannelMixerUnit, 
                             kAudioUnitProperty_StreamFormat, 
                             kAudioUnitScope_Input, 
                             masterChannelMixerUnitloop, 
                             &stereoStreamFormat, 
                             sizeof(stereoStreamFormat));




static OSStatus masterChannelMixerUnitCallback(void *inRefCon, 
                              AudioUnitRenderActionFlags *ioActionFlags, 
                              const AudioTimeStamp *inTimeStamp, 
                              UInt32 inBusNumber, 
                              UInt32 inNumberFrames, 
                              AudioBufferList *ioData)

{

   // ref.equnit;
    //AudioUnitRender(engineDescribtion.channelMixers[inBusNumber], ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);
    Engine *engine= (Engine *) inRefCon;
    AudioUnitRender(engineDescribtion.equnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);

    if(engine->isrecording)
    {
        ExtAudioFileWriteAsync(engine->recordingfileref, inNumberFrames, ioData);

    }


    return 0;

}

** konfiguracja nagrań **

-(void)startrecording

{

    NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    destinationFilePath = [[NSString alloc] initWithFormat: @"%@/testrecording.wav", documentsDirectory];
    destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false);

    OSStatus status;

    // prepare a 16-bit int file format, sample channel count and sample rate
    AudioStreamBasicDescription dstFormat;
    dstFormat.mSampleRate=44100.0;
    dstFormat.mFormatID=kAudioFormatLinearPCM;
    dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
    dstFormat.mBytesPerPacket=4;
    dstFormat.mBytesPerFrame=4;
    dstFormat.mFramesPerPacket=1;
    dstFormat.mChannelsPerFrame=2;
    dstFormat.mBitsPerChannel=16;
    dstFormat.mReserved=0;

    // create the capture file
  status=  ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &dstFormat, NULL, kAudioFileFlags_EraseFile, &recordingfileref);
    CheckError( status ,"couldnt create audio file");
        // set the capture file's client format to be the canonical format from the queue
 status=ExtAudioFileSetProperty(recordingfileref, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &stereoStreamFormat);

    CheckError( status ,"couldnt set input format");

    ExtAudioFileSeek(recordingfileref, 0);
 isrecording=YES;

  // [documentsDirectory release];


}

edytuj 1

Naprawdę kłuję w ciemnościach tutaj, ale czy muszę używać konwertera audio, czy też kExtAudioFileProperty_ClientDataFormat się tym zajmie?

edytuj 2

Im dołączam 2 próbki audio. Pierwszym z nich jest oryginalny dźwięk, który Im pętli i próbuje skopiować. Drugi to nagrany dźwięk tej pętli. Mam nadzieję, że może dać komuś wskazówki, co się dzieje.

Oryginalny mp3

Problem z nagrywaniem mp3


10
2017-08-03 17:30


pochodzenie


Głupie pytanie, ale czy sprawdziłeś, czy sizeof (AudioUnitSampleType); zwraca ten sam rozmiar, do którego przypisujesz mBytesPerPacket? - Nik Reiman
Sprawdziłem dwukrotnie, aby się upewnić. Są one tej samej wielkości. - dubbeat
@dubbeat hv zrobiłeś to z nagrywaniem dźwięku - Aadil


Odpowiedzi:


Po kilku dniach łez i przeciągania włosów mam rozwiązanie.

W moim kodzie i innych przykładach widziałem extaudiofilewriteasync w wywołaniu zwrotnym dla jednostki zdalnej, jak to.

** wywołanie zwrotne remoteiounit **

static OSStatus masterChannelMixerUnitCallback(void *inRefCon, 
                              AudioUnitRenderActionFlags *ioActionFlags, 
                              const AudioTimeStamp *inTimeStamp, 
                              UInt32 inBusNumber, 
                              UInt32 inNumberFrames, 
                              AudioBufferList *ioData)

{


    AudioUnitRender(engineDescribtion.equnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);


    if(isrecording)
    {
        ExtAudioFileWriteAsync(engine->recordingfileref, inNumberFrames, ioData);


    }



    return 0;

}

W tym wywołaniu odbierającym dane audio z innego urządzenia audio, które stosuje eqs i miksuje dźwięk.

Usunąłem wywołanie extaudiofilewrasasync z wywołania zwrotnego remoteio do tego drugiego wywołania zwrotnego, które zdalne wywołuje i plik pomyślnie pisze!

*funkcja zwrotna equnits *

static OSStatus outputCallback(void *inRefCon, 
                               AudioUnitRenderActionFlags *ioActionFlags, 
                               const AudioTimeStamp *inTimeStamp, 
                               UInt32 inBusNumber, 
                               UInt32 inNumberFrames, 
                               AudioBufferList *ioData) {  


    AudioUnitRender(engineDescribtion.masterChannelMixerUnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);

   //process audio here    

    Engine *engine= (Engine *) inRefCon;


    OSStatus s;

    if(engine->isrecording)
    {
        s=ExtAudioFileWriteAsync(engine->recordingfileref, inNumberFrames, ioData);


    }


    return noErr;

}

W celu pełnego zrozumienia, dlaczego moje rozwiązanie zadziałało, ktoś mógłby mi wyjaśnić, dlaczego zapisywanie danych do pliku z listy błędów Iodata w pilocie powoduje zniekształcony dźwięk, ale zapisywanie danych jeszcze jeden krok w dół łańcucha skutkuje doskonałym dźwiękiem?


9
2017-08-05 16:08



Czy mógłbyś wyjaśnić swoje rozwiązanie? Stoję w obliczu tego samego problemu. Dane audio zapisane do pliku w wywołaniu zwrotnym są zniekształcone. W którym callbacku powinniśmy to zapisać? - Namratha
To naprawdę zależy od twojego AUGraph. Z doświadczenia wiem, że próba zapisu dźwięku na dysk z wyjściowego wywołania zwrotnego zdalnego (węzeł 0) często nie działa. Zamiast tego umieść go w wejściowym wywołaniu zwrotnym dla innego węzła. Jeśli napiszesz pełniejsze pytanie z kodem źródłowym, być może będę mógł Ci pomóc. - dubbeat