알꾸 제작일지 #1 — 알람을 꾸며보자, 아이디어부터 SF2 사운드폰트까지

알람 앱이 하나 있음. 근데 이 알람 앱은 좀 다름.

알람이 울릴 때 나오는 화면과 소리를 내 마음대로 꾸밀 수 있는 앱. 갤러리 사진으로 슬라이드쇼도 만들고, 직접 멜로디도 만들고, 목소리도 녹음해서 알람 소리로 쓸 수 있는 — 그런 앱을 만들어보기로 함.

이름은 Alku(알꾸). 한국어로는 ‘알람 꾸미기’, 핀란드어로는 ‘시작’이라는 뜻임. 이름값을 하려면 갈 길이 멀지만, 일단 시작은 했음.

이 글은 아이디어 구상부터 MVP 구현, 그리고 “이 소리가 음악이라고?”라는 자괴감을 거쳐 SF2 사운드폰트까지 도달한 하루짜리 개발 기록임. 시리즈로 계속 이어질 예정.

시작은 단순한 불만에서

아침에 알람이 울림. 기본 알람음. 짜증남. 좋아하는 노래로 바꿔볼까 — 근데 그러려면 음원 파일을 따로 구해야 함. 귀찮음.

유튜브 음악을 알람으로 쓸 수 있으면 좋겠다는 생각을 함. 근데 YouTube, Spotify, SoundCloud 전부 ToS에서 알람용 백그라운드 재생을 금지하고 있음. 이건 앱스토어 심사에서 바로 리젝 사유임.

그래서 방향을 틀었음. 남의 음악을 가져오는 게 안 되면, 직접 만들면 되지 않나?

MIDI 시퀀서를 넣어서 간단한 멜로디를 직접 찍을 수 있게 하고, 갤러리 사진으로 알람 화면도 꾸밀 수 있게 하고, 목소리 녹음까지 — 이 세 가지를 합치면 꽤 재밌는 알람 앱이 될 거 같음.

하루 만에 MVP 전체 구현

기술 스택은 Flutter + Riverpod 3.x + GoRouter. Feature 기반 폴더 구조로 잡고, 의존성 17개를 한 번에 세팅함.

하루 동안 만든 기능 목록이 꽤 됨.

  • 기본 알람 CRUD — Model, Repository, Service, Provider, Screen 전체 레이어
  • 커스텀 알람 화면 — 갤러리에서 사진 골라 슬라이드쇼로 보여줌. 그라데이션 오버레이까지.
  • 알람 소리 설정 — 내장톤, 로컬 음악 스캔(on_audio_query), Share Intent로 다른 앱에서 음원 공유 수신까지 3탭 UI
  • 음성 녹음 + 이펙트 — record 패키지로 녹음, flutter_soloud로 6종 이펙트 적용
  • 멜로디 메이커 — 16×5 펜타토닉 그리드 시퀀서, 5종 악기, WAV 렌더링 후 알람으로 저장

초기 커밋 기준 110개 파일, 9,859줄. 하루 치고는 양이 꽤 나옴.

근데 문제가 있었음.

“이게 음악이야?” — 사인파의 한계

멜로디 메이커를 재생해봄. 삐- 삐삐- 삐삐삐-. 학교 종 울리는 것도 아니고, 이건 그냥 전자음 장난감이었음.

원인은 명확함. 사인파(sine wave) 합성으로 소리를 만들고 있었기 때문임. 수학적으로 정확한 주파수의 파형을 그려서 소리를 내는 방식인데, 이걸로는 피아노도 오르골도 아닌 그냥 ‘삐’ 소리밖에 안 남.

ADSR 엔벨로프도 넣고, 리버브도 흉내내보고, 배음(harmonic)도 섞어봤지만 근본적으로 한계가 있음. 사인파는 사인파임.

이걸 가지고 “내일 면접이라 웅장한 음악으로 기상하고 싶어” 같은 유즈케이스를 충족시키는 건 물리적으로 불가능했음.

대안 탐색 — 8가지 방법 비교

음악 품질을 올릴 수 있는 방법을 전부 조사해봄.

  • AI 음악 생성 API (Suno, MusicGen 등) — 품질 최고. 근데 API 비용이 올라감. 무료 티어가 있긴 한데 상용 앱에 쓰기엔 불안정함.
  • 로컬 AI 생성 (on-device) — 모바일에서 돌리기엔 모델이 너무 큼. 현실성 없음.
  • 프리셋 MIDI 파일 번들 — 무드별로 미리 만들어둔 MIDI를 앱에 포함. 괜찮은데 수동 제작이 필요함.
  • 프로시저럴 음악 생성 — 코드 진행 + 패턴 알고리즘으로 자동 작곡. 가능성 있음.
  • SF2 사운드폰트 — General MIDI 표준 악기 128개를 실제 녹음된 샘플로 재생. 이게 답이었음.

결정적으로, dart_melty_soundfont라는 라이브러리가 이미 pubspec.yaml에 들어가 있었음. flutter_pcm_sound(실시간 PCM 스피커 출력)와 같은 개발자가 만든 Pure Dart SF2 렌더러임. 있는 걸 안 쓰고 사인파를 끙끙대고 있었던 거임.

SF2 사운드폰트 엔진으로 교체

TimGM6mb.sf2(5.97MB)를 assets에 내장함. General MIDI 호환이라 128개 악기를 전부 쓸 수 있고, 리버브와 코러스도 내장되어 있음.

기존 사인파 합성 코드를 전부 걷어내고, Synthesizer 기반으로 다시 짬. 핵심 변경 사항은 이랬음.

GM 악기 매핑 — 피아노(0), 오르골(10), 마림바(12), 실로폰(13), 종(14). 같은 5개 악기인데 이제 진짜 악기 소리가 남.

코드 반주 자동 생성 — 멜로디(ch0)와 코드(ch1)를 MIDI 채널로 분리함. I-vi-IV-V 코드 진행이 4스텝마다 자동으로 깔림. 이것만으로도 “음악” 느낌이 확 살아남.

스마트 패턴 생성기 — 기존 25% 확률 랜덤(=비음악적 소음)을 음악적 패턴 5종으로 교체함.

  • 상행/하행 아르페지오
  • 4음 스케일 프레이즈
  • 콜 앤 리스폰스 (질문-응답 구조)
  • 리듬 오스티나토 (반복 패턴)

랜덤 버튼을 눌러도 이제 나름 음악처럼 들림. 장난감에서 악기로 한 단계 올라간 느낌.

삽질 기록 — 실제로 겪은 문제들

재생 중 정지가 안 됨. FlutterPcmSound는 PCM 데이터를 버퍼에 밀어넣는 방식이라, _isPlaying = false로 플래그만 바꿔서는 이미 버퍼에 들어간 오디오가 계속 나옴. FlutterPcmSound.release()로 버퍼째 날려야 즉시 정지됨.

볼륨이 너무 작음. renderMonoInt16이 내부적으로 16384 스케일(Int16 최대값의 절반)을 사용함. x2 볼륨 부스트를 수동으로 걸어서 해결.

앱이 버벅임. SF2 파일(5.97MB)을 파싱하는 게 메인 스레드에서 돌아가는 게 문제였음. Isolate로 빼려고 시도했는데, Synthesizer 객체가 Isolate 경계를 넘지 못함 (직렬화 불가). 결국 메인 스레드에서 로드하되, 홈 화면에서 미리 워밍업시키는 방식으로 타협함. 260프레임 스킵이 52프레임으로 줄어듦. 완벽하진 않지만 체감은 나아짐.

미니 키보드 두 건반이 동시에 눌림. GestureDetector 히트 테스트 범위 문제. 건반 위젯 간격과 터치 영역을 조정해서 해결.

이런 삽질들이 쌓여서 “하루 만에 만듦” 뒤에 숨겨진 진짜 시간이 됨.

현재 상태와 다음 작업

지금까지 만든 결과물을 정리하면 이런 상태임.

  • 퍼플 테마 + 글래스모피즘 UI — 그라데이션 배경, 반투명 카드, 바텀 네비 4탭
  • 홈 대시보드 — 시간대별 인사말, 소리 만들기/화면 꾸미기/활성 알람 섹션
  • 알꾸 스튜디오 — 피아노롤 그리드, 미니 키보드, 사운드 웨이브 시각화, 마스터 믹스
  • SF2 사운드폰트 엔진 — GM 128악기 지원, 코드 반주, 스마트 패턴 생성
  • 커밋: 32 files changed, +3,245 lines

다음 과제는 멜로디의 음악성을 더 끌어올리는 것임. SF2로 악기 소리 자체는 좋아졌는데, 자동 생성되는 멜로디가 “음악”이라고 부르기엔 아직 부족함. 프리셋 MIDI 파일을 무드별로 번들하거나, 프로시저럴 작곡 알고리즘을 더 정교하게 만들거나, 아니면 결국 AI 생성 API를 붙이거나 — 방법을 좀 더 찾아봐야 할 거 같음.

실제 기기 빌드 테스트, 앱 아이콘 디자인, 음성 녹음 실기기 검증도 남아있음. 갈 길이 멀지만 하루 만에 여기까지 온 것치곤 나쁘지 않음.

다음 제작일지에서 계속.

댓글 남기기