본문 바로가기
ios 뽀개기/objective-c

ios objective c 코어오디오 다루기 2 - AudioStreamBasicDescription으로 다양한 주파수의 음원만들기

by 인생여희 2018. 11. 6.
반응형

 ios objective c 코어오디오 다루기 2 - AudioStreamBasicDescription으로 다양한 주파수의 음원만들기




#import <AudioToolbox/AudioToolbox.h>

#import <Foundation/Foundation.h>


#define SAMPLE_RATE 44100    // 초당 44,100 샘플이나 44.1kHz 샘플율

#define DURATION 5.0    //얼마나 많은 오디오의 초를 만들기를 원하는지

 //#define FILENAME_FORMAT @"%0.3f-square.aif"    // 삐익~~~  티비 신호 나갔을때 음

 #define FILENAME_FORMAT @"%0.3f-saw.aif"

//#define FILENAME_FORMAT @"%0.3f-sine.aif" //파일이름 넣기  //솔음으로 쭉~



int main(int argc, const char * argv[]){

    

    //인자값이 존재하지 않으면

    if(argc < 2)

    {

        printf("usage: catonefileGenerator n \n(where n is tone is Hz)");

        return -1;

    }

    

    //생성하길 원하는 음색 주파수의 보동소수점 수

    double hz =  atof(argv[1]);

    assert(hz > 0);

    

    NSLog(@"generating %f hz tone",hz);

     //파일에 대한 경로 생성

    NSString *fileName = [NSString stringWithFormat:FILENAME_FORMAT, hz];

    NSString *filePath = [[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent: fileName];

    NSURL *fileURL = [NSURL fileURLWithPath: filePath];

    NSLog (@"path: %@", fileURL);

    

    //오디오 파일을 만들기 위해서 파일이 포함하는 오디오의 설명을 제공

    //prepare the format

    //오디오 스트림의 가장 광범위한 특성정의: 얼마나 많은 채널을 가졌는지, 형식은 무엇인지 비트율 등등

    AudioStreamBasicDescription asbd;

    //무엇인가를 설정하기 전에 항상 0으로 초기화

    memset(&asbd, 0, sizeof(asbd));

    

    //파일에 작성할 데이터를 나타내기 위해서 AudioStreamBasicDescription의 개별 필드를 사용해야 한다.(여기서는 44100 데이터율을 가지는 하나의 채널 pcm인 스트림을 나타낸다.)

    //16비트 샘플을 사용하기 때문에 각 프레임은 2바이트가 됨

    asbd.mSampleRate = SAMPLE_RATE;

    asbd.mFormatID = kAudioFormatLinearPCM;

    asbd.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;

    asbd.mChannelsPerFrame = 1;

    asbd.mFramesPerPacket = 1;

    asbd.mBitsPerChannel = 16;

    asbd.mBytesPerFrame = 2;

    asbd.mBytesPerPacket = 2;

    

    //설정한 url에 작성할 준비가 된 AudioFileID를 만들라고 코어오디오에 요청

    AudioFileID audioFile;

    OSStatus audioErr = noErr;

    audioErr = AudioFileCreateWithURL((__bridge CFURLRef)fileURL, kAudioFileAIFFType, &asbd, kAudioFileFlags_EraseFile, &audioFile);

    

    

    assert(audioErr == noErr);

    

    //초당 sample_rate 샘플에서 소리의 duration 초에 얼마나 많은 샘플이 필요한지 계산한다.

    long maxSampleCount = SAMPLE_RATE * DURATION;

    //카운터 변수

    long sampleCount = 0;

    

    UInt32 bytesToWrite = 2;

    //얼마나 많은 샘플이 파장에 있는지 알아야 하기 때문에 파형을 만드는 샘플을 위한 값을 계산할 수 있다.

    double wavelengthInSamples = SAMPLE_RATE / hz;

    NSLog(@"wavelengthInSameple = %f", wavelengthInSamples);

    

    while (sampleCount < maxSampleCount) {

        for (int i = 0; i < wavelengthInSamples; i++) {

            

            

             // square wave

/*             SInt16 sample;

             if (i < wavelengthInSamples/2) {

             sample = CFSwapInt16HostToBig (SHRT_MAX);

             } else {

             sample = CFSwapInt16HostToBig (SHRT_MIN);

             }

             audioErr = AudioFileWriteBytes(audioFile,

             false,

             sampleCount*2,

             &bytesToWrite,

             &sample);

             assert (audioErr == noErr);

            sampleCount++ ;

   */

    

            

             // saw wave

            //인텔 cpu에서 구동된다, 따라서 cpu의 표현에서 빅엔디언으로 바이트를 변경. 이전 맥인 power pc 같은 빅엔디언 cpu에서도 동작한다.

             SInt16 sample = CFSwapInt16HostToBig (((i / wavelengthInSamples) * SHRT_MAX *2) -

             SHRT_MAX);

            //샘플을 계산한 값을 저장하기

             audioErr = AudioFileWriteBytes(audioFile,

             false,

             sampleCount*2,

             &bytesToWrite,

             &sample);

             assert (audioErr == noErr);

            //새로운 데이터를 파일의 증가된 위치에 작성

             sampleCount++;

             

             

            

            // sine wave

            /*

            SInt16 sample =  CFSwapInt16HostToBig((SInt16)SHRT_MAX * sin(2 * M_PI * (i/wavelengthInSamples)));

            audioErr = AudioFileWriteBytes(audioFile, false, sampleCount*2, &bytesToWrite, &sample);

            assert(audioErr == noErr);

            

             sampleCount++ ;

             */

        }

    }

    

    audioErr = AudioFileClose(audioFile);

    assert(audioErr == noErr);

    NSLog(@"wrote %ld samples " , sampleCount);

    


    

    return 0;

}



//출력

/*

 2018-11-06 16:49:33.249486+0900 2[1772:475724] generating 4545.000000 hz tone

 2018-11-06 16:49:33.250084+0900 2[1772:475724] path: file:///Users/service/Library/Developer/Xcode/DerivedData/2-ghsrtbjzgtcjceddqdfgtajtvyql/Build/Products/Debug/4545.000-saw.aif

 2018-11-06 16:49:33.250454+0900 2[1772:475724] wavelengthInSameple = 9.702970

 2018-11-06 16:49:34.043224+0900 2[1772:475724] wrote 220500 samples

 Program ended with exit code: 0

 해당 경로에 위에서 만든 톤의 파일이 만들어 진다.

 */



반응형

댓글