[{"data":1,"prerenderedAt":5710},["ShallowReactive",2],{"navigation":3,"/blog/case-studies/mobile-app-for-music-catalog-post":734,"/blog/case-studies/mobile-app-for-music-catalog-surround":1092,"/blog/case-studies/mobile-app-for-music-catalog-related":1097},[4,70,207,312,721],{"title":5,"path":6,"stem":7,"children":8,"page":69},"Case Study","/blog/case-study","blog/case-study",[9,13,17,21,25,29,33,37,41,45,49,53,57,61,65],{"title":10,"path":11,"stem":12},"Ambistream – Multi-Layer Streaming Platform","/blog/case-study/ambistream-building-a-multi-layer-streaming-platform-from-a-spark-of-an-idea","blog/case-study/ambistream-building-a-multi-layer-streaming-platform-from-a-spark-of-an-idea",{"title":14,"path":15,"stem":16},"Custom Chromecast & AirPlay Casting App","/blog/case-study/chromecast-airplay-casting-app-case-study","blog/case-study/chromecast-airplay-casting-app-case-study",{"title":18,"path":19,"stem":20},"Direct Music Licensing Platform Case Study","/blog/case-study/dlm-music-catalog-case-study","blog/case-study/dlm-music-catalog-case-study",{"title":22,"path":23,"stem":24},"Assembly Instructions App - Galeco Mobile App","/blog/case-study/galeco-mobile-app-case-study","blog/case-study/galeco-mobile-app-case-study",{"title":26,"path":27,"stem":28},"MemoSonic: Building an Audio Memory Game","/blog/case-study/how-we-built-memosonic-accessible-audio-memory-game-flutter","blog/case-study/how-we-built-memosonic-accessible-audio-memory-game-flutter",{"title":30,"path":31,"stem":32},"Loyalty Program App for Shopping Mall","/blog/case-study/loyalty-program-application-case-study","blog/case-study/loyalty-program-application-case-study",{"title":34,"path":35,"stem":36},"Mobile Application for Music Catalogs","/blog/case-study/mobile-app-for-music-catalog","blog/case-study/mobile-app-for-music-catalog",{"title":38,"path":39,"stem":40},"Universal Music Data Parser for 20+ Platforms","/blog/case-study/musicdata-lab-universal-music-data-parser-case-study","blog/case-study/musicdata-lab-universal-music-data-parser-case-study",{"title":42,"path":43,"stem":44},"Panther ML/AI Pricing Recommendation Tool","/blog/case-study/panther-pricing-recommendation-tool-case-study","blog/case-study/panther-pricing-recommendation-tool-case-study",{"title":46,"path":47,"stem":48},"4D Grupa Roofing Wholesalers Platform","/blog/case-study/roofing-wholesalers-website-case-study","blog/case-study/roofing-wholesalers-website-case-study",{"title":50,"path":51,"stem":52},"Talent Alpha HR Frontend Platform","/blog/case-study/talent-alpha-hr-platform-case-study","blog/case-study/talent-alpha-hr-platform-case-study",{"title":54,"path":55,"stem":56},"Ticketing & Events Platform Development","/blog/case-study/ticketing-events-platform-case-study","blog/case-study/ticketing-events-platform-case-study",{"title":58,"path":59,"stem":60},"Turn Fans into Superfans — Roadie.co","/blog/case-study/turn-fans-into-superfans-roadie-co","blog/case-study/turn-fans-into-superfans-roadie-co",{"title":62,"path":63,"stem":64},"Walkative 2.0 Global Booking Engine","/blog/case-study/walkative-2-booking-platform-case-study","blog/case-study/walkative-2-booking-platform-case-study",{"title":66,"path":67,"stem":68},"Why Merch Is the New Royalty Check, and How Tech Is Closing the Gap","/blog/case-study/why-merch-is-the-new-royalty-check","blog/case-study/why-merch-is-the-new-royalty-check",false,{"title":71,"path":72,"stem":73,"children":74,"page":69},"Music Data","/blog/music-data","blog/music-data",[75,79,83,87,91,95,99,103,107,111,115,119,123,127,131,135,139,143,147,151,155,159,163,167,171,175,179,183,187,191,195,199,203],{"title":76,"path":77,"stem":78},"13 Distributors, 5 File Formats, Zero Standards -The Reality of Music Royalty Data","/blog/music-data/13-distributors-5-file-formats-zero-standards-the-reality-of-music-royalty-data","blog/music-data/13-distributors-5-file-formats-zero-standards-the-reality-of-music-royalty-data",{"title":80,"path":81,"stem":82},"830 Ways to Say Spotify - Normalizing Music Streaming Data","/blog/music-data/830-ways-to-say-spotify-normalizing-music-streaming-data","blog/music-data/830-ways-to-say-spotify-normalizing-music-streaming-data",{"title":84,"path":85,"stem":86},"Why Music Companies Need AI-Powered Analytics (And How We Built One)","/blog/music-data/ai-powered-analytics-dashboard-django-clickhouse-ollama","blog/music-data/ai-powered-analytics-dashboard-django-clickhouse-ollama",{"title":88,"path":89,"stem":90},"AI Rehearsal: Spaced Repetition for Your Musical Ideas","/blog/music-data/ai-rehearsal-spaced-repetition-for-musical-ideas","blog/music-data/ai-rehearsal-spaced-repetition-for-musical-ideas",{"title":92,"path":93,"stem":94},"Audio Project Organization Is a Mess — Here's Why","/blog/music-data/audio-project-organization-mess","blog/music-data/audio-project-organization-mess",{"title":96,"path":97,"stem":98},"Why Audio Search Is Still Broken and How to Fix It with Embeddings","/blog/music-data/audio-search-broken-fix-with-embeddings","blog/music-data/audio-search-broken-fix-with-embeddings",{"title":100,"path":101,"stem":102},"AI Song Structure Analysis: Intro, Verse, Chorus","/blog/music-data/automatic-song-structure-analysis-how-ai-detects-intro-verse-chorus","blog/music-data/automatic-song-structure-analysis-how-ai-detects-intro-verse-chorus",{"title":104,"path":105,"stem":106},"The Broken Feedback Loop in Music Collaboration","/blog/music-data/broken-feedback-loop-music-collaboration","blog/music-data/broken-feedback-loop-music-collaboration",{"title":108,"path":109,"stem":110},"Building a Claude Skill for DDEX Validation: Automate Music Metadata Checks with AI","/blog/music-data/building-a-claude-skill-for-ddex-validation-music-metadata","blog/music-data/building-a-claude-skill-for-ddex-validation-music-metadata",{"title":112,"path":113,"stem":114},"Building a Custom Music Delivery Platform on the Revelator API","/blog/music-data/building-a-custom-music-delivery-platform-on-the-revelator-api","blog/music-data/building-a-custom-music-delivery-platform-on-the-revelator-api",{"title":116,"path":117,"stem":118},"Building a Suno AI Remix App with Nuxt & Firebase","/blog/music-data/building-a-suno-remix-app-with-nuxt-and-firebase","blog/music-data/building-a-suno-remix-app-with-nuxt-and-firebase",{"title":120,"path":121,"stem":122},"C2PA & DDEX: Authenticity Meets Rights in the Age of AI Music","/blog/music-data/c2pa-and-ddex-authenticity-meets-rights-in-the-age-of-ai-music","blog/music-data/c2pa-and-ddex-authenticity-meets-rights-in-the-age-of-ai-music",{"title":124,"path":125,"stem":126},"C2PA in Music: A Claude MCP for Reading Content Provenance","/blog/music-data/c2pa-in-music-mcp","blog/music-data/c2pa-in-music-mcp",{"title":128,"path":129,"stem":130},"Data Modeling in MongoDB Using Design Patterns","/blog/music-data/data-modeling-in-mongodb-with-the-usage-of-design-patterns","blog/music-data/data-modeling-in-mongodb-with-the-usage-of-design-patterns",{"title":132,"path":133,"stem":134},"Office Hours with MusicTech Lab's DDEX Expert","/blog/music-data/ddex-office-hours-musictech","blog/music-data/ddex-office-hours-musictech",{"title":136,"path":137,"stem":138},"DDEX Open Source Projects Review","/blog/music-data/ddex-open-source-projects-review","blog/music-data/ddex-open-source-projects-review",{"title":140,"path":141,"stem":142},"Extracting Data from Ableton .als and .asd Files","/blog/music-data/extracting-data-from-ableton-als-asd-files","blog/music-data/extracting-data-from-ableton-als-asd-files",{"title":144,"path":145,"stem":146},"Maciej Dulski on Sound Connections Podcast","/blog/music-data/from-startups-to-musictech-maciej-dulski-on-sound-connections-podcast","blog/music-data/from-startups-to-musictech-maciej-dulski-on-sound-connections-podcast",{"title":148,"path":149,"stem":150},"How to Transcribe Video to Text Using OpenAI Whisper","/blog/music-data/how-to-transcribe-video-to-text-using-whisper","blog/music-data/how-to-transcribe-video-to-text-using-whisper",{"title":152,"path":153,"stem":154},"Epidemic Sound MCP with Claude for Devs","/blog/music-data/how-to-use-epidemic-sound-mcp-with-claude","blog/music-data/how-to-use-epidemic-sound-mcp-with-claude",{"title":156,"path":157,"stem":158},"Hybrid Database Model in Django for Speed","/blog/music-data/hybrid-database-model-in-django-as-a-performance-booster","blog/music-data/hybrid-database-model-in-django-as-a-performance-booster",{"title":160,"path":161,"stem":162},"Introduction to generating DDEX file using Python","/blog/music-data/introduction-to-generating-ddex-file-using-python","blog/music-data/introduction-to-generating-ddex-file-using-python",{"title":164,"path":165,"stem":166},"Maintaining Music Tech Tools: The SLA Dilemma for Small Teams","/blog/music-data/maintaining-music-tech-tools-the-sla-dilemma-for-small-teams","blog/music-data/maintaining-music-tech-tools-the-sla-dilemma-for-small-teams",{"title":168,"path":169,"stem":170},"Querying Bandcamp Revenue Reports with Natural Language — Meet mtl-bandcamp-mcp","/blog/music-data/mtl-bandcamp-mcp-open-source-revenue-dashboard","blog/music-data/mtl-bandcamp-mcp-open-source-revenue-dashboard",{"title":172,"path":173,"stem":174},"mtl-metadata-mcp: Open Source Audio Metadata Embedding for Claude Code","/blog/music-data/mtl-metadata-mcp-open-source-audio-metadata-embedding","blog/music-data/mtl-metadata-mcp-open-source-audio-metadata-embedding",{"title":176,"path":177,"stem":178},"MusicTech Resources for Builders","/blog/music-data/musictech-resources-curated-insights-for-the-musictech-builders","blog/music-data/musictech-resources-curated-insights-for-the-musictech-builders",{"title":180,"path":181,"stem":182},"Poland's Creative Tech and MusicTech Rise","/blog/music-data/polands-creative-tech-sector-is-on-the-rise-and-musictech-is-part-of-it","blog/music-data/polands-creative-tech-sector-is-on-the-rise-and-musictech-is-part-of-it",{"title":184,"path":185,"stem":186},"Batch ISRC Enrichment That Turns Messy Catalogs Into Clean Data","/blog/music-data/scout-isrc-metadata-enrichment-spotify-musicbrainz","blog/music-data/scout-isrc-metadata-enrichment-spotify-musicbrainz",{"title":188,"path":189,"stem":190},"Music Self-Publishing: The Emuze.me Story","/blog/music-data/self-publishing-in-the-music-industry-a-tale-of-emuze-me","blog/music-data/self-publishing-in-the-music-industry-a-tale-of-emuze-me",{"title":192,"path":193,"stem":194},"Understanding the API First Approach","/blog/music-data/understanding-the-api-first-approach","blog/music-data/understanding-the-api-first-approach",{"title":196,"path":197,"stem":198},"The Voice Memo Graveyard Problem","/blog/music-data/voice-memo-graveyard-problem","blog/music-data/voice-memo-graveyard-problem",{"title":200,"path":201,"stem":202},"Which Database for Music Data? Redshift vs BigQuery vs ClickHouse and When to Use Each","/blog/music-data/which-database-for-music-data-redshift-vs-bigquery-vs-clickhouse","blog/music-data/which-database-for-music-data-redshift-vs-bigquery-vs-clickhouse",{"title":204,"path":205,"stem":206},"Why we decided to use wavesurfer.js","/blog/music-data/why-we-decided-to-use-wavesurfer","blog/music-data/why-we-decided-to-use-wavesurfer",{"title":208,"path":209,"stem":210,"children":211,"page":69},"Newsletter","/blog/newsletter","blog/newsletter",[212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300,304,308],{"title":213,"path":214,"stem":215},"Music Industry Tech Openings (April 2024 Update)","/blog/newsletter/music-industry-tech-openings-april-2024-update","blog/newsletter/music-industry-tech-openings-april-2024-update",{"title":217,"path":218,"stem":219},"Music Industry Tech Openings (April 2025 Update)","/blog/newsletter/music-industry-tech-openings-april-2025-update","blog/newsletter/music-industry-tech-openings-april-2025-update",{"title":221,"path":222,"stem":223},"Music Industry Tech Openings (August 2024 Update)","/blog/newsletter/music-industry-tech-openings-august-2024-update","blog/newsletter/music-industry-tech-openings-august-2024-update",{"title":225,"path":226,"stem":227},"Music Industry Tech Openings (December 2024 Update)","/blog/newsletter/music-industry-tech-openings-december-2024-update","blog/newsletter/music-industry-tech-openings-december-2024-update",{"title":229,"path":230,"stem":231},"Music Industry Tech Openings (February 2025 Update)","/blog/newsletter/music-industry-tech-openings-february-2025-update","blog/newsletter/music-industry-tech-openings-february-2025-update",{"title":233,"path":234,"stem":235},"Music Industry Tech Openings (January 2025 Update)","/blog/newsletter/music-industry-tech-openings-january-2025-update","blog/newsletter/music-industry-tech-openings-january-2025-update",{"title":237,"path":238,"stem":239},"Music Industry Tech Openings (July 2024 Update)","/blog/newsletter/music-industry-tech-openings-july-2024-update","blog/newsletter/music-industry-tech-openings-july-2024-update",{"title":241,"path":242,"stem":243},"Music Industry Tech Openings (June 2024 Update)","/blog/newsletter/music-industry-tech-openings-june-2024-update","blog/newsletter/music-industry-tech-openings-june-2024-update",{"title":245,"path":246,"stem":247},"Music Industry Tech Openings (March 2025 Update)","/blog/newsletter/music-industry-tech-openings-march-2025-update","blog/newsletter/music-industry-tech-openings-march-2025-update",{"title":249,"path":250,"stem":251},"Music Industry Tech Openings (May 2024 Update)","/blog/newsletter/music-industry-tech-openings-may-2024-update","blog/newsletter/music-industry-tech-openings-may-2024-update",{"title":253,"path":254,"stem":255},"Music Industry Tech Openings (May 2025 Update)","/blog/newsletter/music-industry-tech-openings-may-2025","blog/newsletter/music-industry-tech-openings-may-2025",{"title":257,"path":258,"stem":259},"Music Industry Tech Openings (November 2024 Update)","/blog/newsletter/music-industry-tech-openings-november-2024-update","blog/newsletter/music-industry-tech-openings-november-2024-update",{"title":261,"path":262,"stem":263},"Music Industry Tech Openings (October 2024 Update)","/blog/newsletter/music-industry-tech-openings-october-2024-update","blog/newsletter/music-industry-tech-openings-october-2024-update",{"title":265,"path":266,"stem":267},"Music Industry Tech Openings (September 2024 Update)","/blog/newsletter/music-industry-tech-openings-september-2024-update","blog/newsletter/music-industry-tech-openings-september-2024-update",{"title":269,"path":270,"stem":271},"MusicTech Insights #1 by Maciej Dulski","/blog/newsletter/musictech-insights-1-curated-by-maciej-dulski","blog/newsletter/musictech-insights-1-curated-by-maciej-dulski",{"title":273,"path":274,"stem":275},"Provenance, Not Detection, Is the Durable Answer","/blog/newsletter/musictech-insights-10-curated-by-jim-anderson","blog/newsletter/musictech-insights-10-curated-by-jim-anderson",{"title":277,"path":278,"stem":279},"What CMOs can teach us about innovation in uncertain times","/blog/newsletter/musictech-insights-10-curated-by-joanna-kurkowska","blog/newsletter/musictech-insights-10-curated-by-joanna-kurkowska",{"title":281,"path":282,"stem":283},"Feeling the MusicTech Momentum","/blog/newsletter/musictech-insights-2-curated-by-maciej-dulski","blog/newsletter/musictech-insights-2-curated-by-maciej-dulski",{"title":285,"path":286,"stem":287},"AI in Music: Hype, Hope, and a Human Touch","/blog/newsletter/musictech-insights-3-curated-by-drew-thurlow","blog/newsletter/musictech-insights-3-curated-by-drew-thurlow",{"title":289,"path":290,"stem":291},"The Music Metadata Conundrum","/blog/newsletter/musictech-insights-4-curated-by-amanda-schupf","blog/newsletter/musictech-insights-4-curated-by-amanda-schupf",{"title":293,"path":294,"stem":295},"7 Rounds in the First 10 Days of November 2025","/blog/newsletter/musictech-insights-5-curated-by-maciej-dulski","blog/newsletter/musictech-insights-5-curated-by-maciej-dulski",{"title":297,"path":298,"stem":299},"The End of an Era: It's All About to Crash","/blog/newsletter/musictech-insights-6-curated-by-sigurdur-arnason","blog/newsletter/musictech-insights-6-curated-by-sigurdur-arnason",{"title":301,"path":302,"stem":303},"Low-Code Magic Won't Solve MusicTech Reality","/blog/newsletter/musictech-insights-7-curated-by-mariusz-smenzyk","blog/newsletter/musictech-insights-7-curated-by-mariusz-smenzyk",{"title":305,"path":306,"stem":307},"The New Economics of Game Music","/blog/newsletter/musictech-insights-8-curated-by-kenny-vaughan","blog/newsletter/musictech-insights-8-curated-by-kenny-vaughan",{"title":309,"path":310,"stem":311},"Music Business Meets Direct-to-Fan","/blog/newsletter/musictech-insights-9-curated-by-yaw-asamani","blog/newsletter/musictech-insights-9-curated-by-yaw-asamani",{"title":313,"path":314,"stem":315,"children":316,"page":69},"Software Development","/blog/software-development","blog/software-development",[317,321,325,329,333,337,341,345,349,353,357,361,365,369,373,377,381,385,389,393,397,401,405,409,413,417,421,425,429,433,437,441,445,449,453,457,461,465,469,473,477,481,485,489,493,497,501,505,509,513,517,521,525,529,533,537,541,545,549,553,557,561,565,569,573,577,581,585,589,593,597,601,605,609,613,617,621,625,629,633,637,641,645,649,653,657,661,665,669,673,677,681,685,689,693,697,701,705,709,713,717],{"title":318,"path":319,"stem":320},"Benefits of Outsourcing Software Development","/blog/software-development/10-benefits-of-outsourcing-software-development-services","blog/software-development/10-benefits-of-outsourcing-software-development-services",{"title":322,"path":323,"stem":324},"10 Steps to Find the Best MVP Developers","/blog/software-development/10-steps-to-find-the-best-mvp-developers-for-your-startup-idea","blog/software-development/10-steps-to-find-the-best-mvp-developers-for-your-startup-idea",{"title":326,"path":327,"stem":328},"1,200 Looms Later: How Async Video Became My Development Superpower","/blog/software-development/1200-looms-how-async-video-became-our-development-superpower","blog/software-development/1200-looms-how-async-video-became-our-development-superpower",{"title":330,"path":331,"stem":332},"Communication Strategy in Outsourcing Projects","/blog/software-development/5-steps-to-implement-an-effective-communication-strategy-in-outsourcing-software-development-project","blog/software-development/5-steps-to-implement-an-effective-communication-strategy-in-outsourcing-software-development-project",{"title":334,"path":335,"stem":336},"7 Best Practices for Outsourcing Software Development","/blog/software-development/7-best-practices-for-outsourcing-software-development","blog/software-development/7-best-practices-for-outsourcing-software-development",{"title":338,"path":339,"stem":340},"9 Reasons Why Saleor.io Is Best for eCommerce","/blog/software-development/9-reasons-why-the-saleor-io-platform-is-the-best-choice-for-your-ecommerce-website","blog/software-development/9-reasons-why-the-saleor-io-platform-is-the-best-choice-for-your-ecommerce-website",{"title":342,"path":343,"stem":344},"A Look at Bravelab.io’s Clutch 2021 Year In Review","/blog/software-development/a-look-at-bravelab-ios-clutch-2021-year-in-review","blog/software-development/a-look-at-bravelab-ios-clutch-2021-year-in-review",{"title":346,"path":347,"stem":348},"A quick introduction to profit sharing implementation","/blog/software-development/a-quick-introduction-to-profit-sharing-implementation","blog/software-development/a-quick-introduction-to-profit-sharing-implementation",{"title":350,"path":351,"stem":352},"AI Audio Similarity Search: The Future of Sound Library Discovery","/blog/software-development/ai-audio-similarity-search-for-sound-libraries","blog/software-development/ai-audio-similarity-search-for-sound-libraries",{"title":354,"path":355,"stem":356},"Automate Repetitive Tasks for Better Results","/blog/software-development/automate-repetitive-tasks-to-improve-your-business-performance","blog/software-development/automate-repetitive-tasks-to-improve-your-business-performance",{"title":358,"path":359,"stem":360},"Automating Success: The Art of Unified Documentation","/blog/software-development/automating-success-the-art-of-unified-documentation","blog/software-development/automating-success-the-art-of-unified-documentation",{"title":362,"path":363,"stem":364},"Brave 3.0 Website Redesign, Part 2: Solution","/blog/software-development/brave-3-0-how-we-conducted-website-redesign-part-2-solution","blog/software-development/brave-3-0-how-we-conducted-website-redesign-part-2-solution",{"title":366,"path":367,"stem":368},"Brave 3.0, Part 4: Tech Stack and Recap","/blog/software-development/brave-3-0-part-4-technologies-behind-and-final-series-recap","blog/software-development/brave-3-0-part-4-technologies-behind-and-final-series-recap",{"title":370,"path":371,"stem":372},"Brave 3.0 – redesign process part 1. The Challenge","/blog/software-development/brave-3-0-redesign-process-part-1-challenge","blog/software-development/brave-3-0-redesign-process-part-1-challenge",{"title":374,"path":375,"stem":376},"Brave 3.0 – redesign process, part 3. Lesson learned","/blog/software-development/brave-3-0-redesign-process-part-3-lesson-learned","blog/software-development/brave-3-0-redesign-process-part-3-lesson-learned",{"title":378,"path":379,"stem":380},"Bravelab.io: Top Software Developer by Clutch","/blog/software-development/bravelab-io-is-recognized-as-a-top-custom-software-developer-by-clutch","blog/software-development/bravelab-io-is-recognized-as-a-top-custom-software-developer-by-clutch",{"title":382,"path":383,"stem":384},"Bravelab.io: Top Developer in Poland by Clutch","/blog/software-development/bravelab-io-named-top-software-developer-in-poland-by-clutch","blog/software-development/bravelab-io-named-top-software-developer-in-poland-by-clutch",{"title":386,"path":387,"stem":388},"MusicTech Lab Partners with LALAL.AI","/blog/software-development/bravelab-partners-with-the-audio-lalal-ai","blog/software-development/bravelab-partners-with-the-audio-lalal-ai",{"title":390,"path":391,"stem":392},"MusicTech Lab Partners with The Audio Programmer","/blog/software-development/bravelab-partners-with-the-audio-programmer","blog/software-development/bravelab-partners-with-the-audio-programmer",{"title":394,"path":395,"stem":396},"Bravelab's team about productivity","/blog/software-development/bravelabs-team-about-productivity","blog/software-development/bravelabs-team-about-productivity",{"title":398,"path":399,"stem":400},"Braveloper","/blog/software-development/braveloper","blog/software-development/braveloper",{"title":402,"path":403,"stem":404},"Bravely App: Boost Productivity with Django","/blog/software-development/bravely-app-how-to-be-more-productive-with-django-quick","blog/software-development/bravely-app-how-to-be-more-productive-with-django-quick",{"title":406,"path":407,"stem":408},"DIY MIDI Controller for Ableton with Arduino","/blog/software-development/building-a-diy-midi-controller-for-ableton-live-with-arduino","blog/software-development/building-a-diy-midi-controller-for-ableton-live-with-arduino",{"title":410,"path":411,"stem":412},"C2PA in Ableton: Making AI Music Provenance Visible Inside Your DAW","/blog/software-development/c2pa-in-ableton-max-for-live","blog/software-development/c2pa-in-ableton-max-for-live",{"title":414,"path":415,"stem":416},"Change Detection mechanism in Angular","/blog/software-development/change-detection-mechanism-in-angular","blog/software-development/change-detection-mechanism-in-angular",{"title":418,"path":419,"stem":420},"Communication Channels in Remote Work","/blog/software-development/comparison-of-the-communication-channels-in-remote-work","blog/software-development/comparison-of-the-communication-channels-in-remote-work",{"title":422,"path":423,"stem":424},"Connecting Your Max for Live Device to a Cloud API","/blog/software-development/connecting-your-max-for-live-device-to-a-cloud-api","blog/software-development/connecting-your-max-for-live-device-to-a-cloud-api",{"title":426,"path":427,"stem":428},"From Voice Memo to Studio: The Cross-Platform Problem for Creators","/blog/software-development/cross-platform-problem-for-creators","blog/software-development/cross-platform-problem-for-creators",{"title":430,"path":431,"stem":432},"Cultural transformation through the pandemic era","/blog/software-development/cultural-transformation-through-the-pandemic-era","blog/software-development/cultural-transformation-through-the-pandemic-era",{"title":434,"path":435,"stem":436},"D-Commerce Decoded: Cutting Through the Hype","/blog/software-development/d-commerce-decoded-cutting-through-the-hype","blog/software-development/d-commerce-decoded-cutting-through-the-hype",{"title":438,"path":439,"stem":440},"Dev Meeting 002: Intro to DDD","/blog/software-development/dev-meeting-002-introduction-to-domain-driven-design-ddd","blog/software-development/dev-meeting-002-introduction-to-domain-driven-design-ddd",{"title":442,"path":443,"stem":444},"Dev Meeting 003: Web3 Primer","/blog/software-development/dev-meeting-003-web3-primer","blog/software-development/dev-meeting-003-web3-primer",{"title":446,"path":447,"stem":448},"Dev Meeting 004: Introduction to Event Storming","/blog/software-development/dev-meeting-004-introduction-to-event-storming","blog/software-development/dev-meeting-004-introduction-to-event-storming",{"title":450,"path":451,"stem":452},"Dev Meeting 001: Kubernetes is a Framework","/blog/software-development/dev-meeting-kubernetes-is-a-framework","blog/software-development/dev-meeting-kubernetes-is-a-framework",{"title":454,"path":455,"stem":456},"Did You Know? 10 Developer Tips from Real Codebases","/blog/software-development/did-you-know-dev-tips-part-1","blog/software-development/did-you-know-dev-tips-part-1",{"title":458,"path":459,"stem":460},"10 Surprising MusicTech Facts (Part 2)","/blog/software-development/did-you-know-musictech-facts-part-2","blog/software-development/did-you-know-musictech-facts-part-2",{"title":462,"path":463,"stem":464},"Django-cms and GraphQL","/blog/software-development/django-cms-and-graphql","blog/software-development/django-cms-and-graphql",{"title":466,"path":467,"stem":468},"Does Zappa make it super easy?","/blog/software-development/does-zappa-make-it-super-easy","blog/software-development/does-zappa-make-it-super-easy",{"title":470,"path":471,"stem":472},"Establishing cooperation between Netlify and Bravelab","/blog/software-development/establishing-cooperation-between-netlify-and-bravelab","blog/software-development/establishing-cooperation-between-netlify-and-bravelab",{"title":474,"path":475,"stem":476},"Export Ableton Locators to JSON via Max for Live","/blog/software-development/exporting-ableton-live-locators-to-json-with-max-for-live","blog/software-development/exporting-ableton-live-locators-to-json-with-max-for-live",{"title":478,"path":479,"stem":480},"IT Outsourcing: Success and Failure Factors","/blog/software-development/factors-that-contribute-to-the-success-or-failure-of-an-it-outsourcing-project","blog/software-development/factors-that-contribute-to-the-success-or-failure-of-an-it-outsourcing-project",{"title":482,"path":483,"stem":484},"Flutter 2022 Strategy: Analyzing the Roadmap","/blog/software-development/flutter-strategy-for-2022-analyzing-the-new-flutter-roadmap","blog/software-development/flutter-strategy-for-2022-analyzing-the-new-flutter-roadmap",{"title":486,"path":487,"stem":488},"Git Better #1 — Commit Message Convention","/blog/software-development/git-better-1-see-more-with-a-commit-message-convention","blog/software-development/git-better-1-see-more-with-a-commit-message-convention",{"title":490,"path":491,"stem":492},"Hasura in action. How to use it with Django","/blog/software-development/hasura-in-action","blog/software-development/hasura-in-action",{"title":494,"path":495,"stem":496},"Holacracy why and where we are","/blog/software-development/holacracy-why-and-where-we-are","blog/software-development/holacracy-why-and-where-we-are",{"title":498,"path":499,"stem":500},"How does JavaScript work","/blog/software-development/how-does-javascript-work","blog/software-development/how-does-javascript-work",{"title":502,"path":503,"stem":504},"How important is good UX/UI design?","/blog/software-development/how-important-is-good-ux-ui-design","blog/software-development/how-important-is-good-ux-ui-design",{"title":506,"path":507,"stem":508},"How repetitive tasks impact your business","/blog/software-development/how-repetitive-tasks-impact-your-business","blog/software-development/how-repetitive-tasks-impact-your-business",{"title":510,"path":511,"stem":512},"Becoming a Vue.js Dev: Do Paid Trials Work?","/blog/software-development/how-to-become-a-vue-js-developer-and-whether-paid-trials-in-it-work-out","blog/software-development/how-to-become-a-vue-js-developer-and-whether-paid-trials-in-it-work-out",{"title":514,"path":515,"stem":516},"How to Build an MVP in 6 Steps","/blog/software-development/how-to-build-a-minimum-viable-product-mvp-in-6-steps","blog/software-development/how-to-build-a-minimum-viable-product-mvp-in-6-steps",{"title":518,"path":519,"stem":520},"How to conduct workshops for creative industry?","/blog/software-development/how-to-conduct-workshops-for-creative-industry","blog/software-development/how-to-conduct-workshops-for-creative-industry",{"title":522,"path":523,"stem":524},"How to easily create form in Angular","/blog/software-development/how-to-easily-create-form-in-angular","blog/software-development/how-to-easily-create-form-in-angular",{"title":526,"path":527,"stem":528},"How to export orders in Saleor.io to XLSX file","/blog/software-development/how-to-export-orders-in-saleor-io-to-xlsx-file","blog/software-development/how-to-export-orders-in-saleor-io-to-xlsx-file",{"title":530,"path":531,"stem":532},"Handling High Loads on E-Commerce Platforms","/blog/software-development/how-to-handle-high-loads-on-e-commerce-platform-with-ease","blog/software-development/how-to-handle-high-loads-on-e-commerce-platform-with-ease",{"title":534,"path":535,"stem":536},"How to launch Saleor.io shop instance within 40h","/blog/software-development/how-to-launch-saleor-io-shop-instance-within-40h","blog/software-development/how-to-launch-saleor-io-shop-instance-within-40h",{"title":538,"path":539,"stem":540},"First Steps to Build a Business Relationship","/blog/software-development/how-to-make-the-first-step-to-establish-a-business-relationship","blog/software-development/how-to-make-the-first-step-to-establish-a-business-relationship",{"title":542,"path":543,"stem":544},"Multi-Tenant Apps with Django and Saleor.io","/blog/software-development/how-to-manage-tenants-in-the-multitenant-app-based-on-django-tenants-and-saleor-io-platform","blog/software-development/how-to-manage-tenants-in-the-multitenant-app-based-on-django-tenants-and-saleor-io-platform",{"title":546,"path":547,"stem":548},"Notion Backup Tool Built in 3 Days with Python","/blog/software-development/how-we-built-a-notion-backup-tool-in-3-days-with-pythonvue-and-why","blog/software-development/how-we-built-a-notion-backup-tool-in-3-days-with-pythonvue-and-why",{"title":550,"path":551,"stem":552},"Important new features in Python 3.8","/blog/software-development/important-new-features-in-python-3-8","blog/software-development/important-new-features-in-python-3-8",{"title":554,"path":555,"stem":556},"Installing Proxmox on dedicated server from OVH","/blog/software-development/installing-proxmox-on-dedicated-server-from-ovh","blog/software-development/installing-proxmox-on-dedicated-server-from-ovh",{"title":558,"path":559,"stem":560},"Integrating SignNow E-Signatures into Your Django Application","/blog/software-development/integrating-signnow-e-signatures-into-your-django-application","blog/software-development/integrating-signnow-e-signatures-into-your-django-application",{"title":562,"path":563,"stem":564},"Tempus Metronome and GetSongBPM API","/blog/software-development/integrating-tempus-metronome-with-the-getsongbpm-api-what-bpm-really-means-and-how-to-use-it","blog/software-development/integrating-tempus-metronome-with-the-getsongbpm-api-what-bpm-really-means-and-how-to-use-it",{"title":566,"path":567,"stem":568},"Introducing MusicTech Poland","/blog/software-development/introducing-musictech-poland","blog/software-development/introducing-musictech-poland",{"title":570,"path":571,"stem":572},"Vue.js as a Frontend for Saleor.io","/blog/software-development/is-it-possible-to-use-vue-js-as-a-frontend-for-saleor-io-platform","blog/software-development/is-it-possible-to-use-vue-js-as-a-frontend-for-saleor-io-platform",{"title":574,"path":575,"stem":576},"Is your business ready for the cashless era?","/blog/software-development/is-your-business-ready-for-the-cashless-era","blog/software-development/is-your-business-ready-for-the-cashless-era",{"title":578,"path":579,"stem":580},"Is your face ready to buy?","/blog/software-development/is-your-face-ready-to-buy","blog/software-development/is-your-face-ready-to-buy",{"title":582,"path":583,"stem":584},"JS Frameworks: Trends and Opportunities","/blog/software-development/javascript-trending-frameworks-and-market-opportunities","blog/software-development/javascript-trending-frameworks-and-market-opportunities",{"title":586,"path":587,"stem":588},"Kanban Board: Boost Your Team Productivity","/blog/software-development/kanban-board-methodology-hack-your-companys-productivity","blog/software-development/kanban-board-methodology-hack-your-companys-productivity",{"title":590,"path":591,"stem":592},"Verified Human Cert MCP Server: Prove Your Music Is Human-Made, Right from the Terminal","/blog/software-development/mcp-verified-human-cert-open-source","blog/software-development/mcp-verified-human-cert-open-source",{"title":594,"path":595,"stem":596},"Migrating from TravisCI to Github Actions","/blog/software-development/migrating-from-travisci-to-github-actions","blog/software-development/migrating-from-travisci-to-github-actions",{"title":598,"path":599,"stem":600},"MusicTech Lab: Top Software Developer by Clutch","/blog/software-development/musictechlab-is-recognized-as-a-top-custom-software-developer-by-clutch","blog/software-development/musictechlab-is-recognized-as-a-top-custom-software-developer-by-clutch",{"title":602,"path":603,"stem":604},"MusicTech Lab x Verified Human: Building a Trust Layer for Human-Made Music","/blog/software-development/musictechlab_blog_verified_human_partnership","blog/software-development/musictechlab_blog_verified_human_partnership",{"title":606,"path":607,"stem":608},"MusicXML: Standard for Music Notation","/blog/software-development/musicxml-standard-for-music-notation-and-education","blog/software-development/musicxml-standard-for-music-notation-and-education",{"title":610,"path":611,"stem":612},"Only a few books but dozens of ideas","/blog/software-development/only-a-few-books-but-dozens-of-ideas","blog/software-development/only-a-few-books-but-dozens-of-ideas",{"title":614,"path":615,"stem":616},"Overdue Invoices and Issue Tracker Integration","/blog/software-development/overdue-invoices-integration-with-the-issue-tracking-system","blog/software-development/overdue-invoices-integration-with-the-issue-tracking-system",{"title":618,"path":619,"stem":620},"Performing SAML SSO using JWT in Django","/blog/software-development/performing-saml-sso-using-jwt-in-django","blog/software-development/performing-saml-sso-using-jwt-in-django",{"title":622,"path":623,"stem":624},"Progressive Web Apps for Mobile Development","/blog/software-development/progressive-web-apps-a-new-way-of-creating-mobile-application","blog/software-development/progressive-web-apps-a-new-way-of-creating-mobile-application",{"title":626,"path":627,"stem":628},"Recruitment System: Gmail, Jira, and CRM","/blog/software-development/recruitment-system-integrating-gmail-bravely-jira-slack-and-copper-crm","blog/software-development/recruitment-system-integrating-gmail-bravely-jira-slack-and-copper-crm",{"title":630,"path":631,"stem":632},"Scratch Me: Chrome Extension for Leads","/blog/software-development/scratch-me-a-simple-chrome-extension-which-will-increase-your-productivity","blog/software-development/scratch-me-a-simple-chrome-extension-which-will-increase-your-productivity",{"title":634,"path":635,"stem":636},"Scratch Me – integration with the Copper CRM","/blog/software-development/scratch-me-integration-with-the-copper-crm","blog/software-development/scratch-me-integration-with-the-copper-crm",{"title":638,"path":639,"stem":640},"SignNow MCP Server: E-Signatures Straight from Claude Code","/blog/software-development/signnow-mcp-server-e-signatures-from-claude-code","blog/software-development/signnow-mcp-server-e-signatures-from-claude-code",{"title":642,"path":643,"stem":644},"Music Industry Tech Openings (March 2024 Update)","/blog/software-development/technical-job-opportunities-in-the-music-industry","blog/software-development/technical-job-opportunities-in-the-music-industry",{"title":646,"path":647,"stem":648},"Thanks app – a Management 3.0 solution","/blog/software-development/thanks-app-a-management-3-0-solution","blog/software-development/thanks-app-a-management-3-0-solution",{"title":650,"path":651,"stem":652},"Colonial Pipeline Case: 7 Security Reminders","/blog/software-development/the-case-of-colonial-pipeline-and-7-security-reminders","blog/software-development/the-case-of-colonial-pipeline-and-7-security-reminders",{"title":654,"path":655,"stem":656},"The Evolution and Future of E-commerce Platforms","/blog/software-development/the-evolution-and-future-of-e-commerce-platforms","blog/software-development/the-evolution-and-future-of-e-commerce-platforms",{"title":658,"path":659,"stem":660},"The Gender Gap in the Tech Industry","/blog/software-development/the-gender-gap-in-the-tech-industry","blog/software-development/the-gender-gap-in-the-tech-industry",{"title":662,"path":663,"stem":664},"First Attempt to Implement 4DX at Bravelab.io","/blog/software-development/the-very-first-attempt-to-implement-4dx-in-bravelab-io","blog/software-development/the-very-first-attempt-to-implement-4dx-in-bravelab-io",{"title":666,"path":667,"stem":668},"The WTF Scale: IT Project Complexity","/blog/software-development/the-wtf-programming-scale-measuring-it-project-complexity","blog/software-development/the-wtf-programming-scale-measuring-it-project-complexity",{"title":670,"path":671,"stem":672},"Top 10 articles through the eyes of our developers","/blog/software-development/top-10-articles-through-the-eyes-of-our-developers","blog/software-development/top-10-articles-through-the-eyes-of-our-developers",{"title":674,"path":675,"stem":676},"Top 6 apps made with Flutter","/blog/software-development/top-6-apps-made-with-flutter","blog/software-development/top-6-apps-made-with-flutter",{"title":678,"path":679,"stem":680},"Uber 101: How Uber Made It to the Top","/blog/software-development/uber-101-how-this-ride-sharing-behemoth-made-it-to-the-top","blog/software-development/uber-101-how-this-ride-sharing-behemoth-made-it-to-the-top",{"title":682,"path":683,"stem":684},"MusicTech Lab Partners with Music Glue","/blog/software-development/unifying-artists-and-audiences-exploring-music-glue","blog/software-development/unifying-artists-and-audiences-exploring-music-glue",{"title":686,"path":687,"stem":688},"Why AI Will Defeat Traditional HR","/blog/software-development/warning-why-artificial-intelligence-will-defeat-traditional-hr","blog/software-development/warning-why-artificial-intelligence-will-defeat-traditional-hr",{"title":690,"path":691,"stem":692},"What is a Discovery Document?","/blog/software-development/what-is-discovery-document","blog/software-development/what-is-discovery-document",{"title":694,"path":695,"stem":696},"What is Flutter, and Why is it Worth Considering?","/blog/software-development/what-is-flutter-and-why-is-it-worth-considering","blog/software-development/what-is-flutter-and-why-is-it-worth-considering",{"title":698,"path":699,"stem":700},"What is a Watermarked Song?","/blog/software-development/what-is-watermarked-song","blog/software-development/what-is-watermarked-song",{"title":702,"path":703,"stem":704},"Choosing a Frontend Framework for the Web","/blog/software-development/which-framework-should-you-choose-for-the-frontend-web-platform-development","blog/software-development/which-framework-should-you-choose-for-the-frontend-web-platform-development",{"title":706,"path":707,"stem":708},"Why DAWs Are the Wrong Tool for Starting a Song","/blog/software-development/why-daws-wrong-tool-for-starting-song","blog/software-development/why-daws-wrong-tool-for-starting-song",{"title":710,"path":711,"stem":712},"Why the Programming World Loves Python","/blog/software-development/why-the-programming-world-loves-python","blog/software-development/why-the-programming-world-loves-python",{"title":714,"path":715,"stem":716},"Why We Don't Build Chat From Scratch (And Neither Should You)","/blog/software-development/why-we-dont-build-chat-from-scratch","blog/software-development/why-we-dont-build-chat-from-scratch",{"title":718,"path":719,"stem":720},"Why we use Sanity.io","/blog/software-development/why-we-use-sanity-io","blog/software-development/why-we-use-sanity-io",{"title":722,"path":723,"stem":724,"children":725,"page":69},"Sportstech","/blog/sportstech","blog/sportstech",[726,730],{"title":727,"path":728,"stem":729},"BeatBuddy Replay: Video Analysis App Challenges","/blog/sportstech/beatbuddy-replay-video-analysis-app-for-swimmers-flutter","blog/sportstech/beatbuddy-replay-video-analysis-app-for-swimmers-flutter",{"title":731,"path":732,"stem":733},"How to Create a Watch Face App for Garmin Watch","/blog/sportstech/how-to-create-watch-face-app-for-garmin-watch","blog/sportstech/how-to-create-watch-face-app-for-garmin-watch",{"id":735,"title":34,"authors":736,"badge":737,"body":739,"category":1062,"client":1063,"date":1066,"description":1067,"extension":1068,"faq":736,"featured":1069,"featuredOrder":1070,"hidden":69,"image":1071,"keyTakeaways":1073,"meta":1086,"navigation":1069,"path":35,"seo":1087,"status":736,"stem":36,"tags":1088,"teaser":736,"__hash__":1091},"posts/blog/case-study/mobile-app-for-music-catalog.md",null,{"label":5,"color":738},"#E91E63",{"type":740,"value":741,"toc":1050},"minimark",[742,746,749,754,779,781,785,818,820,824,832,856,858,862,926,928,932,939,957,967,969,973,979,985,994,996,1000,1019,1021,1025],[743,744,745],"p",{},"Content creators, music publishers, and producers need their catalogs where their audience is — on mobile. Our white-label mobile app for music catalogs was built to solve exactly that: a ready-to-deploy Flutter application that brings music libraries to iOS and Android with a professional audio player, playlists, search, downloads, and more.",[747,748],"hr",{},[750,751,753],"h2",{"id":752},"the-problem","The Problem",[755,756,763,769,774],"div",{"className":757},[758,759,760,761,762],"grid","grid-cols-1","md:grid-cols-3","gap-4","my-8",[764,765],"spotlight-card",{"description":766,"title":767,"icon":768},"Customers live on Spotify, Apple Music, and Tidal — but many music businesses are still desktop-first, missing mobile-native users entirely.","Clients Are Mobile","i-lucide-smartphone",[764,770],{"description":771,"title":772,"icon":773},"Revenues from big platforms keep shrinking. Diversifying through direct-to-fan channels and cultivating super-fans is no longer optional.","Shrinking Platform Revenue","i-lucide-trending-down",[764,775],{"description":776,"title":777,"icon":778},"While other industries embraced digital tools, many music businesses still deal with paper contracts, email chains, and outdated processes.","Analog Practices","i-lucide-file-stack",[747,780],{},[750,782,784],{"id":783},"features","Features",[755,786,788,793,798,803,808,813],{"className":787},[758,759,760,761,762],[764,789],{"description":790,"title":791,"icon":792},"Built-in media player using iOS/Android native audio services. Background playback, lock screen controls, waveform visualisation, and stem switching.","Audio Player","i-lucide-play-circle",[764,794],{"description":795,"title":796,"icon":797},"Staff-curated and user-created playlists. Organise, customise, and share collections of tracks.","Playlists","i-lucide-list-music",[764,799],{"description":800,"title":801,"icon":802},"Filter by genre, artist, album, duration, mood, theme, BPM, and custom tags. Sort results and apply multiple filters simultaneously.","Advanced Search","i-lucide-search",[764,804],{"description":805,"title":806,"icon":807},"Mark and quickly access preferred songs, albums, or artists. Synced across devices via the backend API.","Favourites","i-lucide-heart",[764,809],{"description":810,"title":811,"icon":812},"Save music locally for offline listening. Background download manager with progress tracking and storage management.","Downloads","i-lucide-download",[764,814],{"description":815,"title":816,"icon":817},"Share tracks and playlists with friends via native share sheets. Deep linking support for direct track access.","Sharing","i-lucide-share-2",[747,819],{},[750,821,823],{"id":822},"architecture","Architecture",[743,825,826,827,831],{},"The app follows a ",[828,829,830],"strong",{},"feature-first architecture"," with clean separation of concerns. Each feature module contains its own UI, BLoC/Cubit state management, repository layer, and models.",[755,833,836,841,846,851],{"className":834},[758,759,835,761,762],"md:grid-cols-2",[764,837],{"description":838,"title":839,"icon":840},"Audio Player, Auth (login, sign-up, reset password, social auth), Browse & Search, Favourites, Playlists, Account Management, Downloads, Filters (genre, mood, theme, BPM).","Feature Modules","i-lucide-layers",[764,842],{"description":843,"title":844,"icon":845},"Native audio service integration with `just_audio` and `audio_service`. Background playback, waveform rendering with `flutter_audio_waveforms`, volume control, and stem switching for multi-track playback.","Audio Engine","i-lucide-music",[764,847],{"description":848,"title":849,"icon":850},"Hasura GraphQL API with `hasura_connect`. Sanity CMS for content. Secure token storage with `flutter_secure_storage`. Offline caching with `background_downloader`.","Data Layer","i-lucide-database",[764,852],{"description":853,"title":854,"icon":855},"Email/password, Google Sign-In, Apple Sign-In. Email verification flow. Password reset with validation. Secure storage for tokens and credentials.","Auth & Security","i-lucide-shield-check",[747,857],{},[750,859,861],{"id":860},"technologies-used","Technologies Used",[755,863,868,872,877,882,887,891,896,901,906,911,916,921],{"className":864},[758,865,760,866,867,762],"grid-cols-2","lg:grid-cols-4","gap-3",[764,869],{"description":870,"title":871,"icon":768},"Cross-platform app","Flutter",[764,873],{"description":874,"title":875,"icon":876},"State management","BLoC / Cubit","i-lucide-blocks",[764,878],{"description":879,"title":880,"icon":881},"API layer","Hasura + GraphQL","i-lucide-plug",[764,883],{"description":884,"title":885,"icon":886},"Content management","Sanity CMS","i-lucide-file-text",[764,888],{"description":889,"title":890,"icon":845},"Audio playback","just_audio",[764,892],{"description":893,"title":894,"icon":895},"Background audio","audio_service","i-lucide-activity",[764,897],{"description":898,"title":899,"icon":900},"Social auth","Sign-In (Google/Apple)","i-lucide-lock",[764,902],{"description":903,"title":904,"icon":905},"CI/CD builds","Codemagic","i-lucide-hammer",[764,907],{"description":908,"title":909,"icon":910},"Error tracking","Sentry","i-lucide-bug",[764,912],{"description":913,"title":914,"icon":915},"i18n support","easy_localization","i-lucide-languages",[764,917],{"description":918,"title":919,"icon":920},"Navigation","auto_route","i-lucide-route",[764,922],{"description":923,"title":924,"icon":925},"Immutable models","Freezed","i-lucide-snowflake",[747,927],{},[750,929,931],{"id":930},"white-label-approach","White-Label Approach",[743,933,934,935,938],{},"The app is designed as a ",[828,936,937],{},"white-label product"," — fully brandable and customisable for different music businesses.",[755,940,942,947,952],{"className":941},[758,759,760,761,762],[764,943],{"description":944,"title":945,"icon":946},"Custom logos, colours, typography, and visual identity. The app looks and feels like your own product.","Your Brand","i-lucide-palette",[764,948],{"description":949,"title":950,"icon":951},"External config file for API keys, environment settings, and feature flags. No code changes needed for basic customisation.","Configurable","i-lucide-settings",[764,953],{"description":954,"title":955,"icon":956},"Expect your branded app published on Google Play and App Store within approximately 4 weeks.","Fast to Market","i-lucide-rocket",[958,959,960],"note",{},[743,961,962,963,966],{},"The basic white-label package starts at ",[828,964,965],{},"€8,700"," — including the app, marketplace submission for iOS and Android, and initial setup support. Custom features and integrations are scoped separately.",[747,968],{},[750,970,972],{"id":971},"client-testimonial","Client Testimonial",[974,975,976],"blockquote",{},[743,977,978],{},"Our goal was to build a music platform enabling us to charge our customers in a subscription model and as one-off payments. MusicTech Lab's developers were super engaged. Thanks to their effort, we prepared MVP and started working on the marketing. The first biggest technology milestone was achieved during five months.",[743,980,981,984],{},[828,982,983],{},"Paweł Przetacznik"," — CIO, IMS S.A",[743,986,987],{},[988,989,993],"a",{"href":990,"rel":991},"https://clutch.co/profile/musictech-lab#review-2063393",[992],"nofollow","See full review on Clutch",[747,995],{},[750,997,999],{"id":998},"faq","FAQ",[755,1001,1003,1007,1011,1015],{"className":1002},[758,759,835,761,762],[764,1004],{"description":1005,"title":1006},"More than half the world (54%) uses mobile devices, surpassing desktop. Most music consumption happens on mobile — Spotify, YouTube Music, Tidal, Apple Music. Reach your audience where they already are.","Why should I move my business to mobile?",[764,1008],{"description":1009,"title":1010},"Within approximately 4 weeks. The timeline may vary based on customisations. Your app will be fully white-labelled with your logos, colours, and brand elements.","When can I expect my app published?",[764,1012],{"description":1013,"title":1014},"Yes. We start with the core features and customise to your requirements. No need to include every \"nice-to-have\" upfront — we add features iteratively as needed.","Can I adjust the app to my needs?",[764,1016],{"description":1017,"title":1018},"The basic package starts at €8,700 — including the app, marketplace submission, and initial support. Custom features, integrations, and ongoing maintenance are scoped separately.","What does the investment look like?",[747,1020],{},[750,1022,1024],{"id":1023},"links","Links",[755,1026,1030,1038,1042,1047],{"className":1027},[1028,1029,867,762],"flex","flex-wrap",[1031,1032],"u-button",{"color":1033,"label":1034,"to":1035,"variant":1036,"target":1037},"primary","iOS App","https://apps.apple.com/us/app/closer-music/id1637404510","subtle","_blank",[1031,1039],{"color":1033,"label":1040,"to":1041,"variant":1036,"target":1037},"Google Play","https://play.google.com/store/apps/details?id=com.closermusic",[1031,1043],{"color":1044,"label":1045,"to":1046,"variant":1036,"target":1037},"neutral","Web Platform","https://www.closermusic.com",[1031,1048],{"color":1044,"label":1049,"to":19,"variant":1036},"Full Platform Case Study",{"title":1051,"searchDepth":1052,"depth":1052,"links":1053},"",2,[1054,1055,1056,1057,1058,1059,1060,1061],{"id":752,"depth":1052,"text":753},{"id":783,"depth":1052,"text":784},{"id":822,"depth":1052,"text":823},{"id":860,"depth":1052,"text":861},{"id":930,"depth":1052,"text":931},{"id":971,"depth":1052,"text":972},{"id":998,"depth":1052,"text":999},{"id":1023,"depth":1052,"text":1024},"case-study",{"name":1064,"logo":1065},"Closer Music","/images/logos/closermusic.webp","2023-06-01T00:00:00.000Z","A white-label Flutter mobile app for music catalogs — built for publishers, producers, and music lovers. Audio player, playlists, search, downloads, and offline mode.","md",true,24,{"src":1072},"/images/case-studies/musictechlab_mobile-app-for-music-catalog.webp",{"enabled":1069,"items":1074},[1075,1077,1080,1083],{"text":1076,"icon":768},"White-label Flutter music app ready for App Store and Google Play in 4 weeks.",{"text":1078,"icon":1079},"Basic package starts at 8,700 EUR including app, store submission, and setup support.","i-lucide-coins",{"text":1081,"icon":1082},"Features include offline downloads, background playback, and advanced search filters.","i-lucide-headphones",{"text":1084,"icon":1085},"Cross-platform codebase with BLoC state management and Hasura GraphQL API.","i-lucide-code",{},{"title":34,"description":1067},[1062,1089,1090],"musictech","mobile","1KZGlKLGCro32dTNOJZFDqpMbdm5t9AkyAlT2rlK7LM",[1093,1095],{"title":30,"path":31,"stem":32,"description":1094,"children":-1},"How we built a tablet-based loyalty app for Forum shopping mall to issue prepaid gift cards based on purchase amounts, with backend API and admin panel.",{"title":38,"path":39,"stem":40,"description":1096,"children":-1},"How we aggregated 200M streaming records from Spotify, Apple Music, YouTube and more into a unified royalty data integration system.",[1098,1649,1907,2451],{"id":1099,"title":10,"authors":736,"badge":1100,"body":1101,"category":1062,"client":1627,"date":1630,"description":1631,"extension":1068,"faq":736,"featured":1069,"featuredOrder":1450,"hidden":69,"image":1632,"keyTakeaways":1634,"meta":1644,"navigation":1069,"path":1645,"seo":1646,"status":736,"stem":12,"tags":1647,"teaser":736,"__hash__":1648,"score":1346},"posts/blog/case-study/ambistream-building-a-multi-layer-streaming-platform-from-a-spark-of-an-idea.md",{"label":5,"color":738},{"type":740,"value":1102,"toc":1614},[1103,1106,1114,1124,1134,1137,1139,1143,1193,1195,1199,1250,1252,1254,1306,1308,1312,1315,1465,1467,1471,1476,1482,1495,1498,1503,1505,1509,1513,1516,1522,1524,1528,1554,1556,1558,1565,1571,1573,1577,1580,1607,1610],[743,1104,1105],{},"Before Ambistream had a roadmap, a name, or even an interface, it began with a simple question at MusicTech Lab:",[974,1107,1108],{},[743,1109,1110],{},[1111,1112,1113],"em",{},"“What if video could be controlled like a musical instrument?”",[743,1115,1116,1117,1120,1121,1123],{},"A Flutter app prototype.",[1118,1119],"br",{},"\nA Chromecast on a table.",[1118,1122],{},"\nA folder full of rehearsal and training videos.",[743,1125,1126,1127,1130,1131,1133],{},"One button: ",[828,1128,1129],{},"PLAY ON TV",".",[1118,1132],{},"\nAnd it worked - barely, but enough to start something bigger.",[743,1135,1136],{},"This is the story of how Ambistream grew from a curiosity into a fully-fledged streaming engine powering creative, educational, and athletic scenarios.",[747,1138],{},[750,1140,1142],{"id":1141},"platform-components","Platform Components",[755,1144,1147,1152,1157,1161,1166,1171,1175,1180,1185,1189],{"className":1145},[758,759,835,1146,761,762],"lg:grid-cols-3",[764,1148],{"description":1149,"icon":1150,"title":1151},"Django-based engine for sessions, media, metadata","i-lucide-server","Backend API",[764,1153],{"description":1154,"icon":1155,"title":1156},"Nuxt 3 platform for scene management and control","i-lucide-layout-dashboard","Web Frontend",[764,1158],{"description":1159,"icon":768,"title":1160},"Flutter app for iOS/Android with casting capabilities","Mobile Application",[764,1162],{"description":1163,"icon":1164,"title":1165},"Dedicated cast app for synchronised playback","i-lucide-cast","Custom Chromecast Receiver",[764,1167],{"description":1168,"icon":1169,"title":1170},"Native remote playback for Apple devices","i-lucide-airplay","AirPlay Integration",[764,1172],{"description":1173,"icon":840,"title":1174},"Layered video + Lottie animations + UI","Overlay Engine",[764,1176],{"description":1177,"icon":1178,"title":1179},"FFmpeg-based transcoding for HLS and MP4","i-lucide-film","Media Pipeline",[764,1181],{"description":1182,"icon":1183,"title":1184},"Google Cloud Run, Firebase Hosting","i-lucide-cloud","Cloud Infrastructure",[764,1186],{"description":1187,"icon":951,"title":1188},"Tools for uploading, organising and configuring scenes","Admin Panel",[764,1190],{"description":1191,"icon":895,"title":1192},"Sentry, UptimeRobot, Cloud Logging","Analytics & Monitoring",[747,1194],{},[750,1196,1198],{"id":1197},"core-features","Core Features",[755,1200,1202,1206,1211,1216,1220,1225,1230,1235,1240,1245],{"className":1201},[758,759,835,761,762],[764,1203],{"description":1204,"icon":840,"title":1205},"Combine video with Lottie animations in real time","Layered Playback",[764,1207],{"description":1208,"icon":1209,"title":1210},"Timeline-based overlay configuration","i-lucide-clapperboard","Scene Builder",[764,1212],{"description":1213,"icon":1214,"title":1215},"Control playback from phone to external display","i-lucide-tablet-smartphone","Remote Controller",[764,1217],{"description":1218,"icon":1164,"title":1219},"Seamless streaming to TVs and monitors","Chromecast / AirPlay Casting",[764,1221],{"description":1222,"icon":1223,"title":1224},"Loops, slow-motion, segment markers","i-lucide-repeat","Playback Controls",[764,1226],{"description":1227,"icon":1228,"title":1229},"Upload and manage assets","i-lucide-folder-open","Media Library",[764,1231],{"description":1232,"icon":1233,"title":1234},"Synchronised playback across devices","i-lucide-monitor-smartphone","Device Sync",[764,1236],{"description":1237,"icon":1238,"title":1239},"Local caching on mobile","i-lucide-wifi-off","Offline Mode (PoC)",[764,1241],{"description":1242,"icon":1243,"title":1244},"Role-based access and user management","i-lucide-users","User Accounts & Permissions",[764,1246],{"description":1247,"icon":1248,"title":1249},"Experimental real-time streaming using WebRTC","i-lucide-zap","Low-Latency Mode",[747,1251],{},[750,1253,861],{"id":860},[755,1255,1257,1260,1265,1268,1272,1277,1281,1286,1290,1294,1299,1304],{"className":1256},[758,865,760,866,867,762],[764,1258],{"description":1259,"icon":768,"title":871},"Mobile & controller",[764,1261],{"description":1262,"icon":1263,"title":1264},"Web platform","i-lucide-globe","Nuxt 3",[764,1266],{"description":1151,"icon":1150,"title":1267},"Django",[764,1269],{"description":1270,"icon":1183,"title":1271},"Scalable backend","Cloud Run",[764,1273],{"description":1274,"icon":1275,"title":1276},"Frontend hosting","i-lucide-flame","Firebase",[764,1278],{"description":1279,"icon":1178,"title":1280},"Transcoding","FFmpeg",[764,1282],{"description":1283,"icon":1284,"title":1285},"Animations","i-lucide-sparkles","Lottie",[764,1287],{"description":1288,"icon":1164,"title":1289},"Cast receiver","Chromecast SDK",[764,1291],{"description":1292,"icon":1169,"title":1293},"Apple devices","AirPlay",[764,1295],{"description":1296,"icon":1297,"title":1298},"Containers","i-lucide-container","Docker",[764,1300],{"description":1301,"icon":1302,"title":1303},"CI/CD","i-lucide-git-branch","GitHub Actions",[764,1305],{"description":908,"icon":910,"title":909},[747,1307],{},[750,1309,1311],{"id":1310},"architecture-layered-rendering-engine","Architecture: Layered Rendering Engine",[743,1313,1314],{},"The core innovation behind Ambistream is its layered rendering approach — video, animations, and UI controls are separate layers composed in real time:",[1316,1317,1321],"pre",{"className":1318,"code":1319,"language":1320,"meta":1051,"style":1051},"language-mermaid shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","graph TB\n    subgraph Controller[\"📱 Mobile Controller\"]\n        A[Flutter App] --> B[Playback Commands]\n    end\n\n    subgraph Backend[\"☁️ Cloud Backend\"]\n        C[Django API] --> D[Media Pipeline]\n        D --> E[HLS / MP4 Transcoding]\n    end\n\n    subgraph Display[\"📺 Display Device\"]\n        F[Video Layer]\n        G[Lottie Animation Layer]\n        H[UI Overlay Layer]\n        F --> I[Composited Output]\n        G --> I\n        H --> I\n    end\n\n    B -->|WebSocket / REST| C\n    B -->|Cast Protocol| Display\n    E -->|Stream| F\n    C -->|Scene Config| G\n    C -->|Controls| H\n","mermaid",[1322,1323,1324,1333,1338,1344,1350,1356,1362,1368,1374,1379,1384,1390,1396,1402,1408,1414,1420,1426,1431,1436,1442,1448,1454,1460],"code",{"__ignoreMap":1051},[1325,1326,1329],"span",{"class":1327,"line":1328},"line",1,[1325,1330,1332],{"class":1331},"sTEyZ","graph TB\n",[1325,1334,1335],{"class":1327,"line":1052},[1325,1336,1337],{"class":1331},"    subgraph Controller[\"📱 Mobile Controller\"]\n",[1325,1339,1341],{"class":1327,"line":1340},3,[1325,1342,1343],{"class":1331},"        A[Flutter App] --> B[Playback Commands]\n",[1325,1345,1347],{"class":1327,"line":1346},4,[1325,1348,1349],{"class":1331},"    end\n",[1325,1351,1353],{"class":1327,"line":1352},5,[1325,1354,1355],{"emptyLinePlaceholder":1069},"\n",[1325,1357,1359],{"class":1327,"line":1358},6,[1325,1360,1361],{"class":1331},"    subgraph Backend[\"☁️ Cloud Backend\"]\n",[1325,1363,1365],{"class":1327,"line":1364},7,[1325,1366,1367],{"class":1331},"        C[Django API] --> D[Media Pipeline]\n",[1325,1369,1371],{"class":1327,"line":1370},8,[1325,1372,1373],{"class":1331},"        D --> E[HLS / MP4 Transcoding]\n",[1325,1375,1377],{"class":1327,"line":1376},9,[1325,1378,1349],{"class":1331},[1325,1380,1382],{"class":1327,"line":1381},10,[1325,1383,1355],{"emptyLinePlaceholder":1069},[1325,1385,1387],{"class":1327,"line":1386},11,[1325,1388,1389],{"class":1331},"    subgraph Display[\"📺 Display Device\"]\n",[1325,1391,1393],{"class":1327,"line":1392},12,[1325,1394,1395],{"class":1331},"        F[Video Layer]\n",[1325,1397,1399],{"class":1327,"line":1398},13,[1325,1400,1401],{"class":1331},"        G[Lottie Animation Layer]\n",[1325,1403,1405],{"class":1327,"line":1404},14,[1325,1406,1407],{"class":1331},"        H[UI Overlay Layer]\n",[1325,1409,1411],{"class":1327,"line":1410},15,[1325,1412,1413],{"class":1331},"        F --> I[Composited Output]\n",[1325,1415,1417],{"class":1327,"line":1416},16,[1325,1418,1419],{"class":1331},"        G --> I\n",[1325,1421,1423],{"class":1327,"line":1422},17,[1325,1424,1425],{"class":1331},"        H --> I\n",[1325,1427,1429],{"class":1327,"line":1428},18,[1325,1430,1349],{"class":1331},[1325,1432,1434],{"class":1327,"line":1433},19,[1325,1435,1355],{"emptyLinePlaceholder":1069},[1325,1437,1439],{"class":1327,"line":1438},20,[1325,1440,1441],{"class":1331},"    B -->|WebSocket / REST| C\n",[1325,1443,1445],{"class":1327,"line":1444},21,[1325,1446,1447],{"class":1331},"    B -->|Cast Protocol| Display\n",[1325,1449,1451],{"class":1327,"line":1450},22,[1325,1452,1453],{"class":1331},"    E -->|Stream| F\n",[1325,1455,1457],{"class":1327,"line":1456},23,[1325,1458,1459],{"class":1331},"    C -->|Scene Config| G\n",[1325,1461,1462],{"class":1327,"line":1070},[1325,1463,1464],{"class":1331},"    C -->|Controls| H\n",[747,1466],{},[750,1468,1470],{"id":1469},"the-story-from-spark-to-platform","The Story: From Spark to Platform",[1472,1473,1475],"h3",{"id":1474},"it-started-with-a-question","It started with a question",[743,1477,1478,1479],{},"In 2023, while working on several MusicTech Lab products, one theme kept coming up:\n",[828,1480,1481],{},"creators and coaches needed better, smarter playback tools.",[1483,1484,1485,1489,1492],"ul",{},[1486,1487,1488],"li",{},"Musicians needed visual cues over their training videos.",[1486,1490,1491],{},"Swimming and sports coaches needed slow-motion loops.",[1486,1493,1494],{},"Stage performers wanted remote-controlled scenes and overlays.",[743,1496,1497],{},"But existing video players couldn’t do any of this. So we built a tiny PoC — Flutter, Chromecast, one big button, one video. It played. It glitched. But it proved the idea possible.",[743,1499,1500],{},[828,1501,1502],{},"The spark was lit.",[747,1504],{},[1472,1506,1508],{"id":1507},"the-journey","The Journey",[1510,1511],"project-timeline",{":items":1512},"[{\"title\":\"R&D — The Deep Dive\",\"description\":\"Explored HLS, DASH, MP4, WebRTC. Tested on old Android TVs and new 4K displays. Discovered Lottie as the key to lightweight, animatable overlays. The layered rendering engine was born: Video → Lottie → UI.\",\"icon\":\"i-lucide-microscope\"},{\"title\":\"MVP — Building the First Version\",\"description\":\"Built a Flutter controller, Nuxt dashboard, Django backend, and custom Chromecast receiver. For the first time: phone controlled TV precisely, videos synced across devices, and overlays played in time with footage.\",\"icon\":\"i-lucide-hammer\"},{\"title\":\"Real Use-Cases Emerge\",\"description\":\"Adopted by coaches, instructors, and creators — music training with tempo cues, swimming coaching with slow-motion replays, live events with remote-controlled scenes, and step-by-step educational overlays.\",\"icon\":\"i-lucide-users\"},{\"title\":\"Scaling Up\",\"description\":\"Multi-device sync, reliable casting for Android/iOS, Cloud Run deployment, automated transcoding pipelines, Scene Builder with timelines, analytics, monitoring, and offline caching prototype.\",\"icon\":\"i-lucide-rocket\"},{\"title\":\"Ambistream 2.0 — The Vision\",\"description\":\"Preparing for broader release as a white-label solution, multi-tenant platform, production-grade streaming engine, and customisable scene editor — a toolkit for creators, athletes, teachers, and performers.\",\"icon\":\"i-lucide-sparkles\"}]",[743,1514,1515],{},"The system started from a spark — now it’s a cornerstone product in the MusicTech Lab ecosystem. And the story continues, frame by frame.",[1517,1518,1519],"tip",{},[743,1520,1521],{},"Ambistream is a MusicTech Lab internal product — built from a spark of an idea into a production-ready streaming engine. It demonstrates how iterative development can turn a simple PoC into a multi-platform system.",[747,1523],{},[750,1525,1527],{"id":1526},"services-deliverables","Services & Deliverables",[755,1529,1531,1535,1540,1545,1547,1550],{"className":1530},[758,759,760,761,762],[764,1532],{"description":1533,"icon":1085,"title":1534},"Backend, frontend, mobile app, and API","Full-Stack Development",[764,1536],{"description":1537,"icon":1538,"title":1539},"From PoC to production-grade platform","i-lucide-flask-conical","R&D & Prototyping",[764,1541],{"description":1542,"icon":1543,"title":1544},"Vision, roadmap, and feature prioritisation","i-lucide-compass","Product Strategy",[764,1546],{"description":1182,"icon":1183,"title":1184},[764,1548],{"description":1177,"icon":1178,"title":1549},"Video Pipeline",[764,1551],{"description":1552,"icon":946,"title":1553},"Controller and dashboard flows","UI/UX",[747,1555],{},[750,1557,972],{"id":971},[974,1559,1560],{},[743,1561,1562],{},[1111,1563,1564],{},"“Ambistream allowed us to build a synchronised, multi-layer playback system we simply couldn’t find on the market. The combination of mobile control, casting, and overlays created entirely new possibilities for training and creative work.”",[743,1566,1567,1570],{},[828,1568,1569],{},"Ambistream Team","\nNew York, USA",[747,1572],{},[750,1574,1576],{"id":1575},"summary-streaming-innovation-creative-control","Summary: Streaming Innovation & Creative Control",[743,1578,1579],{},"Ambistream shows that even highly complex media systems can be developed iteratively:",[755,1581,1584,1589,1594,1598,1602],{"className":1582},[758,865,1583,867,762],"md:grid-cols-5",[764,1585],{"description":1586,"icon":1587,"title":1588},"Spark of an idea","i-lucide-lightbulb","PoC",[764,1590],{"description":1591,"icon":1592,"title":1593},"Deep technical dive","i-lucide-microscope","R&D",[764,1595],{"description":1596,"icon":905,"title":1597},"First working version","MVP",[764,1599],{"description":1600,"icon":956,"title":1601},"Real customers","Production",[764,1603],{"description":1604,"icon":1605,"title":1606},"Broader release","i-lucide-building","White-label",[743,1608,1609],{},"The platform is now used for training, creative performance, live educational formats, and internal production workflows.",[1611,1612,1613],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":1051,"searchDepth":1052,"depth":1052,"links":1615},[1616,1617,1618,1619,1620,1624,1625,1626],{"id":1141,"depth":1052,"text":1142},{"id":1197,"depth":1052,"text":1198},{"id":860,"depth":1052,"text":861},{"id":1310,"depth":1052,"text":1311},{"id":1469,"depth":1052,"text":1470,"children":1621},[1622,1623],{"id":1474,"depth":1340,"text":1475},{"id":1507,"depth":1340,"text":1508},{"id":1526,"depth":1052,"text":1527},{"id":971,"depth":1052,"text":972},{"id":1575,"depth":1052,"text":1576},{"name":1628,"logo":1629,"colorLogo":1069},"Ambistream","/images/logos/ambistream.webp","2025-01-01T00:00:00.000Z","How a late-night experiment grew into a multi-platform streaming engine with overlays, remote control, and Chromecast/AirPlay support.",{"src":1633},"/images/blog/musictechlab_blog_ambistream-streaming-platform.webp",{"enabled":1069,"items":1635},[1636,1638,1640,1642],{"text":1637,"icon":840},"Multi-layer streaming engine combines video, Lottie animations, and UI overlays in real time.",{"text":1639,"icon":956},"Started as a single-button Flutter PoC and grew into a production platform.",{"text":1641,"icon":1164},"Supports Chromecast and AirPlay casting with phone-as-remote-controller design.",{"text":1643,"icon":1243},"Used by coaches, musicians, and performers for training and live event scenarios.",{},"/blog/case-studies/ambistream-building-a-multi-layer-streaming-platform-from-a-spark-of-an-idea",{"title":10,"description":1631},[1062,1089],"B64OkdTDsJdr_qBvySu0HCAHEVSrkHKCtW4dmc28UYI",{"id":1650,"title":58,"authors":1651,"badge":1657,"body":1658,"category":1062,"client":1888,"date":1890,"description":1891,"extension":1068,"faq":736,"featured":69,"featuredOrder":736,"hidden":69,"image":1892,"keyTakeaways":1894,"meta":1902,"navigation":1069,"path":1903,"seo":1904,"status":736,"stem":60,"tags":1905,"teaser":736,"__hash__":1906,"score":1346},"posts/blog/case-study/turn-fans-into-superfans-roadie-co.md",[1652],{"name":1653,"to":1654,"avatar":1655},"Mariusz Smenżyk","https://www.linkedin.com/in/mariusz-smenzyk/",{"src":1656},"/images/people/mariusz-smenzyk2.webp",{"label":5,"color":738},{"type":740,"value":1659,"toc":1877},[1660,1663,1665,1669,1672,1689,1692,1699,1701,1705,1708,1721,1726,1728,1732,1735,1751,1753,1757,1774,1776,1780,1801,1803,1807,1814,1816,1820,1823,1852,1857,1859,1863,1866,1868,1870],[743,1661,1662],{},"Independent artists often face myriad challenges in the vast and ever-evolving music industry landscape. From establishing a solid online presence to effectively managing fanbases, the journey to success can seem daunting. However, with the emergence of innovative platforms like Roadie.co, artists can now access tools and resources to help them confidently navigate this complex terrain.",[747,1664],{},[750,1666,1668],{"id":1667},"navigating-the-digital-stage","Navigating the Digital Stage",[743,1670,1671],{},"One of the most crucial aspects of an artist's career is their online presence. In today's digital age, having a professional website is essential for showcasing music and live shows.",[755,1673,1675,1679,1684],{"className":1674},[758,759,760,761,762],[764,1676],{"description":1677,"icon":1263,"title":1678},"Create attractive, customizable websites that reflect your unique style and sound.","Website Builder",[764,1680],{"description":1681,"icon":1682,"title":1683},"Add and schedule tour dates through an intuitive admin interface.","i-lucide-calendar","Tour Management",[764,1685],{"description":1686,"icon":1687,"title":1688},"Link your own domain for a professional online presence.","i-lucide-link","Custom Domains",[743,1690,1691],{},"Roadie.co simplifies the process of adding and scheduling new tour dates and releases — no more tedious tasks or complicated procedures, allowing artists to focus on what they do best: creating music.",[743,1693,1694],{},[1695,1696],"img",{"alt":1697,"src":1698},"Roadie.co partnership","/images/blog/musictechlab_blog_roadie-partnership.webp",[747,1700],{},[750,1702,1704],{"id":1703},"data-driven-release-management","Data-Driven Release Management",[743,1706,1707],{},"When it comes to releasing new music, strategic planning is critical. Each track, EP, or album release deserves its dedicated page, and that's precisely what Roadie.co provides.",[755,1709,1711,1716],{"className":1710},[758,759,835,761,762],[764,1712],{"description":1713,"icon":1714,"title":1715},"Create personalized pages for every track, EP, or album — easy to share with fans.","i-lucide-disc-3","Release Pages",[764,1717],{"description":1718,"icon":1719,"title":1720},"Gain insights into fanbase behaviour — website visits, social media engagement, and more.","i-lucide-bar-chart-3","Analytics",[1517,1722,1723],{},[743,1724,1725],{},"What sets Roadie.co apart is its commitment to data-driven decision-making. Artists can make informed decisions that drive success and maximize their impact.",[747,1727],{},[750,1729,1731],{"id":1730},"fandom","Fandom",[743,1733,1734],{},"Building a loyal fanbase is essential for long-term success in the music industry. While social media platforms are valuable for reaching fans, they can be fickle and ever-changing.",[755,1736,1738,1743,1747],{"className":1737},[758,759,760,761,762],[764,1739],{"description":1740,"icon":1741,"title":1742},"Build one-on-one connections with fans and convert show attendees into subscribers.","i-lucide-mail","Mailing Lists",[764,1744],{"description":1745,"icon":886,"title":1746},"Craft professional newsletters with easy-to-use templates.","Email Templates",[764,1748],{"description":1749,"icon":807,"title":1750},"Cultivate a dedicated fanbase that stands the test of time.","Superfan Cultivation",[747,1752],{},[750,1754,1756],{"id":1755},"mission-vision-and-values","Mission, Vision and Values",[755,1758,1760,1765,1769],{"className":1759},[758,759,760,761,762],[764,1761],{"description":1762,"icon":1763,"title":1764},"Clear, honest approach to how the platform works and what it costs.","i-lucide-eye","Transparency",[764,1766],{"description":1767,"icon":850,"title":1768},"Artists own their data. Cancel anytime and take your data with you.","Data Ownership",[764,1770],{"description":1771,"icon":1772,"title":1773},"No lock-in. Transfer data and cancel subscriptions at any time.","i-lucide-move","Flexibility",[747,1775],{},[750,1777,1779],{"id":1778},"the-future","The Future",[755,1781,1783,1788,1793,1797],{"className":1782},[758,759,835,761,762],[764,1784],{"description":1785,"icon":1786,"title":1787},"Dedicated pages for press materials and media kits.","i-lucide-newspaper","Press Release Pages",[764,1789],{"description":1790,"icon":1791,"title":1792},"Track and showcase career milestones and achievements.","i-lucide-trophy","Career Highlights",[764,1794],{"description":1795,"icon":1538,"title":1796},"Artists can access new tools and features before anyone else.","Early Access",[764,1798],{"description":1799,"icon":956,"title":1800},"The platform evolves to meet the changing needs of artists.","Constant Evolution",[747,1802],{},[750,1804,1806],{"id":1805},"the-maker","The Maker",[743,1808,1809,1810,1813],{},"Behind Roadie.co is ",[828,1811,1812],{},"Joep",", an artist manager and founder passionate about supporting independent artists. Having witnessed firsthand the struggles faced by emerging talent, Joep set out to create a platform that would level the playing field and give artists the tools they need to succeed.",[747,1815],{},[750,1817,1819],{"id":1818},"the-tech-challenge","The Tech Challenge",[743,1821,1822],{},"MusicTech Lab's cooperation with Roadie started because building a multi-tenant platform is complex. Roadie.co's challenge was to design, set up, and implement an environment and infrastructure for the new version of the platform release. The main thing was to be able to use artists' custom domains and pass all the traffic from the domain to the appropriate tenant/artist.",[755,1824,1826,1830,1835,1840,1844,1848],{"className":1825},[758,759,760,761,762],[764,1827],{"description":1828,"icon":802,"title":1829},"Talked to Roadie.co's developer and gathered the necessary data. Sent a ballpark estimate with a list of tasks.","Discovery",[764,1831],{"description":1832,"icon":1833,"title":1834},"Installed the platform locally to understand backend, API, and frontend workings.","i-lucide-monitor","Platform Analysis",[764,1836],{"description":1837,"icon":1838,"title":1839},"Assessed scalability for immediate needs and future growth.","i-lucide-scale","Scalability Assessment",[764,1841],{"description":1842,"icon":1587,"title":1843},"Proposed the optimal solution by weighing pros and cons, considering limitations versus practicality.","Solution Design",[764,1845],{"description":1846,"icon":1150,"title":1847},"Helped choose the best hosting provider and set up server and domain routing.","Hosting & Routing",[764,1849],{"description":1850,"icon":1302,"title":1851},"Implemented continuous integration and deployment pipelines.","CI/CD Pipelines",[958,1853,1854],{},[743,1855,1856],{},"Through this collaborative effort, MusicTech Lab helped successfully implement Roadie.co's updated platform, ensuring enhanced functionality and scalability to meet the evolving needs of artists and users alike.",[747,1858],{},[750,1860,1862],{"id":1861},"navigating-the-road-to-success","Navigating the Road to Success",[743,1864,1865],{},"Roadie.co is more than just a platform — it's a game-changer for releasing artists and their teams. With its intuitive features, data-driven approach, and unwavering commitment to transparency, Roadie.co empowers artists to reach new heights of success in the music industry.",[747,1867],{},[750,1869,1024],{"id":1023},[755,1871,1873],{"className":1872},[1028,1029,867,762],[1031,1874],{"color":1033,"label":1875,"target":1037,"to":1876,"variant":1036},"Roadie.co","https://roadie.co/",{"title":1051,"searchDepth":1052,"depth":1052,"links":1878},[1879,1880,1881,1882,1883,1884,1885,1886,1887],{"id":1667,"depth":1052,"text":1668},{"id":1703,"depth":1052,"text":1704},{"id":1730,"depth":1052,"text":1731},{"id":1755,"depth":1052,"text":1756},{"id":1778,"depth":1052,"text":1779},{"id":1805,"depth":1052,"text":1806},{"id":1818,"depth":1052,"text":1819},{"id":1861,"depth":1052,"text":1862},{"id":1023,"depth":1052,"text":1024},{"name":1875,"logo":1889},"/images/logos/roadie.svg","2024-03-15T00:00:00.000Z","How Roadie.co helps independent artists build websites, manage tours, release music, and grow their fanbase with data-driven tools and email marketing.",{"src":1893},"/images/blog/musictechlab_blog_turn-fans-into-superfans-roadie-co.webp",{"enabled":1069,"items":1895},[1896,1898,1900],{"text":1897,"icon":1263},"Multi-tenant platform with custom domain routing for independent artist websites.",{"text":1899,"icon":850},"Artists own their data with full portability and no lock-in.",{"text":1901,"icon":845},"Built-in tour management, release pages, mailing lists, and analytics for musicians.",{},"/blog/case-studies/turn-fans-into-superfans-roadie-co",{"title":58,"description":1891},[1062,1089],"2ijydv3IbdmuLJ2Yqvmbx5Ngu03UAHzZ2OLfJJRvSJM",{"id":1908,"title":66,"authors":1909,"badge":1912,"body":1914,"category":1062,"client":736,"date":2410,"description":2411,"extension":1068,"faq":2412,"featured":69,"featuredOrder":736,"hidden":69,"image":2425,"keyTakeaways":2427,"meta":2438,"navigation":1069,"path":2439,"seo":2440,"status":736,"stem":68,"tags":2443,"teaser":736,"__hash__":2450,"score":1340},"posts/blog/case-study/why-merch-is-the-new-royalty-check.md",[1910],{"name":1653,"to":1654,"avatar":1911},{"src":1656},{"label":5,"color":1913},"#f59e0b",{"type":740,"value":1915,"toc":2399},[1916,1925,1929,1932,2010,2017,2020,2025,2029,2036,2039,2048,2066,2072,2078,2082,2085,2092,2109,2116,2120,2123,2126,2129,2155,2158,2164,2168,2171,2174,2195,2198,2203,2207,2214,2221,2227,2231,2234,2311,2315,2318,2321,2323,2333,2337],[743,1917,1918,1919,1924],{},"Selling one $35 band T-shirt generates the same revenue as ",[988,1920,1923],{"href":1921,"rel":1922},"https://royaltyexchange.com/blog/how-music-streaming-platforms-calculate-payouts-per-stream-2025",[992],"8,750 Spotify streams",". That single number explains why the smartest people in the music industry are rethinking where artist revenue actually comes from.",[750,1926,1928],{"id":1927},"the-royalty-math-that-doesnt-work","The royalty math that doesn't work",[743,1930,1931],{},"Let's start with what streaming actually pays. These are real per-stream rates from 2024-2025:",[1933,1934,1935,1951],"table",{},[1936,1937,1938],"thead",{},[1939,1940,1941,1945,1948],"tr",{},[1942,1943,1944],"th",{},"Platform",[1942,1946,1947],{},"Per-Stream Payout",[1942,1949,1950],{},"Per 1,000 Streams",[1952,1953,1954,1966,1977,1988,1999],"tbody",{},[1939,1955,1956,1960,1963],{},[1957,1958,1959],"td",{},"Tidal",[1957,1961,1962],{},"$0.012 - $0.015",[1957,1964,1965],{},"~$12.84",[1939,1967,1968,1971,1974],{},[1957,1969,1970],{},"Apple Music",[1957,1972,1973],{},"$0.007 - $0.01",[1957,1975,1976],{},"~$6.20",[1939,1978,1979,1982,1985],{},[1957,1980,1981],{},"Amazon Music",[1957,1983,1984],{},"$0.004 - $0.008",[1957,1986,1987],{},"~$8.80",[1939,1989,1990,1993,1996],{},[1957,1991,1992],{},"Spotify",[1957,1994,1995],{},"$0.003 - $0.005",[1957,1997,1998],{},"~$3.00",[1939,2000,2001,2004,2007],{},[1957,2002,2003],{},"YouTube Music",[1957,2005,2006],{},"$0.002 - $0.005",[1957,2008,2009],{},"varies",[743,2011,2012,2013,2016],{},"At Spotify's rate, an artist needs roughly ",[828,2014,2015],{},"350,000 streams per month"," just to earn a U.S. minimum wage. That puts streaming income out of reach for the vast majority of working musicians.",[743,2018,2019],{},"Meanwhile, streaming accounts for 69% of total recorded music revenue globally. In 2024, that was $20.4 billion out of $29.6 billion (IFPI). The money is enormous at the platform level, but it gets diluted through labels, distributors, and publishers before it reaches artists.",[958,2021,2022],{},[743,2023,2024],{},"Apple Music's per-stream rate is roughly 2x Spotify's, primarily because every Apple Music listener is a paying subscriber. There is no free tier diluting the pool.",[750,2026,2028],{"id":2027},"merch-the-8x-multiplier","Merch: the 8x multiplier",[743,2030,2031,2032,2035],{},"Here's where the economics flip. According to atVenu, the industry-standard merch analytics platform, the average small to mid-cap artist makes ",[828,2033,2034],{},"8x more per show in gross merchandise sales"," than a year's worth of streaming royalties.",[743,2037,2038],{},"That's not a typo. One show's merch table versus twelve months of streams.",[743,2040,2041,2042,2047],{},"The ",[988,2043,2046],{"href":2044,"rel":2045},"https://www.atvenu.com/post/an-updated-look-at-artist-merch-trends",[992],"numbers behind this"," are straightforward:",[1483,2049,2050,2057,2060,2063],{},[1486,2051,2052,2053,2056],{},"Average merch ",[828,2054,2055],{},"revenue per head"," at live shows is $10.29 in 2025, up 14% from 2024",[1486,2058,2059],{},"Average item prices increased 9% year over year",[1486,2061,2062],{},"A single $35 T-shirt equals ~8,750 Spotify streams in artist revenue",[1486,2064,2065],{},"A $60 hoodie equals ~15,000 streams",[743,2067,2068,2069,1130],{},"And unlike streaming, where revenue depends on algorithmic placement and playlist inclusion, merch revenue is driven by something labels can't easily replicate: ",[828,2070,2071],{},"direct fan connection",[743,2073,2074],{},[1695,2075],{"alt":2076,"src":2077},"Fan browsing merch at a live event","/images/blog/musictechlab_blog_merch-browsing.webp",[750,2079,2081],{"id":2080},"the-fastest-growing-segment-in-recorded-music","The fastest-growing segment in recorded music",[743,2083,2084],{},"This isn't just anecdotal. The industry data backs it up.",[743,2086,2087,2088,2091],{},"IFPI's Global Music Report shows that \"expanded rights\" - which includes merch, licensing, and fan experiences - grew ",[828,2089,2090],{},"21.5% in 2025",". That makes it the fastest-growing segment in the entire recorded music industry, outpacing streaming growth significantly.",[755,2093,2095,2100,2105],{"className":2094},[758,759,760,761,762],[764,2096],{"description":2097,"icon":2098,"title":2099},"Global merchandise market forecast by MIDiA Research, including physical merch, digital merch, and physical music.","i-lucide-shirt","$16.3B by 2030",[764,2101],{"description":2102,"icon":2103,"title":2104},"Expanded rights (merch + licensing + fan experiences) grew 21.5% in 2025 - the fastest-growing segment in recorded music.","i-lucide-trending-up","21.5% Growth",[764,2106],{"description":2107,"icon":1243,"title":2108},"Goldman Sachs estimates an additional $4.3 billion annually from superfan monetization, assuming 20% of paid subscribers spend 2x average.","$4.3B Superfan Opportunity",[743,2110,2111,2112,2115],{},"Goldman Sachs projects global music revenues will ",[828,2113,2114],{},"double to $200 billion by 2035",", with superfan monetization identified as a key growth driver. Their \"Music in the Air\" report estimates the superfan opportunity alone at $4.3 billion annually.",[750,2117,2119],{"id":2118},"fan-designed-merch-the-model-that-changes-everything","Fan-designed merch: the model that changes everything",[743,2121,2122],{},"Traditional merch has a problem: artists (or their labels) design it, manufacture it in bulk, ship it to warehouses, and hope it sells. That means upfront capital, inventory risk, and unsold stock sitting in boxes.",[743,2124,2125],{},"Fan-designed merch flips this model. Fans create designs. Artists approve them. Both parties earn from sales. And nothing gets manufactured until someone actually buys it.",[743,2127,2128],{},"This is the model that a growing number of platforms are building. The economics are compelling:",[1483,2130,2131,2137,2143,2149],{},[1486,2132,2133,2136],{},[828,2134,2135],{},"Zero inventory risk"," - print-on-demand means no unsold stock",[1486,2138,2139,2142],{},[828,2140,2141],{},"Community engagement"," - fans become co-creators, not just consumers",[1486,2144,2145,2148],{},[828,2146,2147],{},"Scalable catalog"," - hundreds of designs without hundreds of SKUs in a warehouse",[1486,2150,2151,2154],{},[828,2152,2153],{},"Global fulfillment"," - POD networks handle printing and shipping worldwide",[743,2156,2157],{},"The global print-on-demand market is now valued at $11-13 billion and growing at 23-26% CAGR. The infrastructure exists. The question is how to connect it to artist storefronts seamlessly.",[743,2159,2160],{},[1695,2161],{"alt":2162,"src":2163},"Direct-to-film printing process for on-demand merch","/images/blog/musictechlab_blog_pod-printing.webp",[750,2165,2167],{"id":2166},"the-tech-stack-that-makes-it-work","The tech stack that makes it work",[743,2169,2170],{},"This is where things get practical. For fan-designed merch to work at scale, you need a pipeline that connects the design platform (where fans create and artists approve) to the storefront (where fans buy) to the fulfillment network (where products get made and shipped).",[743,2172,2173],{},"At MusicTech Lab, we're building exactly this kind of bridge. Our Shopify integration connects product catalogs from merch platforms directly to an artist's Shopify store:",[2175,2176,2177,2183,2189],"ol",{},[1486,2178,2179,2182],{},[828,2180,2181],{},"Product sync"," - approved designs are automatically pushed to Shopify with correct variants (sizes, colors), pricing, and images",[1486,2184,2185,2188],{},[828,2186,2187],{},"Order routing"," - when a fan purchases merch, the order data flows back to the design platform for fulfillment",[1486,2190,2191,2194],{},[828,2192,2193],{},"Inventory-free catalog"," - since everything is print-on-demand, the Shopify store reflects available designs without stock management",[743,2196,2197],{},"The key technical challenge is mapping between two different product models. A design platform thinks in terms of \"approved designs with print areas.\" Shopify thinks in terms of \"products with variants and SKUs.\" The sync layer translates between them, handling variant explosion (one design x multiple sizes x multiple colors = many Shopify variants) and keeping everything in sync as designs are added, updated, or removed.",[1517,2199,2200],{},[743,2201,2202],{},"The same architecture works for any artist-to-storefront integration, not just fan-designed merch. Any catalog that lives outside Shopify - whether it's a label's product database, a print-on-demand API, or a custom merch platform - can use this pattern to keep storefronts automatically in sync.",[750,2204,2206],{"id":2205},"the-risk-fan-fatigue","The risk: fan fatigue",[743,2208,2209,2210,2213],{},"MIDiA Research found that ",[828,2211,2212],{},"39% of fans feel their fandom is being exploited",", and nearly half say merch is becoming unaffordable. As Mark Mulligan from MIDiA puts it: \"You cannot harvest fandom if you are not also nurturing it.\"",[743,2215,2216,2217,2220],{},"The takeaway: merch works best as a ",[828,2218,2219],{},"relationship channel",", not a revenue extraction tool. Fan co-creation helps here - participants spend more willingly than passive buyers.",[2222,2223,2224],"warning",{},[743,2225,2226],{},"Amazon accounts for 39% of physical music merch purchases. Selling only through your own store leaves significant demand on the table. A multi-channel approach (own store + marketplaces) captures more of the market.",[750,2228,2230],{"id":2229},"what-this-means-for-labels-managers-and-artists","What this means for labels, managers, and artists",[743,2232,2233],{},"The shift from streaming royalties to merch as a primary revenue driver isn't a trend. It's a structural change in how the music economy works. Here's what to do about it:",[755,2235,2237,2262,2287],{"className":2236},[758,759,760,761,762],[764,2238,2242],{"description":2239,"icon":2240,"title":2241},"Turn your merch into a revenue engine.","i-lucide-mic","For Artists",[1483,2243,2244,2250,2256],{},[1486,2245,2246,2249],{},[828,2247,2248],{},"Treat merch like your release calendar."," Regular drops, seasonal collections, and limited editions keep fans engaged",[1486,2251,2252,2255],{},[828,2253,2254],{},"Consider fan co-creation."," Fans submit designs, you approve - a creative team with zero payroll",[1486,2257,2258,2261],{},[828,2259,2260],{},"Go multi-channel."," Own Shopify store for margins, marketplace presence for reach",[764,2263,2267],{"description":2264,"icon":2265,"title":2266},"Optimize the merch operation.","i-lucide-briefcase","For Managers & Labels",[1483,2268,2269,2275,2281],{},[1486,2270,2271,2274],{},[828,2272,2273],{},"Track revenue per head."," The $10.29 average RPH in 2025 is a benchmark - if you're below it, there's room to grow",[1486,2276,2277,2280],{},[828,2278,2279],{},"Invest in the tech stack."," Automated catalog sync is infrastructure, not a nice-to-have",[1486,2282,2283,2286],{},[828,2284,2285],{},"Watch the affordability signal."," 39% of fans feel exploited - offer a range from $15 accessories to $60 premium items",[764,2288,2291],{"description":2289,"icon":1085,"title":2290},"Build the connective tissue.","For Music Tech Founders",[1483,2292,2293,2299,2305],{},[1486,2294,2295,2298],{},[828,2296,2297],{},"The integration layer is the opportunity."," Shopify, POD networks, and design tools exist - the glue between them is missing",[1486,2300,2301,2304],{},[828,2302,2303],{},"Think beyond apparel."," Home decor is the fastest-growing POD category in 2026",[1486,2306,2307,2310],{},[828,2308,2309],{},"Build for the long tail."," Millions of mid-tier artists have no merch operation at all",[750,2312,2314],{"id":2313},"the-bottom-line","The bottom line",[743,2316,2317],{},"Streaming built the modern music industry's distribution layer. But it didn't solve the artist revenue problem. Merch - especially tech-enabled, fan-driven, zero-inventory merch - is the strongest candidate to fill that gap.",[743,2319,2320],{},"One T-shirt equals 8,750 streams. One engaged fan community designing merch equals a sustainable revenue engine. The math has never been clearer.",[747,2322],{},[1517,2324,2325],{},[743,2326,2327,2328,1130],{},"At MusicTech Lab, we build the technology that connects music platforms to storefronts. If you're working on artist merch, direct-to-fan commerce, or Shopify integrations for the music industry, ",[988,2329,2332],{"href":2330,"rel":2331},"https://musictechlab.io/contact",[992],"let's talk",[750,2334,2336],{"id":2335},"sources","Sources",[1483,2338,2339,2346,2353,2360,2368,2375,2383,2391],{},[1486,2340,2341,2345],{},[988,2342,2344],{"href":1921,"rel":2343},[992],"How Music Streaming Platforms Calculate Payouts Per Stream (2025)"," - Royalty Exchange",[1486,2347,2348,2352],{},[988,2349,2351],{"href":2044,"rel":2350},[992],"An Updated Look at Artist Merch Trends in 2025"," - atVenu",[1486,2354,2355,2352],{},[988,2356,2359],{"href":2357,"rel":2358},"https://www.atvenu.com/post/how-much-money-artists-make-in-streaming-vs-merchandise-sales",[992],"How Much Money Artists Make in Streaming vs. Merchandise Sales",[1486,2361,2362,2367],{},[988,2363,2366],{"href":2364,"rel":2365},"https://www.midiaresearch.com/blog/global-merchandise-market-to-hit-163-billion-by-2030-but-annual-growth-slows-to-16",[992],"Global Merchandise Market to Hit $16.3 Billion by 2030"," - MIDiA Research",[1486,2369,2370,2367],{},[988,2371,2374],{"href":2372,"rel":2373},"https://www.midiaresearch.com/blog/are-we-reaching-peak-fandom",[992],"Are We Reaching Peak Fandom?",[1486,2376,2377,2382],{},[988,2378,2381],{"href":2379,"rel":2380},"https://www.ifpi.org/ifpi-amidst-highly-competitive-market-global-recorded-music-revenues-grew-4-8-in-2024/",[992],"IFPI Global Music Report: Revenues Grew 4.8% in 2024"," - IFPI",[1486,2384,2385,2390],{},[988,2386,2389],{"href":2387,"rel":2388},"https://www.musicbusinessworldwide.com/global-recorded-music-revenues-hit-31-7bn-in-2025-up-6-4-yoy-users-of-paid-music-subscriptions-reach-837m/",[992],"Global Recorded Music Revenues Hit $31.7B in 2025"," - Music Business Worldwide",[1486,2392,2393,2398],{},[988,2394,2397],{"href":2395,"rel":2396},"https://www.goldmansachs.com/insights/articles/global-music-revenues-are-forecast-to-double-to-200-million-in-2035",[992],"Global Music Revenues Forecast to Double to $200B by 2035"," - Goldman Sachs",{"title":1051,"searchDepth":1052,"depth":1052,"links":2400},[2401,2402,2403,2404,2405,2406,2407,2408,2409],{"id":1927,"depth":1052,"text":1928},{"id":2027,"depth":1052,"text":2028},{"id":2080,"depth":1052,"text":2081},{"id":2118,"depth":1052,"text":2119},{"id":2166,"depth":1052,"text":2167},{"id":2205,"depth":1052,"text":2206},{"id":2229,"depth":1052,"text":2230},{"id":2313,"depth":1052,"text":2314},{"id":2335,"depth":1052,"text":2336},"2026-03-27T00:00:00.000Z","Streaming pays fractions of a cent. Merch pays the bills. Here's how the economics of artist revenue are shifting, and why technology is the key enabler.",[2413,2416,2419,2422],{"question":2414,"answer":2415},"How much does one Spotify stream pay an artist?","In 2024-2025, Spotify pays approximately $0.003 to $0.005 per stream. An artist needs roughly 8,750 streams to match the revenue from selling a single $35 T-shirt.",{"question":2417,"answer":2418},"How big is the global music merch market?","MIDiA Research forecasts the global merchandise market will reach $16.3 billion by 2030. Expanded rights including merch, licensing, and fan experiences grew 21.5% in 2025, making it the fastest-growing segment in recorded music.",{"question":2420,"answer":2421},"What is fan-designed merch?","Fan-designed merch is a model where fans create designs, artists approve them, and both parties earn from sales. It combines community engagement with zero-inventory economics through print-on-demand fulfillment.",{"question":2423,"answer":2424},"How does print-on-demand work for music merch?","Print-on-demand eliminates upfront inventory risk. Products are only manufactured when a customer places an order. The global POD market is valued at $11-13 billion and growing at 23-26% CAGR, making it increasingly viable for artists at any scale.",{"src":2426},"/images/blog/musictechlab_blog_why-merch-is-the-new-royalty-check.webp",{"enabled":1069,"items":2428},[2429,2432,2434,2436],{"text":2430,"icon":2431},"One $35 T-shirt = 8,750 Spotify streams. Merch is structurally more efficient than streaming royalties.","i-lucide-dollar-sign",{"text":2433,"icon":946},"Fan-designed merch eliminates inventory risk and turns fans into co-creators via print-on-demand.",{"text":2435,"icon":1085},"The key tech challenge is the integration layer: design platforms, Shopify, POD fulfillment, with variant explosion across sizes and colors.",{"text":2437,"icon":807},"39% of fans feel their fandom is exploited. Merch works best as a relationship channel, not extraction.",{},"/blog/case-studies/why-merch-is-the-new-royalty-check",{"title":2441,"description":2442},"Why Merch Is the New Royalty Check | MusicTech Lab","One T-shirt equals 8,750 Spotify streams. Learn how merch is becoming the primary revenue engine for artists and what tech makes it possible.",[2444,2445,2446,2447,2448,2449,1089],"merch","royalties","streaming","direct-to-fan","shopify","print-on-demand","wUAIrrrjDGR_U8qj-shJBayE2WRqw3SPWDhCz15eGvE",{"id":2452,"title":26,"authors":2453,"badge":736,"body":2457,"category":1062,"client":5686,"date":5689,"description":5690,"extension":1068,"faq":736,"featured":69,"featuredOrder":736,"hidden":69,"image":5691,"keyTakeaways":5693,"meta":5704,"navigation":1069,"path":5705,"seo":5706,"status":736,"stem":28,"tags":5707,"teaser":736,"__hash__":5709,"score":1340},"posts/blog/case-study/how-we-built-memosonic-accessible-audio-memory-game-flutter.md",[2454],{"name":1653,"to":2455,"avatar":2456},"https://www.linkedin.com/in/msmenzyk",{"src":1656},{"type":740,"value":2458,"toc":5625},[2459,2463,2466,2472,2475,2495,2497,2501,2504,2524,2527,2531,2577,2579,2583,2587,2590,2601,2606,2610,2616,2619,2643,2646,2654,2656,2660,2663,2670,2675,2681,2685,2688,2708,2962,2972,2975,2981,2985,2991,3236,3242,3248,3254,3257,3560,3563,3567,3573,3812,3815,3819,3822,3828,3939,3945,3973,3979,4046,4050,4053,4134,4140,4144,4147,4173,4179,4181,4185,4188,4192,4208,4213,4218,4223,4228,4232,4237,4242,4244,4248,4251,4255,4258,4264,4278,4282,4285,4291,4293,4297,4300,4359,4373,4376,4379,4381,4385,4388,4392,4395,4400,4403,4417,4431,4435,4438,4443,4457,4462,4473,4478,4489,4494,4505,4507,4511,4515,4521,4525,4617,4621,4624,4853,4860,4862,4866,4870,4873,4877,4880,4891,4895,4898,4902,4905,4919,4922,4924,4928,4934,4937,4942,4953,4958,4969,4974,4985,4990,4993,4998,5006,5017,5020,5022,5026,5029,5034,5048,5052,5055,5069,5072,5078,5081,5085,5091,5101,5107,5113,5117,5120,5158,5161,5165,5168,5171,5174,5200,5204,5207,5212,5215,5221,5227,5232,5234,5238,5241,5273,5276,5278,5282,5285,5311,5314,5316,5320,5350,5352,5356,5359,5363,5372,5375,5432,5436,5442,5456,5462,5468,5472,5475,5478,5516,5519,5533,5537,5544,5547,5550,5553,5579,5586,5589,5591,5595,5622],[750,2460,2462],{"id":2461},"it-started-with-a-simple-game","It Started with a Simple Game",[743,2464,2465],{},"Picture this: a rainy Sunday afternoon, kids bouncing off the walls, and a parent desperately trying to find something educational yet fun. We pulled out the classic memory card game - flip two cards, find matching pairs.",[743,2467,2468,2469],{},"The kids loved it. But something clicked in my head: ",[1111,2470,2471],{},"What if instead of matching pictures, we matched sounds?",[743,2473,2474],{},"That question sparked MemoSonic.",[755,2476,2481,2482,2481,2486,2481,2492],{"className":2477},[1028,2478,2479,2480],"flex-row","items-center","justify-center","\n  ",[755,2483],{"className":2484},[2485],"w-1/4",[1695,2487],{"src":2488,"alt":2489,"className":2490},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_0.webp","MemoSonic home screen",[2491],"w-1/2",[755,2493],{"className":2494},[2485],[747,2496],{},[750,2498,2500],{"id":2499},"the-problem-visual-learning-isnt-everything","The Problem: Visual Learning Isn't Everything",[743,2502,2503],{},"Traditional memory games are purely visual. You see an image, remember its position, find its pair. Great for training visual memory, but what about:",[1483,2505,2506,2512,2518],{},[1486,2507,2508,2511],{},[828,2509,2510],{},"Auditory learners"," who process information better through sound?",[1486,2513,2514,2517],{},[828,2515,2516],{},"Young musicians"," trying to recognize chords, scales, or instrument timbres?",[1486,2519,2520,2523],{},[828,2521,2522],{},"Visually impaired children"," who can't participate in traditional memory games at all?",[743,2525,2526],{},"We realized there was a gap. A big one.",[1472,2528,2530],{"id":2529},"what-we-wanted-to-build","What We Wanted to Build:",[1933,2532,2533,2543],{},[1936,2534,2535],{},[1939,2536,2537,2540],{},[1942,2538,2539],{},"Traditional Memory",[1942,2541,2542],{},"MemoSonic",[1952,2544,2545,2553,2561,2569],{},[1939,2546,2547,2550],{},[1957,2548,2549],{},"Visual only",[1957,2551,2552],{},"Sound-first approach",[1939,2554,2555,2558],{},[1957,2556,2557],{},"Static images",[1957,2559,2560],{},"Interactive audio feedback",[1939,2562,2563,2566],{},[1957,2564,2565],{},"Limited accessibility",[1957,2567,2568],{},"Inclusive by design",[1939,2570,2571,2574],{},[1957,2572,2573],{},"One learning style",[1957,2575,2576],{},"Multiple categories for different interests",[747,2578],{},[750,2580,2582],{"id":2581},"building-memosonic-from-idea-to-app","Building MemoSonic: From Idea to App",[1472,2584,2586],{"id":2585},"choosing-the-tech-stack","Choosing the Tech Stack",[743,2588,2589],{},"We needed something that would:",[1483,2591,2592,2595,2598],{},[1486,2593,2594],{},"Work on both iOS and Android",[1486,2596,2597],{},"Handle audio playback smoothly",[1486,2599,2600],{},"Feel responsive and polished",[743,2602,2603,2605],{},[828,2604,871],{}," was the obvious choice. Cross-platform, beautiful animations out of the box, and a fantastic ecosystem for audio libraries.",[1472,2607,2609],{"id":2608},"the-audio-challenge","The Audio Challenge",[743,2611,2612,2613,1130],{},"Here's something most developers don't think about: ",[828,2614,2615],{},"audio is hard",[743,2617,2618],{},"Not the playback itself - that's straightforward. The hard part is:",[2175,2620,2621,2631,2637],{},[1486,2622,2623,2626,2627,2630],{},[828,2624,2625],{},"Timing"," - When a player taps a card, the sound needs to play ",[1111,2628,2629],{},"instantly",". Even 100ms delay feels wrong.",[1486,2632,2633,2636],{},[828,2634,2635],{},"Overlapping sounds"," - What happens when someone taps two cards quickly? Do sounds cut off? Layer?",[1486,2638,2639,2642],{},[828,2640,2641],{},"Memory management"," - 100+ audio files across categories. Load them all? Stream them? Preload the current level?",[743,2644,2645],{},"We went through several iterations:",[1316,2647,2652],{"className":2648,"code":2650,"language":2651},[2649],"language-text","Version 1: Load all audio upfront\n→ Problem: 3-second app startup, memory issues\n\nVersion 2: Stream audio on demand\n→ Problem: Noticeable delay on first play\n\nVersion 3 (Final): Preload current category, lazy-load others\n→ Sweet spot of performance and responsiveness\n","text",[1322,2653,2650],{"__ignoreMap":1051},[747,2655],{},[750,2657,2659],{"id":2658},"the-content-pipeline-generating-300-audio-assets","The Content Pipeline: Generating 300+ Audio Assets",[743,2661,2662],{},"Here's where it gets nerdy (in the best way).",[743,2664,2665,2666,2669],{},"When we started MemoSonic, we had a problem: we needed ",[828,2667,2668],{},"hundreds of audio files",". 168 chord sounds. 14 scale recordings. 8 rhythm patterns. Individual notes. Where do you even get that?",[743,2671,2672],{},[828,2673,2674],{},"Answer: You generate them programmatically.",[743,2676,2677],{},[1695,2678],{"alt":2679,"src":2680},"Terminal output","/images/blog/musictechlab_blog_how-we-built-memosonic_inline_2.png",[1472,2682,2684],{"id":2683},"synthesizing-piano-chords-with-fluidsynth","Synthesizing Piano Chords with FluidSynth",[743,2686,2687],{},"Instead of recording a pianist playing every chord (expensive, time-consuming), we wrote Python scripts that:",[2175,2689,2690,2696,2702],{},[1486,2691,2692,2695],{},[828,2693,2694],{},"Generate MIDI files"," with the exact notes for each chord",[1486,2697,2698,2701],{},[828,2699,2700],{},"Render them through FluidSynth"," using a high-quality Salamander Grand Piano soundfont",[1486,2703,2704,2707],{},[828,2705,2706],{},"Convert to MP3"," via FFmpeg",[1316,2709,2713],{"className":2710,"code":2711,"language":2712,"meta":1051,"style":1051},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Chord intervals (semitones from root)\nCHORD_TYPES = {\n    \"maj\": [0, 4, 7],           # Major: root, major 3rd, perfect 5th\n    \"min\": [0, 3, 7],           # Minor: root, minor 3rd, perfect 5th\n    \"7\": [0, 4, 7, 10],         # Dominant 7th\n    \"m7\": [0, 3, 7, 10],        # Minor 7th\n    \"maj7\": [0, 4, 7, 11],      # Major 7th\n    \"aug\": [0, 4, 8],           # Augmented\n    \"dim\": [0, 3, 6],           # Diminished\n}\n","python",[1322,2714,2715,2721,2733,2772,2801,2834,2866,2899,2928,2957],{"__ignoreMap":1051},[1325,2716,2717],{"class":1327,"line":1328},[1325,2718,2720],{"class":2719},"sHwdD","# Chord intervals (semitones from root)\n",[1325,2722,2723,2726,2730],{"class":1327,"line":1052},[1325,2724,2725],{"class":1331},"CHORD_TYPES ",[1325,2727,2729],{"class":2728},"sMK4o","=",[1325,2731,2732],{"class":2728}," {\n",[1325,2734,2735,2738,2742,2745,2748,2751,2755,2758,2761,2763,2766,2769],{"class":1327,"line":1340},[1325,2736,2737],{"class":2728},"    \"",[1325,2739,2741],{"class":2740},"sfazB","maj",[1325,2743,2744],{"class":2728},"\"",[1325,2746,2747],{"class":2728},":",[1325,2749,2750],{"class":2728}," [",[1325,2752,2754],{"class":2753},"sbssI","0",[1325,2756,2757],{"class":2728},",",[1325,2759,2760],{"class":2753}," 4",[1325,2762,2757],{"class":2728},[1325,2764,2765],{"class":2753}," 7",[1325,2767,2768],{"class":2728},"],",[1325,2770,2771],{"class":2719},"           # Major: root, major 3rd, perfect 5th\n",[1325,2773,2774,2776,2779,2781,2783,2785,2787,2789,2792,2794,2796,2798],{"class":1327,"line":1346},[1325,2775,2737],{"class":2728},[1325,2777,2778],{"class":2740},"min",[1325,2780,2744],{"class":2728},[1325,2782,2747],{"class":2728},[1325,2784,2750],{"class":2728},[1325,2786,2754],{"class":2753},[1325,2788,2757],{"class":2728},[1325,2790,2791],{"class":2753}," 3",[1325,2793,2757],{"class":2728},[1325,2795,2765],{"class":2753},[1325,2797,2768],{"class":2728},[1325,2799,2800],{"class":2719},"           # Minor: root, minor 3rd, perfect 5th\n",[1325,2802,2803,2805,2808,2810,2812,2814,2816,2818,2820,2822,2824,2826,2829,2831],{"class":1327,"line":1352},[1325,2804,2737],{"class":2728},[1325,2806,2807],{"class":2740},"7",[1325,2809,2744],{"class":2728},[1325,2811,2747],{"class":2728},[1325,2813,2750],{"class":2728},[1325,2815,2754],{"class":2753},[1325,2817,2757],{"class":2728},[1325,2819,2760],{"class":2753},[1325,2821,2757],{"class":2728},[1325,2823,2765],{"class":2753},[1325,2825,2757],{"class":2728},[1325,2827,2828],{"class":2753}," 10",[1325,2830,2768],{"class":2728},[1325,2832,2833],{"class":2719},"         # Dominant 7th\n",[1325,2835,2836,2838,2841,2843,2845,2847,2849,2851,2853,2855,2857,2859,2861,2863],{"class":1327,"line":1358},[1325,2837,2737],{"class":2728},[1325,2839,2840],{"class":2740},"m7",[1325,2842,2744],{"class":2728},[1325,2844,2747],{"class":2728},[1325,2846,2750],{"class":2728},[1325,2848,2754],{"class":2753},[1325,2850,2757],{"class":2728},[1325,2852,2791],{"class":2753},[1325,2854,2757],{"class":2728},[1325,2856,2765],{"class":2753},[1325,2858,2757],{"class":2728},[1325,2860,2828],{"class":2753},[1325,2862,2768],{"class":2728},[1325,2864,2865],{"class":2719},"        # Minor 7th\n",[1325,2867,2868,2870,2873,2875,2877,2879,2881,2883,2885,2887,2889,2891,2894,2896],{"class":1327,"line":1364},[1325,2869,2737],{"class":2728},[1325,2871,2872],{"class":2740},"maj7",[1325,2874,2744],{"class":2728},[1325,2876,2747],{"class":2728},[1325,2878,2750],{"class":2728},[1325,2880,2754],{"class":2753},[1325,2882,2757],{"class":2728},[1325,2884,2760],{"class":2753},[1325,2886,2757],{"class":2728},[1325,2888,2765],{"class":2753},[1325,2890,2757],{"class":2728},[1325,2892,2893],{"class":2753}," 11",[1325,2895,2768],{"class":2728},[1325,2897,2898],{"class":2719},"      # Major 7th\n",[1325,2900,2901,2903,2906,2908,2910,2912,2914,2916,2918,2920,2923,2925],{"class":1327,"line":1370},[1325,2902,2737],{"class":2728},[1325,2904,2905],{"class":2740},"aug",[1325,2907,2744],{"class":2728},[1325,2909,2747],{"class":2728},[1325,2911,2750],{"class":2728},[1325,2913,2754],{"class":2753},[1325,2915,2757],{"class":2728},[1325,2917,2760],{"class":2753},[1325,2919,2757],{"class":2728},[1325,2921,2922],{"class":2753}," 8",[1325,2924,2768],{"class":2728},[1325,2926,2927],{"class":2719},"           # Augmented\n",[1325,2929,2930,2932,2935,2937,2939,2941,2943,2945,2947,2949,2952,2954],{"class":1327,"line":1376},[1325,2931,2737],{"class":2728},[1325,2933,2934],{"class":2740},"dim",[1325,2936,2744],{"class":2728},[1325,2938,2747],{"class":2728},[1325,2940,2750],{"class":2728},[1325,2942,2754],{"class":2753},[1325,2944,2757],{"class":2728},[1325,2946,2791],{"class":2753},[1325,2948,2757],{"class":2728},[1325,2950,2951],{"class":2753}," 6",[1325,2953,2768],{"class":2728},[1325,2955,2956],{"class":2719},"           # Diminished\n",[1325,2958,2959],{"class":1327,"line":1381},[1325,2960,2961],{"class":2728},"}\n",[743,2963,2964,2965,2968,2969,1130],{},"12 root notes × 7 chord types = ",[828,2966,2967],{},"84 chords",". Add enharmonic equivalents (C# = Db, etc.) and we hit ",[828,2970,2971],{},"168 unique chord files",[743,2973,2974],{},"The pipeline:",[1316,2976,2979],{"className":2977,"code":2978,"language":2651},[2649],"MIDI generation (midiutil)\n    ↓\nFluidSynth + Salamander Piano SF2\n    ↓\nWAV file\n    ↓\nFFmpeg MP3 encoding\n    ↓\nFinal audio asset\n",[1322,2980,2978],{"__ignoreMap":1051},[1472,2982,2984],{"id":2983},"synthesizing-drum-patterns-from-scratch","Synthesizing Drum Patterns from Scratch",[743,2986,2987,2988,1130],{},"The rhythm category was even more interesting. We didn't use samples at all - we ",[828,2989,2990],{},"synthesized every drum sound mathematically",[1316,2992,2994],{"className":2710,"code":2993,"language":2712,"meta":1051,"style":1051},"def generate_kick(duration_ms=150):\n    \"\"\"Generate a punchy kick drum sound\"\"\"\n    for i in range(num_samples):\n        t = i / SAMPLE_RATE\n        # Pitch envelope: starts high, drops quickly\n        freq = freq_end + (freq_start - freq_end) * math.exp(-decay_rate * t)\n\n        # Main tone with pitch drop\n        tone = math.sin(2 * math.pi * freq * t)\n\n        # Add click transient at the start\n        if t \u003C 0.005:\n            click = (1 - t / 0.005) * 0.5\n        ...\n",[1322,2995,2996,3021,3033,3054,3069,3074,3128,3132,3137,3177,3181,3186,3203,3231],{"__ignoreMap":1051},[1325,2997,2998,3002,3006,3009,3013,3015,3018],{"class":1327,"line":1328},[1325,2999,3001],{"class":3000},"spNyl","def",[1325,3003,3005],{"class":3004},"s2Zo4"," generate_kick",[1325,3007,3008],{"class":2728},"(",[1325,3010,3012],{"class":3011},"sHdIc","duration_ms",[1325,3014,2729],{"class":2728},[1325,3016,3017],{"class":2753},"150",[1325,3019,3020],{"class":2728},"):\n",[1325,3022,3023,3027,3030],{"class":1327,"line":1052},[1325,3024,3026],{"class":3025},"s7zQu","    \"\"\"",[1325,3028,3029],{"class":2719},"Generate a punchy kick drum sound",[1325,3031,3032],{"class":3025},"\"\"\"\n",[1325,3034,3035,3038,3041,3044,3047,3049,3052],{"class":1327,"line":1340},[1325,3036,3037],{"class":3025},"    for",[1325,3039,3040],{"class":1331}," i ",[1325,3042,3043],{"class":3025},"in",[1325,3045,3046],{"class":3004}," range",[1325,3048,3008],{"class":2728},[1325,3050,3051],{"class":3004},"num_samples",[1325,3053,3020],{"class":2728},[1325,3055,3056,3059,3061,3063,3066],{"class":1327,"line":1346},[1325,3057,3058],{"class":1331},"        t ",[1325,3060,2729],{"class":2728},[1325,3062,3040],{"class":1331},[1325,3064,3065],{"class":2728},"/",[1325,3067,3068],{"class":1331}," SAMPLE_RATE\n",[1325,3070,3071],{"class":1327,"line":1352},[1325,3072,3073],{"class":2719},"        # Pitch envelope: starts high, drops quickly\n",[1325,3075,3076,3079,3081,3084,3087,3090,3093,3096,3099,3102,3105,3108,3110,3113,3116,3119,3122,3125],{"class":1327,"line":1358},[1325,3077,3078],{"class":1331},"        freq ",[1325,3080,2729],{"class":2728},[1325,3082,3083],{"class":1331}," freq_end ",[1325,3085,3086],{"class":2728},"+",[1325,3088,3089],{"class":2728}," (",[1325,3091,3092],{"class":1331},"freq_start ",[1325,3094,3095],{"class":2728},"-",[1325,3097,3098],{"class":1331}," freq_end",[1325,3100,3101],{"class":2728},")",[1325,3103,3104],{"class":2728}," *",[1325,3106,3107],{"class":1331}," math",[1325,3109,1130],{"class":2728},[1325,3111,3112],{"class":3004},"exp",[1325,3114,3115],{"class":2728},"(-",[1325,3117,3118],{"class":3004},"decay_rate ",[1325,3120,3121],{"class":2728},"*",[1325,3123,3124],{"class":3004}," t",[1325,3126,3127],{"class":2728},")\n",[1325,3129,3130],{"class":1327,"line":1364},[1325,3131,1355],{"emptyLinePlaceholder":1069},[1325,3133,3134],{"class":1327,"line":1370},[1325,3135,3136],{"class":2719},"        # Main tone with pitch drop\n",[1325,3138,3139,3142,3144,3146,3148,3151,3153,3156,3158,3160,3162,3166,3168,3171,3173,3175],{"class":1327,"line":1376},[1325,3140,3141],{"class":1331},"        tone ",[1325,3143,2729],{"class":2728},[1325,3145,3107],{"class":1331},[1325,3147,1130],{"class":2728},[1325,3149,3150],{"class":3004},"sin",[1325,3152,3008],{"class":2728},[1325,3154,3155],{"class":2753},"2",[1325,3157,3104],{"class":2728},[1325,3159,3107],{"class":3004},[1325,3161,1130],{"class":2728},[1325,3163,3165],{"class":3164},"swJcz","pi",[1325,3167,3104],{"class":2728},[1325,3169,3170],{"class":3004}," freq ",[1325,3172,3121],{"class":2728},[1325,3174,3124],{"class":3004},[1325,3176,3127],{"class":2728},[1325,3178,3179],{"class":1327,"line":1381},[1325,3180,1355],{"emptyLinePlaceholder":1069},[1325,3182,3183],{"class":1327,"line":1386},[1325,3184,3185],{"class":2719},"        # Add click transient at the start\n",[1325,3187,3188,3191,3194,3197,3200],{"class":1327,"line":1392},[1325,3189,3190],{"class":3025},"        if",[1325,3192,3193],{"class":1331}," t ",[1325,3195,3196],{"class":2728},"\u003C",[1325,3198,3199],{"class":2753}," 0.005",[1325,3201,3202],{"class":2728},":\n",[1325,3204,3205,3208,3210,3212,3215,3218,3220,3222,3224,3226,3228],{"class":1327,"line":1398},[1325,3206,3207],{"class":1331},"            click ",[1325,3209,2729],{"class":2728},[1325,3211,3089],{"class":2728},[1325,3213,3214],{"class":2753},"1",[1325,3216,3217],{"class":2728}," -",[1325,3219,3193],{"class":1331},[1325,3221,3065],{"class":2728},[1325,3223,3199],{"class":2753},[1325,3225,3101],{"class":2728},[1325,3227,3104],{"class":2728},[1325,3229,3230],{"class":2753}," 0.5\n",[1325,3232,3233],{"class":1327,"line":1404},[1325,3234,3235],{"class":1331},"        ...\n",[743,3237,3238,3241],{},[828,3239,3240],{},"Kick drum"," - A sine wave that rapidly drops in pitch (150Hz → 50Hz) with a click transient.",[743,3243,3244,3247],{},[828,3245,3246],{},"Snare drum"," - Shell resonance (170Hz with harmonics) + attack transient (450Hz) + filtered noise for the snare wires. Plus a touch of room reverb.",[743,3249,3250,3253],{},[828,3251,3252],{},"Hi-hat"," - White noise mixed with metallic high-frequency tones (6kHz, 8kHz, 10kHz), shaped with ADSR envelopes.",[743,3255,3256],{},"Then we programmed the actual rhythm patterns:",[1316,3258,3260],{"className":2710,"code":3259,"language":2712,"meta":1051,"style":1051},"RHYTHMS = [\n    (\"4_4\", \"4/4 Time\", \"4/4\", 100, [\n        (0, \"kick\", 0),      # Beat 1\n        (1, \"snare\", -2),    # Beat 2\n        (2, \"kick\", -2),     # Beat 3\n        (3, \"snare\", -2),    # Beat 4\n        # Off-beat hi-hats\n        (0.5, \"hihat\", -6),\n        (1.5, \"hihat\", -6),\n        ...\n    ]),\n    (\"swing\", \"Swing\", \"4/4\", 120, [\n        # Triplet-based timing for swing feel\n        (0.66, \"hihat\", -6),  # Swung eighth\n        ...\n    ]),\n]\n",[1322,3261,3262,3272,3312,3339,3365,3390,3416,3421,3447,3470,3474,3479,3516,3521,3547,3551,3555],{"__ignoreMap":1051},[1325,3263,3264,3267,3269],{"class":1327,"line":1328},[1325,3265,3266],{"class":1331},"RHYTHMS ",[1325,3268,2729],{"class":2728},[1325,3270,3271],{"class":2728}," [\n",[1325,3273,3274,3277,3279,3282,3284,3286,3289,3292,3294,3296,3298,3301,3303,3305,3308,3310],{"class":1327,"line":1052},[1325,3275,3276],{"class":2728},"    (",[1325,3278,2744],{"class":2728},[1325,3280,3281],{"class":2740},"4_4",[1325,3283,2744],{"class":2728},[1325,3285,2757],{"class":2728},[1325,3287,3288],{"class":2728}," \"",[1325,3290,3291],{"class":2740},"4/4 Time",[1325,3293,2744],{"class":2728},[1325,3295,2757],{"class":2728},[1325,3297,3288],{"class":2728},[1325,3299,3300],{"class":2740},"4/4",[1325,3302,2744],{"class":2728},[1325,3304,2757],{"class":2728},[1325,3306,3307],{"class":2753}," 100",[1325,3309,2757],{"class":2728},[1325,3311,3271],{"class":2728},[1325,3313,3314,3317,3319,3321,3323,3326,3328,3330,3333,3336],{"class":1327,"line":1340},[1325,3315,3316],{"class":2728},"        (",[1325,3318,2754],{"class":2753},[1325,3320,2757],{"class":2728},[1325,3322,3288],{"class":2728},[1325,3324,3325],{"class":2740},"kick",[1325,3327,2744],{"class":2728},[1325,3329,2757],{"class":2728},[1325,3331,3332],{"class":2753}," 0",[1325,3334,3335],{"class":2728},"),",[1325,3337,3338],{"class":2719},"      # Beat 1\n",[1325,3340,3341,3343,3345,3347,3349,3352,3354,3356,3358,3360,3362],{"class":1327,"line":1346},[1325,3342,3316],{"class":2728},[1325,3344,3214],{"class":2753},[1325,3346,2757],{"class":2728},[1325,3348,3288],{"class":2728},[1325,3350,3351],{"class":2740},"snare",[1325,3353,2744],{"class":2728},[1325,3355,2757],{"class":2728},[1325,3357,3217],{"class":2728},[1325,3359,3155],{"class":2753},[1325,3361,3335],{"class":2728},[1325,3363,3364],{"class":2719},"    # Beat 2\n",[1325,3366,3367,3369,3371,3373,3375,3377,3379,3381,3383,3385,3387],{"class":1327,"line":1352},[1325,3368,3316],{"class":2728},[1325,3370,3155],{"class":2753},[1325,3372,2757],{"class":2728},[1325,3374,3288],{"class":2728},[1325,3376,3325],{"class":2740},[1325,3378,2744],{"class":2728},[1325,3380,2757],{"class":2728},[1325,3382,3217],{"class":2728},[1325,3384,3155],{"class":2753},[1325,3386,3335],{"class":2728},[1325,3388,3389],{"class":2719},"     # Beat 3\n",[1325,3391,3392,3394,3397,3399,3401,3403,3405,3407,3409,3411,3413],{"class":1327,"line":1358},[1325,3393,3316],{"class":2728},[1325,3395,3396],{"class":2753},"3",[1325,3398,2757],{"class":2728},[1325,3400,3288],{"class":2728},[1325,3402,3351],{"class":2740},[1325,3404,2744],{"class":2728},[1325,3406,2757],{"class":2728},[1325,3408,3217],{"class":2728},[1325,3410,3155],{"class":2753},[1325,3412,3335],{"class":2728},[1325,3414,3415],{"class":2719},"    # Beat 4\n",[1325,3417,3418],{"class":1327,"line":1364},[1325,3419,3420],{"class":2719},"        # Off-beat hi-hats\n",[1325,3422,3423,3425,3428,3430,3432,3435,3437,3439,3441,3444],{"class":1327,"line":1370},[1325,3424,3316],{"class":2728},[1325,3426,3427],{"class":2753},"0.5",[1325,3429,2757],{"class":2728},[1325,3431,3288],{"class":2728},[1325,3433,3434],{"class":2740},"hihat",[1325,3436,2744],{"class":2728},[1325,3438,2757],{"class":2728},[1325,3440,3217],{"class":2728},[1325,3442,3443],{"class":2753},"6",[1325,3445,3446],{"class":2728},"),\n",[1325,3448,3449,3451,3454,3456,3458,3460,3462,3464,3466,3468],{"class":1327,"line":1376},[1325,3450,3316],{"class":2728},[1325,3452,3453],{"class":2753},"1.5",[1325,3455,2757],{"class":2728},[1325,3457,3288],{"class":2728},[1325,3459,3434],{"class":2740},[1325,3461,2744],{"class":2728},[1325,3463,2757],{"class":2728},[1325,3465,3217],{"class":2728},[1325,3467,3443],{"class":2753},[1325,3469,3446],{"class":2728},[1325,3471,3472],{"class":1327,"line":1381},[1325,3473,3235],{"class":1331},[1325,3475,3476],{"class":1327,"line":1386},[1325,3477,3478],{"class":2728},"    ]),\n",[1325,3480,3481,3483,3485,3488,3490,3492,3494,3497,3499,3501,3503,3505,3507,3509,3512,3514],{"class":1327,"line":1392},[1325,3482,3276],{"class":2728},[1325,3484,2744],{"class":2728},[1325,3486,3487],{"class":2740},"swing",[1325,3489,2744],{"class":2728},[1325,3491,2757],{"class":2728},[1325,3493,3288],{"class":2728},[1325,3495,3496],{"class":2740},"Swing",[1325,3498,2744],{"class":2728},[1325,3500,2757],{"class":2728},[1325,3502,3288],{"class":2728},[1325,3504,3300],{"class":2740},[1325,3506,2744],{"class":2728},[1325,3508,2757],{"class":2728},[1325,3510,3511],{"class":2753}," 120",[1325,3513,2757],{"class":2728},[1325,3515,3271],{"class":2728},[1325,3517,3518],{"class":1327,"line":1398},[1325,3519,3520],{"class":2719},"        # Triplet-based timing for swing feel\n",[1325,3522,3523,3525,3528,3530,3532,3534,3536,3538,3540,3542,3544],{"class":1327,"line":1404},[1325,3524,3316],{"class":2728},[1325,3526,3527],{"class":2753},"0.66",[1325,3529,2757],{"class":2728},[1325,3531,3288],{"class":2728},[1325,3533,3434],{"class":2740},[1325,3535,2744],{"class":2728},[1325,3537,2757],{"class":2728},[1325,3539,3217],{"class":2728},[1325,3541,3443],{"class":2753},[1325,3543,3335],{"class":2728},[1325,3545,3546],{"class":2719},"  # Swung eighth\n",[1325,3548,3549],{"class":1327,"line":1410},[1325,3550,3235],{"class":1331},[1325,3552,3553],{"class":1327,"line":1416},[1325,3554,3478],{"class":2728},[1325,3556,3557],{"class":1327,"line":1422},[1325,3558,3559],{"class":2728},"]\n",[743,3561,3562],{},"8 rhythm patterns, each with its own BPM, time signature, and accent patterns.",[1472,3564,3566],{"id":3565},"pure-tones-for-note-training","Pure Tones for Note Training",[743,3568,3569,3570,2747],{},"For the Notes category, we used ",[828,3571,3572],{},"pydub's sine wave generator",[1316,3574,3576],{"className":2710,"code":3575,"language":2712,"meta":1051,"style":1051},"NOTES = [\n    (\"c\", \"C\", 261.63),  # C4 (Middle C)\n    (\"d\", \"D\", 293.66),  # D4\n    (\"e\", \"E\", 329.63),  # E4\n    ...\n    (\"c_octave\", \"C (Octave)\", 523.25),  # C5\n]\n\ndef generate_note_audio(frequency, duration_ms):\n    tone = Sine(frequency).to_audio_segment(duration=duration_ms)\n    tone = tone.fade_in(50).fade_out(200)  # Avoid clicks\n    return tone\n",[1322,3577,3578,3587,3617,3647,3677,3682,3712,3716,3720,3739,3770,3804],{"__ignoreMap":1051},[1325,3579,3580,3583,3585],{"class":1327,"line":1328},[1325,3581,3582],{"class":1331},"NOTES ",[1325,3584,2729],{"class":2728},[1325,3586,3271],{"class":2728},[1325,3588,3589,3591,3593,3596,3598,3600,3602,3605,3607,3609,3612,3614],{"class":1327,"line":1052},[1325,3590,3276],{"class":2728},[1325,3592,2744],{"class":2728},[1325,3594,3595],{"class":2740},"c",[1325,3597,2744],{"class":2728},[1325,3599,2757],{"class":2728},[1325,3601,3288],{"class":2728},[1325,3603,3604],{"class":2740},"C",[1325,3606,2744],{"class":2728},[1325,3608,2757],{"class":2728},[1325,3610,3611],{"class":2753}," 261.63",[1325,3613,3335],{"class":2728},[1325,3615,3616],{"class":2719},"  # C4 (Middle C)\n",[1325,3618,3619,3621,3623,3626,3628,3630,3632,3635,3637,3639,3642,3644],{"class":1327,"line":1340},[1325,3620,3276],{"class":2728},[1325,3622,2744],{"class":2728},[1325,3624,3625],{"class":2740},"d",[1325,3627,2744],{"class":2728},[1325,3629,2757],{"class":2728},[1325,3631,3288],{"class":2728},[1325,3633,3634],{"class":2740},"D",[1325,3636,2744],{"class":2728},[1325,3638,2757],{"class":2728},[1325,3640,3641],{"class":2753}," 293.66",[1325,3643,3335],{"class":2728},[1325,3645,3646],{"class":2719},"  # D4\n",[1325,3648,3649,3651,3653,3656,3658,3660,3662,3665,3667,3669,3672,3674],{"class":1327,"line":1346},[1325,3650,3276],{"class":2728},[1325,3652,2744],{"class":2728},[1325,3654,3655],{"class":2740},"e",[1325,3657,2744],{"class":2728},[1325,3659,2757],{"class":2728},[1325,3661,3288],{"class":2728},[1325,3663,3664],{"class":2740},"E",[1325,3666,2744],{"class":2728},[1325,3668,2757],{"class":2728},[1325,3670,3671],{"class":2753}," 329.63",[1325,3673,3335],{"class":2728},[1325,3675,3676],{"class":2719},"  # E4\n",[1325,3678,3679],{"class":1327,"line":1352},[1325,3680,3681],{"class":1331},"    ...\n",[1325,3683,3684,3686,3688,3691,3693,3695,3697,3700,3702,3704,3707,3709],{"class":1327,"line":1358},[1325,3685,3276],{"class":2728},[1325,3687,2744],{"class":2728},[1325,3689,3690],{"class":2740},"c_octave",[1325,3692,2744],{"class":2728},[1325,3694,2757],{"class":2728},[1325,3696,3288],{"class":2728},[1325,3698,3699],{"class":2740},"C (Octave)",[1325,3701,2744],{"class":2728},[1325,3703,2757],{"class":2728},[1325,3705,3706],{"class":2753}," 523.25",[1325,3708,3335],{"class":2728},[1325,3710,3711],{"class":2719},"  # C5\n",[1325,3713,3714],{"class":1327,"line":1364},[1325,3715,3559],{"class":2728},[1325,3717,3718],{"class":1327,"line":1370},[1325,3719,1355],{"emptyLinePlaceholder":1069},[1325,3721,3722,3724,3727,3729,3732,3734,3737],{"class":1327,"line":1376},[1325,3723,3001],{"class":3000},[1325,3725,3726],{"class":3004}," generate_note_audio",[1325,3728,3008],{"class":2728},[1325,3730,3731],{"class":3011},"frequency",[1325,3733,2757],{"class":2728},[1325,3735,3736],{"class":3011}," duration_ms",[1325,3738,3020],{"class":2728},[1325,3740,3741,3744,3746,3749,3751,3753,3756,3759,3761,3764,3766,3768],{"class":1327,"line":1381},[1325,3742,3743],{"class":1331},"    tone ",[1325,3745,2729],{"class":2728},[1325,3747,3748],{"class":3004}," Sine",[1325,3750,3008],{"class":2728},[1325,3752,3731],{"class":3004},[1325,3754,3755],{"class":2728},").",[1325,3757,3758],{"class":3004},"to_audio_segment",[1325,3760,3008],{"class":2728},[1325,3762,3763],{"class":3011},"duration",[1325,3765,2729],{"class":2728},[1325,3767,3012],{"class":3004},[1325,3769,3127],{"class":2728},[1325,3771,3772,3774,3776,3779,3781,3784,3786,3789,3791,3794,3796,3799,3801],{"class":1327,"line":1386},[1325,3773,3743],{"class":1331},[1325,3775,2729],{"class":2728},[1325,3777,3778],{"class":1331}," tone",[1325,3780,1130],{"class":2728},[1325,3782,3783],{"class":3004},"fade_in",[1325,3785,3008],{"class":2728},[1325,3787,3788],{"class":2753},"50",[1325,3790,3755],{"class":2728},[1325,3792,3793],{"class":3004},"fade_out",[1325,3795,3008],{"class":2728},[1325,3797,3798],{"class":2753},"200",[1325,3800,3101],{"class":2728},[1325,3802,3803],{"class":2719},"  # Avoid clicks\n",[1325,3805,3806,3809],{"class":1327,"line":1392},[1325,3807,3808],{"class":3025},"    return",[1325,3810,3811],{"class":1331}," tone\n",[743,3813,3814],{},"Simple, clean, and perfect for ear training.",[1472,3816,3818],{"id":3817},"post-processing-cutting-trimming-normalizing","Post-Processing: Cutting, Trimming, Normalizing",[743,3820,3821],{},"Raw generated audio isn't always game-ready. We wrote additional scripts:",[743,3823,3824,3827],{},[828,3825,3826],{},"Cut scales to ascending only"," - Original scales went up AND down. Too long. We cut them to just the ascending portion:",[1316,3829,3831],{"className":2710,"code":3830,"language":2712,"meta":1051,"style":1051},"def cut_to_ascending(file_path):\n    audio = AudioSegment.from_mp3(file_path)\n    half_point = len(audio) // 2\n    ascending_only = audio[:half_point]\n    ascending_only.export(file_path, format=\"mp3\")\n",[1322,3832,3833,3847,3868,3891,3909],{"__ignoreMap":1051},[1325,3834,3835,3837,3840,3842,3845],{"class":1327,"line":1328},[1325,3836,3001],{"class":3000},[1325,3838,3839],{"class":3004}," cut_to_ascending",[1325,3841,3008],{"class":2728},[1325,3843,3844],{"class":3011},"file_path",[1325,3846,3020],{"class":2728},[1325,3848,3849,3852,3854,3857,3859,3862,3864,3866],{"class":1327,"line":1052},[1325,3850,3851],{"class":1331},"    audio ",[1325,3853,2729],{"class":2728},[1325,3855,3856],{"class":1331}," AudioSegment",[1325,3858,1130],{"class":2728},[1325,3860,3861],{"class":3004},"from_mp3",[1325,3863,3008],{"class":2728},[1325,3865,3844],{"class":3004},[1325,3867,3127],{"class":2728},[1325,3869,3870,3873,3875,3878,3880,3883,3885,3888],{"class":1327,"line":1340},[1325,3871,3872],{"class":1331},"    half_point ",[1325,3874,2729],{"class":2728},[1325,3876,3877],{"class":3004}," len",[1325,3879,3008],{"class":2728},[1325,3881,3882],{"class":3004},"audio",[1325,3884,3101],{"class":2728},[1325,3886,3887],{"class":2728}," //",[1325,3889,3890],{"class":2753}," 2\n",[1325,3892,3893,3896,3898,3901,3904,3907],{"class":1327,"line":1346},[1325,3894,3895],{"class":1331},"    ascending_only ",[1325,3897,2729],{"class":2728},[1325,3899,3900],{"class":1331}," audio",[1325,3902,3903],{"class":2728},"[:",[1325,3905,3906],{"class":1331},"half_point",[1325,3908,3559],{"class":2728},[1325,3910,3911,3914,3916,3919,3921,3923,3925,3928,3930,3932,3935,3937],{"class":1327,"line":1352},[1325,3912,3913],{"class":1331},"    ascending_only",[1325,3915,1130],{"class":2728},[1325,3917,3918],{"class":3004},"export",[1325,3920,3008],{"class":2728},[1325,3922,3844],{"class":3004},[1325,3924,2757],{"class":2728},[1325,3926,3927],{"class":3011}," format",[1325,3929,2729],{"class":2728},[1325,3931,2744],{"class":2728},[1325,3933,3934],{"class":2740},"mp3",[1325,3936,2744],{"class":2728},[1325,3938,3127],{"class":2728},[743,3940,3941,3944],{},[828,3942,3943],{},"Trim chord arpeggios"," - Some chords had unwanted arpeggio intros. FFmpeg to the rescue:",[1316,3946,3950],{"className":3947,"code":3948,"language":3949,"meta":1051,"style":1051},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","ffmpeg -y -i chord.mp3 -ss [start_time] -acodec libmp3lame chord_trimmed.mp3\n","bash",[1322,3951,3952],{"__ignoreMap":1051},[1325,3953,3954,3958,3961,3964,3967,3970],{"class":1327,"line":1328},[1325,3955,3957],{"class":3956},"sBMFI","ffmpeg",[1325,3959,3960],{"class":2740}," -y",[1325,3962,3963],{"class":2740}," -i",[1325,3965,3966],{"class":2740}," chord.mp3",[1325,3968,3969],{"class":2740}," -ss",[1325,3971,3972],{"class":1331}," [start_time] -acodec libmp3lame chord_trimmed.mp3\n",[743,3974,3975,3978],{},[828,3976,3977],{},"Batch update SVG colors"," - Our chord diagrams needed color adjustments to match the app theme. Regex-based batch processing:",[1316,3980,3982],{"className":2710,"code":3981,"language":2712,"meta":1051,"style":1051},"COLOR_REPLACEMENTS = {\n    '#f3f8f3': '#000000',  # Inactive keys: light → dark\n    '#b3cc57': '#C6F222',  # Active keys: old green → MTL lime\n}\n",[1322,3983,3984,3993,4019,4042],{"__ignoreMap":1051},[1325,3985,3986,3989,3991],{"class":1327,"line":1328},[1325,3987,3988],{"class":1331},"COLOR_REPLACEMENTS ",[1325,3990,2729],{"class":2728},[1325,3992,2732],{"class":2728},[1325,3994,3995,3998,4001,4004,4006,4009,4012,4014,4016],{"class":1327,"line":1052},[1325,3996,3997],{"class":2728},"    '",[1325,3999,4000],{"class":2740},"#f3f8f3",[1325,4002,4003],{"class":2728},"'",[1325,4005,2747],{"class":2728},[1325,4007,4008],{"class":2728}," '",[1325,4010,4011],{"class":2740},"#000000",[1325,4013,4003],{"class":2728},[1325,4015,2757],{"class":2728},[1325,4017,4018],{"class":2719},"  # Inactive keys: light → dark\n",[1325,4020,4021,4023,4026,4028,4030,4032,4035,4037,4039],{"class":1327,"line":1340},[1325,4022,3997],{"class":2728},[1325,4024,4025],{"class":2740},"#b3cc57",[1325,4027,4003],{"class":2728},[1325,4029,2747],{"class":2728},[1325,4031,4008],{"class":2728},[1325,4033,4034],{"class":2740},"#C6F222",[1325,4036,4003],{"class":2728},[1325,4038,2757],{"class":2728},[1325,4040,4041],{"class":2719},"  # Active keys: old green → MTL lime\n",[1325,4043,4044],{"class":1327,"line":1346},[1325,4045,2961],{"class":2728},[1472,4047,4049],{"id":4048},"the-numbers","The Numbers",[743,4051,4052],{},"By the end, our content pipeline generated:",[1933,4054,4055,4068],{},[1936,4056,4057],{},[1939,4058,4059,4062,4065],{},[1942,4060,4061],{},"Category",[1942,4063,4064],{},"Files",[1942,4066,4067],{},"Method",[1952,4069,4070,4081,4091,4102,4113,4124],{},[1939,4071,4072,4075,4078],{},[1957,4073,4074],{},"Chords",[1957,4076,4077],{},"168 audio + 168 SVG",[1957,4079,4080],{},"MIDI → FluidSynth → FFmpeg",[1939,4082,4083,4086,4089],{},[1957,4084,4085],{},"Scales",[1957,4087,4088],{},"14 audio + 14 SVG",[1957,4090,4080],{},[1939,4092,4093,4096,4099],{},[1957,4094,4095],{},"Notes",[1957,4097,4098],{},"8 audio + 8 SVG",[1957,4100,4101],{},"pydub sine wave synthesis",[1939,4103,4104,4107,4110],{},[1957,4105,4106],{},"Rhythms",[1957,4108,4109],{},"8 audio + 8 PNG",[1957,4111,4112],{},"Mathematical drum synthesis",[1939,4114,4115,4118,4121],{},[1957,4116,4117],{},"Animals",[1957,4119,4120],{},"18 audio + 18 PNG",[1957,4122,4123],{},"Curated library",[1939,4125,4126,4129,4131],{},[1957,4127,4128],{},"Instruments",[1957,4130,4109],{},[1957,4132,4133],{},"Curated samples",[743,4135,4136,4139],{},[828,4137,4138],{},"Total: 300+ assets",", mostly generated programmatically.",[1472,4141,4143],{"id":4142},"why-this-matters","Why This Matters",[743,4145,4146],{},"Could we have licensed a chord library? Sure. But:",[2175,4148,4149,4155,4161,4167],{},[1486,4150,4151,4154],{},[828,4152,4153],{},"Consistency"," - Every chord sounds identical in timbre, velocity, duration",[1486,4156,4157,4160],{},[828,4158,4159],{},"Customization"," - Need a longer sustain? Change one variable, regenerate",[1486,4162,4163,4166],{},[828,4164,4165],{},"No licensing headaches"," - We own every bit of audio",[1486,4168,4169,4172],{},[828,4170,4171],{},"Educational value"," - We actually understand what we're teaching",[743,4174,4175,4176,1130],{},"Plus, writing a drum synthesizer from scratch is just ",[1111,4177,4178],{},"fun",[747,4180],{},[750,4182,4184],{"id":4183},"the-categories-more-than-just-music","The Categories: More Than Just Music",[743,4186,4187],{},"While we started with music education in mind, we quickly realized the concept works for much more.",[1472,4189,4191],{"id":4190},"musical-categories","Musical Categories",[755,4193,2481,4197,4202,4203],{"className":4194},[1028,2478,4195,4196],"gap-8","items-start",[1695,4198],{"src":4199,"alt":4200,"className":4201},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_3.webp","Category selection",[2491],"\n   ",[1695,4204],{"src":4205,"alt":4206,"className":4207},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_4.webp","Chord diagram",[2491],[743,4209,4210,4212],{},[828,4211,4074],{}," - Can you tell the difference between a major and minor chord? What about diminished vs. augmented? This category trains your ear to recognize the emotional quality of different chord types.",[743,4214,4215,4217],{},[828,4216,4085],{}," - From the bright C Major to the melancholic A Natural Minor, players learn to identify scales by their unique character.",[743,4219,4220,4222],{},[828,4221,4095],{}," - Perfect for beginners learning to identify individual pitches on the musical staff.",[743,4224,4225,4227],{},[828,4226,4106],{}," - 3/4 waltz? 4/4 rock beat? Syncopated funk? Train your rhythmic ear.",[1472,4229,4231],{"id":4230},"beyond-music","Beyond Music",[743,4233,4234,4236],{},[828,4235,4117],{}," - 18 animal sounds, from the roar of a lion to the chirp of a bird. Perfect for younger kids or anyone who just wants a fun challenge.",[743,4238,4239,4241],{},[828,4240,4128],{}," - Can you distinguish a trumpet from a saxophone? A violin from a cello? Harder than you'd think!",[747,4243],{},[750,4245,4247],{"id":4246},"the-game-modes-flexibility-matters","The Game Modes: Flexibility Matters",[743,4249,4250],{},"Not everyone learns the same way. That's why MemoSonic offers two distinct game modes:",[1472,4252,4254],{"id":4253},"memosonic-mode-sound-first","Memosonic Mode (Sound-First)",[743,4256,4257],{},"This is the heart of the app. Tap a card, hear a sound. Remember that sound. Find its match.",[1316,4259,4262],{"className":4260,"code":4261,"language":2651},[2649],"1. Tap card → Hear sound (no visual)\n2. Tap another card → Hear second sound\n3. Match? → Cards reveal and stay\n4. No match? → Cards flip back, remember the sounds!\n",[1322,4263,4261],{"__ignoreMap":1051},[755,4265,2481,4267,2481,4270,2481,4275],{"className":4266},[1028,2478,2479,2480],[755,4268],{"className":4269},[2485],[1695,4271],{"src":4272,"alt":4273,"className":4274},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_5.webp","Memosonic mode",[2491],[755,4276],{"className":4277},[2485],[1472,4279,4281],{"id":4280},"memo-classic-mode-visual-first","Memo Classic Mode (Visual-First)",[743,4283,4284],{},"For those who want a traditional experience, or as a comparison to understand how much harder audio matching is!",[1316,4286,4289],{"className":4287,"code":4288,"language":2651},[2649],"1. Tap card → Image briefly appears (1 second)\n2. Tap another card → Second image appears\n3. Match? → Cards stay revealed\n4. No match? → Images hide, remember positions!\n",[1322,4290,4288],{"__ignoreMap":1051},[747,4292],{},[750,4294,4296],{"id":4295},"difficulty-levels-progressive-challenge","Difficulty Levels: Progressive Challenge",[743,4298,4299],{},"We designed three difficulty levels, each carefully balanced:",[1933,4301,4302,4318],{},[1936,4303,4304],{},[1939,4305,4306,4309,4312,4315],{},[1942,4307,4308],{},"Level",[1942,4310,4311],{},"Cards",[1942,4313,4314],{},"Pairs",[1942,4316,4317],{},"Estimated Time",[1952,4319,4320,4332,4345],{},[1939,4321,4322,4325,4327,4329],{},[1957,4323,4324],{},"Easy",[1957,4326,3443],{},[1957,4328,3396],{},[1957,4330,4331],{},"2-3 minutes",[1939,4333,4334,4337,4340,4342],{},[1957,4335,4336],{},"Normal",[1957,4338,4339],{},"12",[1957,4341,3443],{},[1957,4343,4344],{},"5-7 minutes",[1939,4346,4347,4350,4353,4356],{},[1957,4348,4349],{},"Hard",[1957,4351,4352],{},"20",[1957,4354,4355],{},"10",[1957,4357,4358],{},"10-15 minutes",[755,4360,2481,4362,2481,4365,2481,4370],{"className":4361},[1028,2478,2479,2480],[755,4363],{"className":4364},[2485],[1695,4366],{"src":4367,"alt":4368,"className":4369},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_7.webp","Level selection",[2491],[755,4371],{"className":4372},[2485],[743,4374,4375],{},"The jump from 6 to 12 cards isn't just \"twice as hard\" - it's exponentially more challenging. Your brain can hold about 7 items in working memory. At 12 cards, you're constantly pushing that limit.",[743,4377,4378],{},"At 20 cards? It's a real workout.",[747,4380],{},[750,4382,4384],{"id":4383},"accessibility-designing-for-everyone","Accessibility: Designing for Everyone",[743,4386,4387],{},"Here's where it gets important.",[1472,4389,4391],{"id":4390},"the-visually-impaired-perspective","The Visually Impaired Perspective",[743,4393,4394],{},"Traditional memory games are impossible for blind or visually impaired players. The entire mechanic relies on seeing and remembering visual positions.",[743,4396,4397],{},[828,4398,4399],{},"MemoSonic flips this on its head.",[743,4401,4402],{},"In Memosonic mode, vision is secondary. You're listening, remembering sounds, matching audio. A visually impaired player can:",[2175,4404,4405,4408,4411,4414],{},[1486,4406,4407],{},"Navigate the grid using screen reader or spatial memory",[1486,4409,4410],{},"Tap cards to hear sounds",[1486,4412,4413],{},"Match based purely on audio memory",[1486,4415,4416],{},"Receive audio feedback on success/failure",[755,4418,2481,4420,2481,4423,2481,4428],{"className":4419},[1028,2478,2479,2480],[755,4421],{"className":4422},[2485],[1695,4424],{"src":4425,"alt":4426,"className":4427},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_8.webp","Game completion",[2491],[755,4429],{"className":4430},[2485],[1472,4432,4434],{"id":4433},"design-decisions-for-accessibility","Design Decisions for Accessibility",[743,4436,4437],{},"We made several deliberate choices:",[743,4439,4440],{},[828,4441,4442],{},"High Contrast UI",[1483,4444,4445,4448,4451,4454],{},[1486,4446,4447],{},"Dark background (#0E0F11)",[1486,4449,4450],{},"Bright lime yellow accents (#C6F222)",[1486,4452,4453],{},"Clear white text",[1486,4455,4456],{},"No reliance on color alone for meaning",[743,4458,4459],{},[828,4460,4461],{},"Large Touch Targets",[1483,4463,4464,4467,4470],{},[1486,4465,4466],{},"Cards are generously sized",[1486,4468,4469],{},"Buttons have ample padding",[1486,4471,4472],{},"No precision tapping required",[743,4474,4475],{},[828,4476,4477],{},"Audio Feedback",[1483,4479,4480,4483,4486],{},[1486,4481,4482],{},"Every interaction has sound",[1486,4484,4485],{},"Success/failure clearly distinguishable",[1486,4487,4488],{},"No silent failures",[743,4490,4491],{},[828,4492,4493],{},"Simple Navigation",[1483,4495,4496,4499,4502],{},[1486,4497,4498],{},"Linear flow: Home → Category → Level → Game",[1486,4500,4501],{},"Back button always available",[1486,4503,4504],{},"No complex gestures required",[747,4506],{},[750,4508,4510],{"id":4509},"the-technical-deep-dive-for-fellow-developers","The Technical Deep Dive (For Fellow Developers)",[1472,4512,4514],{"id":4513},"project-architecture","Project Architecture",[1316,4516,4519],{"className":4517,"code":4518,"language":2651},[2649],"lib/\n├── main.dart                    # Entry point, splash screen\n├── core/\n│   ├── routes.dart              # GoRouter navigation\n│   ├── theme.dart               # Material 3 dark theme\n│   └── game_utils.dart          # Category definitions, game data\n├── features/\n│   ├── home_screen.dart         # Category selection grid\n│   ├── level_screen.dart        # Difficulty picker\n│   ├── game_screen.dart         # Main gameplay\n│   └── settings_screen.dart     # Settings hub\n└── widgets/\n    └── app_logo.dart            # Reusable logo component\n",[1322,4520,4518],{"__ignoreMap":1051},[1472,4522,4524],{"id":4523},"key-dependencies","Key Dependencies",[1316,4526,4530],{"className":4527,"code":4528,"language":4529,"meta":1051,"style":1051},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dependencies:\n  flutter_riverpod: ^3.0.1    # State management\n  go_router: ^16.3.0          # Navigation\n  just_audio: ^0.10.5         # Primary audio engine\n  audioplayers: ^6.1.0        # Alternative audio playback\n  flutter_svg: ^2.0.10        # SVG rendering for diagrams\n  shared_preferences: ^2.5.3  # Local settings storage\n","yaml",[1322,4531,4532,4539,4552,4565,4578,4591,4604],{"__ignoreMap":1051},[1325,4533,4534,4537],{"class":1327,"line":1328},[1325,4535,4536],{"class":3164},"dependencies",[1325,4538,3202],{"class":2728},[1325,4540,4541,4544,4546,4549],{"class":1327,"line":1052},[1325,4542,4543],{"class":3164},"  flutter_riverpod",[1325,4545,2747],{"class":2728},[1325,4547,4548],{"class":2740}," ^3.0.1",[1325,4550,4551],{"class":2719},"    # State management\n",[1325,4553,4554,4557,4559,4562],{"class":1327,"line":1340},[1325,4555,4556],{"class":3164},"  go_router",[1325,4558,2747],{"class":2728},[1325,4560,4561],{"class":2740}," ^16.3.0",[1325,4563,4564],{"class":2719},"          # Navigation\n",[1325,4566,4567,4570,4572,4575],{"class":1327,"line":1346},[1325,4568,4569],{"class":3164},"  just_audio",[1325,4571,2747],{"class":2728},[1325,4573,4574],{"class":2740}," ^0.10.5",[1325,4576,4577],{"class":2719},"         # Primary audio engine\n",[1325,4579,4580,4583,4585,4588],{"class":1327,"line":1352},[1325,4581,4582],{"class":3164},"  audioplayers",[1325,4584,2747],{"class":2728},[1325,4586,4587],{"class":2740}," ^6.1.0",[1325,4589,4590],{"class":2719},"        # Alternative audio playback\n",[1325,4592,4593,4596,4598,4601],{"class":1327,"line":1358},[1325,4594,4595],{"class":3164},"  flutter_svg",[1325,4597,2747],{"class":2728},[1325,4599,4600],{"class":2740}," ^2.0.10",[1325,4602,4603],{"class":2719},"        # SVG rendering for diagrams\n",[1325,4605,4606,4609,4611,4614],{"class":1327,"line":1364},[1325,4607,4608],{"class":3164},"  shared_preferences",[1325,4610,2747],{"class":2728},[1325,4612,4613],{"class":2740}," ^2.5.3",[1325,4615,4616],{"class":2719},"  # Local settings storage\n",[1472,4618,4620],{"id":4619},"the-card-flip-animation","The Card Flip Animation",[743,4622,4623],{},"One of the most satisfying parts of the app is the card flip animation. Here's the approach:",[1316,4625,4629],{"className":4626,"code":4627,"language":4628,"meta":1051,"style":1051},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","// Simplified card flip logic\nAnimatedBuilder(\n  animation: _flipAnimation,\n  builder: (context, child) {\n    final angle = _flipAnimation.value * pi;\n    final isFront = angle \u003C pi / 2;\n\n    return Transform(\n      transform: Matrix4.identity()\n        ..setEntry(3, 2, 0.001)  // Perspective\n        ..rotateY(angle),\n      alignment: Alignment.center,\n      child: isFront ? _buildFrontFace() : _buildBackFace(),\n    );\n  },\n)\n","dart",[1322,4630,4631,4636,4644,4657,4672,4697,4720,4724,4733,4751,4778,4790,4807,4835,4842,4849],{"__ignoreMap":1051},[1325,4632,4633],{"class":1327,"line":1328},[1325,4634,4635],{"class":2719},"// Simplified card flip logic\n",[1325,4637,4638,4641],{"class":1327,"line":1052},[1325,4639,4640],{"class":3956},"AnimatedBuilder",[1325,4642,4643],{"class":1331},"(\n",[1325,4645,4646,4649,4651,4654],{"class":1327,"line":1340},[1325,4647,4648],{"class":1331},"  animation",[1325,4650,2747],{"class":2728},[1325,4652,4653],{"class":1331}," _flipAnimation",[1325,4655,4656],{"class":2728},",\n",[1325,4658,4659,4662,4664,4667,4669],{"class":1327,"line":1346},[1325,4660,4661],{"class":1331},"  builder",[1325,4663,2747],{"class":2728},[1325,4665,4666],{"class":1331}," (context",[1325,4668,2757],{"class":2728},[1325,4670,4671],{"class":1331}," child) {\n",[1325,4673,4674,4677,4680,4682,4684,4686,4689,4691,4694],{"class":1327,"line":1352},[1325,4675,4676],{"class":3000},"    final",[1325,4678,4679],{"class":1331}," angle ",[1325,4681,2729],{"class":2728},[1325,4683,4653],{"class":1331},[1325,4685,1130],{"class":2728},[1325,4687,4688],{"class":1331},"value ",[1325,4690,3121],{"class":2728},[1325,4692,4693],{"class":1331}," pi",[1325,4695,4696],{"class":2728},";\n",[1325,4698,4699,4701,4704,4706,4708,4710,4713,4715,4718],{"class":1327,"line":1358},[1325,4700,4676],{"class":3000},[1325,4702,4703],{"class":1331}," isFront ",[1325,4705,2729],{"class":2728},[1325,4707,4679],{"class":1331},[1325,4709,3196],{"class":2728},[1325,4711,4712],{"class":1331}," pi ",[1325,4714,3065],{"class":2728},[1325,4716,4717],{"class":2753}," 2",[1325,4719,4696],{"class":2728},[1325,4721,4722],{"class":1327,"line":1364},[1325,4723,1355],{"emptyLinePlaceholder":1069},[1325,4725,4726,4728,4731],{"class":1327,"line":1370},[1325,4727,3808],{"class":3025},[1325,4729,4730],{"class":3956}," Transform",[1325,4732,4643],{"class":1331},[1325,4734,4735,4738,4740,4743,4745,4748],{"class":1327,"line":1376},[1325,4736,4737],{"class":1331},"      transform",[1325,4739,2747],{"class":2728},[1325,4741,4742],{"class":3956}," Matrix4",[1325,4744,1130],{"class":2728},[1325,4746,4747],{"class":3004},"identity",[1325,4749,4750],{"class":1331},"()\n",[1325,4752,4753,4756,4759,4761,4763,4765,4767,4769,4772,4775],{"class":1327,"line":1381},[1325,4754,4755],{"class":2728},"        ..",[1325,4757,4758],{"class":3004},"setEntry",[1325,4760,3008],{"class":1331},[1325,4762,3396],{"class":2753},[1325,4764,2757],{"class":2728},[1325,4766,4717],{"class":2753},[1325,4768,2757],{"class":2728},[1325,4770,4771],{"class":2753}," 0.001",[1325,4773,4774],{"class":1331},")  ",[1325,4776,4777],{"class":2719},"// Perspective\n",[1325,4779,4780,4782,4785,4788],{"class":1327,"line":1386},[1325,4781,4755],{"class":2728},[1325,4783,4784],{"class":3004},"rotateY",[1325,4786,4787],{"class":1331},"(angle)",[1325,4789,4656],{"class":2728},[1325,4791,4792,4795,4797,4800,4802,4805],{"class":1327,"line":1392},[1325,4793,4794],{"class":1331},"      alignment",[1325,4796,2747],{"class":2728},[1325,4798,4799],{"class":3956}," Alignment",[1325,4801,1130],{"class":2728},[1325,4803,4804],{"class":1331},"center",[1325,4806,4656],{"class":2728},[1325,4808,4809,4812,4814,4816,4819,4822,4825,4827,4830,4833],{"class":1327,"line":1398},[1325,4810,4811],{"class":1331},"      child",[1325,4813,2747],{"class":2728},[1325,4815,4703],{"class":1331},[1325,4817,4818],{"class":2728},"?",[1325,4820,4821],{"class":3004}," _buildFrontFace",[1325,4823,4824],{"class":1331},"() ",[1325,4826,2747],{"class":2728},[1325,4828,4829],{"class":3004}," _buildBackFace",[1325,4831,4832],{"class":1331},"()",[1325,4834,4656],{"class":2728},[1325,4836,4837,4840],{"class":1327,"line":1404},[1325,4838,4839],{"class":1331},"    )",[1325,4841,4696],{"class":2728},[1325,4843,4844,4847],{"class":1327,"line":1410},[1325,4845,4846],{"class":1331},"  }",[1325,4848,4656],{"class":2728},[1325,4850,4851],{"class":1327,"line":1416},[1325,4852,3127],{"class":1331},[743,4854,4855,4856,4859],{},"The trick is the perspective transform (",[1322,4857,4858],{},"setEntry(3, 2, 0.001)",") - it gives that satisfying 3D effect without being distracting.",[747,4861],{},[750,4863,4865],{"id":4864},"lessons-learned","Lessons Learned",[1472,4867,4869],{"id":4868},"_1-audio-latency-is-everything","1. Audio Latency is Everything",[743,4871,4872],{},"In a sound-based game, even tiny delays feel wrong. We spent weeks optimizing audio playback to ensure instant response.",[1472,4874,4876],{"id":4875},"_2-kids-are-brutally-honest-testers","2. Kids Are Brutally Honest Testers",[743,4878,4879],{},"Our first playtest with actual children revealed:",[1483,4881,4882,4885,4888],{},[1486,4883,4884],{},"\"Why is this taking so long?\" (loading screen was 2 seconds)",[1486,4886,4887],{},"\"I already heard that one!\" (audio caching issue)",[1486,4889,4890],{},"\"This is too easy!\" (we added Hard mode)",[1472,4892,4894],{"id":4893},"_3-accessibility-isnt-an-afterthought","3. Accessibility Isn't an Afterthought",[743,4896,4897],{},"Building for accessibility from day one is 10x easier than retrofitting. The decisions we made early (audio-first gameplay, high contrast, large targets) paid off.",[1472,4899,4901],{"id":4900},"_4-simple-beats-complex","4. Simple Beats Complex",[743,4903,4904],{},"Our first design had:",[1483,4906,4907,4910,4913,4916],{},[1486,4908,4909],{},"User accounts",[1486,4911,4912],{},"Leaderboards",[1486,4914,4915],{},"Achievement systems",[1486,4917,4918],{},"Daily challenges",[743,4920,4921],{},"We cut all of it. The core experience - match sounds, train your ear - didn't need any of that. It needed to work flawlessly.",[747,4923],{},[750,4925,4927],{"id":4926},"whats-next-you-tell-us","What's Next? You Tell Us!",[743,4929,4930,4931,1130],{},"We have a bunch of ideas brewing for the next iteration. But here's the thing - ",[828,4932,4933],{},"we'd rather build what you actually want",[743,4935,4936],{},"Take a look at what we're considering:",[743,4938,4939],{},[828,4940,4941],{},"More Categories",[1483,4943,4944,4947,4950],{},[1486,4945,4946],{},"🐦 Bird songs (nature education)",[1486,4948,4949],{},"🌍 World languages (basic vocabulary)",[1486,4951,4952],{},"🎼 Famous melodies (classical music education)",[743,4954,4955],{},[828,4956,4957],{},"Enhanced Accessibility",[1483,4959,4960,4963,4966],{},[1486,4961,4962],{},"🔊 Full VoiceOver/TalkBack support",[1486,4964,4965],{},"📳 Haptic feedback for matches",[1486,4967,4968],{},"🎧 Audio descriptions for all UI elements",[743,4970,4971],{},[828,4972,4973],{},"Multiplayer Mode",[1483,4975,4976,4979,4982],{},[1486,4977,4978],{},"👥 Turn-based competition",[1486,4980,4981],{},"⚡ Who can match faster?",[1486,4983,4984],{},"🏠 Family game night feature",[743,4986,4987],{},[828,4988,4989],{},"Something else entirely?",[743,4991,4992],{},"Maybe you're a music teacher who needs specific intervals training. Maybe you work with visually impaired students and have insights we haven't considered. Maybe your kid is obsessed with dinosaurs and you want dinosaur sounds.",[743,4994,4995],{},[828,4996,4997],{},"We're listening.",[743,4999,5000,5001,5005],{},"Drop us a line at ",[988,5002,5004],{"href":5003},"mailto:support@musictechlab.io","support@musictechlab.io"," and tell us:",[1483,5007,5008,5011,5014],{},[1486,5009,5010],{},"Which feature would you use most?",[1486,5012,5013],{},"What's missing that would make MemoSonic perfect for you?",[1486,5015,5016],{},"Any category ideas we haven't thought of?",[743,5018,5019],{},"The best features come from real users with real needs. Don't be shy - your idea might end up in the next update.",[747,5021],{},[750,5023,5025],{"id":5024},"the-dream-memosonic-as-a-physical-toy","The Dream: MemoSonic as a Physical Toy",[743,5027,5028],{},"Here's an idea that won't leave our heads...",[743,5030,5031],{},[828,5032,5033],{},"What if MemoSonic wasn't just an app, but a physical toy you could hold in your hands?",[755,5035,2481,5037,2481,5040,2481,5045],{"className":5036},[1028,2478,2479,2480],[755,5038],{"className":5039},[2485],[1695,5041],{"src":5042,"alt":5043,"className":5044},"/images/blog/musictechlab_blog_how-we-built-memosonic_inline_9.webp","Hardware concept",[2491],[755,5046],{"className":5047},[2485],[1472,5049,5051],{"id":5050},"the-vision","The Vision",[743,5053,5054],{},"Picture a compact device with a grid of large, tactile buttons. Each button:",[1483,5056,5057,5060,5063,5066],{},[1486,5058,5059],{},"Lights up with RGB LEDs",[1486,5061,5062],{},"Plays a sound when pressed",[1486,5064,5065],{},"Has a satisfying click",[1486,5067,5068],{},"Is large enough for small hands (and accessible for everyone)",[743,5070,5071],{},"An 8×8 matrix would give us 64 buttons - enough for complex games while keeping each button big enough to press comfortably:",[1316,5073,5076],{"className":5074,"code":5075,"language":2651},[2649],"[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n[🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘] [🔘]\n",[1322,5077,5075],{"__ignoreMap":1051},[743,5079,5080],{},"Easy mode? Use a 3×2 section. Hard mode? The whole grid lights up.",[1472,5082,5084],{"id":5083},"why-does-this-idea-excite-us","Why Does This Idea Excite Us?",[743,5086,5087,5090],{},[828,5088,5089],{},"Screen-free play."," Parents increasingly want toys that don't involve staring at a screen. A physical MemoSonic would sit on the kitchen table, travel in a backpack, work without WiFi.",[743,5092,5093,5096,5097,5100],{},[828,5094,5095],{},"True tactile accessibility."," For visually impaired users, physical buttons in fixed positions are ",[1111,5098,5099],{},"far"," easier to navigate than a touchscreen. You can feel your way around. Build muscle memory. No screen reader required.",[743,5102,5103,5106],{},[828,5104,5105],{},"Multiplayer without devices."," Gather around the table. Take turns. Compete. No \"pass the phone\" awkwardness.",[743,5108,5109,5112],{},[828,5110,5111],{},"Durability."," Kids are rough. A well-designed hardware toy can survive drops, spills, and sibling conflicts.",[1472,5114,5116],{"id":5115},"what-it-could-look-like-technically","What It Could Look Like Technically",[743,5118,5119],{},"If we were to build this, we'd probably explore:",[1483,5121,5122,5128,5134,5140,5146,5152],{},[1486,5123,5124,5127],{},[828,5125,5126],{},"ESP32 or Raspberry Pi Pico"," as the brain",[1486,5129,5130,5133],{},[828,5131,5132],{},"I2S audio"," for quality sound output",[1486,5135,5136,5139],{},[828,5137,5138],{},"NeoPixel/WS2812B"," LEDs for button illumination",[1486,5141,5142,5145],{},[828,5143,5144],{},"Rechargeable battery"," with USB-C charging",[1486,5147,5148,5151],{},[828,5149,5150],{},"SD card slot"," for custom sound packs",[1486,5153,5154,5157],{},[828,5155,5156],{},"Bluetooth LE"," for optional app companion (stats, new sounds)",[743,5159,5160],{},"The app and hardware could even sync - unlock new sounds on the device by mastering them in the app first.",[1472,5162,5164],{"id":5163},"the-accessibility-angle","The Accessibility Angle",[743,5166,5167],{},"This is where it gets really exciting.",[743,5169,5170],{},"For a blind child, a touchscreen memory game is possible but challenging. A physical device with buttons in consistent positions? That's a game they can master as well as any sighted player. Maybe better - they've been training their auditory memory their whole life.",[743,5172,5173],{},"We imagine:",[1483,5175,5176,5182,5188,5194],{},[1486,5177,5178,5181],{},[828,5179,5180],{},"Raised symbols"," on each button for tactile identification",[1486,5183,5184,5187],{},[828,5185,5186],{},"Audio position announcements"," (\"Button 3\" when pressed)",[1486,5189,5190,5193],{},[828,5191,5192],{},"Haptic feedback"," for matches and mismatches",[1486,5195,5196,5199],{},[828,5197,5198],{},"Braille labeling"," on the device",[1472,5201,5203],{"id":5202},"is-this-something-youd-want","Is This Something You'd Want?",[743,5205,5206],{},"Right now, this is just an idea - a dream sketched on whiteboards and discussed over coffee. We haven't built a prototype yet. We're not sure if we will.",[743,5208,5209],{},[828,5210,5211],{},"But we could, if there's real interest.",[743,5213,5214],{},"Would you buy a physical MemoSonic for your kids? For a classroom? For a visually impaired family member? Would you back it on Kickstarter?",[743,5216,5217,5220],{},[828,5218,5219],{},"Let us know."," If enough people say \"yes, build this thing!\" - we just might.",[743,5222,5223,5224,5226],{},"📧 ",[988,5225,5004],{"href":5003}," - subject line: \"Hardware MemoSonic\"",[743,5228,5229],{},[1111,5230,5231],{},"If the response is strong enough, we'll start prototyping and document the entire journey. Stay tuned.",[747,5233],{},[750,5235,5237],{"id":5236},"try-it-yourself","Try It Yourself",[743,5239,5240],{},"MemoSonic is available now:",[1483,5242,5243,5254,5264],{},[1486,5244,5245,5248,5249],{},[828,5246,5247],{},"Web",": ",[988,5250,5253],{"href":5251,"rel":5252},"https://memosonic.musictechlab.io/",[992],"memosonic.musictechlab.io",[1486,5255,5256,5248,5259],{},[828,5257,5258],{},"iOS",[988,5260,5263],{"href":5261,"rel":5262},"https://apps.apple.com/pl/app/memosonic/id6743499949",[992],"App Store",[1486,5265,5266,5248,5269],{},[828,5267,5268],{},"Android",[988,5270,1040],{"href":5271,"rel":5272},"https://play.google.com/store/apps/details?id=com.memosonic.app",[992],[743,5274,5275],{},"Whether you're a music teacher looking for ear training tools, a parent wanting educational screen time, or someone who just wants to see if they can beat their kids at a memory game - give it a try.",[747,5277],{},[750,5279,5281],{"id":5280},"the-bigger-picture","The Bigger Picture",[743,5283,5284],{},"MemoSonic started as a rainy day experiment. It became something more - a proof that:",[2175,5286,5287,5293,5299,5305],{},[1486,5288,5289,5292],{},[828,5290,5291],{},"Learning doesn't have to look like learning."," The best educational tools feel like play.",[1486,5294,5295,5298],{},[828,5296,5297],{},"Accessibility opens doors."," By designing for sound-first gameplay, we accidentally created something that works for people we hadn't initially considered.",[1486,5300,5301,5304],{},[828,5302,5303],{},"Simple ideas can have big impact."," Flip cards, match sounds. That's it. But the applications - music education, auditory training, inclusive gaming - are vast.",[1486,5306,5307,5310],{},[828,5308,5309],{},"Software is just the beginning."," The same concept that works on a phone could work on a physical device - maybe even better for some users.",[743,5312,5313],{},"Sometimes the best projects come from playing with your kids.",[747,5315],{},[750,5317,5319],{"id":5318},"resources","Resources",[1483,5321,5322,5329,5336,5343],{},[1486,5323,5324],{},[988,5325,5328],{"href":5326,"rel":5327},"https://flutter.dev",[992],"Flutter Documentation",[1486,5330,5331],{},[988,5332,5335],{"href":5333,"rel":5334},"https://pub.dev/packages/just_audio",[992],"just_audio Package",[1486,5337,5338],{},[988,5339,5342],{"href":5340,"rel":5341},"https://www.w3.org/WAI/standards-guidelines/mobile/",[992],"Accessibility Guidelines for Mobile Apps",[1486,5344,5345],{},[988,5346,5349],{"href":5347,"rel":5348},"https://docs.espressif.com/projects/esp-adf/en/latest/",[992],"ESP32 Audio Projects",[747,5351],{},[750,5353,5355],{"id":5354},"for-clients-what-to-know-before-commissioning-a-mobile-app","For Clients: What to Know Before Commissioning a Mobile App",[743,5357,5358],{},"We thought it might be useful to share some honest insights from building MemoSonic - especially if you're considering commissioning a mobile app yourself.",[1472,5360,5362],{"id":5361},"timeline-reality","Timeline Reality",[743,5364,5365,5368,5369,1130],{},[828,5366,5367],{},"MemoSonic from idea to production:"," ~10 calendar months, but effectively ",[828,5370,5371],{},"2-3 weeks of intense work",[743,5373,5374],{},"Why the difference? Because projects have their own rhythm - there are pauses for testing ideas, gathering feedback, handling other priorities. Realistically:",[1933,5376,5377,5387],{},[1936,5378,5379],{},[1939,5380,5381,5384],{},[1942,5382,5383],{},"Phase",[1942,5385,5386],{},"Time",[1952,5388,5389,5397,5405,5412,5420],{},[1939,5390,5391,5394],{},[1957,5392,5393],{},"Prototype / proof of concept",[1957,5395,5396],{},"1-2 days",[1939,5398,5399,5402],{},[1957,5400,5401],{},"Core functionality",[1957,5403,5404],{},"3-5 days",[1939,5406,5407,5410],{},[1957,5408,5409],{},"UI/UX polish",[1957,5411,5404],{},[1939,5413,5414,5417],{},[1957,5415,5416],{},"Testing, bugs, deployment",[1957,5418,5419],{},"2-5 days",[1939,5421,5422,5427],{},[1957,5423,5424],{},[828,5425,5426],{},"Effective total",[1957,5428,5429],{},[828,5430,5431],{},"2-3 weeks",[1472,5433,5435],{"id":5434},"where-do-most-problems-occur","Where Do Most Problems Occur?",[743,5437,5438,5441],{},[828,5439,5440],{},"1. Audio/Media"," - Sounds simple (\"just play a sound\"), but:",[1483,5443,5444,5447,5450,5453],{},[1486,5445,5446],{},"Playback latency issues",[1486,5448,5449],{},"Conflicts when sounds overlap",[1486,5451,5452],{},"Differences between iOS and Android behavior",[1486,5454,5455],{},"Library bugs (e.g., \"Message responses can be sent only once\")",[743,5457,5458,5461],{},[828,5459,5460],{},"2. iOS Builds"," - Every mobile project confirms this. Certificates, provisioning profiles, App Store review. Android is simpler.",[743,5463,5464,5467],{},[828,5465,5466],{},"3. Content and Copyright"," - Want to use a famous melody? Images from the internet? You either generate your own assets or buy licenses. (We had to remove Metallica from the project for this reason.)",[1472,5469,5471],{"id":5470},"simple-ideas-complex-threads","Simple Ideas → Complex Threads",[743,5473,5474],{},"MemoSonic is \"just\" a memory game with sounds. Sounds like a weekend project, right?",[743,5476,5477],{},"And yet:",[1483,5479,5480,5486,5492,5498,5504,5510],{},[1486,5481,5482,5485],{},[828,5483,5484],{},"300+ audio files"," to generate (chords, scales, rhythms, animal sounds)",[1486,5487,5488,5491],{},[828,5489,5490],{},"Content generation pipeline"," - Python, FluidSynth, FFmpeg, sound synthesis",[1486,5493,5494,5497],{},[828,5495,5496],{},"Two game modes"," with different logic",[1486,5499,5500,5503],{},[828,5501,5502],{},"Three difficulty levels"," with balancing",[1486,5505,5506,5509],{},[828,5507,5508],{},"Accessibility"," - contrast, large buttons, audio feedback",[1486,5511,5512,5515],{},[828,5513,5514],{},"Card animations"," with 3D perspective",[743,5517,5518],{},"What seems like a \"simple app\" often requires:",[1483,5520,5521,5524,5527,5530],{},[1486,5522,5523],{},"Integration with multiple libraries",[1486,5525,5526],{},"Handling edge cases",[1486,5528,5529],{},"Testing on various devices",[1486,5531,5532],{},"Iterations based on user feedback",[1472,5534,5536],{"id":5535},"the-golden-rule","The Golden Rule",[974,5538,5539],{},[743,5540,5541],{},[828,5542,5543],{},"MVP in 5 days, polishing - endless.",[743,5545,5546],{},"The first working version comes together quickly. But the difference between \"it works\" and \"it works well on every device, looks professional, and doesn't crash\" - that's weeks of additional work.",[1472,5548,5549],{"id":2313},"The Bottom Line",[743,5551,5552],{},"If you're planning to build an app, budget for:",[1483,5554,5555,5561,5567,5573],{},[1486,5556,5557,5560],{},[828,5558,5559],{},"Time:"," 2-3x your initial estimate",[1486,5562,5563,5566],{},[828,5564,5565],{},"Complexity:"," Simple features often hide complex implementations",[1486,5568,5569,5572],{},[828,5570,5571],{},"Platform quirks:"," iOS, Android and web behave differently",[1486,5574,5575,5578],{},[828,5576,5577],{},"Content:"," Creating or licensing assets takes time and money",[743,5580,5581,5582,5585],{},"The silver lining? ",[828,5583,5584],{},"Cross-platform frameworks like Flutter"," mean you get both iOS and Android from a single codebase. One team, one codebase, two app stores. That's a massive time and cost saver compared to building native apps separately.",[743,5587,5588],{},"The good news? With the right team and realistic expectations, even ambitious ideas can become polished products. MemoSonic started as a rainy Sunday vibe-coded game with kids. Now it's a  people train their ears.",[747,5590],{},[1472,5592,5594],{"id":5593},"try-memosonic","Try MemoSonic",[1483,5596,5597,5606,5614],{},[1486,5598,5599,5602,5603],{},[828,5600,5601],{},"Web:"," ",[988,5604,5253],{"href":5251,"rel":5605},[992],[1486,5607,5608,5602,5611],{},[828,5609,5610],{},"iOS:",[988,5612,5263],{"href":5261,"rel":5613},[992],[1486,5615,5616,5602,5619],{},[828,5617,5618],{},"Android:",[988,5620,1040],{"href":5271,"rel":5621},[992],[1611,5623,5624],{},"html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":1051,"searchDepth":1052,"depth":1052,"links":5626},[5627,5628,5631,5635,5643,5647,5651,5652,5656,5661,5667,5668,5675,5676,5677,5678],{"id":2461,"depth":1052,"text":2462},{"id":2499,"depth":1052,"text":2500,"children":5629},[5630],{"id":2529,"depth":1340,"text":2530},{"id":2581,"depth":1052,"text":2582,"children":5632},[5633,5634],{"id":2585,"depth":1340,"text":2586},{"id":2608,"depth":1340,"text":2609},{"id":2658,"depth":1052,"text":2659,"children":5636},[5637,5638,5639,5640,5641,5642],{"id":2683,"depth":1340,"text":2684},{"id":2983,"depth":1340,"text":2984},{"id":3565,"depth":1340,"text":3566},{"id":3817,"depth":1340,"text":3818},{"id":4048,"depth":1340,"text":4049},{"id":4142,"depth":1340,"text":4143},{"id":4183,"depth":1052,"text":4184,"children":5644},[5645,5646],{"id":4190,"depth":1340,"text":4191},{"id":4230,"depth":1340,"text":4231},{"id":4246,"depth":1052,"text":4247,"children":5648},[5649,5650],{"id":4253,"depth":1340,"text":4254},{"id":4280,"depth":1340,"text":4281},{"id":4295,"depth":1052,"text":4296},{"id":4383,"depth":1052,"text":4384,"children":5653},[5654,5655],{"id":4390,"depth":1340,"text":4391},{"id":4433,"depth":1340,"text":4434},{"id":4509,"depth":1052,"text":4510,"children":5657},[5658,5659,5660],{"id":4513,"depth":1340,"text":4514},{"id":4523,"depth":1340,"text":4524},{"id":4619,"depth":1340,"text":4620},{"id":4864,"depth":1052,"text":4865,"children":5662},[5663,5664,5665,5666],{"id":4868,"depth":1340,"text":4869},{"id":4875,"depth":1340,"text":4876},{"id":4893,"depth":1340,"text":4894},{"id":4900,"depth":1340,"text":4901},{"id":4926,"depth":1052,"text":4927},{"id":5024,"depth":1052,"text":5025,"children":5669},[5670,5671,5672,5673,5674],{"id":5050,"depth":1340,"text":5051},{"id":5083,"depth":1340,"text":5084},{"id":5115,"depth":1340,"text":5116},{"id":5163,"depth":1340,"text":5164},{"id":5202,"depth":1340,"text":5203},{"id":5236,"depth":1052,"text":5237},{"id":5280,"depth":1052,"text":5281},{"id":5318,"depth":1052,"text":5319},{"id":5354,"depth":1052,"text":5355,"children":5679},[5680,5681,5682,5683,5684,5685],{"id":5361,"depth":1340,"text":5362},{"id":5434,"depth":1340,"text":5435},{"id":5470,"depth":1340,"text":5471},{"id":5535,"depth":1340,"text":5536},{"id":2313,"depth":1340,"text":5549},{"id":5593,"depth":1340,"text":5594},{"name":5687,"logo":5688},"MusicTech Lab","/images/logos/memosonic-app.png","2026-01-08T00:00:00.000Z","The story behind MemoSonic, a Flutter-based educational game that turns sound recognition into play, with accessibility for visually impaired users.",{"src":5692},"/images/blog/musictechlab_blog_how-we-built-memosonic-accessible-audio-memory-game-flutter.webp",{"enabled":1069,"items":5694},[5695,5698,5700,5702],{"text":5696,"icon":5697},"300+ audio assets generated programmatically using Python, FluidSynth, and FFmpeg.","i-lucide-terminal",{"text":5699,"icon":1082},"Sound-first gameplay makes the app accessible to visually impaired players by design.",{"text":5701,"icon":1248},"Effective development took 2-3 weeks despite a 10-month calendar timeline.",{"text":5703,"icon":845},"6 categories cover chords, scales, rhythms, notes, animals, and instruments.",{},"/blog/case-studies/how-we-built-memosonic-accessible-audio-memory-game-flutter",{"title":26,"description":5690},[1062,5708],"development","EpQHhZ99WiwpfNwqAZy1Tpb3DU7mhR5z4TDWIwaKj0c",1780305151463]