찍찍이 류의 구간 반복학습 앱을 한번쯤은 써보았을 것이다. 상당수의 앱은 A-B구간 반복만을 지원하며, 사용자가 수동으로 설정을 해야 비로소 선택된 구간이 반복되게 된다.

여기서 한 걸음 더 나아가, 오디오를 자동 분석해서 문장 단위로 자동으로 끊어서 구간반복을 보다 쉽게 지원하는 앱들이 있는데 이를 여기서 소개해보려 한다.

안드로이드에서 아마도 가장 유명한 구간반복 앱은 워크오디오북이다. 국내에서 만들어진 것도 몇가지 있었지만 게중에 유명했던 WaveLoop는 개발이 중단되고, ICS부터 플레이 속도가 조절이 안되는 등등의 몇몇 결함이 보이더니 구글 플레이 배포가 갑자기 중단되었다. (※추가: 검색하다가 우연히 발견하게 된, 2011년 경에 공개된 waveloop소스 https://code.google.com/archive/p/waveloop/)

본인이 생각하는 이상적은 구간 반복학습 앱의 기능은 다음과 같다.
- 음성의 문장단위 자동 인식 및 반복 가능
- 복수개의 문장단위 지원
- 시각적인 파형 보여주기 및 파형의 드래그를 통한 문장 구간의 손쉬운 선택
- 자막 지원 등의 보조적 기능
- 플레이 속도 조절 기능

이러한 기능을 모두 가지고 있는 앱은 현재 안드로이드에 없으며 (2014년 이 글을 쓸 당시), 이 기능중에 일부를 지원하지는 않지만 아마도 가장 잘 만들고 완성도가 높은 앱은 워크오디오북이 아닐까 싶다.
2015년 5월 현재, 이 모든 기능을 잘 지원하는 앱은 필자가 제작자인 클론 리플레이어이다.

워크오디오북
유명한 반복 어학 학습앱 워크오디오북! (2013년 출시됨)
- 플레이 속도를 조절하는 기능은 없다.
- 문장 단위 자동 인식이 매우 훌륭하다.
- 사용자가 문장 구간을 직접 설정할 수 있다. (터치 드래그)
- 자막을 잘 지원한다. (SRT, HTML 자체 포맷 지원, SAMI(smi) 미지원)
- 그밖에, 오디오 북을 받을 수 있는 기능 등등이 최신 버전에 추가됨
- 비교적 최근 유료화가 되어서 설치시간이 일정시간 지나면 유료로 업그레이드하라는 메시지가 뜬다.
- 유료버전으로 업그레이드하지 않으면 하루 10분만 쓸 수 있다.
- 플레이를 10분만 할 수 있다는 제한말고는 나머지 기능은 모두 정상 작동
- 워크오디오북 자체 자막(html) + MP3 오디오북 파일을 앱에서 손쉽게 다운로드 받을 수 있다.

워크오디오북은 파형을 분석하는 속도가 매우 빨라서, 1시간 mp3도 거의 10초 안에 처리해낸다. 놀라운 속도다. (※추가: 이 속도의 비결은 다름이 아니라, ringdroid에서 쓰던 방식과 같이 MP3의 모든 샘플을 읽는 방식이 아니라, 각 프레임에서 global_gains값을 재빠르게 읽어서 보여주던 방식어었다.)

매우 깔끔하게 잘 만들어진 워크오디오북이지만 단점이 없는 것은 아니다. 우선 배속재생을 아직 지원하지 않는다. 아마도 내부적으로 안드로이드의 기본 내장 미디어플레이어를 통해 재생하는 것으로 보이며, 안드로이드 6.0 이하 버전은 기본 플레이어가 배속재생을 지원하지 않은다는 점 때문에 배속 재생 기능이 빠진 것으로 보인다. 또한 mp3 파일만 지원한다. 요즈음 쉽게 접할 수 있는 ogg 등등을 지원하지 않는다. (다만 이는 큰 문제로 보이지는 않는다.) 또한, mp4와 같은 동영상의 오디오 재생 역시 지원하지 않는다.
기타, 저자가 함께 지원하고 있는 오디오북으 호환성 문제가 있다. 오디오북에 포함된 자막은 html이라는 독특한 형식인데, 이것은 html 파일이라서 일반 브라우져로 볼 수도 있는 등의 장점이 있으나, 이 자막을 다른 어플이 지원하지는 않는다. (클론 리플레이어는 이를 지원하고 있다.) 그밖에 함께 제공하고 있는 오디오북에 포함된 원본 mp3 파일은 유명한 리브리복스.org 사이트에서 제공하는 음원인데, 발음이 상당히 빠른 편이라 초급 영어 학습자에게는 그다지 적합하지는 않아 보인다. (물론 AP 뉴스 혹은 CNN 뉴스 등등보다는 쉬운 편)


클론 리플레이어 (영어 구간 반복 듣기 베타)

본인이 개발자이며, 기존에 나온 앱들이 불편하다고 느껴서 개발하기 시작하였다. :)
공개된 오픈소스 링드로이드 소스를 사용하여서 링드로이드의 장점을 십분 활용하였다.
(개인적으로 이름붙인 프로젝트명 내부 명칭은 링드로이드 프로그램을 기반으로 한 것에 착안하여 링드로이드클론이라고 이름 붙였고, 앱 이름은 별 특징없이 "어학반복학습기"라고 하였고, 현재 정식 명칭은 클론 리플레이어 이다.)
- 플레이 속도를 조절 0.5~2배속 (버전 2.52부터) 
- 문장 단위 자동 인식이 그럭저럭 쓸만함 (high pass 필터를 추가한 이후에는 많이 좋아졌다)
- 자막을 지원한다 (SAMI지원 외 공개 자막 라이브러리를 사용하여서, SRT/SCC/LRC등등의 여러 포맷의 자막 지원)
- MP4 파형 보기 지원 (오디오 디코딩에 ffmpeg 사용함. 버전 2.50부터. MP4의 경우는 영상 보기도 지원 가능)
- 사용자가 문장의 구간을 직접 조절 할 수 있다.
- UI가 간단하여 사용이 손쉬운 편이다.
- 오디오 파일의 특정 구간을 잘라서 파일로 손쉽게 저장 가능(링드로이드의 기능 + FFmpeg 인코딩 동시 지원)
- 워크오디오북에서 받은 자막 + MP3 재생을 잘 지원.
- 개발이 활발. 몇일에 한번씩 새로운 버전이 나오고 있다 :)
- 아직 베타버전 상태라서 일부 기능이 안정적이지 않다. (2015년 3월 이후로 상당히 안정적이 되었다)

워크오디오북은 파형 분석속도가 타의 추종을 불허한다. 1시간 이상 분량의 MP3도 파형 분석 속도가 10초 수준이다. 워크오디오북에서는 파형을 모두 읽는 방식이 아니라 MP3의 각 프레임의 global_gain값만 읽어 보여주는 방식이다. 또한, 모든 음성 구간을 분석하는 것이 아니라, 보이는 부분의 구간만 재빠르게 분석하 매우 빠르다. 반면 본인이 개발하고 있는 클론리플레이어는 MP3 공개 라이브러리중에 가장 빠르다는 libmpg123을 사용하는데도 1시간짜리 mp3 분석이 1분 가까이 소요된다. 최초 시동시에 작동 반응 속도를 빠르게 하기 위해서 2015년 5월(?) 버전부터 mp3의 앞부분 ~2분 분량 정도를 무조건 읽고나서 즉각적으로 화면으로 보여준 후에, 나머지 파일은 백그라운드로 읽고, 모든 것이 완료되면 다시 나머지 분량의 파형을 갱신해서 화면에 표시하도록 하였으며,이러한 방식으로 로딩시간으로 인해 기다리게되는 불편함을 어느정도 해소시켰다.

클론 리플레이어의 그밖에 특징

자막을 리스트로 보기 - 일반적으로 자막 한줄만 나오는 방식 대신에 자막을 모두 볼 수 있도록 하였다.
- 문장 단위 자동 인식은 서서히 개선중 - Voice segmentation에 관련된 자료/논문을 읽어보며 구현중이다.
- 현재 RMS체크 / High-pass 필터 / Log 에너지 체크 적용됨.
- 간단하고 자연스러운 UI - 아이콘 최소화. 쉬운 사용에 중점을 두었으며, Holo 스타일과 어울리게 만듦
  - 최신 버전의 경우에는 최신 안드로이드 버전의 사용자는 Material 스타일과 어울리게 하였다.
- 원래 링드로이드 앱이 가지고 있던 파형 터치 드래그의 자연스러운 애니메이션을 그대로 유지/개선
- 왠만한 자막 편집기보다 나은 간단한 자막 편집기능을 지원한다. (SRT 및 SAMI 포맷으로 저장 가능)
- 최신 버전의 경우 대본 파일도 지원한다. 즉, 자막은 아니지만 일반 텍스트 파일을 같이 볼 수 있도록 하였다.
- 대본 파일을 직접 편집하는 것도 지원한다. 따라서 사용자가 메모를 함께 적어 넣을 수도 있다.
- 2015년 4월 이후로는 내장된 웹사전+단어장을 함께 지원한다.
- 구간 반복 횟수 지정 가능 (구간 반복이 완료되면 다음 구간으로 이동)
- 폴더플레이 지원 (폴더 아래의 모든 오디오 재생) 및 셔플 및 전체 오디오 반복 회수 지원
- 포드캐스트 다운로드 지원 및 자막/스크립트 다운로드 지원. (VOA / TED / Storynory 등등)
- 최신 버전의 경우 유튜브의 특정 채널을 통해서 영상을 다운받아 볼 수 있다.
- 영상을 재생하는 경우에는 영상을 함께 보는 것도 지원한다.
- 최신 안드로이드 6.0을 사용하는 경우에는 영상도 배속 보기를 지원한다. 따라서 영어 학습뿐만 아니라 다운받을 수 있는 인터넷 강으로 빠른 속도로 재생하는 것도 가능해졌다.
- 최신 버전의 경우, 기존의 여러 A-B 구간 지정앱에서 사용하던 전통적인 방식의 AB 구간 지정도 함께 지원하게 되었다.
- ※추가: 최신 버전의 경우 구글 ExoPlayer를 사용한 보다 정확한 동영상 구간 반복을 지원한다.


by dumpcookie 2014. 11. 2. 20:04

소니 HDR-HC3를 2007년에 병행수입 제품을 구입해서 지금까지 사용중이다. HDR-HCx 시리즈는 6mm테입을 사용한다. 6mm테입을 쓰게되는 장점은, 내장 HDD용량 걱정없이 테입을 교체하는 것만으로 시간제한 없이 계속 찍을 수 있다는 것. 아무튼 2007년부터 지금까지 잘 사용했으니 거의 본전은 뽑고도 남을만큼 찍었다. (그래봤자 일년에 10개 테입)



거의 고장없이 사용하다가 2010년 즈음에 LCD가 제대로 표시안되고 이상해지더니 몇년간은 액정 없이 그냥 사용하고 있었다.

그런데 몇일전에 테입을 꺼내는데 이상하게 다시 뚜껑이 닫혀지지 않는것이다. 아... 이제 맛이 갈 때가 되었구나.

검색을 좀 하니, LCD는 10~15만원 수리비가 나오는 것으로 보아서 수리비만 도합 20만원이 넘겠다 싶어서, 중고나라에서 HDR-HC3 / HC5 기종을 검색하니 18~25만원 사이였고 이정도면 중고를 구입하는게 낫겠다 싶었다. 정품은 60~100만원인데 물건이 풀린지 오래라서 그런지 중고가 단가가 낮게 형성되어있었다. 그러나 중고품이 나오는 족족 금방 팔리는 현실. 물건도 많이 나오는 것은 아니어서 언제까지 기다릴 수만은 없었다.

그래서 다시 인터넷을 검색하여, 이와 비슷한 증상의 고장인 경우에 자가 조치법이 있는지 살펴보았다. 그런데 다행이도 이와 같은 뚜껑이 닫히지 않는 고장은 상당히 빈번하며, 쉽고 고칠 수 있는 방법이 비교적 최근에 유튜브 동영상으로 올라와 있었다. (2014년7월에 올라온 영상)

http://youtu.be/CBqP-Q86UyM

소니의 다른 테입 기종도 이와 거의 비슷한 방식으로 고칠 수 있다는 영상도 몇몇 보였다.

(동영상 캡쳐사진: 오른쪽 하단의 땜납 두개 부분이 구동 모터이며, (+)전극은 붉은색쪽 캠코더 하단이다. 실수로 전극을 바꾸어도 망가지지는 않으니 안심하고 실험해볼 수 있다)

(실제 작업할때는 분해하지 말고, 위와 같이 캠코더 하단에 있는 구동모터 땜납부분에 3~4V 직류전원을 흘려준다)

뚜껑이 닫히지 않는 오류는 C:32:11 오류 코드를 LCD에 표시하며, 3~4V 직류를 테입 구동 모터에 흘려주기만 하는 것만으로도 다시 원상복구 된다!!

본인의 경우에, 테입을 집어넣었는데 캠코더에서 삑삑거리며 오류가 나서 테입을 빼보았더니, 테입이 삐져나와 있었으며,  그 이후로 테입을 다시 집어넣을 수 없고, 뚜껑은 열린채로 닫히지 않았었다. 이는 아마도 불량한(?) 테입이 원인이 되어서 구동 모터의 오작동의 원인이 되었고, 캠코더는 이를 구동모터나 캠코더 자체의 오류로 판단하여 자동으로 뚜껑이 닫히지 않도록 하여 더 이상 테입이 망가진다거나 파손되는 것을 방지하려는 프로그래밍된 안전장치가 작동한 같은 것으로 추측된다.

아무튼 동영상에서는 ~1.2V 근처의 AA배터리를 3개 연결해서 ~4V정도를 만들어서 모터를 구동시키는 방법을 설명한다. 모터가 구동되면 뚜껑은 다시 닫혀질 수 있게끔 된다. 그래서 본인은 AA배터리 2개를 직렬로 연결해서 ~3V정도 만들어서 동영상에서 설명한 방법대로 구동모터를 구동시켜 보았다. 처음에는 극성을 제대로 몰라서 해맸는데, 동영상에 설명되어있기를 +극성을 바닥쪽 구동모터 땜납 부분에, -극성은 나머지 땜납에 대면 된다. 이게 제대로 되면 모터가 돌아가는 소리가 나고, 배터리를 다시 끼워서 전원을 켜고 뚜껑을 닫기를 시도해 보면 멀쩡하게 닫히게 된다!!

(그래서 다시 고장을 일으켰을때에 집어넣었던 6mm테입을 넣고 구동시켜보니(물론 삐져나왔던 테입은 다시 감아서), 다시 똑같은 양상으로 오류가 나고 뚜껑이 또 닫히지 않았다 ^^;; 다시 같은 방식으로 고친 후에, 이번에는 아무 문제 없는 테입을 넣어서 한차례 리와인드가 잘 작동하는지 구동모터 작동여부를 확인하고, 다시 예전의 고장을 일으킨 테입을 집어넣고 리와인드를 하니 정상 작동!!!)

뚜껑이 닫히지 않는 C:32:11 오류가 나는 경우에는 소니 HDR-HCx 모델 혹은 DCR기종도 같은 방식으로 고칠 수 있다고 하니 이 방법을 써서 자가수리를 하시길 바란다.

(수리영상을 공개해준 GotNoEvidence씨에게 감사드립니다)

'자가수리' 카테고리의 다른 글

HDR-HC3 flash error 복구하기  (0) 2021.02.21
by dumpcookie 2014. 10. 25. 06:13

음성파일의 재생속도를 조절하기 위해서 검색을 해보니 그중에 가장 간단한 방식을 sonic 라이브러리(LGPL)가 지원하고 있었다. sonic-ndk라는 안드로이드에 직접 적용한 간단한 앱 소스도 있었다.

https://github.com/waywardgeek/sonic-ndk

이게 약간 낡아서 최신 빌드환경에서 빌드가 제대로 안되길래 몇가지 메시지를 추가해 주었으며 변경된 소스는 다음에서 받을 수 있다.

https://github.com/wkpark/sonic-ndk

Sonic라이브러리에서 쓰는 재생속도 조절 방식은 음성에 대해서 적합하다고 하며 빠른 재생속도에도 아주 자연스러운 목소리를 들을 수 있는 장점이 있었다. (자세한 내용은 다음 링크를 참조하세요)

http://dev.vinux-project.org/sonic/

소스를 보면 매우 간단한 방식으로 처리하고 있으며, 다음과 같은 방식으로 사용된다.

...
Sonic sonic = new Sonic(sampleRate, nChannels);
// sampleRate는 오디오 파일로부터, 채널도 오디오파일로부터

byte samples[] = new byte[4096];
byte modifiedSamples[] = new byte[2048];

sonic.setSpeed(speed); // 재생속도 설정
do {
    try {
        bytesRead = soundFile.read(samples, 0, samples.length); // WAV파일로부터 읽음
    } catch (IOException e) {
        e.printStackTrace();
        return;
    }
    if (bytesRead > 0) {
        sonic.putBytes(samples, bytesRead); // sonic라이브러리로 변형.
    } else {
        sonic.flush();
    }
    int available = sonic.availableBytes();

    if (available > 0) {
        if(modifiedSamples.length < available) {
            modifiedSamples = new byte[available*2];
        }

        sonic.receiveBytes(modifiedSamples, available);
        track.write(modifiedSamples, 0, available); // AudioTrack에 쓴다.
    }
} while (bytesRead > 0);
track.flush();

...

추가: 참고로 sonic 라이브러리는 안드로이드 M 버전부터 정식으로 채용되어 안드로이드에서도 사용할 수 있게 되었고 이를 이용한 재생 속도 조절이 안드로이드 자체적으로도 가능하게 되었다.

추가된 sonic 소스: https://android.googlesource.com/platform/external/sonic/

by dumpcookie 2014. 10. 2. 23:17

카톡으로 가끔 퍼나르는 얘기는 출처없는 유언비어/인신공격성 성격의 얘기가 대부분이어서 믿지 않는편인데, 얼마전에도 믿기 어려운 그림이 퍼날러지고 있어서 그 출처를 살펴보았다.


FAKEFAKE

관련 뉴스를 검색해보니 http://forum.koreairanianchurch.net/bbs/board.php?bo_table=news_arab&wr_id=1436 등등이 나오고, 출처로 http://www.westernjournalism.com/barbaric-muslims-sew-mouth-eye-shut-girl-professed-jesus-savior/ 이렇게 되어있다. 2014년 4월에 나온 이야기이다.

그래서 이번에는 영어로 검색해보니 검색 결과는 좀 더 많이 나왔으나, 이 사진이 FAKE라고 주장하는 사이트도 다음과 같이 있었다. http://www.muslimsarenotterrorists.com/2014/04/reality-behind-girl-with-sewn-mouth-and-eye-saudi-arabia.html 사이트 이름에도 알 수 있듯이 이 사이트는 무슬림이 테러리스트가 아니라고 말하고 있다.

잘 읽어보면 사진의 원 출처는 일본 사이트이며, 일본 사이트로 들어가서 그림을 찾아보면 원본 사진이 나오고 사진은 2008년에 찍은 사진이라는 것이다. (위 링크로 가면 설명 나옵니다. 혐오 사이트라서 링크걸지 않았습니다.) 직접 사이트에 들어가서 살펴보니 원본 사진은 정말로 2008년도에 나왔고, 일본인이였다. 사우디아라비아 소녀라는 말은 거짓말인것이다.

게임 끝.

카톡에 가끔 올라오는 출처 불명의 얘기는 직접 확인하기 전에는 퍼뜨리지도 말고 믿지도 말자.

※추가: 사실 이 그림보다 더 ㄷㄷ한 사실은, 단순히 카톡의 우리말 한글 내용뿐만 아니라, 이 조작된 사실이 올라간 상당수의 외국 사이트들이다. 다행스럽게도(?) 위 사실을 퍼나른 국내 메이져 사이트들은 거의 안보였고 게시판에 올라간 수준들의 글이었으나, 해외 사이트는 꽤 무차별적으로 올라가 있었다. (상당수의 글은 2014년. 몇몇 글은 2012년에도 올라옴)

사이트 몇개를 들어가보니 덧글에 이 글은 가짜라는 덧글이 달린 곳도 종종 보였고, 그 덧글에는 다음과 같은 추가적인 내용의 사이트도 일본인이라고 말하고 있다고 알려주었다. http://motleynews.net/2012/09/26/bagelheads-japans-hot-trend-of-injecting-saline-in-forehead-for-that-bagel-look/ (혐짤 주의. 2012년 글임에 유의)

단, 이런 류의 글들은 비교적 트위터나 facebook에 올라가면 꽤 빠른 시간에 검증되어서 사라져버리는 것인지.. 트위터나 facebook에서는 찾아보려 해도 쉽게 찾지 못하였다. 또 다른 한편으로는 이슬람에 관련되어 좋지 않은 얘기들이 상당수 올라오고 있다는 사실도 눈에 뜨인다.

앞으로는 이슬람에 관련되어서 이상한 소문이 들린다면 반드시 원문을 추적해보리라 생각해본다.

by dumpcookie 2014. 9. 23. 22:37

JLayer가 상당히 느린 관계로 libmpg123을 적용해보기로 하였습니다.

MAD에는 저수준의 API가 있어서 ringdroid에 입맞에 맞춰서 적용하는게 손쉬웠지만 libmpg123의 경우에는 저수준의 API함수를 사용하는 예제가 없어서 소스를 훝어보던 차에 *framebyframe*류의 저수준 API함수가 비교적 최근(2009년)에 추가되어 있더군요. 이를 이용하여 libmpg123을 이용한 decoder를 만들어서 넣었고 잘 작둥함을 확인하였습니다. 관련 내용을 검색해봐도 저수준 API 함수를 사용하는 예제는 찾을 수 없었습니다만, 사용방법은 간단하였고 어렵지 않게 적용할 수 있었습니다.

소스는 https://github.com/wkpark/ringdroid master 브렌치에 올려두었습니다~

libmpg123을 사용하는 Mpg123Decoder.c JNI wrapper는 https://github.com/thasmin/android-mp3decoders를 참고하였고, 골격은 MAD에서 사용하던 방식과 거의 같고, readNextFrame() / decodeFrame()등의 저수준 API를 사용하는 부분 등등은 재작성 했습니다.


/* JNI 일부 */ JNIEXPORT float JNICALL Java_com_ringdroid_soundfile_Mpg123Decoder_readNextFrame (JNIEnv *env, jclass c, jlong handle) { MP3File *mp3 = (MP3File*)handle; int err = mpg123_framebyframe_next(mp3->handle); char buf[256]; sprintf(buf, "readNextFrame() err = %d", err); __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", buf); return err; } JNIEXPORT float JNICALL Java_com_ringdroid_soundfile_Mpg123Decoder_decodeFrame (JNIEnv *env, jclass c, jlong handle) { MP3File *mp3 = (MP3File*)handle; size_t bytes = 0; unsigned char *dummy; int err = mpg123_framebyframe_decode(mp3->handle, NULL, &dummy, &bytes); char buf[256]; sprintf(buf, "decodeFrame() bytes = %d", bytes); __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", buf); if (err != MPG123_OK) __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", mpg123_plain_strerror(err)); mp3->leftSamples = bytes / 2; /* buffer는 단지 저장장소일 뿐 실제로 short로 저장되므로 (short *)로 cast해야 하고 실제 데이터 개수는 bytes 수의 1/2 */ mp3->offset = 0; sprintf(buf, "decodeFrame() err = %d", err); __android_log_write(ANDROID_LOG_INFO, "mp3decode-jni", buf); return err != MPG123_OK ? 0 : bytes; } ...

(framebyframe* 저수준 API는 위에서 볼 수 있듯이 매우 간단합니다)

by dumpcookie 2014. 9. 15. 17:44

아직 마땅한 이름은 정하지 못했고, ringdroid에 아주 초 간단 Voice segmentation 기능을 추가하고 개선시킨 반복 듣기용 영어 어학 학습기를 만들어봤습니다.

ringdroid가 워낙 잘 만든 놈이라서, 기능 추가하는 것도 어렵지 않고, 기존에 나와있던 반복 학습기들의 단점 보완을 목표로 해서 개선시키고 있습니다.

장점

1. 예쁘다. :)

2. UI가 쉽고 간단.

단점

1. JLayer가 너무 느리다ㅠ : 너무 느리다면 waveform을 캐싱하는 방법도 고려해야 할 듯.

2. Voice segmentation 개선 필요. : 현재는 silence 경계 판단이 매우 매우 간단한 알고리즘 (최소 noise + rms 체크)

개선점

1. Voice Recognition을 사용한 자동 자막 기능. (반자동 기능으로?)

2. 배터리 절약 모드(?) - 색상을 어둡게 하거나 몇가지 선택 가능한 테마로

3. 이어폰으로 간단한 제어가능하도록

4. 음악 파일 디렉토리 지정 가능하도록

5. OGG 지원 (일단 읽기만이라도)


Screenshot_2014-09-11-20-00-31.png 표시 중

by dumpcookie 2014. 9. 12. 17:12

MAD 라이브러리 라이선스가 GPL이다보니 다른 라이선스를 가진 MP3 디코더를 찾아보다가 JLayer를 적용해보았습니다.

MAD 라이브러리에비해 조금 느리기는 하지만 사용 방법이 상당히 쉬운 편이어서 어렵지 않게 적용할 수 있었습니다.

JLayer가 적용된 ringdroid는 https://github.com/wkpark/ringdroid master 브렌치에 적용하였습니다.

다음은 JLayer가 적용된 소스코드의 일부입니다.

(MAD 라이브러리와 비교했을때, JLayer는 상당히 느린편이네요)


...
        mFileSize = (int)mInputFile.length();

        FileInputStream stream = new FileInputStream(mInputFile);

        Decoder decoder = new Decoder();
        Bitstream bitstream = new Bitstream(stream);

        int pos = 0;
        int gain = 0;

        try {
            Header header = bitstream.readFrame();

            int nChannel = (header.mode() == Header.SINGLE_CHANNEL) ? 1 : 2;
            mGlobalChannels = nChannel;

            mLayer = header.layer();
            mVersion = header.version();

            while (true) {
                if (mProgressListener != null) {
                    boolean keepGoing = mProgressListener.reportProgress(
                            pos * 1.0 / mFileSize);
                    if (!keepGoing) {
                        break;
                    }
                }

                SampleBuffer frame = (SampleBuffer) decoder.decodeFrame(header, bitstream);
                short[] pcm = frame.getBuffer();
                bitstream.closeFrame();

                double sum = 0.0f;
                int k = 0;
                int tmp;
                Log.d(TAG, "pcm length = " + frame.getBufferLength());
                for (int j = 0; j < frame.getBufferLength(); j++) {
                    tmp = pcm[k] > 0 ? pcm[k] : -pcm[k];
                    sum += tmp / 32767.0f;
                    k += nChannel;
                }
                gain = (int) (sum / frame.getBufferLength() * 255);
...

by dumpcookie 2014. 9. 12. 11:34

어학 반복 학습기를 구상하다가 ringdroid를 개선해보기로 하였습니다.

ringdroid는 상당히 초창기에 만들어졌던 꽤 유명한 안드로이드 앱인데, 이것의 문제점은 내장된 MP3 해석기가 외부 라이브러리 의존없이 상당히 간단하게 구현된 관계로, waveform이 제대로 나오지 않는 것입니다. (※추가) ringdroid 원 소스는 MP3의 모든 샘플을 읽는 방식이 아니라 MP3의 global_gain 정보를 읽어들여 이를 사용해서 Waveform을 그리는 방식입니다. 그러나 global_gain 절대값을 단순히 사용하는 등의 문제로 waveform이 제대로 나오지 않던 것이었습니다.

그래서 검색을 조금 해보니 WaveLoop라는 국내 개발자가 수년전에 만들었던 어학 반복 학습기의 소스를 발견하게 됩니다. 이것은 ringdroid의 소스를 상당히 변형하고, libmad MP3 디코딩 라이브러리 (GPL)를 사용하여서 MP3 waveform을 잘 보여주게 개선되어있었습니다. 그런데 어떤 문제때문인지 현재는 play 스토어에서 내려가있더군요. (※추가: 우연히 발견한 것인데, WaveLoop 소스가 GPLv2로 풀려 code.google.com에 올라와 있었습니다. https://code.google.com/archive/p/waveloop/ 단, 이 소스는 중요한 작동 코드가 빠져있어서 의도대로 작동되지 않습니다. WaveLoop 소스코드를 살펴보면 이것은 OpenSLES를 사용하여 배속재생을 조절하고 있었습니다.)

MP3 파일을 직접 읽기 위해서 mpg123 혹은 libmad등의 라이브러리를 쓸 수 있는데, badlogic에서 만들어 공개한 소스를 사용하여 ringdroid를 개선시켜보았으며, ringdroid에서 아무런 문제가 없이 libmad를 사용하여 waveform이 정상적으로 나오도록 수정해보았습니다. (http://www.badlogicgames.com/wordpress/?p=231 링크에서 사용된 방식 참고)

소스는 https://github.com/wkpark/ringdroid의 mad 브랜치에서 확인하실 수 있습니다.

Screenshot_2014-09-09-21-56-02.png 표시 중

by dumpcookie 2014. 9. 9. 21:59

apk를 unzip으로 풀어야 하는 경우가 간혹 있을 수 있다. 이 경우에 알아야 하는 기본적인 상식은 다음과 같다.

1. unzip으로 풀어서 다시 압축하면 반드시 재사이닝을 해야 한다. (사이닝 키가 없는 경우는 물론 제외하고)

2. zip으로 다시 압축하는 경우에 png/mp3 등등의 이미 압축된 파일은 압축하지 않는다.

    -n .Z:.zip:.tiff:.gif:.png:.mp3:.jpg 옵션을 사용하면 된다.

3. 디렉토리 스트럭처는 압축하지 않는다. AssetManager등에서 오류를 일으키기때문이다.

   이 경우 zip ../foobar.apk $(find . -type f)와 같은 명령으로 디렉토리는 제외하고 압축한다.

by dumpcookie 2014. 9. 5. 21:25

젤리빈 소스를 통채로 가져와서 기본 디바이스를 한번 빌드하고, 이 상태에서 앱을 개발하면 편리한 잇점이 있다.

그런데 이 환경에서 native 라이브러리를 컴파일 해서 ICS가 올라간 폰에 앱을 올렸더니 reloc_library 오류가 나면서 __open_2 라는 심볼을 못찾아 오류를 내고 있었다.

arm-eabi-objdump -R libfoobar.so 명령으로 foobar 라이브러리에 __open_2 심볼을 찾아보니 있었고, 예전에 ICS 소스트리에서 컴파일했던 잘 돌아가던 구버전의 라이브러리는 __open_2 심볼을 찾아볼 수가 없었다.

__open_2라는 심볼이 무엇인가 구글로 검색해서 살펴보니 2012년에 bionic/libc 소스에 추가된 부분이었다.

https://github.com/CyanogenMod/android_bionic/commit/8118f62a7d3f1af1edb47e0bc2a49af1d523ae0f#diff-e0d07145fa9f6b0a5562c1be920578ec

이와 관련된 Android.mk파일을 찾아서 FORTIFY_SOURCE를 어떻게 정의하고 있나 살펴봤더니, 아니나다를까 일부 native 라이브러리는 FORTIFY_SOURCE 정의를 끄고 컴파일하고 있었다.

그래서 LOCAL_CFLAGS := -U_FORTIFY_SOURCE 라인을 Android.mk에 추가한 후에 라이브러리를 젤리빈 소스트리에서 다시 컴파일하고 심볼을 objdump -R 명령으로 다시 살펴보니 __open_2 심볼이 사라졌다. 빙고~!

그리고 당연히도 reloc_library 오류가 나지 않고 아무런 문제 없이 앱이 실행된다~

by dumpcookie 2014. 8. 30. 11:39
| 1 2 3 4 5 6 7 |