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