원문 주소
http://www.adobe.com/devnet/flash/articles/dynamic_sound_generation/

쓸데없는 설명이 너무 많아서 글을 조금 손질했습니다.


플래시 플레이어 10에서 소리 동적 생성하기
플래시 플레이어 10 배포판에는 동적 생성한 소리를 재생하기 위한 새로운 기능이 포함되었습니다. 플래시 플레이어 10 이전에, 플래시 플레이어에서 재생되는 모든 소리는 불러온 MP3 파일의 날 것 그대로인 정보가 기반이었습니다. 이제 불러온 소리의 자료를 수정할 수 있습니다.(수정한 소리를 재생도 할 수 있습니다) 아니면 MP3 파일을 불러오지 않고 소리 자료를 만들 수도 있고, 생성한 자료를 기반으로 소리를 재생할 수도 있습니다.

이 글에서는 플래시 플레이어에서 동적 생성한 소리를 사용하는 방법을 보여주는 두 견본 애플리케이션을 설명합니다.

견본 애플리케이션 DynamicSoundSample1은 소리의 음높이(진동수)를 조절합니다. 이 애플리케이션은 불러온 MP3 파일의 소리 자료를 바이트 배열로서 읽어서 소리 샘플sound sample 을 제거함으로써 출력할 소리 자료를 조절하여 음높이를 올립니다(삽화 1을 보세요). 슬라이더 컨트롤을 원하는 음높이 치우침 계수(100%에서 200% 사이)로 끌어 당기고 Play 버튼을 눌러보세요. 컴퓨터 스피커가 음소거 상태인지 확인하시고요.
바이트 배열 = ByteArray 인스턴스

[Flash] http://liverwort.tistory.com/attachment/cfile26.uf@155DD92D4AC7E4C84A79DC.swf


삽화 1. 견본 애플리케이션 DynamicSoundSample1


두 번째 견본 애플리케이션 DynamicSoundSample2은 글자를 국제 모스 부호로서 재생하기 위한 소리를 생성합니다. 이 애플리케이션은 소리 파형sound waveform 을 바이트 배열에 저장되는 소리 샘플로서 생성합니다. Sound 객체는 이 바이트 배열 자료를 이용해 소리를 생성합니다.(삽화 2를 보세요) 모스 부호로 변환하고픈 글자를 입력하고 Play 버튼을 눌러보세요.(컴퓨터 스피커가 음소거 상태인지 확인하시고요) 글자가 모스 부호로서 재생됩니다.

[Flash] http://liverwort.tistory.com/attachment/cfile30.uf@204E4F0F4AC7E571256332.swf


삽화 2. 견본 애플리케이션 DynamicSoundSample2


준비물
이 글의 플래시들을 제작하려면 다음 소프트웨어와 파일이 필요합니다.

플래시 플레이어 10
내려받기

플래시 CS4 전문가용
체험

구입

견본 파일
dynamic_sound_generation.zip (ZIP, 2 MB)

견본 파일 폴더에는 다음 파일들이 들었습니다.
· DynamicSoundSample1.fla: 첫 번째 견본 애플리케이션의 주(main) 플래시 CS4 파일
· DynamicSoundSample1.as: 첫 번째 견본 애플리케이션의 문서 클래스(document class)가 정의된 액션스크립트 파일
· test.mp3: 첫 번째 견본 애플리케이션에 쓰이는 MP3 음원
· SoundPitchShift.as: 조절된 음높이(진동수)로 소리를 재생하는 데 쓰는 SoundPitchShift 클래스가 정의된 액션스크립트 파일(com/adobe/flash/samples에 있습니다)
· DynamicSoundSample2.fla: 두 번째 견본 애플리케이션의 주 플래시 CS4 파일
· DynamicSoundSample2.as: 두 번째 견본 애플리케이션의 문서 클래스(document class)가 정의된 액션스크립트 파일
· MorseCode.as: 모스 부호 소리를 생성하는 데 쓰는 MorseCode 클래스가 정의된 액션스크립트 파일(com/adobe/flash/samples에 있습니다)

미리 필요한 지식
플래시로 일반적인 애플리케이션을 제작해봤어야 합니다.


동적 소리 생성 기초
플래시 플레이어 10에서는 MP3 자료를 싣지 않은 Sound 객체에서 play() 메서드를 호출할 수 있습니다. 그러면 Sound 객체는 주기적으로 sampleData 이벤트(타입이 SampleDataEvent인 객체)를 전달합니다. sampleData 이벤트에 대한 이벤트 처리자에서 Sound 객체의 소리 버퍼에 추가할 소리 샘플을 넣을 수 있습니다. 2048개에서 8192개 사이의 부동소수점 수 쌍을 포함하는 바이트 배열을 생성하여 소리 샘플을 넣습니다. 각 부동소수점 수 쌍은 소리 샘플을 나타냅니다. 한 수는 샘플의 왼쪽 채널의 진폭(-1.0에서 1.0 사이)을, 다른 수는 오른쪽 채널의 진폭을 나타냅니다. SampleDataEvent 객체에는 data 속성(타입은 ByteArray)이 있습니다. data 속성의 write~~ 메서드를 이용하여 샘플 자료가 담긴 바이트 배열을 장착하면 Sound 객체의 소리 버퍼에 추가됩니다.

플래시 플레이어 10에는 extract() 메서드가 새로 포함되며, 이 메서드는 Sound 클래스에 추가되었습니다. MP3 파일을 싣은 Sound 객체에서 이 메서드를 호출하여 소리 자료를 추출할 수 있습니다. 그 다음 소리 샘플을 조작한다거나 추가한다거나 제거하여 이 자료를 변경할 수 있으며, 동적 생성한 자료를 이용하는 다른 Sound 객체용으로도 쓸 수 있습니다.


DynamicSoundSample1 코드 이해하기
DynamicSoundSample1 애플리케이션은 MP3 소리 자료를 Sound 객체로 불러옵니다. 그리고 extract() 메서드를 사용하여 소리 자료를 ByteArray 객체에 탑재하고, 소리 자료를 수정해 소리의 음높이를 조절합니다. 그러면 두 번째 Sound 객체는 수정된 자료를 sampleData 이벤트를 이용해 재생합니다.

인터페이스 정의하기
DynamicSoundSample1은 이 애플리케이션의 문서 클래스입니다. 액션스크립트 3.0 애플리케이션의 문서 클래스는 MovieClip 클래스를 상속하는 클래스입니다. 문서 클래스는 애플리케이션의 최상위 수준의 기능성을 결정합니다. 플래시 CS4에서는 Publish Settings에서 SWF 애플리케이션의 문서 클래스를 설정할 수 있습니다. (File -> Publish Settings에서 Flash 탭을 선택하고 Script 펼침 메뉴 옆의 Settings 버튼을 누르세요.)

사용자 삽입 이미지
삽화 3. DynamicSoundSample1.FLA의 스테이지 구성

// DynamicSoundSample1 클래스의 생성자 메서드
public function DynamicSoundSample1() {
    sampleMP3 = new Sound();
    var urlReq:URLRequest = new URLRequest("test.mp3");
    sampleMP3.load(urlReq);
    sampleMP3.addEventListener(Event.COMPLETE, loaded);
    playButton.addEventListener(MouseEvent.CLICK, playSound);
}


음높이가 치우쳐진 소리 재생하기
// DynamicSoundSample1 클래스의 playSound() 메서드
public function playSound(event:Event):void {
    playButton.label = "Stop";
    playButton.removeEventListener(MouseEvent.CLICK, playSound);
    playButton.addEventListener(MouseEvent.CLICK, stopSound);
   
    soundPitchShift = new SoundPitchShift();
    soundPitchShift.play(sampleMP3, pitchShiftSlider.value / 100);
    pitchShiftSlider.addEventListener(SliderEvent.CHANGE, adjustPitch);
    soundPitchShift.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
}


DynamicSoundSample1 클래스에서는 볼 장 다 봤습니다. SoundPitchShift 클래스로 넘어갑니다.

// SoundPitchShift 클래스의 play() 메서드
public function play(srcSound:Sound, pitchShiftFactor:Number):void {
    this.srcSound = srcSound;
    this.pitchShiftFactor = pitchShiftFactor;
    position = 0;
   
    var morphedSound:Sound = new Sound(); // MP3 자료가 없는 Sound 객체...
    morphedSound.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleDataHandler);
    // ...인데 play()를 호출해버렸다! 이제 sampleData 이벤트 전달 시작.
    soundChannel = morphedSound.play();
    soundChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
}


// SoundPitchShift 클래스의 sampleDataHandler() 메서드
private function sampleDataHandler(event:SampleDataEvent):void {
    var bytes:ByteArray = new ByteArray();
    position += srcSound.extract(bytes, 4096, position);
    event.data.writeBytes(shiftBytes(bytes));
}


// SoundPitchShift 클래스의 shiftBytes() 메서드
private function shiftBytes(bytes:ByteArray):ByteArray {
    var skipCount:Number = 0;
    var skipRate:Number = 1 + (1 / (pitchShiftFactor - 1));
    var returnBytes:ByteArray = new ByteArray();
    bytes.position = 0;
    while(bytes.bytesAvailable > 0) {
        skipCount++;
        if (skipCount <= skipRate) {
            returnBytes.writeFloat(bytes.readFloat()); // 왼쪽 채널
            returnBytes.writeFloat(bytes.readFloat()); // 오른쪽 채널
        }else{
            // 한 샘플 건너뜁니다. (readFloat()은 네 바이트씩 뽑는 메서드입니다)
            bytes.position += 8;
            skipCount = skipCount - skipRate;
        }
    }
    return returnBytes;
}

skipRate는 음높이 치우침 계수(pitchShiftFactor 속성)에 기반합니다. 계수가 2.0이면 skipRate는 2.0이고 모든 둘째 소리 샘플이 제거됩니다. 계수가 1.5(3/2)면 skipRate는 3.0이고 모든 셋째 소리 샘플이 제거됩니다. 계수가 1.333(4/3)이면 skipRate는 4.0이고 모든 넷째 소리 샘플이 제거됩니다. 샘플을 제거하면 소리의 음높이(진동수)가 올라갑니다.
그런데 왜 샘플을 제거하면 진동수가 올라가는 건가요 '-'?

소리 중지하기
// SoundPitchShift 클래스의 soundCompleteHandler 메서드.
// 이건 soundChannel에 등록한 수신자라서 SoundPitchShift 객체 자신에다 이벤트를 다시 보냅니다.

private function soundCompleteHandler(event:Event):void {
   dispatchEvent(event);
}


// DynamicSoundSample1 클래스의 soundCompleteHandler() 메서드.
// 이건 SoundPitchShift 객체에 등록한 수신자입니다.

public function soundCompleteHandler(event:Event):void {
   playButton.label = "Play MP3";
   playButton.removeEventListener(MouseEvent.CLICK, stopSound);
   playButton.addEventListener(MouseEvent.CLICK, playSound);
}


// DynamicSoundSample1 클래스의 stopSound() 메서드.
public function stopSound(event:Event):void {
   soundPitchShift.stop();
}


어이없게도 원문에는 모스 부호 생성 애플리케이션을 설명하는 내용이 없습니다. 여기서 끝;

Posted by codeonwort
,