아직 마땅한 이름은 정하지 못했고, 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

안드로이드는 음성인식(Speech Recognize)기능을 지원하고 있습니다.


그런데 안드로이드에서 지원하는 음성인식이 두가지 방식이라는 사실은 잘 모르시는 분들이 많습니다. 하나는 잘 알려진, 구글 음성인식 검색을 지원하는 음성인식 엔진이며, 다른 하나는 안드로이드 소스에 들어있으며 SpeechRecorder라는 안드로이드 내장 앱 등등에서 쓰이고 있는 Nuance SREC 네이티브 엔진입니다.

안드로이드의 음성인식 엔진은 두가지

구글 음성인식 검색용 엔진은 offline에서는 사용할 수 없었으나 (젤리빈부터 가능), Nuance SREC 엔진은 자체 내장 native 엔진이기때문에 offline에서 사용 가능하다는 장점이 있으며, 아파치 라이선스로 모든 소스가 공개되어 있다는 장점이 있습니다!

최근에 젤리빈에서 지원하기 시작한 오프라인 음성인식 지원은 Nuance SREC을 사용한 오프라인 음성인식이 아닌 것으로 보입니다. (http://forum.xda-developers.com/showthread.php?t=2014946 참조해서 보면 오프라인으로 쓰고자 하는 경우 데이터를 받게끔 되어있습니다. http://www.youtube.com/watch?v=BTARRXP_I24 넥서스 7에서 오프라인 음성인식 사용하기 영상 참조)

반면, 현재 SREC은 영문만 지원하는 단점이 있습니다. (SREC에서 쓰이는 사전도 영문만 있고, grammar도 영문만 지원) 또한 일반적인 grammar 문법은 잘 지원하지만 dictation을 아직 지원하지 않습니다.

Nuance SREC 엔진은 2008/2009년에 공개되었는데도 많이 사용되지 않고 있는 것은 아마도 관련 문서가 아직은 거의 없기 때문이 아닌가 합니다. (혹은 다른 음성인식 라이브러리를 사용한다거나 해서??)
비교적 최근에 데비안 프로젝트에서 Nuance SREC엔진을 포팅하려는 시도가 있는 것 같은데 별다른 진척은 없는 상태입니다. https://github.com/arthurv/srec 참조

추가: Nuance srec을 이용해 kinect를 리눅스상에서 쓸 수 있게 포팅한 (소스를 보면 고친 부분은 거의 없음) 것도 있더군요. http://www.keyboardmods.com/2011/10/kinect-speech-recognition-in-linux.html 이것을 보면 리눅스상에서도 많은 수고 없이도 사용할 수도 있을 것으로 생각됩니다.

그밖에 더 자세한 내용은 다음 사이트를 참조하시기 바랍니다.


Nuance SREC 음성엔진을 사용하는 프로젝트

그런데 Nuance SREC엔진은 안드로이드 SDK API로 지원되지 않으므로, 이 자체 내장 엔진을 이용해서 앱을 만드려면 android.speech.srec.* 소스를 복사해서 사용하는 방식으로 만들어야 합니다. 이와 같은 방식으로 안드로이드 내장 음성인식 엔진 SREC을 사용하는 대표적인 프로젝트/앱이 다음과 같은 것이 있습니다.

소스 예제

android.speech.srec.Recognizer 자바 소스를 살펴보면 다음과 같은 식으로 사용할 수 있다는 주석이 있습니다.
(아래 소스를 조금 보기좋게 해 두었습니다.)
https://github.com/CyanogenMod/android_frameworks_base/tree/jellybean/core/java/android/speech/srec
https://github.com/CyanogenMod/android_frameworks_base/blob/jellybean/core/java/android/speech/srec/Recognizer.java - CyanogenMod 소스

// create and start audio input
InputStream audio = new MicrophoneInputStream(11025, 11025*5);
// create a Recognizer
String cdir = Recognizer.getConfigDir(null);
Recognizer recognizer = new Recognizer(cdir + "/baseline11k.par");
// create and load a Grammar
Recognizer.Grammar grammar =
    recognizer.new Grammar(cdir + "/grammars/VoiceDialer.g2g");
// setup the Grammar to work with the Recognizer
grammar.setupRecognizer();
// fill the Grammar slots with names and save, if required
grammar.resetAllSlots();
for (String name : names) grammar.addWordToSlot("@Names", name, null, 1, "V=1");
// names 배열에 이름을 넣어두면 인식됨 예를 들어 { "hello", "foobar", "kim" }
grammar.compile();
grammar.save("/mnt/sdcard/foo.g2g"); // path를 고쳐둠
// start the Recognizer
recognizer.start();
// loop over Recognizer events
while (true) {
    switch (recognizer.advance()) {
    case Recognizer.EVENT_INCOMPLETE:
    case Recognizer.EVENT_STARTED:
    case Recognizer.EVENT_START_OF_VOICING:
    case Recognizer.EVENT_END_OF_VOICING:
        // let the Recognizer continue to run
        continue;
    case Recognizer.EVENT_RECOGNITION_RESULT:
        // success, so fetch results here!
        for (int i = 0; i < recognizer.getResultCount(); i++) {
            String result = recognizer.getResult(i, Recognizer.KEY_LITERAL);
            Log.d(TAG, "result = " + result); // 인식 결과값 출력
        }
        break;
    case Recognizer.EVENT_NEED_MORE_AUDIO:
        // put more audio in the Recognizer
        recognizer.putAudio(audio);
        continue;
    default:
        // notifyFailure();
        break;
    }
    break;
}
// stop the Recognizer
recognizer.stop();
// destroy the Recognizer
recognizer.destroy();
// stop the audio device
audio.close();

위의 소스를 거의 고치지 않고서 이를 이용해 간단한 샘플 앱을 만들어보니 자체 내장 음성인식 엔진 SREC이 아주 잘 작동하는 것을 확인하였습니다. (아래 링크를 참조하세요)
(이렇게 확인하고 구글링을 더 해보니 2011년에 이미 다른 분이 이 테스트를 해보신 모양입니다 :) http://www.eoeandroid.com/thread-54280-1-1.html 참고)

기타 참고 사이트


요청이 계속 있어서 간단한 앱을 급조했습니다~

(ICS 배포 이후부터 일부 기종은 srec을 제거한 상태인 기종의 경우에 libsrec_jni가 내장되지 않아서 제대로 작동하지 않습니다.)

https://github.com/wkpark/srec-example

컴파일하고 설치한 후에 사용법은 다음과 같습니다.

1. Start 버튼을 누른다.

2. Dial 123 123 같은 식의 VoiceDialer 명령을 내려본다. (이 명령 세트는 VoiceDialer.g2g 그래머 파일에 있는 내용)

(VoiceDialer.g2g는 external/srec/config/en.us/grammars/VoiceDialer.grxml 파일을 참조하세요)

컴파일된 앱: (libsrec_jni.so가 자체 내장된 기종에서만 제대로 작동합니다)

srec-example.apk



by dumpcookie 2013. 3. 16. 23:05

영어 학습에 도움이 될만한 앱을 만드는 중입니다.

screenshot


영어학습 앱을 떠올리면 단어장/깜깜이/플래시 카드와 같은 기능은 거의 필수적으로 필요하고, 여기에 사용 될 단어장이 필요하게 되어서, 공개된 단어장 리스트를 살펴보게 되었습니다. 그러나 왠만해서는 라이선스가 정확히 명시되고 그 출처가 분명한 단어 리스트를 찾기가 어렵더군요.

단어 리스트를 찾기 전에 먼저 출처 및 라이선스가 분명한 영어 사전 데이터를 찾아보니, 공개된 영어 사전으로는 유명한 WordNet 자료와 GCIDE 프로젝트가 있었습니다.

그밖에 방대한 Wiktionary (http://en.wiktionary.org/wiki/Wiktionary:Main_Page)를 참고할 수 있을 것입니다.

저작권에 관련된 부분을 좀 더 명확히 하기 위해서 관련 정보를 찾아보니 KLDP에 다음과 같은 글이 있었습니다. http://kldp.org/node/83345저작권있는 사전의 발음기호만 수집해서 배포해도 될까요? (글쓴이: xylosper 토,2007/06/16)
이 내용을 일부 적어보면,

  • 특별한 창작성이 없는 단어 목록은 저작권 보호를 받지 못한다고 한다.
  • 대부분의 공개되어있는 한-영사전은 창작성이 있는 부분(뜻, 예문이나, 발음기호 등등)에 대한 정확한 출처를 명시하지 못하고 있다. (engdic이 대표적인 예)

아무튼 이러한 사실을 염두해두고 자료를 검색해보았습니다.

출처가 불분명하지만 광범위하게 퍼져있는 자료들

  • 교과부 지정 초등영어 기본 800단어 - 검색해보면 무수한 HWP/엑셀 자료를 찾아볼 수 있었습니다.
    예) 
    http://goo.gl/xNyqO
    • 단어목록이 거의 유사하나 내용이나 몇몇 단어들이 추가된 경우도 있고, 그 원 출처가 일치하지는 않는 듯.
  • 교과부 지정 중고교 2067단어 - 역시 검색하면 무수한 HWP 자료들.
    • 중고교 2800단어라고 불리는 자료는 2067 단어 + 초등학교 수준의 단어를 합한 것
    • 2067단어라고 이름 붙여놓고 여기에 새로운 단어를 추가한 경우도 있다.
    • 이 자료들 역시 그 원래의 출처가 일치하지 않는 것으로 보였다.
  • 그밖에 많은 자료들은 그 출처가 불분명하며, HWP파일이나 엑셀 파일을 열어서 살펴보면 학원에서 배포하던 자료이거나, 기타 개인이 만든 자료인 듯 편집이 투박하고 일관성이 없는 경우도 많았다.
  • Barron's GRE 3500 단어 : Barron's GRE 3500 책 시리즈에 나온 단어목록에 간략한 뜻과 함께 누군가가 추가로 단어를 합하여 올린 자료가 비교적 광범위하게 퍼져있다. 예를 들어 4759 단어 http://quizlet.com/47571/barrons-gre-wordlist-4759-words-flash-cards/ - quizlet에 올라온 이 자료가 바로 Barron's GRE 단어목록.
    -> 아마도 누군가가 Barron's GRE 3500 단어목록 + alpha를 하고, 단어 뜻을 추가한 듯 하다. (원 출처가 제대로 명시가 안되어 있으므로, 단어의 뜻을 누가 추가한 것인지 알기 어려웠다)

출처가 분명하고 라이선스도 분명한 자료들

  • http://www.freevocabulary.com/ SAT용 5천 단어 - 개인 및 학급에서 사용 가능. 상업적 사용 불가 - 그런데 이 자료가 몇몇 잘 알려진 사이트에서 그대로 사용되고 있었다. (이것이 허락을 받아서 쓰이고 있는 것인지 아닌지는 알 수 없었으나, 그 출처가 제대로 명시되지 않은 것으로 보아서는 도용일 것으로 추축됩니다)
  • 그밖에 몇몇 사이트에서 올려놓은 단어목록들은 개인 및 학급에서 사용 가능하나 상업적으로 사용이 불가한 경우가 대부분이었다.

사정이 이렇다보니 단어 목록을 가져오는 것은 저작권상 문제가 없다고 하더라도, 그 단어의 뜻은 출처가 불분명하며, 저작권 문제의 소지가 있는 예문이나 단어의 뜻을 그대로 가져다쓰기는 어려운 난점이 있게됩니다. 따라서 저작권 문제가 없는 단어장을 만들기 위해서는,

  1. 영-영 사전의 경우라면 Wordnet에서 사전의 뜻을 최대한 단순화시키거나, 여러가지 뜻이 있는 경우에는 주요한 뜻 두어개 + 동의어 위주로 추출 + 예문 1개정도만 추출하는 방식으로 만든다. (이 작업도 만만하지 않을 것입니다)
  2. 영-한 사전의 경우라면 사전의 뜻을 1) 원저작자에게 허락을 받거나 2) 직접 수동으로 입력하여 만들거나 ^^;;

그밖에 다음과 같은 사항들은 저작권 문제 없는 사전을 만드는데 참고할만하거나 개인적인 메모 사항입니다.

  1. 빈도수 단어목록을 사용하여 빈도수가 높은 단어를 우선순위를 높게 둘 수도 있으며, 다른 단어장과의 차별점이 될 수 있다.
    Wiktionary의 단어 빈도수 목록 http://en.wiktionary.org/wiki/Wiktionary:Frequency_lists
    http://invokeit.wordpress.com/frequency-word-lists/ 참고
  2. 네이버나 다음의 사전 사이트에서 중/고교 단어 목록 자료를 긁어온 후에 이를 바탕으로 빈도순/중복단어 우선순 등등의 2차 가공을 한 단어 목록을 만드는 것도 가능할 것이다

여기까지 정리해놓고나서, 예전에 리눅스에서 유명했던, GPL로 공개되었던 (그러나 그 출처가 불분명하다 하여 슬금슬금 배포판에서 자취를 감추게 된) 영-한 사전인 engdic의 사전 데이터가 궁금하기도 하고, 일부 인터넷에서 공개 사전서비스를 하고 있는 사전 자료 등등이 궁금하기도 해서, 공개 영-한 사전 데이타를 찾아보고 재밌는 사실을 발견하게 됩니다.

공개 영-한 사전인 engdic에 관한 이야기는 다음 포스팅으로 이어집니다~

by dumpcookie 2013. 3. 2. 01:42
| 1 2 |