UI 최전선

Windows 7에서 Phone 녹음

Charles Petzold

코드 샘플 다운로드

image: Charles Petzold1984 년 애플이 Macintosh를 소개 하는 아주 초기 홍보 포스터 중 하나에 다음과 같은 아주 매력적인 표현이 마우스 디자인을 홍보 한 것이 있습니다. 「 버튼이 두 개인 마우스도 있지만, Macintosh에 하나입니다. 버튼을 누르면 실수 따 윈 없다. 」

물론 이것은 전혀 사실이 아닙니다. 단추에 여러 기능을 할당 하면 단추가 여러 개 있는 것 처럼 혼동 됩니다. 그러나, 마우스를 누르고 실수할 가능성이 없는 것은 물론 UI 디자인을 간결 하 게 되는 것에 대 한 설득력 있는 주장 이다.

스마트 폰의 프로그래밍, UI 요소 수를 최소한으로 줄이는 것이 매우 중요 합니다. 휴대 전화는 별로 크지 않습니다. 대부분의 단추를 삽입할 수 없지만 단추 누르기 핑거 마우스 만큼 정확 하지는 않습니다. 단추가 너무 많은 경우에, 당신은 틀린 버튼을 누를 수도 있습니다.

반대로, UI 요소의 수를 제한 하면 프로그램의 기능이 제한 되는 경우가 많기 때문에, 어디에 선 긋기는 매우 悩ましい 것입니다. 인생은 타협의 산물입니다.

디자인의 진화

I thought it would be fun to write a Windows Phone 7 program that allows recording short vocal memos, such as “Remember to pick up the dry cleaning” and “Had a great idea for a movie: Boy meets girl.”

이러한 프로그램은 물론 유용한 데, 공공 장소에서 새로운 윈도 즈 Phone을 자랑 하는 구실도 사용 됩니다. 그 보다 더 중요 하다 고 생각은 휴대폰에서 지원 되는 녹음 및 재생에 대 한 클래스를 실제로 사용해 보는 대단한 기회 라는 점입니다.

하지만 프로그램의 디자인은 예상 보다 까다로울 것으로 나타났습니다. 단 한 줄도 작성, 고치지 않은 상태에서 머리에 여러 번 프로그램 디자인을 다시 하였습니다.

처음에는 녹음과 재생 라는 두 개의 단추를 제공 하며 모두 토글 단추 처럼 작동 시킨 충분 하다 고 생각 했습니다. 즉, 녹음 버튼을 눌러 녹음을 시작 하 고 다시 눌러 중지 하십시오. 이 프로그램에서는 격리 된 저장소에 음성 데이터를 저장 합니다. 재생 버튼을 누르면 저장 된 오디오 데이터를 재생 합니다. 녹음 버튼을 누를 때마다 이전 메모를 대체 하 고, 메모를 제거 하려면 삭제 단추를 제공 하지 않습니다.

또한 음성 인식 기능을 구현 하 여 프로그램 단추를 재생만 될 수도 있습니다. 프로그램에서 녹음 한 오디오를 포함 하는 경우에만 데이터를 저장할 수 있습니다. 그러나, 특정 방법으로 수동 임계값 설정을 사용 하지 않으면 주변 소음 및 실제 소리를 구별 하는 것은 대단히 어려워 했다. 따라서 하나의 버튼 디자인은 포기 했다.

원래 계획은 메모를 인 경우에 적합 합니다 여러 개의 메모를 녹음 하려면 적합 하지 않습니다. 거기에 프로그램에 보유 하 오디오 파일을 하나만 사용 하 여 새 메모를 녹음할 때마다 마지막 끝에 추가 하는 것을 생각 했다. 큰 파일을 한 번만 저장 되기 때문에 재생 버튼을 누르면 모든 메모가 계속 재생 됩니다. 물론 프로그램에서이 파일을 무한 하 게 확장할 수 없으므로 전체 파일을 삭제 하 고 모든 메모를 제거 하려면 제거 단추를 꼭 필요 합니다.

물론, 좋은 디자인은 아닙니다. 사실, 메모에 대해 별도의 파일을 보관 하 고 노트를 개별적으로 제거할 수 있도록 해야 합니다. 그러나 이렇게 하려면 재생 및 삭제할 수 있도록 모든 개별 파일을 사용자에 게 표시 해야 할 프로그램을 단번에 복잡 하 게 되었다. 파일을 선택 하려면 ListBox 검색 하 고 모든 메모를 확인할 수 있는 방법이 반드시 필요 합니다. 쪽지를 확인 하려면 사용자가 키워드를 지정 하 고 또한 불쾌 한 것은 실제 파일 이름을 사용 해야 합니다.

점점 복잡해 집니다. 이제는 먹지 않습니다. 저기 단계의 자동 응답기 기능을 가진 휴대폰을 살펴 보았습니다. 전화를 걸거나 메모는 개별적으로 녹음 되어 있지만 각 숫자가 표시 된 상태에서 쉽게 볼 수 있습니다. 재생 단추와 이전 통화 및 다음 전화를 참조 하는 [이전 페이지] 단추 및 [다음] 단추가 있습니다. 메모 또는 호출을 삭제 하면 해당 번호가 다시 매겨집니다. 메모의 번호가 매겨지도록 할 수도 하지 않을 수 있겠지만, 휴대 전화 화면에 자동 응답기 보다 크다는 것을 이용 하 여 각 메모 (녹음 일, 길이, 파일 크기 등)을 볼 수 있다고 합니다.

진짜로 일이 진행 되는 프로그램의 기본 화면에 ListBox를 추가한 경우 노트의 선택 뿐만 아니라 재생 하는 데에도 사용할 수 있다는 것을 알았을 때 였습니다.

프로그램 사용

최종 디자인은 물론 단순 최대한 추구 하는 것은 완전 한 기능을 갖춘 정보 관리 시스템의 사이에서 고민 끝에 타협의 산물입니다. 이번 칼럼에서 다운로드할 수 있는 SpeakMemo 프로젝트는 Silverlight for Phone Windows 용으로 작성 되었으며 Windows Development Tools Phone 7 필요 합니다. 프로그램은 모바일 에뮬레이터에서 실행할 수 있습니다. 에뮬레이터에서는 프로그램이 제대로 작동 하는 것 처럼 보이지만 실제로는 녹음 재생 되지 않습니다.

처음으로 SpeakMemo 프로그램을 실행 하와그림 1 과 같은 화면이 표시 됩니다.

image: The Initial SpeakMemo

그림 1SpeakMemo의 초기 화면

단추는 하나 뿐입니다. Or, at least one enabled button on a fairly uncluttered screen. 단추에는 격리 된 저장소 공간의 크기와 크기에 해당 하는 가능한 음성 녹음의 길이를 표시 하 고 있습니다. (단, 17 시간 동안 연속으로 메모를 녹음할 수 있는 것은 아니다).

[Record] 단추를 누르면 빨간색 점멸 단추로 바뀌고 단추에서 녹음 중 메모의 길이를 나타내는 표시기를 수시로 업데이트 됩니다 (그림 2 참조).

image: SpeakMemo While Recording

그림 2녹음 중인 SpeakMemo

다시 [record] 버튼을 누르면 녹음 한 메모 녹음 시간, 길이에서 차지 하는 저장 공간 크기 및 재생 단추를 화면에 표시 됩니다 (그림 3 참조).

image: SpeakMemo with One Memo

그림 31-노트를 저장 한 SpeakMemo

당연히, 재생 버튼을 누르면 메모를 재생 모드, 재생 및 일시 중지 모드 사이를 단추의 모양이 바뀝니다.

참고 하나만으로 발견 하기가 쉽지 않을 수 있지만 미리 녹음 된참고그림 4 와 같은 새로운 것 들부터 순서 대로 ListBox에 저장 하기 때문에 녹음 된 메모가 많은 경우 목록을 스크롤하여 독립적으로 재생할 수 있습니다.

image: The SpeakMemo ListBox

그림 4SpeakMemo ListBox

Silverlight의 강력한 기능 중 하나는 ListBox의 항목의 모양을 정의할 수 있는 DataTemplate입니다. DataTemplate은 단추 같은 다른 컨트롤을 포함할 수 있습니다. DataTemplate에 단추를 포함 하는 실용적인 응용 프로그램을 개발 하는 것은 기쁜 것입니다.

메모를 개별적으로 제거 하 여 수집 된 메모를 관리할 수도 있습니다. 메모를 선택 하 고 [delete] 단추가 활성화 됩니다. DataTemplate에 단추를 추가 하는 것이 요령 이며 Silverlight의 또 다른 기술을 사용 하 고 [delete] 내에 또 다른 2 개의 단추를 추가 했습니다. 이러한 단추는 다음 delete를 누르면 나타나는 익숙한 확인 기능을 전환 합니다 (그림 5 참조).

image: Confirming a Delete

그림 5삭제 확인

메모를 재생 하 여 메모를 선택할 수 있지만 재생 단추 오른쪽에 있는 영역을 눌러 메모를 재생 하지 않고 선택할 수 있습니다. 이 프로그램은 한 개의 메모를 재생 하는 동안 메모를 녹음 하 고 동시에 더 많은 메모를 삭제할 수 있습니다.

핸드폰과 소리

한 때 Windows 7에서 Phone Microsoft. NET Framework System.Speech 네임 스페이스에 포함 된 음성 인식 및 텍스트 음성 변환의 일부를 지 원하는 것으로 간주 되 고 있었습니다. 아마도 이러한 기능은 향후 지원 될 것입니다.

그때까지, Microsoft.Xna.Framework.Audio 네임 스페이스의 클래스를 사용 하 여 휴대 전화의 마이크를 통해 음성을 통합 하 고 휴대 전화의 스피커를 통해 재생 합니다. 이 네임 스페이스의 클래스는 클래스 이지만, XNA Silverlight 프로그래밍 방식으로도 사용할 수 있습니다. XNA 클래스를 Silverlight 프로젝트에서 사용 하려면 Microsoft.Xna.Framework.dll에 대 한 참조를 프로젝트 참조에 추가 하 여 경고를 무시 하면 됩니다.

Microsoft.Xna.Framework.Audio 네임 스페이스의 클래스는 Microsoft.Xna.Framework.Media 네임 스페이스의 클래스와는 전혀 관계가 없습니다. Media 네임 스페이스에는 모바일 음악 라이브러리에 저장 된 음악을 재생 하는 클래스가 포함 되어 있습니다. 이것은 MP3 또는 WMA 형식으로 압축 된 오디오 파일에서 Song 형식의 개체로 변환 합니다. 이 칼럼에서는 필자의 『 Programming Windows Phone 7 』 (Microsoft Press, 2010 년)의 제 18 장에서 나오는 음악 라이브러리에 액세스 하는 방법에 대해 설명 합니다. 이 책는bit.ly/dr0Hdz (영문 사이트)에서 무료로 다운로드할 수 있습니다. In a blog entry on my Web site, I also demonstrate how to play MP3 or WMA files that are stored within the program itself, or which are downloadable over the Internet (bit.ly/ea73Fz).

반면에 Microsoft.Xna.Framework.Audio 네임 스페이스에서는 표준 PCM 형식 압축 되지 않은 오디오 데이터를 처리 합니다. 이것은 Windows 오디오 CD 및 WAV 파일과 같은 기술입니다. PCM은 아날로그 소리의 진폭을 일정 비율 (일반적으로 초당 8000-48000 견본)에서 샘플링 되며이 단원에서는 일반적으로 8 비트 또는 16 비트 값으로 저장 됩니다. 특정 사운드 파일에 필요한 저장소 크기를 재생 시간 (초), 샘플 레이트, 샘플링 당 바이트 수를 곱한 값입니다 (스테레오의 경우에는 그 두 배입니다).

Windows 응용 프로그램에서 Phone 7 음성 인식 기능을 지원 해야 하는 경우 (보통은 웹 서비스를 통해) 해당 기능을 제공 해야 합니다. 마찬가지로 텍스트를 음성으로 변환 해야 하는 프로그램은 웹 서비스를 사용 하거나 휴대폰에서 지원 될 때까지 기다려야 합니다. Windows 용 Microsoft Phone Translator 응용 프로그램에서는 Microsoft Translator 서비스 (microsofttranslator.com)를 사용 하 여 음성 기능을 제공 합니다. Translator Starter Kit의 코드와 설명서는 MSDN (/library/gg521144 (VS.92) msdn.microsoft.com .aspx, 영문) 및 AppHub (create.msdn.com/education/catalog/sample/translatorstarterkit, 영문)에 게시 합니다.

XNA 오디오 서비스를 사용 하는 경우 Silverlight는 비디오 새로 고침 빈도와 거의 같은 속도로 정적 FrameworkDispatcher.Update 메서드를 호출 해야 합니다 (Phone Windows 7에서 비디오 화면 주사율은 초당 약 30 회). XNA에 대 한 온라인 설명서의 「 Windows 응용 프로그램에서 Phone XNA Framework 이벤트 활성화 」 (msdn.microsoft.com/library/ff842408)에 대 한 정보가 포함 되어 있습니다. SpeakMemo 인 경우 XnaFrameworkDispatcherService 클래스를 사용 하 여이 프로세스를 수행 합니다. 이 클래스의 인스턴스는 App.xaml 파일에서 만듭니다.

녹음

휴대 전화의 마이크를 통해 녹음할 수 Microphone 클래스를 사용 합니다. 아마도이 클래스의 인스턴스는 다음 예제와 같이 정적 Default 속성을 사용 하 여 만들 수 있습니다.

Microphone microphone = Microphone.Default;

또한 All 속성에서 Microphone 개체의 컬렉션을 지정할 수도 있지만이 경우 사용자가 마이크를 선택할 수 있는 목록을 표시 합니다.

샘플 속도는 고정 되어 있으며 변경할 수 없으며, SampleRate 속성에서 초당 16000 샘플 임을 알 수 있습니다. 나이키 스 트 샘플에 대 한 정리에 따르면,이는 주파수가 8000 Hz까지 구타를 녹음할 때 적합 합니다. 이 주파수는 인간의 목소리에는 적합 하지만 그다지 높은 음악 음질을 기대할 수 없습니다. 각 샘플은 너비의 모노입니다. 즉, 녹음 된 소리는 1 초에 32000 바이트 필요 하며 분 단위로 환산 1.9 MB입니다.

마이크의 데이터는 단순한 바이트 배열 버퍼에 저장 되 고 프로그램으로 제공 됩니다. BufferReady 이벤트 처리기를 구현 하 여 Start 메서드를 호출 하 여 녹음을 시작 합니다. Microphone 객체에서 BufferReady 이벤트가 발생 한 후 코드에서 바이트 배열을 지정 하 고 GetData 메서드를 호출 합니다. GetData 메서드는 값이 반환 될 때 버퍼에는 PCM 데이터를 포함 하 고 있습니다. 녹음을 중지 하려면 GetData 메서드를 다시 호출 하 여 마지막 부분 버퍼를 가져옵니다. GetData 메서드는 배열에서 전송 된 바이트 수를 반환 합니다. 마지막으로, Stop 메서드를 호출 합니다.

Microphone 객체에 지정할 수 있는 유일한 옵션은 GetData 메서드에 전달 되는 버퍼의 크기 (바이트)입니다. The BufferSize property is a TimeSpan value that must be between 100 ms and 1,000 ms (one second) in increments of 10 ms. In SpeakMemo, I left it at the default value of 1,000.

유용성을 높이려면 Microphone 클래스에는 버퍼 크기 및 시간을 상호 변환 하는 두 개의 메서드가 있습니다. 그러나 이러한 메서드는 이름에 "sample"가 포함 되어 있기 때문에 조금 소지가 있습니다. GetSampleDuration 메서드는 바이트를 32000으로 나누어 해당 하는 시간 (초)을 나타내는 TimeSpan을 반환 합니다. GetSampleSizeInBytes 메서드는 초 단위로 측정 길이에 32000 TimeSpan을 곱합니다.

SpeakMemo에서 녹음 하는 동안 제네릭 List 컬렉션에 32000 바이트의 버퍼를 여러 누적 됩니다. 녹음/녹화를 중지 하면 모든 버퍼를 격리 된 저장소의 파일에 저장 합니다.

참고 특정 키워드 기능을 구현 하지 않기로 결정 후 파일의 내용을 PCM 데이터에 대 한 추가 정보는 포함 시 키 지 않는 것을 결정 했다. 그러나 Silverlight for Windows Phone에 대 한 IsolatedStorageFile 클래스에는 파일을 만든 날짜 또는 마지막 수정 날짜 및 시간으로 액세스 하기 위한 메서드가 지원 되지 않는다는 것을 알고 매우 놀랍게도,이 정보는 사용자를 위해 필수 라고 생각 합니다.

따라서 파일 이름에 날짜와 시간을 포함 해야 했습니다. 첫 번째 단계는 서식 옵션에 문자 "s"와 "u"를 사용 하 여 DateTime 개체의 파일 이름을 만들려고 했지만, 더 이상 없습니다. (실패의 원인에 대 한 독자의 과제로 남겨 두어야 합니다). 그 후, 여러 가지 날짜 및 시간 구성 요소를 결합 하 여 고유한 파일 이름을 생성 했습니다.

XNA 음성 미리 듣기

Microsoft.Xna.Framework.Audio 네임 스페이스의 클래스와 연관 된 SoundEffect SoundEffectInstance 클래스를 사용 하면 녹음 된 음악을 재생할 수 있습니다. XNA 게임에서 이러한 클래스의 일반적인 기능에서 상상 하는 이름입니다. 그러나 정적 SoundEffect.FromStream 메서드는 RIFF 헤더가 포함 된 표준 Windows WAV 파일을 가리키는 Stream 개체를 사용 해야 합니다. 이 예에서는 파일 형식에 대 한 세부가 필요 하지 않습니다.

대신에 WAV PCM 데이터를 수정 하지 않고 전부 처리 하려면 SoundEffectInstance 클래스에서 파생 된 DynamicSoundEffectInstance 클래스를 사용 합니다. 이 클래스는 Microphone 클래스에서 생성 된 데이터 및 사용자 고유의 파형 데이터를 동적으로 만들 수 있는 프로그램 (합성 프로그램)에 이상적입니다.

DynamicSoundEffectInstance 생성자에는 샘플 속도 및 채널 수 있어야 합니다. 즉, 마이크를 통해 생성 된 데이터 클래스를 사용할 때는 다음과 같이 하 여 일관성을 유지 해야 합니다.

DynamicSoundEffectInstance playback = 
  new DynamicSoundEffectInstance(
  microphone.SampleRate, AudioChannels.Mono);

한편, 고속 재생 하 고 빨리 다람쥐 처럼 음성을 사용 하는 경우 첫 번째 인수를 두 배로 합니다. DynamicSoundEffectInstance 클래스는 데이터 16 비트 샘플 크기를 가정 하 고 있습니다. 이 클래스는 재생을 제어 하기 위해 Play, Pause, Resume 및 Stop 메서드는 현재 상태를 나타내는 State 속성이 있습니다. The class works somewhat the opposite of Microphone: It fires a BufferNeeded event when it requires a new buffer. 개발자가 해야 할 것은, PCM 데이터를 버퍼링 하 여 SubmitBuffer 메서드를 호출 하는 것입니다.

재생 중에 소리가 고르지 않게 하려면 DynamicSoundEffectInstance 클래스에서 버퍼 큐를 관리할 수 있으며 이전 버퍼 재생 되는 동안 새 버퍼를 보냅니다. 이러한 작업에 도움이 되는이 클래스에는 큐에 있는 버퍼 수를 나타내는 PendingBufferCount 속성이 있습니다. PendingBufferCount 값이 2로, BufferNeeded 이벤트가 발생 합니다.

그러나 PCM 데이터를 조회 하면 마음에 BufferNeeded 이벤트를 무시 하 고 SubmitBuffer 메서드를 호출할 수 있습니다. 애초에 SpeakMemo 프로그램은 이런 방식으로 DynamicSoundEffectInstance 클래스를 사용 하 고 있었기 때문 인데, 버퍼 재생이 종료 시기를 결정할 수 없는 것으로 나타났습니다. DynamicSoundEffectInstance 클래스는 상태 변경 이벤트를 사용 하지 않고 있었다고 하더라도 버퍼의 끝 부분에서 재생 상태를 중지 된 상태로 전환 되지 않습니다. 다음 버퍼를 대기만 하면 됩니다. 이 정보를 인식할 수 없기 때문에 프로그램에서 재생 및 일시 정지 단추 모양이 제대로 전환 되지 못했습니다.

이번에는 BufferNeeded 이벤트를 처리 하기로 결정 했지만 용도는 PendingBufferCount 속성 값을 확인 하는 것입니다. PendingBufferCount 속성 값이 0에 도달 하면 버퍼 재생을 종료 합니다.

저장소 문제

SpeakMemo에서 녹음 한 메모를 격리 된 저장소에 저장 합니다. 개념적으로, 격리 된 저장소는 응용 프로그램의 개인 영역 이지만, 실제로는 데스크톱 컴퓨터의 하드 드라이브와 비슷한 이동 통신 전반에 있는 저장소 공간의 한 부분 이다. 격리 된 저장소에는 모든 응용 프로그램의 실행 파일 외에도 휴대폰의 사진 도서관, 음악 라이브러리, 비디오 라이브러리 등이 포함 됩니다. Windows 7의 하드웨어 사양 Phone은 휴대폰에는 격리 된 저장소 공간에 대 한 최소한 8 기가바이트 플래시 메모리, 저장소 공간이 부족 하면 휴대 전화에서 사용자에 게 알리는 것을 요구 하 고 있습니다.

참고 파일을 저장 하는 것에 대해서 너무 걱정 하지 않았다. 오히려 걱정 이었는데, 힙과 프로그램 이었습니다. Windows 7의 하드웨어 사양 Phone은 플래시 메모리 저장소 이외의 256 MB의 RAM이 필요 합니다. 이것은 응용 프로그램이 실행 되는 동안 메모리에서 차지 하는 프로그램의 로컬 힙에서를 제공 합니다. 실험 한 결과, SpeakMemo에서 메모리 부족 예외가 발생 하기 전에 배열에 최대 90 MB 할당 되는 것으로 나타났습니다. 이 크기는 47 분 마이크를 통해 음성을 통합 하는 것과 같습니다.

그렇다고 Windows Phone 7 프로그램의 녹화 시간을 50 분 이내에 제한 될 필요는 없습니다. 그러나 47 분 이상 연속 녹음 하려면 버퍼를 격리 된 저장소에 저장 하 여 지속적으로 메모리를 해제 하 고 슬라이드에는 단계별로 파일을 로드 해야 합니다. SpeakMemo는 이러한 디자인을 하 고 있습니다. SpeakMemo에서는 그 파일 전체를 저장 하 고 로드 하며이 매우 간결한 구조를 포기할 마음이 진행 하지 못했습니다.

이러한 이유로, 메모의 길이를 최대 10 분으로 설정 했습니다. 녹음 된 메모를이 시간에 도달 하면 녹음을 중지 하 여 메모를 저장 합니다 (이 프로세스에는 몇 초가 걸릴 수 있음). 프로그램을 간단 하 게 경고를 표시 하지 않습니다. 사용자가 중지 단추를 클릭 한 것 처럼 녹음을 중지 합니다. 이 자동 중지 및 저장소 작업 부하, 프로그램을 종료 하거나 비활성 (기다리기가 지루한 독자 중) 할 때이 문제가 발생 합니다.

물론 10 분 동안 메모를 재생 작업은 그다지 유용 하지 않습니다. 재생 재생 모드 및 일시 중단 모드를 전환 시키지만, 되감기 및 빨리 감기 없습니다. 이러한 기능을 추가할 수 있지만이를 위해 필요한 요소는 알 수 없네요.

Yes: more buttons. Slider에도 적합 한지 모른다.

Charles Petzold is a longtime contributing editor to MSDN Magazine*. His new book, “Programming Windows Phone 7” (Microsoft Press, 2010) is available as a free download from bit.ly/dr0Hdz.*

Thanks to the following technical expert for reviewing this article: Mark Hopkins