문제가 된다면 삭제하겠습니다-_-

전에 WireShark를 이용해서 알송패킷을 캡쳐했을 때 보면 특정주소의 WebService를 요청해서 가져오게 되어있었습니다. http://mudchobo.tomeii.com/tt/434

실제 전송하는 데이터는 MD5값인데, 이게 어떻게 생성되는지 몰라서 구글에서 검색을 하니 어떤 블로그에서 시도한 흔적을 발견했습니다. 거기에 있는 댓글에서 발견했습니다^^
http://dialup.egloos.com/152001

"MP3 파일의 경우 strChecksum 값은 ID3태그등을 제외한 순수 MP3 음악 데이터를 앞에서부터 163840 바이트 읽어서 MD5로 돌린 값입니다. " 라고 친절하게 답변이....-_-

그래서 이렇게 하니까 잘 되더라구요. 아래는 샘플 코드입니다.
필요한 라이브러리는 MD5생성해주는 corelib가 필요합니다.
http://code.google.com/p/as3corelib/
[code]<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    applicationComplete="applicationCompleteHandler()">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            import flash.text.engine.ContentElement;
            import mx.messaging.messages.HTTPRequestMessage;
            import mx.rpc.http.HTTPService;
            import com.adobe.crypto.MD5;
            private function applicationCompleteHandler():void
            {
                var fs:FileStream = new FileStream();
                fs.open(new File("C:/Users/mudchobo/Downloads/임재범 - 사랑이라서.mp3"), FileMode.READ);
                var fileSize:int = fs.bytesAvailable;
               
                for (var i:int = 0; i < 500000; i++)
                {
                    if (fs.bytesAvailable >= 3 && fs.readUTFBytes(3) == "ID3")
                    {
                        var sizeByte:ByteArray = new ByteArray();
                       
                        // ID3v2길이구하기
                        fs.position += 3;
                        fs.readBytes(sizeByte, 0, 4);
                        var id3Size:int = sizeByte[0] << 21 | sizeByte[1] << 14 | sizeByte[2] << 7 | sizeByte[3];
                        fs.position = id3Size + 10;
                        break;
                    }
                }
               
                // ID3태그 없는 경우
                if (i == 500000)
                {
                    fs.position = 0;
                }
               
                // 공백있는 ID3태그에 대한 처리
                for (i = 0; i < 50000; i++)
                {
                    if (fs.readUnsignedByte() == 255)
                    {
                        var a:int = fs.readUnsignedByte();
                        if ((a >> 5) == 7)
                        {
                            fs.position += -2;
                            break;
                        }
                    }
                }
               
                // 163840만큼 읽어서 md5생성
                var data:ByteArray = new ByteArray();
                fs.readBytes(data, 0, 163840);
                var md5:String = MD5.hashBytes(data);
               
                // 웹서비스 요청
                var httpService:HTTPService = new HTTPService();
                httpService.method = HTTPRequestMessage.POST_METHOD;
                httpService.contentType = "application/soap+xml";
                httpService.url = "http://lyrics.alsong.co.kr/alsongwebservice/service1.asmx";
                httpService.request = new XML('<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="ALSongWebServer/Service1Soap" xmlns:ns1="ALSongWebServer" xmlns:ns3="ALSongWebServer/Service1Soap12"><SOAP-ENV:Body><ns1:GetLyric5><ns1:stQuery><ns1:strChecksum>' + md5 + '</ns1:strChecksum><ns1:strVersion>2.0 beta2</ns1:strVersion><ns1:strMACAddress>ffffffffffff</ns1:strMACAddress><ns1:strIPAddress>255.255.255.0</ns1:strIPAddress></ns1:stQuery></ns1:GetLyric5></SOAP-ENV:Body></SOAP-ENV:Envelope>');
                httpService.addEventListener(ResultEvent.RESULT, resultHandler);
                httpService.addEventListener(FaultEvent.FAULT, faultHandler);
                httpService.send();
            }
           
            private function resultHandler(event:ResultEvent):void
            {
                trace("싱크가사 = " + event.result.Envelope.Body.GetLyric5Response.GetLyric5Result.strLyric);
            }
           
            private function faultHandler(event:FaultEvent):void
            {
                trace(event.toString());
            }
           
        ]]>
    </mx:Script>
</mx:WindowedApplication>
[/code]
여기서 알송가사에서 제공하는 웹서비스는 WebService인데, HTTPService로 요청한 이유는 wsdl문서가 어디있는지 못찾겠음 ㄷㄷ 그래서 그냥 httpservice로 xml통채로 넘겨버리니-_- 되더라구요 ^^
xml넘길 때 strCheckSum값만 md5구한걸로 넘기면 돼요^^

[code]싱크가사 = [00:00.00]하루 하루 그대만 보여서<br>[00:23.28]매일매일 눈을 가리고 살아<br>[00:31.34]그대 곁을 나조차도 모르게 머물며<br>[00:38.91]메마른 내 가슴이 그댈 잊어버리지 못한 이유는<br>[00:00.00]<br>[00:00.00]<br>[00:49.93]사랑이라서 사랑이라서<br>[00:56.06]두번다시 못볼 사랑이라서<br>[00:00.00]<br>[01:03.32]하늘이 하는 일 돌릴 수 없는 일<br>[01:11.39]이렇게 사는게 힘들면 그녈 보내줄텐데<br>[01:19.51]죽어서 보라고 그래서 보라고<br>[01:26.42]그때라도 사랑한 마음이 남아있게된다면<br>[01:34.53]그때쯤에<br>[00:00.00]<br>[01:42.93]어딜가도 그대만 보여서<br>[01:49.88]매일매일 나를 지우고 살아<br>[01:57.28]한순간도 바람처럼 떠날줄 모르고<br>[02:04.71]죽어도 내가슴이 그댈 떠나보내지 못한 이유는<br>[00:00.00]<br>[02:15.49]사랑이라서 사랑이라서<br>[02:23.68]가슴가득 맺힌 사랑이라서<br>[00:00.00]<br>[02:29.68]하늘이 하는 일 돌릴 수 없는 일<br>[02:37.81]이렇게 사는게 힘들면 그녈 보내줄텐데<br>[02:45.79]죽어서 보라고 그래서 보라고<br>[02:52.51]그때라도 사랑한 마음이 남아있게 된다면<br>[03:00.90]그때쯤에<br>[00:00.00]<br>[03:04.66]간절히 바랬어 너에게 가는일<br>[00:00.00]<br>[03:33.19]하늘이 하는 일 돌릴 수 없는 일<br>[03:41.80]이렇게 사는게 힘들면 그녈 보내줄텐데<br>[03:49.23]죽어서 보라고 그래서 보라고<br>[03:56.56]그때라도 사랑한 마음이 남아있게된다면<br>[04:04.29]그때쯤에<br>[/code]

PS. HTTPService에서 xml전송해서 하는 거 어떻게 하는지 몰랐는데, 그냥 httpservice에 있는 request객체에 xml을 생성해서 넣어주면 된다는....-_-

 
Posted by 머드초보
,
 
Flex ANT관련 자료는 지돌스타님이 자세히 써주셨기때문에 참고해주세요.
http://blog.jidolstar.com/505

mxmlc로 컴파일을 해본적이 없어서 작성하는데에 욕봤습니다.
우선 ANT에서 제공하는 태그들이 있는데요. 그걸 이용해서 하려고 하는데 잘 안돼서-_- 그냥 exec로 작성했습니다 ㅠㅠ

그냥 rsl을 사용하지 않은 프로젝트는 ant로 매우 쉽게 할 수 있는데, RSL을 사용하면 조금 복잡해집니다.

RSL로 사용할 Flex Library Project를 하나 만듭니다. 그리고 클래스나 MXML을 추가하게 되면 bin디렉토리에 *.swc파일이 생깁니다. 이걸이용해서 메인프로젝트에서 컴파일을 해야합니다. 또한 *.swc파일을 이용해서 optimizer된 *.swf를 만들어야합니다.
[code]<target name="optimizer">
    <unzip src="${SWC파일}" dest="${SWC파일을 풀어놓을 디렉토리}" />
    <exec executable="${optimizer.exe파일 경로}">
        <arg line="-input '${SWC파일 풀어놓은 디렉토리}/library.swf'" />
        <arg line="-output '{아웃풋할 파일명.swf}'" />
    </exec>
</target>[/code]
몰랐는데, SWC파일 풀면 library.swf가 나오는데, 그걸 optimizer.exe한 것이 Flex Builder에서 나오는 swf파일이랑 같은것이더라구요(알고보니 나만 몰랐던거....다 알고있었음!-_-)
이렇게 하면 swf파일이 만들어집니다.
그럼 메인프로젝트 컴파일 하려면 이런식으로 하면 됩니다.
[code]<target name="compile">
    <exec executable="${mxmlc.exe파일 경로}">
        <arg line="-verify-digests=false" />
        <arg line="-runtime-shared-library-path '${rsl swc파일경로}' '${rsl경로위치url}'" />
        <arg line="-o '${아웃풋 경로}'" />
        <arg line="'${소스mxml메인파일}'" />
    </exec>
</target>[/code]
compile하기전에 optimizer target을 depends해야함^^
아마 verify-digests는 properties에서 설정할 때 체크하는 그것일꺼에요. 음..저는 이런식으로 하니까 되더라구요-_- -runtime-shared-library-path에서 swc파일 경로랑 rsl경로위치url(나중에 파일을 올릴 때 해당 위치에 있어야할 url입니다)로 지정하니 되더군요. 이것때문에 고생을 좀 해서-_-
메인프로젝트에 SWC파일을 LIB로 사용한다면 이런식으로 해야하구요^^
[code]<arg line="-library-path+='${basedir}/libs/Mate_08_8_1.swc'" />[/code]
ftp올리는 것도 지돌스타님 블로그에 잘 정리 되어있음!
http://blog.jidolstar.com/506
이러면 원클릭 배포가 가능해짐-_- 귀차니즘을 위한 ANT임!-_-
 
Posted by 머드초보
,
 
ActionScript3가 제공하는 Sound클래스에서 구하는 재생시간은 구하는데 너무 오래걸립니다.
Sound객체를 생성에 Complete이벤트가 발생한 다음에야 재생시간을 구할 수 있습니다.
재생목록에 추가를 해서 그냥 간단히 재생시간을 보여줘야하는데, 100곡을 재생목록에 추가를 해버리면 AIR애플리케이션이 미친듯이 메모리를 잡아먹는 것을 볼 수 있습니다-_-;

그래서 찾아보니, mp3 Header정보를 이용해서 재생시간을 구할 수 있습니다.

재생시간 = 파일크기 * 8 / 비트레이트 로 구할 수 있습니다.
그러면 비트레이트만 구하면 되는데, 이건 MP3Header에서 찾을 수 있습니다.

MP3 BITRATE는 http://www.datavoyage.com/mpgscript/mpeghdr.htm에 의하면 MPEG버전, LAYER, Bitrate Index로 구할 수 있습니다. MP3는 각각 Frame별로 Header가 존재하는데, 거기서 위에 정보를 구할 수 있는 것 같습니다.

ID3v2태그가 있는 경우는 ID3v2태그 다음에 MP3Header가 나옵니다. 그렇다면 ID3v2태그의 길이를 구해서 그 다음부터 MP3Header를 찾아야 합니다. ID3v2태그는 길이가 가변적입니다.그래서 총길이를 알아야하는데, 총길이는 ID3v2태그 맨 앞에 나오는 10byte Header부분에서 구할 수 있습니다.

이 Header부분의 6byte~10byte까지가 ID3v2의 총 길이인데요. 여기의 값이 00 00 1F 76(00011111 01110110)이라면 각각 MSB를 제거하여 붙인 값이 총 길이가 된다더군요. 00111111110110 -> 4086byte.

우선 C#으로 구현해놓은 소스가 있습니다. 그것을 Actionscript3로 변환했습니다(구현하려니 힘들어서 ㅠ)
C#소스 -> http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=79

제가 변환한 AS3용 MP3Header클래스입니다. 제가 가지고 있는 MP3 대부분 테스트해봤는데 잘 되더라구요.
invalid-file

MP3Header클래스


사용법은 이렇게 쓰시면 됩니다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
    creationComplete="init()">
    <mx:Script>
        <![CDATA[
            import util.MP3Header;
            private function init():void
            {
                var mp3Header:MP3Header = new MP3Header();
                mp3Header.readMP3Information("D:/눈물이 글썽 - 서진영.MP3");
                trace("BITRATE = " + mp3Header.intBitRate);
                trace("Frequency = " + mp3Header.intFrequency);
                trace("Mode = " + mp3Header.strMode);
                trace("LengthFormatted = " + mp3Header.strLengthFormatted);
                trace("Length = " + mp3Header.intLength);
            }
        ]]>
    </mx:Script>   
</mx:WindowedApplication>
[/code]
[code]
BITRATE = 64
Frequency = 44100
Mode = Stereo
LengthFormatted = 04:00
Length = 240
[/code]

 
Posted by 머드초보
,
 
다...다른 방법을 검색해서 구했습니다-_-;
하지만, 이건 한글은 이제 잘 읽는 것 같은데......한자를 못 읽습니다-_-; 원래 안되는건가....-_-;

우선 ID3Parser 링크입니다. 매우 빠른 속도로 ID3데이터를 가져옵니다.
http://blog.ashier.com/2007/11/08/id3-parser/

여기서 한글을 읽을 수 있게 수정하는 부분이......
보면 ID3데이터를 추출해오는 부분이 있습니다.
거기서 한글로 추출할 수 있게 변경합니다.

[code]
private function parseFrames():void {
    var id:String = "";
    var size:uint = 0;
    if(fs.position <length) {
        try {
            id = fs.readUTFBytes(frameIdSize);
            size = fs.readUnsignedInt();
            if (version>= 3) {
                fs.readByte();
                fs.readByte();
            }
            if(id.match(regEx)) {
                var obj:Object = new Object();
                obj.encoding = fs.readByte();
                obj.text = fs.readUTFBytes(size - 1);
                frames[id] = obj;
            }
            parseFrames();
        }catch(e:Error) {}
    }
}
[/code]
이 부분이 있는데요. 한글을 읽어오는 readUTFBytes 부분을 바꿔줍니다.
[code]
//obj.text = fs.readUTFBytes(size - 1);
if (obj.encoding == "1")
{
    obj.text = StringUtil.trim(fs.readMultiByte(size - 1, "unicode"));
}
else
{
    obj.text = StringUtil.trim(fs.readMultiByte(size - 1, "EUC-KR"));
}
[/code]
보니까 obj.encoding이 1인 값은 unicode로 인코딩 된 것 같아요. obj.encoding이 0인 값은 EUC-KR로...
이렇게 하니까 잘 되네요....가끔 공백을 추출해오고 그래서 trim처리했습니다.

아래글은 ID3v1방식 추출 방법 및 ID3v2의 다른 추출 방식 입니다^^ 참고하세요~
http://mudchobo.tomeii.com/tt/356
 
Posted by 머드초보
,
 
그......sound객체를 이용해서 하는 것이라니라 직접 바이트로 읽어서-_-; 하는 법이 있더라구요.
우선 ID3v1태그는 음악내용 맨 뒤에 있습니다. 그래서 추출하기는 쉽습니다.

http://cafe.naver.com/flexcomponent.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=10087
flexcomponent에서 혀니님께서 작성하신 글입니다.

그 다음 ID3v2태그는 맨 앞에 있습니다. 또한 이것을 추출하는 방법이 만만치 않습니다-_-;
왜냐하면 이건 뭐 길이도 가변적이고, 태그가 복잡합니다-_-;
그래서 태그를 공부하는 것보다 누가 만들어 놓은 것을 찾는 게 더 빠를 듯하여.....-_-;
구글신님께 부탁드리니 잘 찾아주셨습니다 ^^

http://blog.benstucki.net/?id=3

이것을 그대로 사용하시면 한글이 깨집니다.
사용자 삽입 이미지

저 위에 소스를 다운 받아서 첫번째 ID3v1에서 사용한 방법을 사용합니다.
ID3Reader.as파일에 readTextFrame이라는 함수가 있는데요.
이게 텍스트를 읽어올 때 사용하는 함수인 것 같습니다.
[code]
//obj.text = bytes.readUTFBytes(size-1);
obj.text = bytes.readMultiByte(size-1, "EUC-KR");
[/code]
요렇게 바꿔줍니다-_-;
그런 다음에 실행하면 한글이 잘 나옵니다.
사용자 삽입 이미지
하지만........-_-;
기존에 Actionscript에서 제공하는 Sound클래스에서 추출하는 ID3에서 잘나오는 한글(즉 UTF-8로 인코딩 된 것)은 여기서 읽으면 잘 안나옵니다-_-; 이거 추출하는 프로그램 만드신 분이 잘못 만든건지 잘 모르겠는데요. 확인해봐야할 것 같네요 ㅠ

사용자 삽입 이미지
헉...-_-; 인코딩을 unicode로 바꾸니까 잘 나오네요. 기존에 Actionscript에서 잘 나오는 것은 unicode로 되어있어서 그런거였나요? ㅠ 더 확인해봐야겠습니다 ㅠ
이거 말고, 요아래 것으로 하면 잘 되네요.

ID3v2추출하는 다른 방법입니다.
http://mudchobo.tomeii.com/tt/357
 
Posted by 머드초보
,