스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
ShazamKit을 사용하여 규모에 맞는 맞춤형 카탈로그 생성
ShazamKit을 사용하여 맞춤형 카탈로그를 빌드하고 앱 내에 있는 모든 오디오 소스를 기기만으로 정확히 검색하도록 지원하는 방법을 알아보세요. 새로운 ShazamKit CLI를 통해 오디오 서명을 손쉽게 생성하고 규모에 맞는 카탈로그를 빌드하는 방법을 확인하세요. 또한 TV 프로그램의 여러 시즌 또는 팟캐스트의 여러 에피소드와 같은 대용량 오디오 콘텐츠와 동기화할 수 있도록 앱을 빠르게 업데이트하는 방법을 보여드리고, 앱이 시간 범위를 사용하여 오디오 소스 내의 주요 순간에 정확하게 대응할 수 있도록 하는 ShazamKit API 및 SHMediaItems의 업데이트를 소개합니다. ShazamKit에 대한 자세한 내용을 알아보려면 WWDC21의 ‘Explore ShazamKit(ShazamKit 살펴보기)' 및 ‘Create custom audio experiences with ShazamKit(ShazamKit으로 맞춤형 오디오 경험 만들기)'를 시청하시기 바랍니다.
리소스
관련 비디오
WWDC23
WWDC21
-
다운로드
♪♪
ShazamKit 팀 엔지니어 Neil Foley입니다 2021년 ShazamKit가 도입되었는데요 Shazam의 거대한 레코드 뮤직 카탈로그죠 CustomCatalog 매칭도 도입했는데요 개발자들이 자신의 오디오를 매칭해 동기화 경험을 제공할 수 있게 됐죠 대규모 카탈로그 작업시 능률을 올릴 수 있도록 업데이트를 좀 했는데요 오늘은 서명, 카탈로그 미디어 아이템 등 기존 ShazamKit 개념을 일부 사용할 겁니다 아직 잘 모르신다면 Shazam 및 ShazamKit와 관련된 작년 WWDC의 두 세션을 참고하세요 간략히 말씀드리면 ShazamKit는 오디오를 매치되는 특수 포맷으로 전환하게 합니다 이걸 '서명'이라고 하는데요 서명은 참조 서명을 만들기 위해 메타데이터를 포함하는 미디어 아이템과 결합됩니다 '참조 서명'은 '커스텀 카탈로그'라는 파일에 함께 저장될 수 있고요 ShazamKit는 이렇습니다 이제 대규모 커스텀 카탈로그를 함께 구축해 보죠 멋진 카탈로그 만드는 팁과 트릭도 알려드릴게요 현재 커스텀 카탈로그 워크플로우는 매칭하고 싶은 콘텐츠 양이 적다면 커스텀 카탈로그로 쉽게 만드실 수 있습니다 다음 순서대로 하시면 됩니다 ShazamKit가 승인하는 포맷으로 오디오를 녹음하세요
시그니처로 바꾸기 위해 서명 생성기를 사용하시고요
이걸 메타데이터에 주석으로 다시고 커스텀 카탈로그에 저장하세요 이게 끝입니다 Shazam 경험 제공이 가능해요 어떤 단계는 약간 버거울 수 있습니다 특히 오디오 프래그래밍에 친숙하지 않으신 분들이라면요 샘플링 속도나 버퍼 다루기가 어려울 수 있죠 경험이 많은 개발자에게도요 Shazam이 가능하게 만들고 싶은 콘텐츠가 어마어마하게 많다면 어떻게 해야 할까요?
이 워크플로우는 힘들 수 있습니다
콘텐츠 양이 많다면 금방 관리하기 힘들어지죠 여러분 자신을 위해 워크플로우를 개선하시려면 오디오를 서명으로 바꾸는 코드를 쓰고 더 많은 코드가 로드되어 미디어 아이템과 연결해야 하죠 콘텐츠를 바꿀 때마다 이 작업을 반복해야 합니다 오디오 매칭을 원하신다면 큰 투자인 거죠 콘텐츠를 ShazamKit와 동기화하고 싶으시다면 어떤 게 언제 보일지 알려면 복잡한 로직이 필요합니다 이 워크플로우를 간단하게 해줄 개선 사항을 알려드리죠 빠르게 데모로 살펴볼게요 Alex가 2021년 온스크린 수업에서 수학 퀴즈를 동기화한 FoodMath 앱인데요 여기에 ShazamKit의 최신 기능을 업데이트했습니다 이제 어떻게 동기화되는지 FoodMath 영상을 보죠
26초로 넘어가 초록 사과 2개, 3개 제가 가진 사과는 총 몇 개일까요? 시간재기...시작 ♪♪ 시간 다됐어요 어떻게 했는지 볼까요? 56초로 넘어가 오늘은 좀더 다양한 걸 해보죠 쇼핑에 가서 빨간 사과 2개와 초록 사과 2개를 샀습니다 저는 이번에 총 몇 개의 사과를 샀을까요? 시간 재기...시작
시간 다 됐네요 잘 작동하네요 영상과 동기화된 콘텐츠가 많아서 '지금'이라고 하면 바로 메뉴가 뜹니다 콘텐츠가 더이상 관련 없으면 때맞춰 바로 사라지고요 어떤 원리일까요? 코드를 한 번 봅시다 단순한 루프네요 우리가 전에 사용했던 델리게이트 콜백 대신에 세션에 Async Sequence를 사용하고 있네요 매치를 나타내는 열거형을 반환하고 안될 경우 오류나죠 전 매치에만 관심이 있어서 루프는 여기에서만 볼게요 디스플레이에 대한 결과값을 만들기 위해 미디어 아이템은 필요한 콘텐츠로 제한할게요
이 앱에서는 그렇게 많은 게 보이진 않겠네요 우리가 만든 matchResult로 가능한 SwiftUI 뷰 정도가 있겠네요 로직과 타임코드가 단순하고 동기화도 완벽하네요 하지만 어떻게 이렇게 동기화가 잘 되는 거죠? FoodMath의 비밀은 풍부한 커스텀 카탈로그에 있죠 ShazamKit 보완 툴로 카탈로그를 만들었어요 여러분도 앱의 풍부한 경험을 만들기 위해 사용하실 수 있죠 Shazam CLI는 macOS 13에 포함되어 콘텐츠 동기화를 쉽게 할 수 있게 해줍니다 커스텀 카탈로그 만들 때 반복되는 일들도 자동화할 수 있도록 도와주죠 그럼 보여드렸던 카탈로그를 업데이트 해보겠습니다 두 번째 데모입니다
FoodMath 영상 파일에 포함된 폴더인데요 동일한 폴더에 제 터미널도 있습니다 Signature 명령어를 사용해 영상을 서명으로 바꾸기 위해 CLI를 사용해 볼게요
영상 파일을 입력값으로 하고 서명 출력값을 구체화하죠
서명이 생겼고요
이제 커스텀 카탈로그를 만들기 위해 이 서명을 미디어 아이템과 결합시켜 볼게요 CLI는 여기 복사할 미디어 아이템 기술을 위해 단순한 CSV 파일을 받아들입니다
콘텐츠를 동기화하기 위해 필요한 모든 걸 기술하죠
여긴 타이틀을 구체화한 곳이고요 여긴 방정식에 대해 정의한 커스텀 JSON 필드입니다 헤더는 미디어 아이템에 프로퍼티를 배치하죠 매핑에 대한 자세한 정보는 flag.의 도움으로 custom-catalogue create 명령어를 실행시키면 됩니다
SCV 헤더와 미디어 아이템 프로퍼티의 관계를 기술하죠 이제 이들을 커스텀 카탈로그에 결합할게요 create 명령어를 실행하면...
서명, CSV 파일은 통과하고 카탈로그를 출력합니다
좋아요 이제 카탈로그가 생겼네요 최신 FoodMath 에피소드를 빨리 액세스할 수 있게 됐는데 이걸 카탈로그 파일에 추가해 보겠습니다 여기 있는 파일을 복사할게요
이게 새 에피소드에 대한 미디어 아이템이고요
새로운 미디어인 영상을 통과하는 update 명령어를 실행해 카탈로그를 업데이트할게요
다 됐습니다 카탈로그 만들기에 대해 빠르게 살펴 보았는데요 여러분도 저처럼 써보실 수 있을 거예요
FoodMath 앱에 실제로 에피소드가 몇 개 나왔는데요 이걸 모두 이 카탈로그에 넣고자 합니다 모든 에피소드 폴더를 통과하는 단순 스크립트를 써서 커스텀 카탈로그에 결합시켰어요 실행해 볼게요
됐네요 이제 모든 에피소드를 나타내는 카탈로그가 생겼네요 카탈로그 내부를 자세히 하려고 display 명령을 사용했고요 다 된 것 같네요 이미 우리의 새 카탈로그를 참조하고 있네요 이제 수학 공부를 위한 작업을 좀 해보죠
30초로 넘어가 사과는 총 몇 개일까요? 시간 재기...시작 ♪♪ 시간 다 됐네요 어떻게 했는지 보죠 정말 잘하네요 이 에피소드 좋아요 새 에피소드는 어떤지 그것도 한 번 봅시다
15초로 넘어가 몇 년 동안 저는 과카몰리가 맛있다고 생각해서 나만의 레시피를 만들었습니다 아보카도 4개가 있는데요 친구가 놀러왔어요 이제 2명이니까 반으로 나눠야겠죠? 제 아보카도는 몇 개일까요? 시간재기...시작 ♪♪
맞습니다 2개가 필요하죠 이제 과카몰리를 함께 만들어 봅시다 ♪♪
한 번 먹어볼까요?
음, 맛있네요 여러분도 즐거우셨길 바라요 다음에 만나죠
와! 새로운 호스트네요 아주 재밌어요 어쨌든 바로 동기화 경험이 풍부해졌네요 Shazam CLI는 많은 명령어를 지원합니다 뭐가 있는지 볼까요?
오디오 트랙이 있는 미디어 파일에서 서명을 만들 수 있는데요 커스텀 카탈로그는 서명과 미디어 카탈로그를 결합하여 만들 수 있습니다 카탈로그 내용을 보여줄 수 있고요 서명과 미디어 아이템 모두 추가, 삭제, 내보내기가 가는하죠 다음으로 CLI가 영상에서 서명을 어떻게 만들었는지 살펴보도록 하죠
SHSignatureGenerator은 모든 플랫폼에서 이용 가능한 signatureFromAsset라는 메소드를 가집니다 이거면 오디오 버퍼를 직접 뺄 필요가 없죠 오디오 트랙에 AVAsset를 통과시켜 서명으로 바꾸고요 에셋에 트랙이 여러 개라면 모두 섞여서 서명이 모든 걸 캡처하도록 할 겁니다 이제 미디어를 나타내는 서명이 생겼네요 어떻게 콘텐츠와 정확히 동기화했을까요? Timed MediaItem API가 그 정답입니다 미디어 아이템에 시간 범위를 첨부하여 언제 시작하고 끝나는지 쉽게 구체화가 가능하죠 미디어 아이템 또한 시간 범위가 다양하여 서명의 한 부분 이상을 타겟으로 할 수 있습니다 노래 코러스를 타겟으로 하는 미디어 아이템이 있다고 하죠 그럼 재생되는 각 위치에 시간 범위 추가가 가능합니다
시간 범위 구체화는 노래가 언제 시작하고 끝나는지 알 수 있을 때 유용하죠 ShazamKit는 시작점과 끝점인 시간 범위와 동기화된 매치 콜백을 전달할 겁니다 서명에는 많은 미디어 아이템이 포함될 수 있어 이 콜백에는 범위 내 특정 지점의 아이템만 포함하죠 콜백과 명령에서의 미디어 아이템 반환에는 규칙이 몇 개 있는데 그걸 한 번 살펴 봅시다
시간 범위를 벗어난 아이템은 반환되지 않습니다 범위 안에 있어야만 반환되죠 가장 최근 이벤트가 가장 먼저 오고요
시간 범위가 없는 아이템은 항상 마지막에 반환되지만 명령되지는 않습니다 시간 범위가 없는 아이템은 전체 참조 서명에 적용되는 글로벌 정보 저장에 딱이죠 저도 FoodMath 사례에서 에피소드명 저장에 사용했어요 다른 아이템이 범위에 없으면 나타나죠
미디어 아이템에 시간 범위가 있고 영역 내에 위치하지 않는다면 ShazamKit는 기본 매치 정보로 아이템을 반환할 겁니다 predictedCurrentMatch 오프셋과 frequencySkew 같은 중요 프로퍼티를 항상 이렇게 얻을 수 있죠 코드도 어렵지 않습니다 시간 범위가 있는 아이템은 timeRanges 프로퍼티를 구체화하여 만들어지는데요 이건 Swift Ranges의 배열입니다 이것도 timeRanges 프로퍼티를 사용해 다시 읽힐 수 있죠 Objective-C 프로그래머 분들은 새로운 SHRange 클래스를 대체 드롭으로 사용하실 수 있습니다 이제 어떻게 만드는지 보셨으니 멋진 카탈로그를 만들 수 있는 팁과 트릭을 살펴 보죠 먼저, 미디어 한 조각에 작은 서명 여러 개는 피하세요 서명은 나타내는 미디어에 대한 일대일 매핑입니다 노래든 영상이든 가지고 있는 오디오 한 조각엔 전체 지속 기간 동안 서명을 하나만 만드세요
긴 서명은 ShazamKit가 오디오 피크를 더 잘 매치해 정확도가 더 좋아질 수 있습니다 여러 서명 참조에 요청 서명이 겹치는 문제도 피할 수 있게 해주죠
Timed MediaItem API를 사용해 동기화된 콘텐츠를 개별 영역에 타겟팅하세요 오디오 조각을 서명 여러 개로 나눌 필요가 없습니다 미디어 조각이 하나지만 미디어 아이템은 다양한 사례를 보았는데요 Shazam이 가능하게 하고픈 콘텐츠 양이 엄청 많다면 어떻게 해야 할까요? 어떻게 나눌 수 있죠? 커스텀 카탈로그 전반의 콘텐츠를 나눌 때 균형을 이뤄야 할 게 있습니다 각 미디어 에셋에 대한 개별 카탈로그를 만들면 올바른 카탈로그 로딩을 위해 어떤 오디오 조각이 재생되고 있는지 알아야 하죠 한 카탈로그에 한꺼번에 집어 넣으면 다운로드 용량도 커지고 돈도 더 많이 필요합니다 하지만 더 많은 오디오 조각을 매치할 수 있죠 여러분이 만든 카탈로그 파일에 단단히 초점이 맞춰져야 합니다 음액 트랙별, 전체 앨범별 카탈로그가 있다고 해보죠 아티스트의 음악 전체에 대한 건 아니고요 나누려면 실행 시간 동안 뭘 로딩할 지 결정해야 합니다 이건 커스텀 카탈로그를 API에 더하여 가능합니다
사용 사례에 도움이 될지 한 번 직접 해보세요 동일하게 들리는 오디오 자산이 여러 개 있다면 쇼의 인트로 음악은 항상 똑같겠죠 각 에피소드 당 맞춤형 경험을 제공하고 싶다면 즉, 다른 트랙에서 샘플링된 노래를 제공하고 싶다면 주파수 왜곡으로 구분해 보세요 오디오를 왜곡하면 녹음본의 주파수가 조정됩니다 이렇게 하면 오디오 사운드가 달라지지만 그 양이 적다면 보통 사람의 귀는 못 듣고 ShazamKit만 알아챌 겁니다 그러니 오디오 녹음본일 경우 커스텀 카탈로그를 만들고 변형된 주파수로 틀어보세요 ShazamKit는 오디오에 매치될 겁니다 frequencySkew 프로퍼티를 통해 왜곡의 양도 보고할 거고요 코드에서는 어떻게 해야 할까요?
사람의 귀나 ShazamKit가 알아채지 못할 정도로 변화시키지 않고 오디오를 왜곡할 수 있는 양은 제한이 있습니다
왜곡을 5%으로 유지하는 건 안전합니다 왜곡된 여러 녹음본을 충분히 차별화할 수 있고요 이를 위해 frequencySkewRanges를 사용하세요 미디어 아이템은 특정 왜곡 범위 내에 속해야만 반한될 겁니다
범위는 오디오가 원본과 얼마나 다른지 비율로 구체화되고요 0이라는 값은 오디오 왜곡이 없다는 뜻이고 0.01이라는 값은 왜곡이 1%라는 뜻입니다 이 프로퍼티로 미디어 아이템의 프로퍼티에 액세스 해보세요
앱에서는 다음 순서대로 하시면 됩니다 먼저 본래 오디오 녹음본의 참조 서명을 만드세요 그 다음 미디어 아이템을 취해 왜곡도는 3~4%로 제한하세요 커스텀 카탈로그에 배치하시고
이제 오디오를 3~4% 왜곡해서 틀어보세요 그럼 미디어 아이템이 반환될 겁니다 왜곡되지 않은 오디오나 왜곡된 오디오를 범위 밖에서 틀면 미디어 아이템은 반환되지 않을 겁니다 이게 바로 '주파수 왜곡'입니다
올해의 업데이트 내용을 살펴 보셨으니 놀라운 동기화 경험을 제공하실 수 있겠네요 다음을 기억하세요 첫째, 미디어 에셋마다 하나의 서명을 만드세요 그럼 정확도는 나아지고 창작 파이프라인도 간단해집니다 signatureFromAsset으로 서명을 만드세요 광범위한 미디어를 수용하거든요 로우 레벨 오디오 디테일을 더이상 다룰 필요가 없단 거죠
새 API로 동기화 콘텐츠를 관심 영역에 타겟팅하세요 단순한 API에 엄청난 정확도가 결합된 겁니다 Shazam CLI로 간단하게 커스텀 카탈로그를 만드세요 이건 대용량 미디어 처리에서 해야 할 귀찮은 일을 줄여주고 만들고자 하는 경험에 집중할 수 있게 해주죠 이상 ShazamKit의 최신 업데이트 내용이었습니다 이제 어디에서나 Shazam이 가능하게 만들 수 있습니다 오늘 논의한 모든 정보와 문서화 링크는 본 세션에 첨부되어 있습니다 함께해 주셔서 감사합니다 나머지 WWDC22도 즐겨 보세요
-
-
4:26 - Food Math Matcher
/* See LICENSE folder for this sample’s licensing information. Abstract: The model that is responsible for matching against the catalog and update the SwiftUI Views. */ import ShazamKit import AVFAudio struct MatchResult { var title: String? var equation: Equation? var episode: Episode? var answerRange: ClosedRange<Int>? var hasContent: Bool { equation != nil || title != nil || answerRange != nil } } class Matcher: NSObject, ObservableObject, SHSessionDelegate { @Published var matchResult: MatchResult? private var session: SHSession! private let audioEngine = AVAudioEngine() private var matchingTask: Task<Void, Never>? = nil func match(catalog: SHCustomCatalog) throws { session = SHSession(catalog: catalog) session.delegate = self let audioFormat = AVAudioFormat(standardFormatWithSampleRate: audioEngine.inputNode.outputFormat(forBus: 0).sampleRate, channels: 1) audioEngine.inputNode.installTap(onBus: 0, bufferSize: 2048, format: audioFormat) { [weak session] buffer, audioTime in session?.matchStreamingBuffer(buffer, at: audioTime) } try AVAudioSession.sharedInstance().setCategory(.record) AVAudioSession.sharedInstance().requestRecordPermission { [weak self] success in guard success, let self = self else { return } Task.detached { try? self.audioEngine.start() } } Task { @MainActor in for await case .match(let match) in session.results { self.matchResult = match.matchResult } } } } extension SHMatch { var matchResult: MatchResult { mediaItems.reduce(into: MatchResult()) { result, mediaItem in result.title = result.title ?? mediaItem.title result.episode = result.episode ?? mediaItem.episode result.equation = result.equation ?? mediaItem.equation result.answerRange = result.answerRange ?? mediaItem.answerRange } } }
-
13:51 - Timed Media Items
// Restrict this media item to only describe the first 5 seconds let mediaItem = SHMediaItem(properties: [ .title: "Title", .timeRanges:[0.0..<5.0] ]) let timeRanges: [Range<TimeInterval>] = mediaItem.timeRanges
-
16:02 - Combine Catalogs
let parentCatalog = SHCustomCatalog() parentCatalog.add(from: URL(fileURLWithPath: "/path/to/Episode1.shazamcatalog")) parentCatalog.add(from: URL(fileURLWithPath: "/path/to/Episode2.shazamcatalog")) parentCatalog.add(from: URL(fileURLWithPath: "/path/to/Episode3.shazamcatalog"))
-
16:58 - Frequency Skew
func within(range: Range<Float>, for matchedMediaItem: SHMatchedMediaItem) -> Bool { range.contains(matchedMediaItem.frequencySkew) }
-
17:21 - Frequency Skew Ranges
// Restrict this media item to only describe the first 5 seconds let mediaItem = SHMediaItem(properties: [ .title: “Frequency Skewed Audio”, .frequencySkewRanges:[0.01..<0.02] ]) let frequencySkewRanges: [Range<Float>] = mediaItem.frequencySkewRanges
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.