AIR로 사운드 재생이 가능한 것을 알았습니다-_-;
초초초초초간단한 MP3플레이어를 만들어봤습니다.
사운드 컨트롤하기 참 쉽게 되어있군요.
아래는 대략 소스입니다.
[code]
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute" width="400" height="300" viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
private var file:File = new File();
private var req:URLRequest;
private var sound:Sound;
private var channel:SoundChannel;
private var pausePosition:int;
public function findFile():void {
try {
file.addEventListener(Event.SELECT, selectFileHandler);
file.browse();
} catch (error:Error) {
Alert.show("파일열기 실패했습니다.");
}
}
public function selectFileHandler(event:Event):void {
if (channel != null) {
channel.stop();
}
sound = new Sound();
sound.addEventListener(Event.COMPLETE, onSoundLoaded);
sound.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
sound.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
pausePosition = 0;
textFileName.text = event.currentTarget.nativePath;
sound.load(new URLRequest(event.currentTarget.nativePath));
btnPlay.enabled = true;
}
public function onLoadProgress(event:ProgressEvent):void {
var loadedPct:Number = Math.round(100 * (event.bytesLoaded / event.bytesTotal));
trace("The sound is " + loadedPct + "% loaded.");
fileLoadingPB.setProgress(loadedPct, 100);
}
public function onSoundLoaded(event:Event):void {
var localSound:Sound = event.target as Sound;
textArtist.text = localSound.id3.artist;
textSongName.text = localSound.id3.songName;
}
public function onIOError(event:IOErrorEvent):void {
Alert.show("The sound could not be loaded: " + event.text);
trace("The sound could not be loaded: " + event.text);
}
public function btnPlayClickHandler(event:Event):void {
btnPlay.enabled = false;
btnStop.enabled = true;
channel = sound.play(pausePosition);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
channel.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
}
private function onEnterFrame(event:Event):void {
var estimatedLength:int =
Math.ceil(sound.length / (sound.bytesLoaded / sound.bytesTotal));
var playbackPercent:uint =
Math.round(100 * (channel.position / estimatedLength));
playPB.setProgress(playbackPercent, 100);
trace("Sound playback is " + playbackPercent + "% complete.");
}
private function onPlaybackComplete(event:Event):void {
btnPlay.enabled = false;
btnStop.enabled = false;
trace("The sound has finished playing.");
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function btnStopClickHandler(event:Event):void {
btnPlay.enabled = true;
btnStop.enabled = false;
pausePosition = channel.position;
channel.stop();
}
]]>
</mx:Script>
<mx:ProgressBar id="fileLoadingPB" x="125.5" y="160" mode="manual"/>
<mx:ProgressBar id="playPB" x="125.5" y="196" mode="manual" label="PLAYING %1%"/>
<mx:Label x="72.5" y="196" text="재생바" height="28" width="45" textAlign="right"/>
<mx:Label x="72.5" y="160" text="파일읽기" height="28" textAlign="right"/>
<mx:Label x="82.5" y="35" text="제목 :" width="44" textAlign="right"/>
<mx:Label x="82.5" y="61" text="가수명 :" textAlign="right"/>
<mx:Label x="82.5" y="87" text="파일명 :" textAlign="right"/>
<mx:Button id="btnPlay" x="91.5" y="248" label="플레이" click="btnPlayClickHandler(event);" enabled="false"/>
<mx:Button id="btnStop" x="158.5" y="248" label="일시정지" click="btnStopClickHandler(event);" enabled="false"/>
<mx:Button x="236.5" y="248" label="파일열기" click="findFile();"/>
<mx:Text id="textSongName" x="134.5" y="35" text="KHJ 바보" width="191"/>
<mx:Text id="textArtist" x="134.5" y="61" text="KHJ 돼지" width="191"/>
<mx:Text id="textFileName" x="134.5" y="87" text="KHJ 멍충이" width="191"/>
</mx:WindowedApplication>
[/code]
소스를 보면 그리 어렵지 않습니다.
Sound라는 클래스가 있습니다.
사운드객체를 하나 선언하고, 파일명으로 URLRequest를 이용해 객체를 생성해서 그걸 Sound객체의 load메소드를 통해서 로드를 한 다음에, play만 해주면됩니다.
게다가 이것저것 자체적으로 지원해주는게 많습니다. 일시정지를 할 수 있게 stop을 하기전에 channal이라는 클래스를 통해 현재 position을 얻어오면 stop한다음에 그 포지션으로부터 다시 시작할 수 있습니다.
재생완료시 이벤트를 추가할 수 있고, 파일이 로드될 때 이벤트 등의 이벤트를 지원하는군요.
PS. AIR로 MP3플레이어만들면 더 멋있을 것 같은데-_-;
'분류 전체보기'에 해당되는 글 547건
- 2008.04.21 [AIR/FLEX] 에어를 이용한 초초초초초간단 MP3플레이어-_-;
- 2008.04.18 [Springframework] 어노테이션(annotation)을 이용한 초간단 AOP예제-_-;
- 2008.04.17 [JAVA] log4j의 초간단 사용법 - 날짜별, 패키지(클래스)별, 파일생성 9
- 2008.04.16 [이클립스팁] 우연히 알아낸 페이지간에 탭 전환-_-; 6
- 2008.04.15 [Springframework] Properties 스프링어플리케이션에서 사용해봅시다.
정말 초간단예제군요-_-;
어노테이션을 사용하면 굉장히 편해져요.
저번주 스터디시간에 한 내용을-_-;
AOP를 적용하려면 인터페이스가 있어야 돼요.
Apple이라는 인터페이스를 만들어 봅시다.
com.mudchobo.example4라는 패키지에 Apple이라는 interface를 만듭시다.
Apple.java
[code]
package com.mudchobo.example4;
public interface Apple {
public void println();
}
[/code]
println이라는 메소드가 하나있네요. 구현해봅시다.
AppleImpl.java
[code]
package com.mudchobo.example4;
public class AppleImpl implements Apple {
@Override
public void println(){
System.out.println("Apple : 맛있다");
}
}
[/code]
사과는 맛있다 라는 메시지를 출력하는군요. 그럼 AOP....(갑자기 두리녀석이 전화를..-_-; 갑자기 2시간남겨놓고 술먹자고 전화하는 이상한놈이네요-_-;)
AOP 클래스를 만들어봅시다.
[code]
package com.mudchobo.example4;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AnnotLoggingAspect {
@Around("execution(public * com.mudchobo.example4.*.println*(..))")
public void logging(ProceedingJoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
try {
System.out.println("before : " + methodName);
joinPoint.proceed();
System.out.println("after : " + methodName);
} catch (Throwable e) {
System.out.println("예외가 발생했어요!");
}
}
}
[/code]
Around는 before, after, 예외 등을 다 포함하고 있죠. 그냥 메소드하나 구현하는거라고 보면 돼요.
execution은 AspectJ의 정규식을 넣으면 돼요. 문법은 검색 고고싱~--;
저건 맨앞에는 public, private정하는거고, 두번째는 리턴타입(*면 전부다겠죠?), 그다음은 패키지명 쓰고, (..)부분은 파라메터관련된 부분이죠. 검색고고싱~
저건 com.mudchobo.example4패키지에서 모든클래스중에 println으로 시작하는 메소드에 aop를 적용하겠다는 얘기에요. println메소드는 우리가 방금 구현한 Apple인터페이스에 있죠.
스프링 설정파일을 봅시다. 최상위 폴더에 applicationContext.xml파일로 지정합시다.
[code]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy />
<bean id="apple" class="com.mudchobo.example4.AppleImpl" />
<bean class="com.mudchobo.example4.AnnotLoggingAspect" />
</beans>
[/code]
자 보면, apple이라는 bean은 우리가 만든 사과클래스구요. aop클래스를 bean으로 해서 선언해주었어요.
만약 SpringIDE를 설치했다면 왼쪽에 보시면 aop가 어디에 또는 몇개 적용이 되어있는지 나와요.
그럼 메인클래스를 보도록 해요.
Main4.java
[code]
package com.mudchobo.example4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main4 {
public static void main(String[] args) {
String configLocation = "applicationContext.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
Apple apple = (Apple) context.getBean("apple");
apple.println();
}
}
[/code]
설정파일을 불러와서 ApplicationContext를 만들고, 거기서 apple이라는 bean을 불러옵니다.
그리고, apple.println()메소드를 호출하게 되면 aop가 적용되어 호출됩니다.
Apple : 맛있다
after : println
PS.회사프로그램에 스프링을 이용해서 AOP를 적용해보았는데요. 코드가 깔끔해지고, 참 좋은 것 같아요.
회사프로그램에서 예외처리하는 부분이 굉장히 많았는데 이것을 따로 빼서 하나로 합치니-_-; 코드가독성이 올라가네요. 암튼, 좀 더 배워봐야겠네요.
로그 찍는 거 별로 안좋아하는데 로그를 찍어보니까 더 좋은 것 같아요 ^^
게다가 log4j라는 매우 우수한 로그찍는 프로그램이 있습니다.
sysout에서 벗어나봅시다-_-; 습관적으로 sysout을-_-(System.out.println()......-_-)
우선 이클립스에서 프로젝트를 하나 만들어봅시다.
log4j를 받아봅시다.
http://logging.apache.org/log4j/1.2/download.html
1.2버전입니다. 받아서 log4j-1.2.15.jar파일을 라이브러리에 추가합시다.
log4j설정파일을 만들어봅시다.
최상위 폴더에다가 log4j.properties파일을 만듭시다.
[code]
# Log4j Setting file
log4j.rootLogger=INFO, console
# Daily file log
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File=D:/mudchobo/Log/glv.log
log4j.appender.logfile.DatePattern='.'yyyy-MM-dd
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=[%d{HH:mm:ss}][%-5p](%F:%L) - %m%n
# Console log
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%-5p %l - %m%n
# log level and appender
log4j.logger.com.mudchobo=DEBUG, console
log4j.logger.com.mudchobo.Test=INFO, logfile
[/code]
대략 내용을 살펴보면 log4j.rootLogger는 최상위 로거입니다.
모든 INFO레벨이상의 로그는 다 console로 찍겠다는 겁니다.
(레벨에는 DEBUG, INFO, WARN, ERROR, FATAL 순인데, 예를 들어 INFO레벨로 지정해두면 logger.debug로 찍는 로그는 나타나지 않습니다. INFO레벨 이상것만 나타납니다.)
console은 아래 #Console log쪽에 보시면
log4j.appender.console <- 요 이름입니다.
요 console은 자세히보면 ConsoleAppender라는 클래스입니다. 이건 말그대로 콘솔에 로그를 찍어준다는 겁니다. layout에는 PatternLayout을 지정할 수 있는데 저 패턴은 뭐 레벨이 뭐고, 클래스가 뭐고, 메시지찍고 뭐 그런 내용입니다. 검색 고고싱-_-;
그리고, 파일에다가 출력 할 수 있는데, DailyRollingFileAppender클래스를 이용합니다. 이눔은 말그대로 매일매일 다른로그를 사용하게 만듭니다. 로그이름이 위와 같이 glv.log라면, 해당로그가 어제날짜인데 로그를 찍으려고 하면 기존에 있던 파일은 glv.log.2008-04-17 이렇게 바꿔줍니다.
아래부분에 보면 log4j.logger. 다음에 패키지명이나 클래스명을 지정해놓고, 로그레벨과 출력할 로그를 지정할 수 있는데요. 해당 클래스나 패키지의 로그는 저걸로 찍겠다는 겁니다. Test클래스는 logfile로 찍힌다는 겁니다.
그리고, rootLogger가 colsole로 지정되어 있기 때문에 console에도 찍히겠죠? ^^
로그를 찍어봅시다.
TestLogging이라는 프로젝트 이름으로 만듭시다.
Test클래스를 만들어봅시다.
Test.java
[code]
package com.mudchobo;
import org.apache.log4j.Logger;
public class Test {
private Logger logger = Logger.getLogger(getClass());
public void println() {
logger.info("안녕하세요! Test입니다");
}
}
[/code]
Test2클래스를 만들어봅시다.
Test2.java
[code]
package com.mudchobo;
import org.apache.log4j.Logger;
public class Test2 {
private Logger logger = Logger.getLogger(getClass());
public void println() {
logger.info("안녕하세요! Test2입니다.");
}
}
[/code]
TestLogging클래스를 만들어봅시다. 메인을 만들어야합니다.
[code]
package com.mudchobo;
public class TestLogging {
public static void main(String[] args) {
Test test = new Test();
Test2 test2 = new Test2();
test.println();
test2.println();
}
}
[/code]
자 그럼 콘솔에는
INFO com.mudchobo.Test.println(Test.java:10) - 안녕하세요! Test입니다.
INFO com.mudchobo.Test.println(Test.java:10) - 안녕하세요! Test입니다.
INFO com.mudchobo.Test2.println(Test2.java:10) - 안녕하세요! Test2입니다.
INFO com.mudchobo.Test2.println(Test2.java:10) - 안녕하세요! Test2입니다.
이렇게 출력이 될 것이고 로그파일에는
[19:56:35][INFO ](Test.java:10) - 안녕하세요! Test입니다.
이것만 출력될 것입니다.
위에 콘솔에 두번 찍힌 이유는 Rootlogger도 찍고, 아래 패키지를 지정한 로그도 찍었기 때문이죠.
그리고, 파일에는 한번만 쓰여진 이유는 파일에 쓰는건
log4j.logger.com.mudchobo.Test=INFO, logfile 여기 이 Test클래스 하나죠-_-;
이상입니다-_-;
우연히 오늘 이클립스로 삽질을 하다가-_-; 컨트롤을 누르고 우연히 페이지다운을 클릭했더니-_-;
다음 페이지로 탭이 전환이 되는 겁니다!!!-_-;
컨트롤 누르고 페이지업하면 전 페이지로.....-_-;
Ctrl + Page Down, Ctrl + Page Up....
PS. 나만 몰랐나?-_-; 그냥 단축키를 전부 외울까-_-;
보통 어플리케이션에서 Properties를 사용하려면 Properties클래스를 사용해서...
Properties properties = new Properties();
properties.load(new FileInputStream("C:/~~~파일명경로");
String mudchobo = properties.getProperty("mudchobo");
이렇게 하면 풀경로를 다 적어줘야지 되더라구요.
이 파일이 클래스패스에 넣어두면 classpath:file.properties 하면 먹혔으면 좋겠는데 안먹히더라구요-_-;
그래서 스프링을 사용하면 클래스패스에 넣어도 할 수 있어요!(아놔 이렇게 하는거 맞나-_-)
properties패키지에 있는 file.properties파일을 불러올겁니다.
mudchobo=dwaeji
hermusseri=meongchungi
2개의 property가 있습니다.
우선 applicationContext.xml파일입니다.
[code]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="properties/file" />
<bean id="messageSourceAccessor"
class="org.springframework.context.support.MessageSourceAccessor">
<constructor-arg ref="messageSource" />
</bean>
</beans>
[/code]
잘 보면 messageSource라는 bean이 있는데 이것은 ResourceBundleMessageSource구요.
p:basename은 해당패키지에서 파일을 찾더라구요.
properties라는 패키지에 file.properties파일을 지정했습니다.
그다음 bean은 MessageSourceAccessor인데요. 말그대로 메시지소스를 접근하는 접근자라고 자신을 표현하고 있네요. 이것의 생성자로 해당 messageSource를 받는군요.
애플리케이션에서 봅시다.
[code]
package test;
import java.util.Locale;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.MessageSourceAccessor;
public class Test {
public static void main(String[] args) {
String[] configLocation = {"applicationContext.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(configLocation);
MessageSourceAccessor msAccessor =
(MessageSourceAccessor)context.getBean("messageSourceAccessor");
System.out.println(context.getMessage("mudchobo", null, Locale.getDefault()));
System.out.println(context.getMessage("hermusseri", null, Locale.getDefault()));
System.out.println(msAccessor.getMessage("mudchobo"));
System.out.println(msAccessor.getMessage("hermusseri"));
}
}
[/code]
MessageSourceAccessor를 선언해서 해당 bean을 가져옵니다.
그러면 MessageSourceAccessor를 통해서 Message를 가져올 수 있습니다.
저걸 사용하지 않게 된다면 ApplicationContext인터페이스에서 getMessage를 지원해서 저걸 통해서도 가져올 수 있습니다. 저렇게 가져온다면, 여기저기 다른 클래스에서 사용하게 된다면 context를 해당 클래스로 넘겨야하는데 이건 applicationContext에서 MessageSourceAccessor를 DI해버리면 해당 클래스에서 사용할 수 있겠죠?^^
다시 말하지만... 정말 이것말곤 방법이 없나-_-; 그냥 Properties에서 할 수 있을 것 같은데-_-;