왜 자작 음악 플레이어의 소리가 흩날릴까
개시하다
며칠 전에 나는 자기 집을 위한 음악 플레이어를 만들었다.음악 플레이어도 좀 특이하지만, 따로 랩베리피로 시작한 스트리밍 서버에서 보비스의 소리를 받아 스피커를 재생하는 물건이다.
Music Player Daemon은 스트리밍 서버로 사용됩니다.
도대체 왜 했을까
Music Player Daemon은 음악 파일이 저장된 디렉토리에서 음악 파일을 재생성하는 데몬입니다.음악 파일이 있는 서버에서 사운드를 낼 수 있지만 래스퍼리 피에는 스피커가 없습니다.그리고 가능하다면 다른 터미널로 소리를 틀고 싶습니다.이를 위한 용도로 뮤직플레이어 데몬은 HTTPD로서도 편지를 배달할 수 있는 기능이 있다.
개인적인 용도로 음악 파일은 랩버리 피로 한 곳에 보관하고 다른 터미널은 듣고 싶은 그런 구조를 만들려고 한다.
하지만 뮤직플레이어 대몬이 공식 제공한 컨트롤러 mpc는 HTTPD에 게시된 소리를 재생할 수 없다.브라우저 등으로 HTTPD의 URL을 열면 되지만 조작하는 곳과 재생하는 곳이 달라 조금 납득하기 어렵다.
그래서 소리를 틀고 곡을 진행할 수 있는 다음 송신 정도의 지령선 도구를 만들고 싶다.
방법
Go 언어로 만들었어요.
명령
-addr
은 Music Player Daemon의 주소(IP:PORT)를 플래그로, HTTPD의 URL을 -stream
플래그로 지정합니다.환경 변수는 기본값을 제공합니다.뮤직플레이어 데몬과의 통신은
github.com/fhs/gompd/mpd
패키지가 있어서 그걸 사용했어요.스피커github.com/hajimehoshi/oto
를 어떻게 재생하는지에 관해서는oto의 저자인 Hajime Hoshi에게 Vorbis의 디코딩 방법github.com/jfreymuth/oggvorbis
을 추천하기 때문에 이 방법을 사용했다.문제가 생기다
만드는 과정에서 나는 왜 푸푸 소리를 내는지 알아차렸다.일지에서 조사를 했지만 잘 모르겠습니다.vim-jp의 슬랙 여러분도 디버깅에 참여했지만 모르겠습니다. 다음과 같은 추측을 했습니다.
흐르는 전송 서버에서 바이트열을 수신하고oggvolbis로 디코딩하여oto에서 이런 프로세스를 재생하는 데 버퍼링할 수 없습니다
다양한 버퍼링과 처리를 시도했지만 전혀 개선되지 않았습니다. 라이브러리 어딘가에 오류가 있다고 생각했습니다.
유감스럽지만, 오류는 당신의 코드입니다.
각종 조사에서 다음과 같은 코드에 문제가 있음을 발견하였다.
samples := make([]float32, bufferSize)
for {
st.Read(samples)
for i, val := range samples {
if val < -1 {
val = -1
}
if val > +1 {
val = +1
}
valInt16 := int16(val * (1<<15 - 1))
low := byte(valInt16)
high := byte(valInt16 >> 8)
buf[i*2+0] = low
buf[i*2+1] = high
}
player.Write(buf)
}
이것은 oggvorbis
버퍼 구역에서 샘플을 채취하여low/high로 스피커로 나누는 처리입니다.이 코드 자체는oto를 사용한 음성 재생 라이브러리github.com/faiface/beep
에서 참고한 것이다.스피커에 기록된 바이트열buf
은 샘플링 버퍼samples
([]flat32)를 low/high로 분해하여 samples
사이즈의 2배이다.numBytes := bufferSize * 2
buf := make([]byte, numBytes)
실제로 상술한 코드의 st.Read(samples)
는 되돌아오는 값이 있다.이것은 읽는 샘플의 수이지만, 매번 읽는 횟수는 다르다.이 값을 사용하지 않고 samples
를 슬라이스하면 쓰레기는 고정 사이즈로 만든 buf
뒤에 남는다.변명입니다만, 이 인코딩beep에서 빌려주세요.은 했습니다.(핑계를 대는 것 같다)이
buf
뒤에 만들어진 망가진 소리 데이터가 매번 스피커로 흐르기 때문에 찰칵찰칵 소리가 날아야 한다.for i, val := range samples[:n] {
if val < -1 {
val = -1
}
if val > +1 {
val = +1
}
valInt16 := int16(val * (1<<15 - 1))
low := byte(valInt16)
high := byte(valInt16 >> 8)
buf[i*2+0] = low
buf[i*2+1] = high
}
player.Write(buf[:n*2])
읽을 수량과 쓸 수량의 슬라이스를 통해 오류가 제거되었습니다.Go 언어에서는 소킷 통신 프로그램을 만들 때 아래 코드를 자주 볼 수 있지만, 결과적으로 실현되지 못한 것과 같다.var buf [4096]byte
n, err := conn.Read(buf[:])
if err != nil {
return err
}
fmt.Println(string(buf[:n]))
끝말
읽은 데이터는 읽은 크기로 처리하십시오. (자동 끊기)
Reference
이 문제에 관하여(왜 자작 음악 플레이어의 소리가 흩날릴까), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/mattn/articles/2c11c179e4dd811f6d7f텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)