Shazam ทำงานอย่างไร อัลกอริธึมการจดจำเพลง การพิมพ์ลายนิ้วมือ และการประมวลผล
เผยแพร่แล้ว: 2022-03-11คุณได้ยินเพลงที่คุ้นเคยในคลับหรือร้านอาหาร คุณฟังเพลงนี้เป็นพันครั้งเมื่อนานมาแล้ว และความซาบซึ้งในเพลงนี้สัมผัสได้ถึงหัวใจของคุณจริงๆ พรุ่งนี้คุณอยากจะฝากหัวใจไว้มาก แต่คุณจำชื่อมันไม่ได้! โชคดีที่ในโลกแห่งอนาคตอันน่าทึ่งของเรา คุณมีโทรศัพท์ที่ติดตั้งซอฟต์แวร์จดจำเพลงไว้ และคุณก็รอดแล้ว คุณสามารถผ่อนคลายได้เพราะซอฟต์แวร์บอกชื่อเพลงให้คุณ และคุณรู้ว่าคุณสามารถได้ยินมันซ้ำแล้วซ้ำเล่าจนกระทั่งมันกลายเป็นส่วนหนึ่งของคุณ...หรือคุณเบื่อมัน
เทคโนโลยีมือถือ พร้อมด้วยความก้าวหน้าอย่างมากในการประมวลผลสัญญาณเสียง ทำให้นักพัฒนาอัลกอริธึมสามารถสร้างตัวจดจำเพลงได้ แอพจดจำเพลงที่ได้รับความนิยมมากที่สุดตัวหนึ่งคือ Shazam หากคุณบันทึกเพลง 20 วินาที ไม่ว่าจะเป็นอินโทร ท่อน หรือคอรัส จะสร้างลายนิ้วมือสำหรับตัวอย่างที่บันทึกไว้ ศึกษาฐานข้อมูล และใช้อัลกอริธึมการจดจำเพลงเพื่อบอกคุณว่าคุณกำลังฟังเพลงใดอยู่ .
แต่ Shazam ทำงานอย่างไร อัลกอริธึมของ Shazam ถูกเปิดเผยสู่โลกโดยนักประดิษฐ์ Avery Li-Chung Wang ในปี 2546 ในบทความนี้ เราจะพูดถึงพื้นฐานของอัลกอริธึมการจดจำเพลงของ Shazam
อนาล็อกเป็นดิจิตอล - การสุ่มตัวอย่างสัญญาณ
แท้จริงแล้วเสียงคืออะไร? มันเป็นวัสดุลึกลับบางอย่างที่เราไม่สามารถสัมผัสได้ แต่สิ่งที่บินเข้าไปในหูของเราและทำให้เราได้ยินสิ่งต่าง ๆ หรือไม่?
แน่นอนว่านี่ไม่ใช่กรณีทั้งหมด เรารู้ว่าในความเป็นจริง เสียงคือการสั่นสะเทือนที่แพร่กระจายเป็นคลื่นกลของแรงดันและการกระจัด ผ่านตัวกลาง เช่น อากาศหรือน้ำ เมื่อการสั่นสะเทือนนั้นมาถึงหูของเรา โดยเฉพาะแก้วหู มันจะเคลื่อนกระดูกเล็กๆ ซึ่งส่งการสั่นสะเทือนต่อไปไปยังเซลล์ขนเล็กๆ ที่อยู่ลึกลงไปในหูชั้นในของเรา ในที่สุด เซลล์ขนเล็กๆ จะสร้างแรงกระตุ้นทางไฟฟ้า ซึ่งส่งไปยังสมองของเราผ่านเส้นประสาทหู
อุปกรณ์บันทึกเลียนแบบกระบวนการนี้ค่อนข้างใกล้เคียง โดยใช้แรงดันของคลื่นเสียงเพื่อแปลงเป็นสัญญาณไฟฟ้า คลื่นเสียงจริงในอากาศเป็นสัญญาณแรงดันต่อเนื่อง ในไมโครโฟน อุปกรณ์ไฟฟ้าตัวแรกที่พบสัญญาณนี้จะแปลเป็นสัญญาณแรงดันไฟฟ้าแบบแอนะล็อก - ต่อเนื่องกันอีกครั้ง สัญญาณต่อเนื่องนี้ไม่ค่อยมีประโยชน์ในโลกดิจิทัล ดังนั้นก่อนที่จะสามารถประมวลผลได้ จะต้องแปลเป็นสัญญาณแยกที่สามารถจัดเก็บแบบดิจิทัลได้ ทำได้โดยจับค่าดิจิตอลที่แสดงถึงแอมพลิจูดของสัญญาณ
การแปลงเกี่ยวข้องกับการหาปริมาณของอินพุต และจำเป็นต้องมีข้อผิดพลาดเล็กน้อย ดังนั้น แทนที่จะทำการแปลงเพียงครั้งเดียว ตัวแปลงอนาล็อกเป็นดิจิตอลจะทำการแปลงจำนวนมากบนชิ้นส่วนที่เล็กมากของสัญญาณ - กระบวนการที่เรียกว่าการสุ่มตัวอย่าง
ทฤษฎีบท Nyquist-Shannon บอกเราว่าอัตราการสุ่มตัวอย่างที่จำเป็นในการจับความถี่ที่แน่นอนในสัญญาณต่อเนื่อง โดยเฉพาะอย่างยิ่ง ในการจับความถี่ทั้งหมดที่มนุษย์ได้ยินในสัญญาณเสียง เราต้องสุ่มตัวอย่างสัญญาณที่ความถี่สองเท่าของช่วงการได้ยินของมนุษย์ หูของมนุษย์สามารถตรวจจับความถี่ได้ประมาณระหว่าง 20 Hz ถึง 20,000 Hz ด้วยเหตุนี้ เสียงจึงมักถูกบันทึกที่อัตราการสุ่มตัวอย่างที่ 44,100 Hz นี่คืออัตราการสุ่มตัวอย่างของ Compact Disc และยังเป็นอัตราที่ใช้บ่อยที่สุดกับเสียง MPEG-1 (VCD, SVCD, MP3) (แต่เดิม Sony เลือกอัตราเฉพาะนี้เพราะสามารถบันทึกบนอุปกรณ์วิดีโอดัดแปลงที่ทำงานด้วยความเร็ว 25 เฟรมต่อวินาที (PAL) หรือ 30 เฟรมต่อวินาที (โดยใช้เครื่องบันทึกวิดีโอขาวดำ NTSC) และครอบคลุมแบนด์วิดท์ 20,000 Hz ที่คิดว่าจำเป็น จับคู่อุปกรณ์บันทึกอนาล็อกระดับมืออาชีพในสมัยนั้น) ดังนั้น เมื่อเลือกความถี่ของตัวอย่างที่ต้องการบันทึก คุณอาจต้องการใช้ 44,100 Hz
การบันทึก - การจับเสียง
การบันทึกสัญญาณเสียงที่สุ่มตัวอย่างทำได้ง่าย เนื่องจากการ์ดเสียงสมัยใหม่มาพร้อมกับตัวแปลงอนาล็อกเป็นดิจิตอลอยู่แล้ว เพียงเลือกภาษาโปรแกรม ค้นหาไลบรารีที่เหมาะสม ตั้งค่าความถี่ของตัวอย่าง จำนวนช่อง (โดยทั่วไปจะเป็นโมโนหรือสเตอริโอ) ขนาดตัวอย่าง (เช่น ตัวอย่าง 16 บิต ). จากนั้นเปิดสายจากการ์ดเสียงของคุณเหมือนกับสตรีมอินพุตใดๆ และเขียนลงในอาร์เรย์ไบต์ นี่คือวิธีที่สามารถทำได้ใน Java:
private AudioFormat getFormat() { float sampleRate = 44100; int sampleSizeInBits = 16; int channels = 1; //mono boolean signed = true; //Indicates whether the data is signed or unsigned boolean bigEndian = true; //Indicates whether the audio data is stored in big-endian or little-endian order return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian); } final AudioFormat format = getFormat(); //Fill AudioFormat with the settings DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); final TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info); line.open(format); line.start();
เพียงอ่านข้อมูลจาก TargetDataLine
(ในตัวอย่างนี้ แฟล็กที่ running
อยู่คือตัวแปรโกลบอลที่เธรดอื่นหยุดทำงาน - ตัวอย่างเช่น หากเรามี GUI ที่มีปุ่ม STOP)
OutputStream out = new ByteArrayOutputStream(); running = true; try { while (running) { int count = line.read(buffer, 0, buffer.length); if (count > 0) { out.write(buffer, 0, count); } } out.close(); } catch (IOException e) { System.err.println("I/O problems: " + e); System.exit(-1); }
โดเมนเวลาและโดเมนความถี่
สิ่งที่เรามีในอาร์เรย์ไบต์นี้คือสัญญาณที่บันทึกในโดเมนเวลา สัญญาณโดเมนเวลาแสดงถึงการเปลี่ยนแปลงแอมพลิจูดของสัญญาณเมื่อเวลาผ่านไป
ในช่วงต้นปี 1800 Jean-Baptiste Joseph Fourier ได้ค้นพบอย่างน่าทึ่งว่าสัญญาณใดๆ ในโดเมนเวลานั้นเทียบเท่ากับผลรวมของสัญญาณไซนูซอยด์ธรรมดาจำนวนหนึ่ง (อาจเป็นอนันต์) โดยที่องค์ประกอบไซนูซอยด์แต่ละส่วนมีความถี่ แอมพลิจูดที่แน่นอน และเฟส. ชุดของไซนูซอยด์ที่รวมกันเป็นสัญญาณโดเมนเวลาดั้งเดิมเรียกว่าอนุกรมฟูริเยร์
กล่าวอีกนัยหนึ่ง มันเป็นไปได้ที่จะแสดงสัญญาณโดเมนเวลาใดๆ โดยเพียงแค่ให้ชุดของความถี่ แอมพลิจูด และเฟสที่สอดคล้องกับไซนูซอยด์แต่ละอันที่ประกอบเป็นสัญญาณ การแสดงสัญญาณนี้เรียกว่าโดเมนความถี่ ในบางวิธี โดเมนความถี่จะทำหน้าที่เป็นประเภทของลายนิ้วมือหรือลายเซ็นสำหรับสัญญาณโดเมนเวลา โดยให้การแสดงสัญญาณไดนามิกแบบคงที่
ภาพเคลื่อนไหวต่อไปนี้สาธิตอนุกรมฟูริเยร์ของคลื่นสี่เหลี่ยม 1 Hz และวิธีสร้างคลื่นสี่เหลี่ยม (โดยประมาณ) จากส่วนประกอบไซน์ สัญญาณจะแสดงในโดเมนเวลาด้านบนและโดเมนความถี่ด้านล่าง
การวิเคราะห์สัญญาณในโดเมนความถี่ทำให้หลายๆ อย่างง่ายขึ้นอย่างมาก สะดวกกว่าในโลกของการประมวลผลสัญญาณดิจิทัลเนื่องจากวิศวกรสามารถศึกษาสเปกตรัม (การแสดงสัญญาณในโดเมนความถี่) และกำหนดความถี่ที่มีอยู่และความถี่ที่ขาดหายไป หลังจากนั้น เราสามารถทำการกรอง เพิ่มหรือลดความถี่บางความถี่ หรือเพียงแค่จดจำโทนเสียงที่แน่นอนจากความถี่ที่กำหนด
การแปลงฟูริเยร์แบบไม่ต่อเนื่อง
ดังนั้นเราจึงต้องหาวิธีแปลงสัญญาณของเราจากโดเมนเวลาเป็นโดเมนความถี่ ที่นี่เราขอความช่วยเหลือจาก Discrete Fourier Transform (DFT) DFT เป็นวิธีการทางคณิตศาสตร์สำหรับการวิเคราะห์ฟูริเยร์บนสัญญาณแบบไม่ต่อเนื่อง (สุ่มตัวอย่าง) โดยจะแปลงรายการจำกัดของตัวอย่างฟังก์ชันที่มีระยะห่างเท่าๆ กันเป็นรายการสัมประสิทธิ์ของการรวมตัวของไซนูซอยด์ที่ซับซ้อนอย่างจำกัด เรียงลำดับตามความถี่ โดยพิจารณาว่าไซนูซอยด์เหล่านั้นได้รับการสุ่มตัวอย่างในอัตราเดียวกันหรือไม่
อัลกอริธึมตัวเลขที่ได้รับความนิยมมากที่สุดสำหรับการคำนวณ DFT คือการแปลงฟูเรียร์แบบเร็ว (FFT) รูปแบบที่ใช้บ่อยที่สุดของ FFT คืออัลกอริธึม Cooley–Tukey นี่คืออัลกอริทึมแบบแบ่งและพิชิตที่แบ่ง DFT แบบเรียกซ้ำออกเป็น DFT ขนาดเล็กจำนวนมาก ในขณะที่การประเมิน DFT โดยตรงต้องใช้การดำเนินการ O( n 2 ) ด้วย Cooley-Tukey FFT ผลลัพธ์เดียวกันจะถูกคำนวณในการดำเนินการ O( n log n )
การค้นหาไลบรารีที่เหมาะสมสำหรับ FFT นั้นไม่ใช่เรื่องยาก นี่คือบางส่วนของพวกเขา:
- C – FFTW
- C ++ – EigenFFT
- Java – JTransform
- Python – NumPy
- Ruby – Ruby-FFTW3 (ส่วนต่อประสานกับ FFTW)
ด้านล่างนี้เป็นตัวอย่างของฟังก์ชัน FFT ที่เขียนในภาษา Java (FFT นำจำนวนเชิงซ้อนเป็นอินพุต หากต้องการทำความเข้าใจความสัมพันธ์ระหว่างจำนวนเชิงซ้อนกับฟังก์ชันตรีโกณมิติ โปรดอ่านสูตรของออยเลอร์)
public static Complex[] fft(Complex[] x) { int N = x.length; // fft of even terms Complex[] even = new Complex[N / 2]; for (int k = 0; k < N / 2; k++) { even[k] = x[2 * k]; } Complex[] q = fft(even); // fft of odd terms Complex[] odd = even; // reuse the array for (int k = 0; k < N / 2; k++) { odd[k] = x[2 * k + 1]; } Complex[] r = fft(odd); // combine Complex[] y = new Complex[N]; for (int k = 0; k < N / 2; k++) { double kth = -2 * k * Math.PI / N; Complex wk = new Complex(Math.cos(kth), Math.sin(kth)); y[k] = q[k].plus(wk.times(r[k])); y[k + N / 2] = q[k].minus(wk.times(r[k])); } return y; }
และนี่คือตัวอย่างสัญญาณก่อนและหลังการวิเคราะห์ FFT:
การรับรู้เพลง: ลายนิ้วมือเพลง
ผลข้างเคียงที่โชคร้ายอย่างหนึ่งของ FFT คือเราสูญเสียข้อมูลจำนวนมากเกี่ยวกับเวลา (แม้ว่าในทางทฤษฎีสามารถหลีกเลี่ยงสิ่งนี้ได้ แต่ค่าโสหุ้ยในการแสดงก็มหาศาล) สำหรับเพลงสามนาที เราจะเห็นความถี่และขนาดของมันทั้งหมด แต่เราไม่รู้ว่ามันปรากฏเมื่อใดในเพลง แต่นี่คือข้อมูลสำคัญที่ทำให้เพลงเป็นอย่างนั้น! ยังไงก็ตาม เราจำเป็นต้องรู้ว่าความถี่ที่แต่ละความถี่ปรากฏขึ้นเมื่อใด

นั่นเป็นเหตุผลที่เราแนะนำชนิดของหน้าต่างบานเลื่อนหรือกลุ่มข้อมูล และแปลงข้อมูลเพียงส่วนนี้เท่านั้น ขนาดของแต่ละส่วนสามารถกำหนดได้หลายวิธี ตัวอย่างเช่น หากเราบันทึกเสียงในรูปแบบสเตอริโอด้วยตัวอย่าง 16 บิตที่ 44,100 Hz หนึ่งวินาทีของเสียงดังกล่าวจะเป็น 44,100 ตัวอย่าง * 2 ไบต์ * 2 ช่องสัญญาณ ≈ 176 kB ถ้าเราเลือก 4 kB สำหรับขนาดของก้อน เราจะมีข้อมูล 44 ชิ้นที่จะวิเคราะห์ในทุก ๆ วินาทีของเพลง ความหนาแน่นเพียงพอสำหรับการวิเคราะห์รายละเอียดที่จำเป็นสำหรับการระบุเสียง
กลับไปที่การเขียนโปรแกรม:
byte audio [] = out.toByteArray() int totalSize = audio.length int sampledChunkSize = totalSize/chunkSize; Complex[][] result = ComplexMatrix[sampledChunkSize][]; for(int j = 0;i < sampledChunkSize; j++) { Complex[chunkSize] complexArray; for(int i = 0; i < chunkSize; i++) { complexArray[i] = Complex(audio[(j*chunkSize)+i], 0); } result[j] = FFT.fft(complexArray); }
ในวงใน เรากำลังใส่ข้อมูลโดเมนเวลา (ตัวอย่าง) ลงในจำนวนเชิงซ้อนที่มีส่วนจินตภาพ 0 ในวงรอบนอก เราวนซ้ำผ่านส่วนทั้งหมดและทำการวิเคราะห์ FFT ในแต่ละส่วน
เมื่อเรามีข้อมูลเกี่ยวกับการสร้างความถี่ของสัญญาณแล้ว เราสามารถเริ่มสร้างลายนิ้วมือดิจิทัลของเพลงได้ นี่เป็นส่วนที่สำคัญที่สุดของกระบวนการรับรู้เสียงของ Shazam ทั้งหมด ความท้าทายหลักที่นี่คือวิธีแยกแยะในมหาสมุทรของความถี่ที่จับได้ว่าความถี่ใดสำคัญที่สุด โดยสังหรณ์ใจ เราค้นหาความถี่ที่มีขนาดสูงสุด (ปกติเรียกว่าพีค)
อย่างไรก็ตาม ในเพลงเดียว ช่วงของความถี่สูงอาจแตกต่างกันระหว่าง C ต่ำ - C1 (32.70 Hz) และ C - C8 สูง (4,186.01 Hz) นี่เป็นช่วงใหญ่ที่จะครอบคลุม ดังนั้น แทนที่จะวิเคราะห์ช่วงความถี่ทั้งหมดพร้อมกัน เราสามารถเลือกช่วงความถี่ที่เล็กกว่าหลายๆ ช่วง โดยเลือกตามความถี่ทั่วไปของส่วนประกอบทางดนตรีที่สำคัญ และวิเคราะห์แยกกัน ตัวอย่างเช่น เราอาจใช้ช่วงเวลาที่ผู้ชายคนนี้เลือกสำหรับการนำอัลกอริธึม Shazam ไปใช้งาน ได้แก่ 30 Hz - 40 Hz, 40 Hz - 80 Hz และ 80 Hz - 120 Hz สำหรับโทนเสียงต่ำ (เช่น ครอบคลุมกีตาร์เบส เป็นต้น) และ 120 Hz - 180 Hz และ 180 Hz - 300 Hz สำหรับโทนเสียงกลางและสูง (ครอบคลุมเสียงร้องและเครื่องดนตรีอื่นๆ เกือบทั้งหมด)
ภายในแต่ละช่วงเวลา เราสามารถระบุความถี่ที่มีขนาดสูงสุดได้ ข้อมูลนี้เป็นลายเซ็นสำหรับเพลงท่อนนี้ และลายเซ็นนี้จะกลายเป็นส่วนหนึ่งของลายนิ้วมือของเพลงโดยรวม
public final int[] RANGE = new int[] { 40, 80, 120, 180, 300 }; // find out in which range is frequency public int getIndex(int freq) { int i = 0; while (RANGE[i] < freq) i++; return i; } // result is complex matrix obtained in previous step for (int t = 0; t < result.length; t++) { for (int freq = 40; freq < 300 ; freq++) { // Get the magnitude: double mag = Math.log(results[t][freq].abs() + 1); // Find out which range we are in: int index = getIndex(freq); // Save the highest magnitude and corresponding frequency: if (mag > highscores[t][index]) { points[t][index] = freq; } } // form hash tag long h = hash(points[t][0], points[t][1], points[t][2], points[t][3]); } private static final int FUZ_FACTOR = 2; private long hash(long p1, long p2, long p3, long p4) { return (p4 - (p4 % FUZ_FACTOR)) * 100000000 + (p3 - (p3 % FUZ_FACTOR)) * 100000 + (p2 - (p2 % FUZ_FACTOR)) * 100 + (p1 - (p1 % FUZ_FACTOR)); }
โปรดทราบว่าเราต้องถือว่าการบันทึกนั้นไม่ได้ทำในสภาพที่สมบูรณ์ (เช่น "ห้องคนหูหนวก") และด้วยเหตุนี้ เราจึงต้องรวมปัจจัยที่คลุมเครือ ควรทำการวิเคราะห์ปัจจัย Fuzz อย่างจริงจัง และในระบบจริง โปรแกรมควรมีตัวเลือกในการตั้งค่าพารามิเตอร์นี้ตามเงื่อนไขของการบันทึก
เพื่อให้ค้นหาด้วยเสียงได้ง่าย ลายเซ็นนี้จะกลายเป็นคีย์ในตารางแฮช ค่าที่สอดคล้องกันคือเวลาที่ชุดความถี่นี้ปรากฏในเพลง พร้อมด้วย ID เพลง (ชื่อเพลงและศิลปิน) ต่อไปนี้คือตัวอย่างว่าระเบียนเหล่านี้อาจปรากฏในฐานข้อมูลอย่างไร
แฮชแท็ก | เวลาเป็นวินาที | เพลง |
---|---|---|
30 51 99 121 195 | 53.52 | เพลง A โดยศิลปิน A |
33 56 92 151 185 | 12.32 | เพลง B โดยศิลปิน B |
39 26 89 141 251 | 15.34 | เพลง C โดยศิลปิน C |
32 67 100 128 270 | 78.43 | เพลง D โดยศิลปิน D |
30 51 99 121 195 | 10.89 | เพลง E โดยศิลปิน E |
34 57 95 111 200 | 54.52 | เพลง A โดยศิลปิน A |
34 41 93 161 202 | 11.89 | เพลง E โดยศิลปิน E |
หากเราใช้ไลบรารีเพลงทั้งหมดผ่านกระบวนการระบุเพลงนี้ เราสามารถสร้างฐานข้อมูลด้วยลายนิ้วมือที่สมบูรณ์ของทุกเพลงในไลบรารี
อัลกอริธึมดนตรี: การระบุเพลง
เพื่อระบุเพลงที่กำลังเล่นอยู่ในคลับ เราบันทึกเพลงด้วยโทรศัพท์ของเรา และทำการบันทึกโดยใช้กระบวนการบันทึกลายนิ้วมือแบบเดียวกับด้านบน จากนั้นเราสามารถเริ่มค้นหาฐานข้อมูลสำหรับแท็กแฮชที่ตรงกัน
เมื่อมันเกิดขึ้น แท็กแฮชจำนวนมากจะสอดคล้องกับตัวระบุเพลงของหลายเพลง ตัวอย่างเช่น อาจเป็นไปได้ว่าเพลงบางเพลง A ฟังดูเหมือนเพลง E บางเพลง แน่นอนว่ามันไม่น่าแปลกใจเลย - นักดนตรีมักจะ "ยืม" ลีคและริฟจากกันและกัน และทุกวันนี้โปรดิวเซอร์ก็สุ่มตัวอย่างเพลงอื่นๆ ทั้งหมด เวลา. ทุกครั้งที่เราจับคู่แท็กแฮช จำนวนการจับคู่ที่เป็นไปได้จะลดลง แต่มีแนวโน้มว่าข้อมูลนี้เพียงอย่างเดียวจะไม่จำกัดการจับคู่ให้เหลือเพียงเพลงเดียว จึงมีอีกสิ่งหนึ่งที่เราต้องตรวจสอบด้วยอัลกอริธึมการจดจำเพลงของเรา นั่นคือจังหวะเวลา
ตัวอย่างที่เราบันทึกในคลับอาจมาจากจุดใดก็ได้ในเพลง ดังนั้นเราจึงไม่สามารถจับคู่การประทับเวลาของแฮชที่ตรงกันกับการประทับเวลาของตัวอย่างของเรา อย่างไรก็ตาม ด้วยแฮชที่ตรงกันหลายรายการ เราสามารถวิเคราะห์เวลา สัมพัทธ์ ของการแข่งขัน และเพิ่มความมั่นใจของเรา
ตัวอย่างเช่น หากคุณดูในตารางด้านบน คุณจะเห็นว่าแฮชแท็ก 30 51 99 121 195
สอดคล้องกับทั้งเพลง A และ Song E หากหนึ่งวินาทีต่อมา เราจับคู่แฮช 34 57 95 111 200
นั่นคืออีกหนึ่ง ตรงกับเพลง A แต่ในกรณีนี้ เรารู้ว่าทั้งแฮชและความแตกต่างของเวลาตรงกัน
// Class that represents specific moment in a song private class DataPoint { private int time; private int songId; public DataPoint(int songId, int time) { this.songId = songId; this.time = time; } public int getTime() { return time; } public int getSongId() { return songId; } }
ให้ i 1 และ i 2 เป็นช่วงเวลาในเพลงที่บันทึก และ j 1 และ j 2 เป็นช่วงเวลาในเพลงจากฐานข้อมูล เราสามารถพูดได้ว่าเรามีการแข่งขันสองนัดที่ตรงกับความแตกต่างของเวลาหาก:
<span style=font-family: TimesNewRoman;> RecordedHash(i 1 ) = SongInDBHash(j 1 ) และ RecordedHash(i 2 ) = SongInDBHash(j 2 ) </span>
<span style=font-family: TimesNewRoman;>AND</span>
<span style=font-family: TimesNewRoman;> abs(i 1 - i 2 ) = abs (j 1 - j 2 ) </span>
สิ่งนี้ทำให้เรามีความยืดหยุ่นในการบันทึกเพลงตั้งแต่ต้น กลาง หรือปลาย
สุดท้าย ไม่น่าเป็นไปได้ที่ทุกช่วงเวลาของเพลงที่เราบันทึกในคลับจะตรงกับทุกช่วงเวลาที่สอดคล้องกันของเพลงเดียวกันในห้องสมุดของเราที่บันทึกไว้ในสตูดิโอ การบันทึกจะมีเสียงรบกวนมากมายที่จะทำให้เกิดข้อผิดพลาดในการแข่งขัน ดังนั้น แทนที่จะพยายามกำจัดทั้งหมดยกเว้นเพลงที่ถูกต้องจากรายการการแข่งขันของเรา ในตอนท้าย เราจัดเรียงเพลงที่ตรงกันทั้งหมดตามลำดับความน่าจะเป็น และเพลงโปรดของเราคือเพลงแรกในรายการจัดอันดับ
จากบนลงล่าง
เพื่อตอบคำถามว่า Shazam ทำงานอย่างไร นี่คือภาพรวมของกระบวนการจดจำและจับคู่เพลงทั้งหมด จากบนลงล่าง:
สำหรับระบบประเภทนี้ ฐานข้อมูลอาจมีขนาดใหญ่มาก ดังนั้นการใช้ฐานข้อมูลที่ปรับขนาดได้บางประเภทจึงเป็นสิ่งสำคัญ ไม่จำเป็นต้องมีความสัมพันธ์เป็นพิเศษ และโมเดลข้อมูลก็ค่อนข้างเรียบง่าย ดังนั้นจึงเป็นกรณีที่ดีสำหรับการใช้ฐานข้อมูล NoSQL บางประเภท
Shazam ทำงานอย่างไร? คุณรู้แล้วตอนนี้
ซอฟต์แวร์จดจำเพลงประเภทนี้สามารถใช้เพื่อค้นหาความคล้ายคลึงกันระหว่างเพลง ตอนนี้คุณเข้าใจวิธีการทำงานของ Shazam แล้ว คุณจะเห็นว่าแอปนี้สามารถมีแอปพลิเคชันต่างๆ ได้อย่างไร นอกเหนือไปจาก Shazaming ที่เล่นเพลงที่ชวนให้นึกถึงอดีตบนวิทยุแท็กซี่ ตัวอย่างเช่น สามารถช่วยในการระบุการลอกเลียนแบบในดนตรี หรือค้นหาว่าใครเป็นแรงบันดาลใจเบื้องต้นให้กับผู้บุกเบิกเพลงบลูส์ แจ๊ส ร็อค ป๊อป หรือแนวเพลงอื่นๆ บางทีการทดลองที่ดีอาจเป็นการเติมฐานข้อมูลตัวอย่างเพลงด้วยดนตรีคลาสสิกของ Bach, Beethoven, Vivaldi, Wagner, Chopin และ Mozart แล้วลองค้นหาความคล้ายคลึงกันระหว่างเพลงต่างๆ คุณคงคิดว่าแม้แต่ Bob Dylan, Elvis Presley และ Robert Johnson ก็เป็นผู้ลอกเลียนแบบ!
แต่ถึงกระนั้นเราก็ไม่สามารถตัดสินลงโทษพวกเขาได้ เพราะดนตรีเป็นเพียงคลื่นที่เราได้ยิน ท่องจำ และวนซ้ำในหัวของเรา ที่ซึ่งมันวิวัฒนาการและเปลี่ยนแปลงไปจนกว่าเราจะบันทึกมันในสตูดิโอและส่งต่อไปยังอัจฉริยะทางดนตรีผู้ยิ่งใหญ่คนต่อไป