@kano/stem-daw 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -0
- package/dist/chat-actions-54Z6URC4.js +7 -0
- package/dist/chat-actions-54Z6URC4.js.map +1 -0
- package/dist/chunk-56PWIP7O.js +1029 -0
- package/dist/chunk-56PWIP7O.js.map +1 -0
- package/dist/chunk-AAVC7KUW.js +145 -0
- package/dist/chunk-AAVC7KUW.js.map +1 -0
- package/dist/chunk-KCOOE2OP.js +1764 -0
- package/dist/chunk-KCOOE2OP.js.map +1 -0
- package/dist/chunk-LO74ZJ4H.js +23923 -0
- package/dist/chunk-LO74ZJ4H.js.map +1 -0
- package/dist/chunk-OFGZURP6.js +247 -0
- package/dist/chunk-OFGZURP6.js.map +1 -0
- package/dist/chunk-OYNES5W3.js +3085 -0
- package/dist/chunk-OYNES5W3.js.map +1 -0
- package/dist/chunk-QQ5NZTHT.js +336 -0
- package/dist/chunk-QQ5NZTHT.js.map +1 -0
- package/dist/chunk-TBXCZFAY.js +13713 -0
- package/dist/chunk-TBXCZFAY.js.map +1 -0
- package/dist/chunk-U44X6QP5.js +281 -0
- package/dist/chunk-U44X6QP5.js.map +1 -0
- package/dist/chunk-UKMELGZL.js +27 -0
- package/dist/chunk-UKMELGZL.js.map +1 -0
- package/dist/components/DAWView.d.ts +19 -0
- package/dist/components/DAWView.js +11 -0
- package/dist/components/DAWView.js.map +1 -0
- package/dist/daw-controller-BjRWcTol.d.ts +339 -0
- package/dist/engine/daw-controller.d.ts +3 -0
- package/dist/engine/daw-controller.js +5 -0
- package/dist/engine/daw-controller.js.map +1 -0
- package/dist/engine/daw-import-stem-fm-config.d.ts +224 -0
- package/dist/engine/daw-import-stem-fm-config.js +7 -0
- package/dist/engine/daw-import-stem-fm-config.js.map +1 -0
- package/dist/fetchStationTracks-SKFT4V3U.js +3 -0
- package/dist/fetchStationTracks-SKFT4V3U.js.map +1 -0
- package/dist/index.d.ts +308 -0
- package/dist/index.js +332 -0
- package/dist/index.js.map +1 -0
- package/dist/interface-DaRj7RkY.d.ts +66 -0
- package/dist/interfaces-5ZlG0Y4Y.d.ts +549 -0
- package/dist/media-session-XTP6PP7Q.js +3 -0
- package/dist/media-session-XTP6PP7Q.js.map +1 -0
- package/dist/note-detection-PPLM7R2H.js +148 -0
- package/dist/note-detection-PPLM7R2H.js.map +1 -0
- package/dist/sampler-audio-B7MBG3YN.js +3 -0
- package/dist/sampler-audio-B7MBG3YN.js.map +1 -0
- package/dist/sampler-store-QPHANXYP.js +3 -0
- package/dist/sampler-store-QPHANXYP.js.map +1 -0
- package/dist/services/track-search-api.d.ts +152 -0
- package/dist/services/track-search-api.js +4 -0
- package/dist/services/track-search-api.js.map +1 -0
- package/dist/store/daw-auth-store.d.ts +31 -0
- package/dist/store/daw-auth-store.js +3 -0
- package/dist/store/daw-auth-store.js.map +1 -0
- package/dist/store/daw-session-store.d.ts +255 -0
- package/dist/store/daw-session-store.js +3 -0
- package/dist/store/daw-session-store.js.map +1 -0
- package/dist/vite/index.d.ts +46 -0
- package/dist/vite/index.js +94 -0
- package/dist/vite/index.js.map +1 -0
- package/dist/workers/analysis-worker.js +379 -0
- package/dist/workers/buffer-player-processor-202602.lavv8e32-ts.js +1 -0
- package/dist/workers/daw-stem-processor.js +228 -0
- package/dist/workers/manifest.json +10 -0
- package/dist/workers/phase-vocoder3.js +920 -0
- package/dist/workers/realtime-pitch-shift-processor.js +2 -0
- package/package.json +151 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/dropped-mix-ids.ts","../src/services/fetchMix.tsx","../src/daw/services/track-search-api.ts"],"names":[],"mappings":"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","file":"chunk-56PWIP7O.js","sourcesContent":["/**\n * List of mix IDs that should be dropped when resolving next mix.\n * This is a separate file to avoid pulling in the hardcode-hot-mixes JSON files\n * which are only used by internal mix-list components.\n */\nexport const NEXT_MIX_ID_DROPPED_ON_RESOLVING_NEXT_MIX: string[] = [];\n\n// export const NEXT_MIX_ID_DROPPED_ON_RESOLVING_NEXT_MIX = ['00000006-0dce-4d4b-8499-9621c1462b3c'];\n","// @ts-nocheck\n// Legacy mix/station GraphQL helpers still used by the DAW; main player uses fetchStationTracks / station-track URLs.\nimport { SAVE_REMOTE_M3U8_AAC_TO_LOCAL, COVER_REMIXES_WHEN_SAVE_TO_LOCAL, PRINT_CURL_COMMAND_ON_SOURCE_FILE_ONLY } from \"@/components/prototype-panel-v2\";\nimport { calculateTempoOrigSzFromBeatDownBeat, resolveMultipleBeatsAndKeysWithBeatsLink } from \"./fetchFeature\";\nimport { /*IStems,*/ ITrackForSequence } from \"@/stem-audio-engine-v3/interface\";\nimport { SAMPLE_RATE, AEV3Controller } from \"@/stem-audio-engine-v3/global-aev3-controller\";\nimport { calculateQuantisedTrackActualDurationFromBeatGrid, getFullDurationFromBeatsLinkSegmentInfo, getDurationFromBeatsLinkUpToLastDownbeat0 } from \"./track-resolvers\";\nimport { AEV3Config } from \"@/stem-audio-engine-v3/aev3-env-config\";\nimport { useCurrentMixJsonStore } from \"@/stem-audio-engine-v3/store/use-current-mix-json-store\";\nimport { NEXT_MIX_ID_DROPPED_ON_RESOLVING_NEXT_MIX } from \"./dropped-mix-ids\";\nimport { replaceMp4ForLocalUse } from \"@/stem-audio-engine-v3/utils/mp4-local-utils\";\n\n// NOTE no slash at last character of VITE_KB_STEMIFY_API_URL\nconst TRACK_CREATOR_ENDPOINT = `${import.meta.env?.VITE_KB_STEMIFY_API_URL || 'https://api.stemplayer.com'}/track-creator`;\nconst LOGIN_LINK = `${import.meta.env?.VITE_KB_STEMIFY_API_URL || 'https://api.stemplayer.com'}/accounts/user/login`;\n// const LOGIN_LINK = 'https://api.staging.stemplayer.com/accounts/user/signup-limited';\n\n// make it test_playback_2/v1\nconst APPLY_HACK_ON_THE_QUANTISED_WAV_FILE_PATH = false;\n\n// already aligning with what platform using, enforced at resolveSingleBeatsAndKeysWithBeatsLink\nconst APPLY_BEAT_GRID_SMOOTHING = true;\nlet FETCH_MIX_CONSOLE_TIME = '';\n\n// Shared GraphQL fragments to avoid duplication\nconst TRACK_ITEM_FRAGMENT = `fragment TrackItem on Track {\n artistDisplayName\n colors\n name\n trackId\n trackMixType\n trackStatus\n isClaimed\n duration\n artwork: image\n artworkGlowColor\n url: url(codec: aac, container: mp4, profile: raw)\n stems {\n aac: url(codec: aac)\n hls: url(codec: hls)\n wav: url(codec: wav)\n mp3: url(codec: mp3)\n stemId\n stemPosition\n }\n}`;\n\nconst MIX_ITEM_FRAGMENT = `fragment MixItem on Mix {\n mixId\n name\n colors\n mixPosition\n tracks {\n ...TrackItem\n }\n popularSelectedStems {\n vocals\n other\n drums\n bass\n }\n}`;\n\nconst _FM_log: typeof console.log = (...data) => {\n return;\n console.log(...data);\n}\n\nconst _FM_log_table: typeof console.table = (...data) => {\n return;\n console.table(...data);\n}\n\nexport const login = async () => {\n const loginUrl = LOGIN_LINK;\n\n try {\n const cachedToken = localStorage.getItem('accessToken');\n const tokenExpiry = localStorage.getItem('tokenExpiry');\n\n if (cachedToken && tokenExpiry && new Date().getTime() < parseInt(tokenExpiry, 10)) {\n const cachedTokenObj = JSON.parse(cachedToken);\n _FM_log('Using cached access token:', cachedTokenObj.accessToken.value);\n return cachedTokenObj.accessToken.value;\n }\n\n let loginPayload: { email: string, password: string };\n try {\n const username = import.meta.env?.VITE_STEM_API_USERNAME;\n const password = import.meta.env?.VITE_STEM_API_PASSWORD;\n if (!username || !password) {\n throw new Error('Username or password not found in environment variables');\n }\n loginPayload = {\n email: username,\n password: password,\n };\n } catch (error) {\n _FM_log(error);\n throw new Error('Username or password not found');\n }\n\n _FM_log('Starting login request...');\n const loginResponse = await fetch(loginUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(loginPayload),\n });\n\n if (!loginResponse.ok) {\n throw new Error('Login failed');\n }\n\n const loginData = await loginResponse.json();\n const accessTokenObj = loginData.data;\n const expiryTime = new Date().getTime() + (20 * 60 * 1000); // Token valid for 20 minutes\n _FM_log('Login successful. Access token:', accessTokenObj.accessToken.value);\n\n localStorage.setItem('accessToken', JSON.stringify(accessTokenObj));\n localStorage.setItem('tokenExpiry', expiryTime.toString());\n\n return accessTokenObj.accessToken.value;\n } catch (error) {\n console.error('Error during login or fetching mix data:', error.message);\n return null;\n }\n};\n\n\nexport const getMixMetadata = async (authToken: string, mixId: string, stationId: string, smoothBeats: boolean = APPLY_BEAT_GRID_SMOOTHING, abortController?: AbortController) => {\n const query = `query GetMix($id: ID!) {\n mix(id: $id) {\n ...MixItem\n }\n}\n\n${TRACK_ITEM_FRAGMENT}\n\n${MIX_ITEM_FRAGMENT}`;\n\n const variables = {\"id\":mixId};\n const queryParams = new URLSearchParams({\n query: query.trim(),\n variables: JSON.stringify(variables),\n operationName: 'GetMix'\n });\n const url = `${TRACK_CREATOR_ENDPOINT}/graphql?${queryParams.toString()}`;\n const headers = {\n Authorization: `Bearer ${authToken}`,\n };\n\n // FETCH_MIX_CONSOLE_TIME = `Getting mix details... ${stationId}/${mixId}`;\n // console.time(FETCH_MIX_CONSOLE_TIME);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: abortController?.signal,\n });\n\n \n const responseData = await response.json();\n // console.timeEnd(FETCH_MIX_CONSOLE_TIME);\n if (response.ok) {\n _FM_log('Successfully fetched the mix details.');\n _FM_log(responseData);\n\n if (!responseData?.data?.mix) {\n console.error('Mix not found or returned null for this ID');\n return null;\n }\n\n responseData.data.mix.remixes = [];\n\n // if (CREATE_UNQUANTISE_MP3_AS_HLS_AAC){\n // downloadAudioStemsUnquantiseMP3ToLocalAndConvertToAAC(responseData);\n // }\n\n // if (CREATE_QUANTISED_WAV_AS_HLS_AAC){\n // downloadAudioStemsQuantiseWAVToLocalAndConvertToAAC(responseData);\n // }\n\n // if (SAVE_REMOTE_M3U8_AAC_TO_LOCAL) {\n // downloadAudioStemsM3U8AndAACToLocal(responseData);\n // }\n\n const trackIds: {id: string, url: string}[] = responseData.data.mix.tracks.map((t)=>{\n return {id: t.trackId, url: t.url}\n });\n const trackIds2: {id: string, url: string}[] = responseData.data.mix.remixes?.length > 0 ? \n responseData.data.mix.remixes[0].tracksmap((t)=>{\n return {id: t.trackId, url: t.url}\n }) : [];\n const tracks = removeDuplicatesById([...trackIds, ...trackIds2]);\n\n // disable this before knowning what beats it return (madmom or beat this)\n const trackBeatsCollection2 = await resolveMultipleBeatsAndKeysWithBeatsLink(tracks, authToken, smoothBeats, window.$currentBeatGridVersion);\n \n // update the return\n responseData.data.mix.tracks.map((t)=>{\n const m_t: ITrackForSequence = (t);\n if (trackBeatsCollection2.data[t.trackId]) {\n replaceMp4Url(m_t);\n addBeatsRelatedParam(m_t, trackBeatsCollection2.data[t.trackId]);\n // m_t.url = `https://d3aj9yujg8n59a.cloudfront.net/tracks/${t.trackId}/96k/track.mp4`;\n m_t.__falseTrack = false;\n m_t.__durationForValidation1 = getFullDurationFromBeatsLinkSegmentInfo(m_t.segmentInfo);\n m_t.__durationForValidation2 = getDurationFromBeatsLinkUpToLastDownbeat0(-1, m_t.beats);\n } else {\n m_t.__falseTrack = true;\n m_t.__durationForValidation1 = 0;\n m_t.__durationForValidation2 = 0;\n // throw Error('Error resolving beats for track');\n }\n // if (m_t.trackId === '02c017e2-bdee-447e-a16f-e84725cc3c90') {\n // debugger;\n // }\n return m_t;\n });\n return responseData;\n } else {\n console.error(`Failed to fetch mix details. ${FETCH_MIX_CONSOLE_TIME}`);\n return null;\n }\n } catch (e) {\n console.timeEnd(FETCH_MIX_CONSOLE_TIME);\n console.error(`Error during mix detail retrieval: ${e}`);\n return null;\n }\n}\n\n// take in optional currentMixPosition, when next mix query failed to work\n// mixPosition will be used as fallback...\nexport const getNextMixMetadata = async (authToken: string, mixId: string, stationId: string, direction: 'prevMixId'|'nextMixId', currentMixPosition: number = -1, smoothBeats: boolean = APPLY_BEAT_GRID_SMOOTHING, abortController?: AbortController) => {\n const query = `query MixesToPlay($id: [ID]!, $first: Int, $afterId: ID, $sort: Sort) {\n stations(ids: $id) {\n stationId\n lastModified\n mixCount\n mixes(first: $first, afterId: $afterId, sort: $sort) {\n ...MixItem\n mixPosition\n }\n }\n}\n\n${TRACK_ITEM_FRAGMENT}\n\n${MIX_ITEM_FRAGMENT}`;\n\n const queryArtist = `query MixesToPlay($id: [ID]!, $first: Int, $afterId: ID) {\n stations: libraryArtists(ids: $id) {\n artist {\n artistId\n stationId: artistId\n }\n lastModified\n mixCount\n mixes(first: $first, afterId: $afterId) {\n ...MixItem\n mixPosition\n }\n }\n}\n\n${TRACK_ITEM_FRAGMENT}\n\n${MIX_ITEM_FRAGMENT}`;\n\n const variables = {\"afterId\":mixId,\"id\":[stationId],\"first\": 3, \"sort\": (direction==='nextMixId' ? 'asc': 'desc')};\n const queryParams = new URLSearchParams({\n query: isStationIdLibraryArtistStation(stationId) ? queryArtist.trim() : query.trim(),\n variables: JSON.stringify(variables),\n operationName: 'MixesToPlay'\n });\n const url = `${TRACK_CREATOR_ENDPOINT}/graphql?${queryParams.toString()}`;\n const headers = {\n Authorization: `Bearer ${authToken}`,\n };\n\n FETCH_MIX_CONSOLE_TIME = `Getting mix details... ${stationId}/${mixId}`;\n // console.time(FETCH_MIX_CONSOLE_TIME);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: abortController?.signal,\n });\n\n \n const responseData = await response.json();\n\n _FM_log('%cnext mix json', 'color: magenta', responseData);\n // console.timeEnd(FETCH_MIX_CONSOLE_TIME);\n if (response.ok || \n (responseData.data?.stations?.[0]?.mixes && responseData.data?.stations?.[0]?.mixes?.length === 0)\n ) {\n _FM_log('Successfully fetched the mix details.');\n _FM_log(responseData);\n \n // debugger;\n // if (responseData.data.stations?.[0].mix.tracks.filter((t)=>['mix', 'seed'].includes(t.trackMixType) && t.__falseTrack).length > 0) {\n // _FM_log(responseData.data)\n // throw Error('this mix does not contain re-processed audio file');\n // }\n\n responseData.data?.stations?.[0]?.mixes.forEach((m)=>m.remixes = []);\n\n // if (CREATE_UNQUANTISE_MP3_AS_HLS_AAC){\n // downloadAudioStemsUnquantiseMP3ToLocalAndConvertToAAC(responseData);\n // }\n\n // if (CREATE_QUANTISED_WAV_AS_HLS_AAC){\n // downloadAudioStemsQuantiseWAVToLocalAndConvertToAAC(responseData);\n // }\n\n // if (SAVE_REMOTE_M3U8_AAC_TO_LOCAL) {\n // downloadAudioStemsM3U8AndAACToLocal(responseData);\n // }\n\n const trackIds: {id: string, url: string}[] = responseData.data?.stations?.[0]?.mixes.map((m)=>m.tracks.map((t)=>{\n return {id: t.trackId, url: t.url}\n }));\n // const trackIds2 = [];\n // const trackIds2 = responseData.data.mix.remixes?.length > 0 ? \n // responseData.data.mix.remixes[0].tracks.map((t)=>(t.trackId)) : \n // [];\n const tracks = removeDuplicatesById([...trackIds].flat(Infinity));\n \n // disable this before knowning what beats it return (madmom or beat this)\n const trackBeatsCollection2 = await resolveMultipleBeatsAndKeysWithBeatsLink(tracks, authToken, smoothBeats, window.$currentBeatGridVersion);\n \n // update the return\n responseData.data?.stations?.[0]?.mixes.forEach((m)=>m.tracks.map((t)=>{\n const m_t: ITrackForSequence = (t);\n if (trackBeatsCollection2.data[t.trackId]) {\n replaceMp4Url(m_t);\n addBeatsRelatedParam(m_t, trackBeatsCollection2.data[t.trackId]);\n // m_t.url = `https://d3aj9yujg8n59a.cloudfront.net/tracks/${t.trackId}/96k/track.mp4`;\n m_t.__falseTrack = false;\n m_t.__durationForValidation1 = getFullDurationFromBeatsLinkSegmentInfo(m_t.segmentInfo);\n m_t.__durationForValidation2 = getDurationFromBeatsLinkUpToLastDownbeat0(-1, m_t.beats);\n } else {\n m_t.__falseTrack = true;\n m_t.__durationForValidation1 = 0;\n m_t.__durationForValidation2 = 0;\n // throw Error('Error resolving beats for track');\n }\n // if (m_t.trackId === '02c017e2-bdee-447e-a16f-e84725cc3c90') {\n // debugger;\n // }\n return m_t;\n }));\n\n // fall back for library artist on stationId\n if (!responseData.data?.stations?.[0]?.stationId){\n if (responseData.data?.stations?.[0]?.artist?.stationId) {\n responseData.data.stations[0].stationId = responseData.data?.stations?.[0]?.artist?.stationId;\n } else {\n responseData.data.stations[0].stationId = '';\n }\n }\n\n // _FM_log(responseData)\n const stationMixCount = responseData.data?.stations?.[0]?.mixCount || 0;\n const mixesLength = responseData.data?.stations?.[0]?.mixes?.length;\n _FM_log_table({\n id: 'autoplay',\n stationId,\n mixId,\n currentMixPosition,\n stationMixCount,\n mixesLength,\n 'isNaN(currentMixPosition*1)': isNaN(currentMixPosition*1),\n });\n \n if (responseData.data?.stations?.[0]?.mixes?.length === 0\n || NEXT_MIX_ID_DROPPED_ON_RESOLVING_NEXT_MIX.includes(responseData.data?.stations?.[0]?.mixes?.[0]?.mixId)\n ) {\n // looks like platform hook can resolve this mixPosition as string\n if (isNaN(currentMixPosition*1)){\n // if there is no currentMixPosition, get the first mix directly\n return getFirstOrLastMixMetadata(authToken, stationId, direction, smoothBeats);\n } else {\n if (currentMixPosition + 1 < stationMixCount) {\n // try resolve next 3 mixes based on current mixPosition + 1\n return getMixesAfterNMetadata(authToken, stationId, direction, currentMixPosition+1, smoothBeats);\n } else {\n // can see if it is last mix of the station\n return getFirstOrLastMixMetadata(authToken, stationId, direction, smoothBeats);\n }\n }\n }\n\n return responseData;\n } else {\n console.error(`Failed to fetch mix details. ${FETCH_MIX_CONSOLE_TIME}`);\n return null;\n }\n } catch (e) {\n // console.timeEnd(FETCH_MIX_CONSOLE_TIME);\n console.error(`Error during mix detail retrieval: ${e}`);\n return null;\n }\n}\n\nexport const getFirstOrLastMixMetadata = async (authToken: string, stationId: string, direction: 'prevMixId'|'nextMixId', smoothBeats: boolean = APPLY_BEAT_GRID_SMOOTHING, abortController?: AbortController) => {\n _FM_log(`getFirstOrLastMixMetadata(${stationId}), ${direction}`);\n \n return getMixesAfterNMetadata(authToken, stationId, direction, 0, smoothBeats, abortController);\n}\n\nexport const getMixesAfterNMetadata = async (authToken: string, stationId: string, direction: 'prevMixId'|'nextMixId', mixPosition: number = 0, smoothBeats: boolean = APPLY_BEAT_GRID_SMOOTHING, abortController?: AbortController) => {\n _FM_log(`getFirstOrLastMixMetadata(${stationId}), ${direction}`);\n \n const query = `query MixesToPlay($id: [ID]!, $first: Int, $after: Int, $sort: Sort) {\n stations(ids: $id) {\n stationId\n lastModified\n mixCount\n mixes(first: $first, after: $after, sort: $sort) {\n ...MixItem\n mixPosition\n }\n }\n}\n\n${TRACK_ITEM_FRAGMENT}\n\n${MIX_ITEM_FRAGMENT}`;\n\n const queryArtist = `query MixesToPlay($id: [ID]!, $first: Int, $after: Int) {\n stations: libraryArtists(ids: $id) {\n artist {\n artistId\n stationId: artistId\n }\n lastModified\n mixCount\n mixes(first: $first, after: $after) {\n ...MixItem\n mixPosition\n }\n }\n}\n\n${TRACK_ITEM_FRAGMENT}\n\n${MIX_ITEM_FRAGMENT}`;\n\n const variables = {\"after\":mixPosition,\"id\":[stationId],\"first\": 3, \"sort\": (direction==='nextMixId' ? 'asc': 'desc')};\n const queryParams = new URLSearchParams({\n query: isStationIdLibraryArtistStation(stationId) ? queryArtist.trim() : query.trim(),\n variables: JSON.stringify(variables),\n operationName: 'MixesToPlay'\n });\n const url = `${TRACK_CREATOR_ENDPOINT}/graphql?${queryParams.toString()}`;\n const headers = {\n Authorization: `Bearer ${authToken}`,\n };\n\n FETCH_MIX_CONSOLE_TIME = `Getting mix details... ${stationId}/first_item}`;\n // console.time(FETCH_MIX_CONSOLE_TIME);\n\n try {\n const response = await fetch(url, {\n method: 'GET',\n headers,\n signal: abortController?.signal,\n });\n\n \n const responseData = await response.json();\n\n _FM_log('%cnext mix json', 'color: magenta', responseData);\n // console.timeEnd(FETCH_MIX_CONSOLE_TIME);\n if (response.ok || \n (responseData.data?.stations?.[0]?.mixes && responseData.data?.stations?.[0]?.mixes?.length === 0)\n ) {\n _FM_log('Successfully fetched the mix details.');\n _FM_log(responseData);\n \n // debugger;\n // if (responseData.data.stations?.[0].mix.tracks.filter((t)=>['mix', 'seed'].includes(t.trackMixType) && t.__falseTrack).length > 0) {\n // _FM_log(responseData.data)\n // throw Error('this mix does not contain re-processed audio file');\n // }\n\n responseData.data?.stations?.[0]?.mixes.forEach((m)=>m.remixes = []);\n\n // if (CREATE_UNQUANTISE_MP3_AS_HLS_AAC){\n // downloadAudioStemsUnquantiseMP3ToLocalAndConvertToAAC(responseData);\n // }\n\n // if (CREATE_QUANTISED_WAV_AS_HLS_AAC){\n // downloadAudioStemsQuantiseWAVToLocalAndConvertToAAC(responseData);\n // }\n\n // if (SAVE_REMOTE_M3U8_AAC_TO_LOCAL) {\n // downloadAudioStemsM3U8AndAACToLocal(responseData);\n // }\n\n const trackIds: {id: string, url: string}[] = responseData.data?.stations?.[0]?.mixes.map((m)=>m.tracks.map((t)=>{\n return {id: t.trackId, url: t.url}\n }));\n // const trackIds2 = [];\n // const trackIds2 = responseData.data.mix.remixes?.length > 0 ? \n // responseData.data.mix.remixes[0].tracks.map((t)=>(t.trackId)) : \n // [];\n const tracks = removeDuplicatesById([...trackIds].flat(Infinity));\n\n // disable this before knowning what beats it return (madmom or beat this)\n const trackBeatsCollection2 = await resolveMultipleBeatsAndKeysWithBeatsLink(tracks, authToken, smoothBeats, window.$currentBeatGridVersion);\n \n // update the return\n responseData.data?.stations?.[0]?.mixes.forEach((m)=>m.tracks.map((t)=>{\n const m_t: ITrackForSequence = (t);\n if (trackBeatsCollection2.data[t.trackId]) {\n replaceMp4Url(m_t);\n addBeatsRelatedParam(m_t, trackBeatsCollection2.data[t.trackId]);\n // m_t.url = `https://d3aj9yujg8n59a.cloudfront.net/tracks/${t.trackId}/96k/track.mp4`;\n m_t.__falseTrack = false;\n m_t.__durationForValidation1 = getFullDurationFromBeatsLinkSegmentInfo(m_t.segmentInfo);\n m_t.__durationForValidation2 = getDurationFromBeatsLinkUpToLastDownbeat0(-1, m_t.beats);\n } else {\n m_t.__falseTrack = true;\n m_t.__durationForValidation1 = 0;\n m_t.__durationForValidation2 = 0;\n // throw Error('Error resolving beats for track');\n }\n // if (m_t.trackId === '02c017e2-bdee-447e-a16f-e84725cc3c90') {\n // debugger;\n // }\n return m_t;\n }));\n\n // fall back for library artist on stationId\n if (!responseData.data?.stations?.[0]?.stationId){\n if (responseData.data?.stations?.[0]?.artist?.stationId) {\n responseData.data.stations[0].stationId = responseData.data?.stations?.[0]?.artist?.stationId;\n } else {\n responseData.data.stations[0].stationId = '';\n }\n } \n\n return responseData;\n } else {\n console.error(`Failed to fetch mix details. ${FETCH_MIX_CONSOLE_TIME}`);\n return null;\n }\n } catch (e) {\n console.timeEnd(FETCH_MIX_CONSOLE_TIME);\n console.error(`Error during mix detail retrieval: ${e}`);\n return null;\n }\n}\n\n/**\n * This Util function is only for prototype page - It will try to do following:\n * 1) Login with the .env info\n * 2) Fetch the Mix Object and Resolve the BeatGrids with getMixMetadata\n * \n * @param url \n * @param smoothBeats \n * @returns \n */\nexport const extractMixIdVer2 = (url:string): string | null => {\n _FM_log(url);\n // Define the regular expression pattern\n const pattern = /^https?:\\/\\/[^/]+\\/(?:set|artist)\\/([^/]+)\\/mix\\/([^/?#]+)(?:\\/|$|\\?)/i;\n\n // Use the match method to apply the regex to the URL\n const match = url.match(pattern);\n\n if (match) {\n // Extract the value from the capturing group\n const mixValue = match[2];\n _FM_log(`Extracted value: ${mixValue}`);\n return mixValue;\n } else {\n _FM_log(\"No match found.\");\n }\n}\n\nexport const extractStationIdVer2 = (url:string): string | null => {\n _FM_log(url);\n // Define the regular expression pattern\n const pattern = /^https?:\\/\\/[^/]+\\/(?:set|artist)\\/([^/]+)\\/mix\\/([^/?#]+)(?:\\/|$|\\?)/i;\n\n // Use the match method to apply the regex to the URL\n const match = url.match(pattern);\n\n if (match) {\n // Extract the value from the capturing group\n const mixValue = match[1];\n _FM_log(`Extracted value: ${mixValue}`);\n return mixValue;\n } else {\n _FM_log(\"No match found.\");\n }\n}\n\nexport const fetchMixDataWithSharedURL = async (url: string, smoothBeats: boolean = APPLY_BEAT_GRID_SMOOTHING, abortController?: AbortController) => {\n \n if (!url) {\n _FM_log('empty');\n return;\n }\n \n const mixId = extractMixIdVer2(url);\n const stationId = extractStationIdVer2(url);\n if (mixId) {\n const token = await login();\n // console.log(token);\n AEV3Config.getInstance().setAccessToken(token);\n if (token) {\n // console.log(token)\n _FM_log(mixId);\n const fetchedData = await getMixMetadata(token, mixId, stationId, smoothBeats, abortController);\n // const data2 = await getNextMixMetadata(token, mixId, stationId, 'asc', smoothBeats);\n // _FM_log(data2);\n // debugger;\n if (fetchedData) {\n return JSON.stringify(fetchedData);\n } else {\n console.error('Failed to fetch mix data');\n }\n }\n } else {\n console.error('Invalid URL or mixId not found');\n }\n};\n\n/**\n * Loads a mix from JSON data and sets it as the current track in the audio engine.\n * This is a shared utility function that can be used by mix list components and other UI components.\n * \n * @param mixJsonString - The JSON string containing the mix data\n * @param mixURL - The URL of the mix (used to extract station ID)\n */\nexport const loadMixFromJsonForPrototype = (mixJsonString: string, mixURL: string): void => {\n try {\n const mixObject = JSON.parse(mixJsonString);\n \n if (!mixObject?.data?.mix) {\n console.error('[loadMixFromJsonForPrototype] Invalid mix object structure:', mixObject);\n throw new Error('Invalid mix object structure');\n }\n \n // Store the mix JSON in Zustand store\n // This allows components to reactively update when a mix is loaded\n useCurrentMixJsonStore.getState().setMixJson(mixJsonString, mixURL);\n \n // Preload seed track\n const seedTrack: ITrackForSequence = mixObject?.data?.mix?.tracks?.filter((t) => t.trackMixType === 'seed')?.[0];\n if (seedTrack) {\n replaceMp4Url(seedTrack);\n const triggerLoadingOfHLS = false;\n AEV3Controller.getInstance().setCurrentSeedTrackObject(seedTrack, 'seed1', triggerLoadingOfHLS);\n } else {\n console.warn('[loadMixFromJsonForPrototype] No seed track found');\n }\n \n // Preload mix track\n const mixTrack: ITrackForSequence = mixObject?.data?.mix?.tracks?.filter((t) => t.trackMixType === 'mix')?.[0];\n if (mixTrack) {\n replaceMp4Url(mixTrack);\n const triggerLoadingOfHLS = false;\n const triggerFromTransition = false;\n AEV3Controller.getInstance().setCurrentMixTrackObject(mixTrack, 'mix1', triggerLoadingOfHLS, triggerFromTransition);\n } else {\n console.warn('[loadMixFromJsonForPrototype] No mix track found');\n }\n \n // Assign optional parameters\n const mixId = mixObject?.data?.mix?.mixId;\n const stationId = extractStationIdFromUrl(mixURL);\n if (mixId) {\n AEV3Controller.getInstance().setCurrentTrackOptionalParam({\n mixId,\n nextMixId: undefined,\n stationId,\n prevMixId: undefined\n });\n } else {\n console.warn('[loadMixFromJsonForPrototype] No mixId found');\n }\n \n } catch (error) {\n console.error('[loadMixFromJsonForPrototype] Error loading mix from JSON:', error);\n throw error;\n }\n};\n\n\nexport const downloadAudioStemsQuantiseWAVToLocalAndConvertToAAC = (data) => {\n const field: 'hls' | 'mp3' | 'wav' = 'wav';\n const convertAsAAC = true;\n\n let stemsObj = [];\n // data.data.mix.tracks.filter((t)=>t.stems.filter((s)=>s.hls!==null).length>0)\n \n let stems = data.data.mix.tracks.map((t)=>(t.stems));\n stems = stems.flat(Infinity);\n\n stems.forEach((s)=>{\n stemsObj = [...stemsObj, s];\n });\n\n\n if (COVER_REMIXES_WHEN_SAVE_TO_LOCAL) {\n // _FM_log(stems);\n // debugger;\n\n stems = data.data.mix.remixes.map((r)=>(r.tracks.map((t)=>(t.stems))));\n stems = stems.flat(Infinity);\n\n // _FM_log(stems);\n // debugger;\n\n stems.forEach((s)=>{\n stemsObj = [...stemsObj, s];\n });\n }\n\n const mp3s = new Set(stemsObj.map((m)=>m[field]));\n _FM_log(mp3s);\n // debugger;\n\n mp3s.forEach((mp3)=>{\n if (!mp3) return;\n const {target_name, source_extension} = parseLocalFilePath(mp3, field);\n // const target_name = filepath[filepath.length-2] +'_'+ filepath[filepath.length-1]\n const payload = {\n url: mp3, // Replace this with your target URL\n target_name: target_name, // The name of the folder you want to save the file in\n source_extension,\n convertAsAAC,\n };\n fetchAndSave(payload);\n });\n}\n\nexport const downloadAudioStemsUnquantiseMP3ToLocalAndConvertToAAC = ( data ) => {\n\n const field: 'hls' | 'mp3' | 'wav' = 'mp3';\n const convertAsAAC = true;\n\n let stemsObj = [];\n // data.data.mix.tracks.filter((t)=>t.stems.filter((s)=>s.hls!==null).length>0)\n \n let stems = data.data.mix.tracks.map((t)=>(t.stems));\n stems = stems.flat(Infinity);\n\n stems.forEach((s)=>{\n stemsObj = [...stemsObj, s];\n });\n\n\n if (COVER_REMIXES_WHEN_SAVE_TO_LOCAL) {\n // _FM_log(stems);\n // debugger;\n\n stems = data.data.mix.remixes.map((r)=>(r.tracks.map((t)=>(t.stems))));\n stems = stems.flat(Infinity);\n\n // _FM_log(stems);\n // debugger;\n\n stems.forEach((s)=>{\n stemsObj = [...stemsObj, s];\n });\n }\n \n const mp3s = new Set(stemsObj.map((m)=>m[field]));\n _FM_log(mp3s);\n // debugger;\n\n mp3s.forEach((mp3)=>{\n if (!mp3) return;\n const {target_name, source_extension} = parseLocalFilePath(mp3, field);\n // const target_name = filepath[filepath.length-2] +'_'+ filepath[filepath.length-1]\n const payload = {\n url: mp3, // Replace this with your target URL\n target_name: target_name, // The name of the folder you want to save the file in\n source_extension,\n convertAsAAC,\n };\n fetchAndSave(payload);\n });\n}\n\nexport const downloadAudioStemsM3U8AndAACToLocal = ( data ) => {\n\n const field: 'hls' | 'mp3' | 'wav' = 'hls';\n const convertAsAAC = false;\n \n let stemsObj = [];\n // data.data.mix.tracks.filter((t)=>t.stems.filter((s)=>s.hls!==null).length>0)\n \n let stems = data.data.mix.tracks.map((t)=>(t.stems));\n stems = stems.flat(Infinity);\n\n stems.forEach((s)=>{\n stemsObj = [...stemsObj, s];\n });\n\n\n if (COVER_REMIXES_WHEN_SAVE_TO_LOCAL) {\n // _FM_log(stems);\n // debugger;\n\n stems = data.data.mix.remixes.map((r)=>(r.tracks.map((t)=>(t.stems))));\n stems = stems.flat(Infinity);\n\n // _FM_log(stems);\n // debugger;\n\n stems.forEach((s)=>{\n stemsObj = [...stemsObj, s];\n });\n }\n\n const mp3s = new Set(stemsObj.map((m)=>m[field]));\n _FM_log(mp3s);\n // debugger;\n\n mp3s.forEach((mp3)=>{\n if (!mp3) return;\n const {target_name, source_extension} = parseLocalFilePath(mp3, field);\n // const target_name = filepath[filepath.length-2] +'_'+ filepath[filepath.length-1]\n const payload = {\n url: mp3, // Replace this with your target URL\n target_name: target_name, // The name of the folder you want to save the file in\n source_extension,\n convertAsAAC,\n };\n fetchAndSave(payload);\n // const target_name = filepath[filepath.length-2] +'_'+ filepath[filepath.length-1]\n const payload2 = {\n url: mp3.replace('.m3u8', '.aac'), // Replace this with your target URL\n target_name: target_name, // The name of the folder you want to save the file in\n source_extension: 'aac',\n convertAsAAC,\n };\n fetchAndSave(payload2);\n });\n}\n\nconst fetchAndSave = (payload: {url: string, convertAsAAC: boolean, target_name: string, source_extension: string}) => {\n // Step 1: Define the URL of the Express endpoint and the payload\n // _FM_log(data.data.mix.tracks[0].stems[0].mp3);\n // return;\n const endpointUrl = 'http://localhost:3001/download';\n\n // _FM_log(payload);\n if (PRINT_CURL_COMMAND_ON_SOURCE_FILE_ONLY) {\n if (!SAVE_REMOTE_M3U8_AAC_TO_LOCAL) {\n // fetch the file and save as target_name\n _FM_log(`curl -v -o ${payload.target_name}.${payload.source_extension} ${payload.url}`);\n \n // ffmpeg command to convert the WAV once\n const ffmpegCommand0 = `ffmpeg -i \"${payload.target_name}.${payload.source_extension}\" -f wav -acodec pcm_s16le -ar 44100 -ac 2 \"${payload.target_name}_mod.${payload.source_extension}\"`;\n _FM_log(ffmpegCommand0);\n\n // ffmpeg command\n // const ffmpegCommand = `ffmpeg -i \"${payload.target_name}_mod.${payload.source_extension}\" -vn -ac 2 -map_metadata -1 -c:a aac -b:a 192k -f hls -hls_allow_cache 1 -hls_list_size 0 -hls_segment_type fmp4 -hls_time 2.048s -hls_segment_filename \"${payload.target_name}.aac\" -hls_flags +split_by_time+single_file \"${payload.target_name}.m3u8\"`;\n const ffmpegCommand = `ffmpeg -i \"${payload.target_name}_mod.${payload.source_extension}\" -vn -ac 2 -map_metadata -1 -c:a libfdk_aac -b:a 64k -f hls -hls_allow_cache 1 -hls_list_size 0 -hls_segment_type fmp4 -hls_time 2.048s -hls_segment_filename \"${payload.target_name}.aac\" -hls_flags +split_by_time+single_file \"${payload.target_name}.m3u8\"`;\n _FM_log(ffmpegCommand);\n } else {\n // fetch the file and save as target_name\n _FM_log(`curl -v -o ${payload.target_name}.${payload.source_extension} ${payload.url}`);\n }\n return;\n }\n\n // debugger;\n\n // Step 2: Make the POST request using fetch\n fetch(endpointUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify(payload)\n })\n .then(response => {\n _FM_log(response);\n })\n // .then(data => {\n // _FM_log('Success:', data);\n // })\n .catch(error => {\n console.error('Error:', error);\n });\n}\n\nexport const uniqueTrackIds = (ids: string[]): string[] => {\n const stringSet: Set<string> = new Set(ids);\n const stringArray: string[] = Array.from(stringSet);\n return stringArray;\n}\n\n// keeping the first appearence\nexport const removeDuplicatesById = (arr: {id: string, url: string | undefined | null}[]) => {\n const seen = new Set();\n return arr.filter(item => {\n if (seen.has(item.id)) {\n return false;\n }\n seen.add(item.id);\n return true;\n });\n}\n\n\nexport const modifyTrackSampleRateValues = (m_t) => {\n const DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE = 44100;\n m_t.tempoOrigSz = Math.ceil((m_t.tempoOrigSz/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n // m_t.tempoOrigSz_Unstable_Ver = Math.ceil((m_t.tempoOrigSz_Unstable_Ver/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n // m_t.tempoOrigSz_V1 = Math.ceil((m_t.tempoOrigSz_V1/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n // m_t.tempoOrigSz_V2 = Math.ceil((m_t.tempoOrigSz_V2/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n\n // m_t.tempoShiftSz = Math.ceil((m_t.tempoShiftSz/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n // m_t.tempoShiftSz_Unstable_Ver = Math.ceil((m_t.tempoShiftSz_Unstable_Ver/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n // m_t.tempoShiftSz_V1 = Math.ceil((m_t.tempoShiftSz_V1/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n // m_t.tempoShiftSz_V2 = Math.ceil((m_t.tempoShiftSz_V2/DO_NOT_CHANGE_ME_ITS_SERVER_PROVIDED_VALUE) * SAMPLE_RATE);\n \n return m_t;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst modifyTrackAndModifyStemUrls = (m_t: ITrackForSequence) => {\n const trackId = m_t.trackId;\n if (m_t.url) {\n // m_t.url = m_t.url.replace(\"https://d3aj9yujg8n59a.cloudfront.net/tracks/\", \"https://d3aj9yujg8n59a.cloudfront.net//tracks/\").replace(\"/track.mp4\", \"/experiment/track.mp4\");\n // m_t.url = m_t.url.replace(\"/96/\", \"/96k/\");\n // _FM_log(m_t.url);\n }\n\n m_t.stems = m_t.stems.map((s)=>{\n \n if (s.wav && APPLY_HACK_ON_THE_QUANTISED_WAV_FILE_PATH) {\n // hack it and replace with new quantised wav loc\n const _tmp = s.wav.split('/');\n const _stem_id = _tmp[_tmp.length-2];\n s.wav = s.wav.replace(_stem_id, trackId);\n s.wav = s.wav.replace('drums.wav', 'test_playback_3/v2/drums.wav');\n s.wav = s.wav.replace('bass.wav', 'test_playback_3/v2/bass.wav');\n s.wav = s.wav.replace('vocals.wav', 'test_playback_3/v2/vocals.wav');\n s.wav = s.wav.replace('other.wav', 'test_playback_3/v2/other.wav');\n }\n\n let result, path;\n \n result = parseLocalFilePath(s.mp3, 'mp3');\n if (result) {\n path = `http://localhost:3001/WEB_SCRAPING_FOLDER/${result.target_name}.m3u8`;\n s.local_hls_from_unquantise_mp3 = path;\n }\n\n result = parseLocalFilePath(s.wav, 'wav');\n if (result) {\n path = `http://localhost:3001/WEB_SCRAPING_FOLDER/${result.target_name}.m3u8`;\n s.local_hls_from_quantised_wav = path;\n }\n\n result = parseLocalFilePath(s.hls, 'hls');\n if (result) {\n path = `http://localhost:3001/WEB_SCRAPING_FOLDER/${result.target_name}.m3u8`;\n s.local_hls_from_remote_original_hls = path;\n }\n\n // _FM_log(s);\n // s.aac = 'tracks{trackID}/96k/track.mp4';\n // s.aac = `https://d3aj9yujg8n59a.cloudfront.net/tracks/${m_t.trackId}/96k/track.mp4`;\n s.aac = m_t.url;\n return s;\n });\n return m_t;\n}\n\nconst parseLocalFilePath = (url: string, field_name: string): {target_name: string, source_extension: string} => {\n if (!url) {\n // console.error(`source url ${url}`)\n return null\n };\n // _FM_log(url)\n const filepath = url.split('/');\n let indexOfStemId = filepath.length-2; // this could change if the path of source file is edited\n if (APPLY_HACK_ON_THE_QUANTISED_WAV_FILE_PATH) {\n indexOfStemId = filepath.length-4;\n }\n const _target_name = filepath[indexOfStemId] +'_'+ filepath[filepath.length-1];\n const _ex = _target_name.split('.');\n const source_extension = _ex[_ex.length-1];\n const target_name = _target_name.replace('.'+source_extension, '');\n const result = {target_name: target_name+'_source_from_'+field_name, source_extension}\n // _FM_log(result)\n return result;\n}\n\nexport const extractStationIdFromUrl = (url:string) => {\n // Define the regular expression pattern\n const pattern = /^https?:\\/\\/[^/]+\\/(?:set|artist)\\/([^/]+)\\/mix\\/([^/?#]+)(?:\\/|$|\\?)/i;\n\n // Use the match method to apply the regex to the URL\n const match = url.match(pattern);\n\n if (match) {\n // Extract the value from the capturing group\n return match[1];\n }\n return '';\n}\n\nexport const isStationIdLibraryArtistStation = (stationId: string) => {\n return stationId?.includes(\"00000014-\");\n}\n\nconst replaceMp4Url = (m_t) => {\n const mp4 = m_t.url;\n m_t.url = replaceMp4ForLocalUse(mp4);\n}\n\nconst addBeatsRelatedParam = (m_t, beats) => {\n m_t.beats = beats.beats;\n m_t.tempoOrigSz = calculateTempoOrigSzFromBeatDownBeat(m_t.beats.map((b)=>(b.timestamp)));\n m_t.duration = calculateQuantisedTrackActualDurationFromBeatGrid(-1, m_t.beats);\n m_t.indices = beats.indices;\n m_t.segmentInfo = beats.segmentInfo;\n m_t.key = beats.key;\n m_t.tonality = beats.tonality;\n m_t.beatSource = beats.beatSource;\n return m_t;\n}","/**\n * Track search & single-track loading for the DAW.\n *\n * Uses the same GraphQL endpoint as the streaming player but provides\n * a simplified interface for searching and loading individual tracks\n * (not full mixes).\n *\n * Also provides \"similar tracks\" from the same station (refresh-mix style)\n * for the suggested stems sidebar.\n */\n\nimport {\n login,\n getNextMixMetadata,\n getMixesAfterNMetadata,\n extractStationIdVer2,\n extractMixIdVer2,\n} from '@/services/fetchMix';\nimport {\n resolveSingleBeatsAndKeysWithBeatsLink,\n calculateTempoOrigSzFromBeatDownBeat,\n} from '@/services/fetchFeature';\nimport {\n calculateQuantisedTrackActualDurationFromBeatGrid,\n getFullDurationFromBeatsLinkSegmentInfo,\n getDurationFromBeatsLinkUpToLastDownbeat0,\n} from '@/services/track-resolvers';\nimport { replaceMp4ForLocalUse } from '@/stem-audio-engine-v3/utils/mp4-local-utils';\nimport { AEV3Config } from '@/stem-audio-engine-v3/aev3-env-config';\nimport { extractBareSessionStationId } from '@/services/fetchStationTracks';\nimport type { ITrackForSequence, IMusicKey, IMusicTonality } from '@/stem-audio-engine-v3/interface';\n\nconst API_BASE = import.meta.env?.VITE_KB_STEMIFY_API_URL || 'https://api.stemplayer.com';\nconst GQL_URL = `${API_BASE}/track-creator/graphql`;\nconst FEAT_API_URL = import.meta.env?.VITE_FEAT_API_URL || 'https://173i5juztg.execute-api.us-west-2.amazonaws.com';\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport type SimilarityMode = 'feature' | 'remix';\n\nexport const SIMILARITY_MODES: { id: SimilarityMode; label: string; description: string }[] = [\n { id: 'feature', label: 'Audio DNA', description: 'Audio fingerprint / text similarity' },\n { id: 'remix', label: 'Remix Match', description: 'Server-side key/BPM/feature matching' },\n];\n\nexport interface SearchResult {\n id: string;\n title: string;\n artist: string;\n artwork: string | null;\n artworkGlowColor: string | null;\n type: string;\n}\n\nexport interface TrackMusicalInfo {\n bpm: number;\n key: IMusicKey;\n tonality: IMusicTonality;\n}\n\nexport interface CompatibilityScore {\n bpmPct: number;\n keyScore: number;\n overall: number;\n camelotTag: string;\n bpmLabel: string;\n}\n\n// ── Camelot wheel ────────────────────────────────────────────────────\n\nconst CAMELOT_MAP: Record<string, string> = {\n 'A:minor': '8A', 'A:major': '11B',\n 'A#:minor': '3A', 'A#:major': '6B',\n 'B:minor': '10A', 'B:major': '1B',\n 'C:minor': '5A', 'C:major': '8B',\n 'C#:minor': '12A', 'C#:major': '3B',\n 'D:minor': '7A', 'D:major': '10B',\n 'D#:minor': '2A', 'D#:major': '5B',\n 'E:minor': '9A', 'E:major': '12B',\n 'F:minor': '4A', 'F:major': '7B',\n 'F#:minor': '11A', 'F#:major': '2B',\n 'G:minor': '6A', 'G:major': '9B',\n 'G#:minor': '1A', 'G#:major': '4B',\n};\n\nexport function getCamelotTag(key: IMusicKey, tonality: IMusicTonality): string {\n return CAMELOT_MAP[`${key}:${tonality}`] || `${key}${tonality === 'minor' ? 'm' : ''}`;\n}\n\nfunction parseCamelot(tag: string): { num: number; letter: string } | null {\n const m = tag.match(/^(\\d+)([AB])$/);\n if (!m) return null;\n return { num: parseInt(m[1], 10), letter: m[2] };\n}\n\n/**\n * Score key compatibility on 0–1 scale using Camelot wheel rules.\n * 1.0 = same position, 0.85 = adjacent (+1/-1 same letter, or A/B swap), 0.5 = two steps, 0.0 = far\n */\nfunction scoreKeyCompatibility(\n refKey: IMusicKey, refTonality: IMusicTonality,\n trackKey: IMusicKey, trackTonality: IMusicTonality,\n): number {\n const refTag = getCamelotTag(refKey, refTonality);\n const trkTag = getCamelotTag(trackKey, trackTonality);\n if (refTag === trkTag) return 1.0;\n\n const ref = parseCamelot(refTag);\n const trk = parseCamelot(trkTag);\n if (!ref || !trk) return 0;\n\n const numDist = Math.min(\n Math.abs(ref.num - trk.num),\n 12 - Math.abs(ref.num - trk.num),\n );\n\n if (numDist === 0 && ref.letter !== trk.letter) return 0.9;\n if (numDist === 1 && ref.letter === trk.letter) return 0.85;\n if (numDist === 1 && ref.letter !== trk.letter) return 0.7;\n if (numDist === 2 && ref.letter === trk.letter) return 0.5;\n return Math.max(0, 0.4 - numDist * 0.05);\n}\n\n/**\n * Score BPM compatibility on 0–1 scale. Handles half/double time.\n * 1.0 = exact match, scales down linearly, 0 at >=15% difference.\n */\nfunction scoreBpmCompatibility(refBpm: number, trackBpm: number): { score: number; ratio: string } {\n const candidates = [trackBpm, trackBpm * 2, trackBpm / 2];\n let bestPct = Infinity;\n let bestLabel = '1x';\n for (const bpm of candidates) {\n const pct = Math.abs(bpm - refBpm) / refBpm;\n if (pct < bestPct) {\n bestPct = pct;\n bestLabel = bpm === trackBpm ? '1x' : bpm > trackBpm ? '2x' : '½x';\n }\n }\n const score = Math.max(0, 1 - bestPct / 0.15);\n return { score, ratio: bestLabel };\n}\n\nexport function computeCompatibility(\n ref: TrackMusicalInfo,\n track: TrackMusicalInfo,\n): CompatibilityScore {\n const keyScore = scoreKeyCompatibility(ref.key, ref.tonality, track.key, track.tonality);\n const { score: bpmScore, ratio } = scoreBpmCompatibility(ref.bpm, track.bpm);\n const bpmPct = Math.round((1 - Math.abs(ref.bpm - track.bpm) / ref.bpm) * 100);\n const overall = keyScore * 0.5 + bpmScore * 0.5;\n\n return {\n bpmPct,\n keyScore: Math.round(keyScore * 100),\n overall: Math.round(overall * 100),\n camelotTag: getCamelotTag(track.key, track.tonality),\n bpmLabel: `${Math.round(track.bpm)} ${ratio !== '1x' ? `(${ratio})` : ''}`.trim(),\n };\n}\n\n// ── Lightweight beats fetch (BPM/key + segmentInfo) ─────────────────\n\n/**\n * Cached slice of the `/beats` response. The endpoint already returns\n * `segmentInfo` alongside bpm/key/tonality, so we capture both in the\n * same trip — every row we compat-enrich becomes free chorus metadata\n * for the hover preview controller without a second network hop.\n *\n * Kept as a single internal record (rather than two parallel maps) so\n * the cache key story stays simple: one trackId → one resolved beats\n * blob, atomically populated.\n */\ninterface CachedBeats {\n info: TrackMusicalInfo;\n /** Raw `[start, end, type][]` triples; type 9 == CHORUS. */\n segmentInfo: [number, number, number][];\n /** Track duration in seconds, when the endpoint exposed it. */\n durationSec: number | null;\n}\n\nconst beatsCache = new Map<string, CachedBeats>();\n\nasync function fetchBeatsRaw(trackId: string): Promise<CachedBeats | null> {\n const cached = beatsCache.get(trackId);\n if (cached) return cached;\n\n try {\n const token = await getToken();\n const url = `${API_BASE}/track-creator/tracks/${trackId}/beats?min_bars=16`;\n const res = await fetch(url, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return null;\n const json = await res.json();\n const d = json?.data;\n if (!d?.bpm || !d?.key) return null;\n const segments = Array.isArray(d.segmentInfo) ? d.segmentInfo as [number, number, number][] : [];\n const durationSec = typeof d.duration === 'number'\n ? d.duration\n : (segments.length > 0 ? segments[segments.length - 1][1] : null);\n const record: CachedBeats = {\n info: { bpm: d.bpm, key: d.key, tonality: d.tonality || 'minor' },\n segmentInfo: segments,\n durationSec,\n };\n beatsCache.set(trackId, record);\n return record;\n } catch {\n return null;\n }\n}\n\nexport async function fetchTrackMusicalInfo(trackId: string): Promise<TrackMusicalInfo | null> {\n const record = await fetchBeatsRaw(trackId);\n return record ? record.info : null;\n}\n\n/**\n * Read-through accessor for the segment + duration metadata captured\n * alongside bpm/key. Returns `null` if the beats endpoint hasn't yet\n * resolved for this track; callers (e.g. the song-preview controller)\n * should either await `fetchTrackMusicalInfo` first or treat `null`\n * as \"fall back to a default preview offset\".\n */\nexport async function fetchTrackSegmentInfo(\n trackId: string,\n): Promise<{ segmentInfo: [number, number, number][]; durationSec: number | null } | null> {\n const record = await fetchBeatsRaw(trackId);\n if (!record) return null;\n return { segmentInfo: record.segmentInfo, durationSec: record.durationSec };\n}\n\n// ── Auth helper ──────────────────────────────────────────────────────\n\nasync function getToken(): Promise<string> {\n const token = await login();\n if (!token) throw new Error('Authentication failed — check .env credentials');\n AEV3Config.getInstance().setAccessToken(token);\n return token;\n}\n\n// ── Mix / session-track URL parsing ──────────────────────────────────\n\nconst MIX_URL_PATTERN = /^https?:\\/\\/[^/]+\\/(?:set|artist)\\/([^/]+)\\/mix\\/([^/?#]+)/i;\nconst SESSION_TRACK_URL_PATTERN = /^https?:\\/\\/[^/]+\\/session\\/([^/]+)\\/track\\/([^/?#]+)/i;\n\nexport function isMixUrl(input: string): boolean {\n return MIX_URL_PATTERN.test(input.trim());\n}\n\nexport function isSessionTrackUrl(input: string): boolean {\n const t = input.trim();\n return SESSION_TRACK_URL_PATTERN.test(t) || extractBareSessionStationId(t) !== null;\n}\n\nexport function isStemUrl(input: string): boolean {\n const trimmed = input.trim();\n return MIX_URL_PATTERN.test(trimmed)\n || SESSION_TRACK_URL_PATTERN.test(trimmed)\n || extractBareSessionStationId(trimmed) !== null;\n}\n\nconst MIX_TRACK_FRAGMENT = `fragment TrackItem on Track {\n trackId\n name\n artistDisplayName\n artwork: image\n artworkGlowColor\n url: url(codec: aac, container: mp4, profile: raw)\n}`;\n\nconst MIX_QUERY = `query GetMix($id: ID!) {\n mix(id: $id) {\n mixId\n name\n tracks { ...TrackItem }\n }\n}\n${MIX_TRACK_FRAGMENT}`;\n\nexport async function fetchTracksFromMixUrl(url: string): Promise<SearchResult[]> {\n const mixId = extractMixIdVer2(url);\n if (!mixId) throw new Error('Could not extract mix ID from URL');\n\n const token = await getToken();\n const params = new URLSearchParams({\n query: MIX_QUERY.trim(),\n variables: JSON.stringify({ id: mixId }),\n operationName: 'GetMix',\n });\n\n const res = await fetch(`${GQL_URL}?${params}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) throw new Error(`Mix fetch failed (${res.status})`);\n const json = await res.json();\n const tracks = json?.data?.mix?.tracks;\n if (!Array.isArray(tracks) || tracks.length === 0) {\n throw new Error('Mix contains no tracks');\n }\n\n return tracks.map((t: any) => ({\n id: t.trackId,\n title: t.name || 'Untitled',\n artist: t.artistDisplayName || 'Unknown',\n artwork: t.artwork || null,\n artworkGlowColor: t.artworkGlowColor || null,\n type: 'MixTrack',\n }));\n}\n\nexport async function fetchTracksFromSessionUrl(url: string): Promise<SearchResult[]> {\n const { fetchStationTrackDataWithSharedURL } = await import('@/services/fetchStationTracks');\n const jsonString = await fetchStationTrackDataWithSharedURL(url);\n if (!jsonString) throw new Error('Could not fetch station track data from session URL');\n\n const stObj = JSON.parse(jsonString);\n const currentTracks: any[] = stObj?.data?.stations?.[0]?.currentTrack ?? [];\n const nextTracks: any[] = stObj?.data?.stations?.[0]?.nextTracks ?? [];\n const allEntries = [...currentTracks, ...nextTracks];\n if (allEntries.length === 0) throw new Error('No tracks found for this session link');\n\n return allEntries\n .filter((e) => e?.track && !e.track.__falseTrack)\n .map((e) => ({\n id: e.track.trackId,\n title: e.track.name || 'Untitled',\n artist: e.track.artistDisplayName || 'Unknown',\n artwork: e.track.artwork || e.track.image || null,\n artworkGlowColor: e.track.artworkGlowColor || null,\n type: 'StationTrack',\n }));\n}\n\n// ── Search ───────────────────────────────────────────────────────────\n\nconst SEARCH_QUERY = `\nquery SearchTracks($name: String, $first: Int, $after: Int) {\n searchItems(filter: { name: $name, searchMode: all }, first: $first, after: $after) {\n tracks {\n ... on Track {\n title: name\n id: trackId\n artist: artistDisplayName\n artwork: image\n artworkGlowColor: artworkHighlightColor\n type: __typename\n }\n ... on ExternalSearchTrack {\n title: name\n id: trackId\n artist: artistDisplayName\n artwork: image\n artworkGlowColor\n type: __typename\n }\n }\n }\n}`;\n\nexport async function searchTracks(query: string, limit = 20, offset = 0): Promise<SearchResult[]> {\n const token = await getToken();\n const params = new URLSearchParams({\n query: SEARCH_QUERY.trim(),\n variables: JSON.stringify({ name: query, first: limit, after: offset }),\n operationName: 'SearchTracks',\n });\n\n const res = await fetch(`${GQL_URL}?${params}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n\n if (!res.ok) throw new Error(`Search failed (${res.status})`);\n const json = await res.json();\n const tracks = json?.data?.searchItems?.tracks ?? [];\n\n return tracks.map((t: any) => ({\n id: t.id,\n title: t.title || 'Untitled',\n artist: t.artist || 'Unknown',\n artwork: t.artwork || null,\n artworkGlowColor: t.artworkGlowColor || null,\n type: t.type || 'Track',\n }));\n}\n\n// ── Lightweight preview-metadata fetch (HLS stem URLs only) ─────────\n\n/**\n * Slim Track lookup used by the hover-preview pipeline. We only need\n * the per-stem HLS playlist URLs (so hls.js can `startLoad(chorusSec)`\n * and pull just the chorus segments) and the duration, not the whole\n * `ITrackForSequence` shape. Avoiding the beat-grid round-trip here\n * matters: the preview controller already shares the `beatsCache`\n * established by compat enrichment, so the first hover usually only\n * pays for *this* request (~150 ms) before audio starts.\n */\nconst TRACK_PREVIEW_QUERY = `\nquery GetTrackPreview($id: ID!) {\n track(id: $id) {\n trackId\n duration\n url: url(codec: aac, container: mp4, profile: raw)\n }\n}`;\n\nexport interface TrackPreviewSources {\n durationSec: number | null;\n /** Multi-track fMP4 URL — the same source the DAW loader uses. We\n * byte-range a few segments out of this for the chorus preview. */\n mp4Url: string | null;\n}\n\nconst previewSourcesCache = new Map<string, TrackPreviewSources>();\n\nexport async function fetchTrackPreviewSources(trackId: string): Promise<TrackPreviewSources | null> {\n const cached = previewSourcesCache.get(trackId);\n if (cached) return cached;\n\n try {\n const token = await getToken();\n const params = new URLSearchParams({\n query: TRACK_PREVIEW_QUERY.trim(),\n variables: JSON.stringify({ id: trackId }),\n operationName: 'GetTrackPreview',\n });\n const res = await fetch(`${GQL_URL}?${params}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) return null;\n const json = await res.json();\n const t = json?.data?.track;\n if (!t) return null;\n const record: TrackPreviewSources = {\n durationSec: typeof t.duration === 'number' ? t.duration : null,\n mp4Url: typeof t.url === 'string' ? t.url : null,\n };\n previewSourcesCache.set(trackId, record);\n return record;\n } catch {\n return null;\n }\n}\n\n// ── Fetch single track details + beats → ITrackForSequence ──────────\n\nconst TRACK_QUERY = `\nquery GetTrack($id: ID!) {\n track(id: $id) {\n trackId\n name\n artistDisplayName\n artwork: image\n artworkGlowColor: artworkHighlightColor\n duration\n url: url(codec: aac, container: mp4, profile: raw)\n colors\n trackMixType\n trackStatus\n isClaimed\n stems {\n aac: url(codec: aac)\n hls: url(codec: hls)\n wav: url(codec: wav)\n mp3: url(codec: mp3)\n stemId\n stemPosition\n }\n }\n}`;\n\nexport async function fetchTrackForDAW(trackId: string): Promise<ITrackForSequence> {\n const token = await getToken();\n\n // 1. Fetch track metadata\n const params = new URLSearchParams({\n query: TRACK_QUERY.trim(),\n variables: JSON.stringify({ id: trackId }),\n operationName: 'GetTrack',\n });\n\n const res = await fetch(`${GQL_URL}?${params}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) throw new Error(`Track fetch failed (${res.status})`);\n const json = await res.json();\n const t = json?.data?.track;\n if (!t) throw new Error('Track not found');\n\n // 2. Resolve beats & musical analysis.\n //\n // Pass `null` for the beat-grid version so the URL is just\n // `…/beats?min_bars=16` and the server returns its current default\n // analysis. We deliberately DO NOT read `window.$currentBeatGridVersion`\n // here: that's a debug global owned by `src/utils/window-debug-tools.ts`\n // and persisted in localStorage. If it's ever stuck on a deprecated\n // version (e.g. `1`), the server 404s the request and the entire\n // DAW import dies before a single track lands on the timeline. The\n // DAW must always use the same default the server hands every other\n // surface, regardless of what someone left in localStorage.\n const beatsResolved = await resolveSingleBeatsAndKeysWithBeatsLink(\n trackId,\n token,\n true, // smooth beats\n null, // beatVersion — always server default, never the debug global\n t.url,\n );\n\n const beats = beatsResolved.data[trackId];\n if (!beats) throw new Error(`Beat analysis unavailable for track ${trackId}`);\n\n // 3. Compose ITrackForSequence\n const track = t as any as ITrackForSequence;\n track.trackDisplayName = t.name;\n const mp4Url = t.url;\n if (!mp4Url) {\n throw new Error(`Track ${trackId} has no MP4 URL`);\n }\n track.url = replaceMp4ForLocalUse(mp4Url) ?? mp4Url;\n track.trackMixType = track.trackMixType || 'seed';\n track.color1Hex = t.colors?.[0] || t.artworkGlowColor || '';\n track.color2Hex = t.colors?.[1] || '';\n track.webMixChunkUrl = '';\n track.webMixChunkCount = 0;\n track.switchInTimes = [];\n\n // Beats enrichment (same as addBeatsRelatedParam in fetchMix)\n track.beats = beats.beats;\n track.tempoOrigSz = calculateTempoOrigSzFromBeatDownBeat(track.beats.map((b) => b.timestamp));\n track.duration = calculateQuantisedTrackActualDurationFromBeatGrid(-1, track.beats);\n track.indices = beats.indices;\n track.segmentInfo = beats.segmentInfo;\n track.key = beats.key;\n track.tonality = beats.tonality;\n track.beatSource = beats.beatSource;\n track.__falseTrack = false;\n track.__durationForValidation1 = getFullDurationFromBeatsLinkSegmentInfo(track.segmentInfo);\n track.__durationForValidation2 = getDurationFromBeatsLinkUpToLastDownbeat0(-1, track.beats);\n\n return track;\n}\n\n// ── Similar tracks via Feature API (audio-fingerprint similarity) ──────\n\nfunction parseFeatureResults(data: any): SearchResult[] {\n if (!Array.isArray(data)) return [];\n return data\n .filter((t: any) => t.uuid || t.id)\n .map((t: any) => ({\n id: t.uuid || t.id,\n title: t.title || 'Untitled',\n artist: t.artist || 'Unknown',\n artwork: t.artwork || null,\n artworkGlowColor: null,\n type: 'SimilarTrack',\n }));\n}\n\n/**\n * Search the Feature API by text query (artist/title).\n * Always works — doesn't require pre-indexed audio features.\n */\nasync function fetchFeaturesByQuery(\n query: string,\n limit: number,\n): Promise<SearchResult[]> {\n const body = new FormData();\n body.append('query', query);\n body.append('num_results', String(limit));\n body.append('include_pca', 'true');\n const res = await fetch(`${FEAT_API_URL}/searchfeatures`, {\n method: 'POST',\n body,\n });\n if (!res.ok) return [];\n return parseFeatureResults(await res.json());\n}\n\n/**\n * Search the Feature API by UUID (audio-fingerprint similarity).\n * Only works for tracks with pre-indexed features.\n */\nasync function fetchFeaturesByUUID(\n uuid: string,\n limit: number,\n): Promise<SearchResult[]> {\n const body = new FormData();\n body.append('uuid', uuid);\n body.append('num_results', String(limit));\n body.append('include_pca', 'true');\n const res = await fetch(`${FEAT_API_URL}/searchfeatures`, {\n method: 'POST',\n body,\n });\n if (!res.ok) return [];\n return parseFeatureResults(await res.json());\n}\n\n/**\n * Fetches sonically similar tracks for a given track ID using the\n * Feature API's /searchfeatures endpoint (PCA-based audio similarity).\n *\n * Tries UUID-based fingerprint lookup first. If the track doesn't have\n * pre-indexed features (common for freshly loaded tracks), falls back\n * to a text query using the track's title/artist from the DAW session.\n */\nexport async function fetchSimilarTracksByFeature(\n trackId: string,\n limit = 12,\n): Promise<SearchResult[]> {\n try {\n const uuidResults = await fetchFeaturesByUUID(trackId, limit);\n if (uuidResults.length > 0) return uuidResults;\n\n const { tracks: sessionTracks } = (await import('../store/daw-session-store')).useDAWSessionStore.getState();\n const sessionTrack = sessionTracks.find(\n (t) => (t.trackData?.trackId || t.id) === trackId,\n );\n if (sessionTrack) {\n const parts = [sessionTrack.displayName, sessionTrack.artistName].filter(Boolean);\n if (parts.length > 0) {\n return await fetchFeaturesByQuery(parts.join(' '), limit);\n }\n }\n\n return [];\n } catch (err) {\n console.error('[fetchSimilarTracksByFeature]', err);\n return [];\n }\n}\n\n// ── Similar tracks via similarTracks query (server-side key/BPM matching) ────\n\n/**\n * Backend candidate-selection strategy. Maps 1:1 to the\n * `SimilarTracksStrategy` enum on the GraphQL server.\n *\n * • `cube_rank` (default, \"Loose pool\")\n * No hard filter on key/tempo. Ranks by torus cube distance with\n * optional embedding-cosine blend (`embeddingWeight`). Today's\n * behaviour when no `strategy` arg is passed.\n *\n * • `embedding_rank_with_bbox` (\"Strict pool\")\n * Filters candidates to a ±N-semitone / ±M% bar-size bbox around\n * the seed, then ranks survivors by audio-embedding cosine. The\n * bbox knobs and `cubeWeight` only do anything in this mode.\n */\nexport type SimilarTracksStrategy = 'cube_rank' | 'embedding_rank_with_bbox';\n\n/**\n * Slim subset of `SimilarTracksRankingInput` we actually surface in the\n * UI. The full input has 13 fields; the rest either redistribute the\n * engagement budget internally (the five `*Share` fields) or have\n * strategy-aware server defaults that are hard to expose meaningfully\n * (`cubeWeight`, `embeddingWeight`, the bbox knobs). Anything not in\n * this type stays on the server-side default.\n *\n * EVERY field is optional. The service strips unset fields before\n * serialising so an untouched request remains byte-identical to the\n * pre-tuning behaviour — important because production GQL introspection\n * is disabled and we can't be 100% certain it's on the same schema rev\n * as staging.\n */\nexport interface SimilarTracksRanking {\n /**\n * Master gain on the engagement bonus. 0 = pure musical similarity,\n * 1 = server default, 2 = strongly favour popular tracks. Clamped\n * server-side to [0, 2].\n */\n collaborativeStrength?: number;\n /**\n * Absolute weight on the binary genre-overlap signal. 0 = ignore\n * genre, server default ~0.5 in cube_rank.\n */\n genreWeight?: number;\n /**\n * Inject the caller's liked tracks into the candidate pool. Server\n * default is `true`.\n */\n prioritizeUserLikes?: boolean;\n}\n\n/**\n * Aggregate args passed to `fetchSimilarTracksByRemix`. Anything left\n * `undefined` is omitted from the GraphQL variables list so the server\n * picks its own defaults.\n */\nexport interface SimilarTracksQueryArgs {\n strategy?: SimilarTracksStrategy;\n ranking?: SimilarTracksRanking;\n}\n\n/**\n * Bbox values applied automatically when the user picks \"Strict pool\".\n * Hard-coded to the server's documented defaults (1 semitone window,\n * ±8% bar size, no major↔minor cross). We don't surface the underlying\n * sliders — if a power user ever needs to tune them, they can introspect\n * the schema themselves.\n */\nconst STRICT_POOL_BBOX = {\n maxSemitoneDiff: 1,\n maxBarSizePctDiff: 8,\n allowOppositeTonality: false,\n} as const;\n\nconst SIMILAR_TRACKS_QUERY = `\nquery SimilarTracks(\n $trackId: ID!,\n $first: Int,\n $after: Int,\n $excludeTrackIds: [ID],\n $strategy: SimilarTracksStrategy,\n $ranking: SimilarTracksRankingInput\n) {\n similarTracks(\n trackId: $trackId,\n first: $first,\n after: $after,\n excludeTrackIds: $excludeTrackIds,\n strategy: $strategy,\n ranking: $ranking\n ) {\n trackId\n name\n artistDisplayName\n colors\n trackStatus\n duration\n isClaimed\n artwork: image\n artworkGlowColor\n }\n}`;\n\nfunction parseSimilarTracksResults(json: any): SearchResult[] {\n const tracks = json?.data?.similarTracks ?? [];\n return tracks\n .filter((t: any) => t.trackId)\n .map((t: any) => ({\n id: t.trackId,\n title: t.name || 'Untitled',\n artist: t.artistDisplayName || 'Unknown',\n artwork: t.artwork || null,\n artworkGlowColor: t.artworkGlowColor || null,\n type: 'RemixMatch',\n }));\n}\n\n/**\n * Build the `ranking` GraphQL input object. Returns `undefined` if the\n * user hasn't touched any tuning knob, so we send no `ranking` arg at\n * all in the default case. When the strategy is \"strict pool\" we also\n * fold in the bbox defaults so the server actually applies the filter.\n */\nfunction buildRankingInput(\n ranking: SimilarTracksRanking | undefined,\n strategy: SimilarTracksStrategy | undefined,\n): Record<string, unknown> | undefined {\n const out: Record<string, unknown> = {};\n if (ranking) {\n if (ranking.collaborativeStrength !== undefined) {\n out.collaborativeStrength = ranking.collaborativeStrength;\n }\n if (ranking.genreWeight !== undefined) {\n out.genreWeight = ranking.genreWeight;\n }\n if (ranking.prioritizeUserLikes !== undefined) {\n out.prioritizeUserLikes = ranking.prioritizeUserLikes;\n }\n }\n if (strategy === 'embedding_rank_with_bbox') {\n // Strict pool only does its filtering when bbox knobs are\n // present, so pin them here. Users who want to tweak the bbox\n // can do it from the schema directly (see introspection script).\n Object.assign(out, STRICT_POOL_BBOX);\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Fetches similar tracks by key/BPM/features using the similarTracks\n * query. No pseudo-mix creation needed — queries directly from a target track.\n *\n * `excludeTrackIds` filters out tracks already in the session.\n *\n * `args` is optional and lets callers pass strategy / ranking overrides\n * sourced from the session store (see `selectSimilarTracksQueryArgs`).\n * When `args` is omitted entirely, the outgoing GraphQL variables are\n * byte-identical to the pre-tuning behaviour.\n */\nexport async function fetchSimilarTracksByRemix(\n trackId: string,\n limit = 12,\n excludeTrackIds?: string[],\n offset = 0,\n args?: SimilarTracksQueryArgs,\n): Promise<SearchResult[]> {\n try {\n const token = await getToken();\n\n const variables: Record<string, unknown> = {\n trackId,\n first: limit,\n after: offset,\n };\n if (excludeTrackIds?.length) {\n variables.excludeTrackIds = excludeTrackIds;\n }\n if (args?.strategy) {\n variables.strategy = args.strategy;\n }\n const ranking = buildRankingInput(args?.ranking, args?.strategy);\n if (ranking) {\n variables.ranking = ranking;\n }\n\n const params = new URLSearchParams({\n query: SIMILAR_TRACKS_QUERY.trim(),\n variables: JSON.stringify(variables),\n operationName: 'SimilarTracks',\n });\n\n const res = await fetch(`${GQL_URL}?${params}`, {\n headers: { Authorization: `Bearer ${token}` },\n });\n if (!res.ok) {\n console.warn(`[fetchSimilarTracksByRemix] similarTracks returned ${res.status}`);\n return [];\n }\n return parseSimilarTracksResults(await res.json());\n } catch (err) {\n console.error('[fetchSimilarTracksByRemix]', err);\n return [];\n }\n}\n\n// ── Similar tracks from station (refresh-mix style) ────────────────────\n\n/**\n * Fetches similar tracks from the same station as the given mix URL.\n * Uses the same \"refresh mix\" logic: next/prev mixes in the station.\n * Returns lightweight previews suitable for the suggested stems sidebar.\n */\nexport async function fetchSimilarTracksFromStation(\n mixUrl: string,\n limit = 8\n): Promise<SearchResult[]> {\n const stationId = extractStationIdVer2(mixUrl);\n const mixId = extractMixIdVer2(mixUrl);\n if (!stationId || !mixId) return [];\n\n const token = await login();\n if (!token) return [];\n\n const seen = new Set<string>();\n const results: SearchResult[] = [];\n\n const addTracksFromMixes = (mixes: any[] | undefined) => {\n if (!mixes) return;\n for (const mix of mixes) {\n const tracks = mix?.tracks ?? [];\n for (const t of tracks) {\n if (t?.trackId && !seen.has(t.trackId) && !t.__falseTrack) {\n seen.add(t.trackId);\n results.push({\n id: t.trackId,\n title: t.name || t.trackDisplayName || 'Untitled',\n artist: t.artistDisplayName || 'Unknown',\n artwork: t.artwork || t.image || null,\n artworkGlowColor: t.artworkGlowColor || null,\n type: t.trackMixType || 'Track',\n });\n if (results.length >= limit) return;\n }\n }\n }\n };\n\n try {\n // Fetch next mixes (after current)\n const nextData = await getNextMixMetadata(\n token,\n mixId,\n stationId,\n 'nextMixId',\n -1,\n true\n );\n addTracksFromMixes(nextData?.data?.stations?.[0]?.mixes);\n\n if (results.length < limit) {\n // Fetch prev mixes (before current)\n const prevData = await getNextMixMetadata(\n token,\n mixId,\n stationId,\n 'prevMixId',\n -1,\n true\n );\n addTracksFromMixes(prevData?.data?.stations?.[0]?.mixes);\n }\n\n if (results.length < limit) {\n // Fallback: fetch by position from start\n const fallbackData = await getMixesAfterNMetadata(\n token,\n stationId,\n 'nextMixId',\n 0,\n true\n );\n addTracksFromMixes(fallbackData?.data?.stations?.[0]?.mixes);\n }\n\n return results.slice(0, limit);\n } catch (err) {\n console.error('[fetchSimilarTracksFromStation]', err);\n return [];\n }\n}\n"]}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { DAWController, DEFAULT_EFFECTS } from './chunk-OYNES5W3.js';
|
|
2
|
+
import { fetchTrackForDAW } from './chunk-56PWIP7O.js';
|
|
3
|
+
import { useDAWSessionStore } from './chunk-KCOOE2OP.js';
|
|
4
|
+
|
|
5
|
+
// src/daw/llm/chat-actions.ts
|
|
6
|
+
function mergeEffects(current, partial) {
|
|
7
|
+
const base = current ?? { ...DEFAULT_EFFECTS };
|
|
8
|
+
return {
|
|
9
|
+
eq: { ...base.eq, ...partial.eq ?? {} },
|
|
10
|
+
compressor: { ...base.compressor, ...partial.compressor ?? {} },
|
|
11
|
+
reverb: { ...base.reverb, ...partial.reverb ?? {} },
|
|
12
|
+
delay: { ...base.delay, ...partial.delay ?? {} }
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async function executeDAWAction(action) {
|
|
16
|
+
const store = useDAWSessionStore.getState();
|
|
17
|
+
const ctrl = DAWController.getInstance();
|
|
18
|
+
switch (action.type) {
|
|
19
|
+
case "addTrack": {
|
|
20
|
+
try {
|
|
21
|
+
const trackData = await fetchTrackForDAW(action.trackId);
|
|
22
|
+
if (!ctrl.isReady()) await ctrl.init();
|
|
23
|
+
const newTrack = store.addTrack(trackData);
|
|
24
|
+
await ctrl.addTrack(trackData);
|
|
25
|
+
return { success: true, message: `Added "${newTrack.displayName}" by ${newTrack.artistName}` };
|
|
26
|
+
} catch (err) {
|
|
27
|
+
return { success: false, message: `Failed to add track: ${err.message}` };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
case "removeTrack": {
|
|
31
|
+
const track = store.getTrackById(action.trackId);
|
|
32
|
+
if (!track) return { success: false, message: "Track not found in session" };
|
|
33
|
+
ctrl.removeTrack(action.trackId);
|
|
34
|
+
store.removeTrack(action.trackId);
|
|
35
|
+
return { success: true, message: `Removed "${track.displayName}"` };
|
|
36
|
+
}
|
|
37
|
+
case "reorderTrack": {
|
|
38
|
+
const track = store.getTrackById(action.trackId);
|
|
39
|
+
if (!track) return { success: false, message: "Track not found" };
|
|
40
|
+
store.reorderTrack(action.trackId, action.newIndex);
|
|
41
|
+
return { success: true, message: `Moved "${track.displayName}" to position ${action.newIndex + 1}` };
|
|
42
|
+
}
|
|
43
|
+
case "setTempo": {
|
|
44
|
+
ctrl.setMasterTempo(action.bpm);
|
|
45
|
+
return { success: true, message: `Tempo set to ${Math.round(action.bpm)} BPM` };
|
|
46
|
+
}
|
|
47
|
+
case "muteTrack": {
|
|
48
|
+
store.setTrackMuted(action.trackId, action.muted);
|
|
49
|
+
ctrl.syncGainsForTrack(action.trackId);
|
|
50
|
+
const track = store.getTrackById(action.trackId);
|
|
51
|
+
return { success: true, message: `${action.muted ? "Muted" : "Unmuted"} "${track?.displayName || "track"}"` };
|
|
52
|
+
}
|
|
53
|
+
case "soloTrack": {
|
|
54
|
+
store.setTrackSoloed(action.trackId, action.soloed);
|
|
55
|
+
ctrl.syncAllGains();
|
|
56
|
+
const track = store.getTrackById(action.trackId);
|
|
57
|
+
return { success: true, message: `${action.soloed ? "Soloed" : "Unsoloed"} "${track?.displayName || "track"}"` };
|
|
58
|
+
}
|
|
59
|
+
case "muteChannel": {
|
|
60
|
+
store.setChannelMuted(action.trackId, action.stemIndex, action.muted);
|
|
61
|
+
ctrl.syncGainsForTrack(action.trackId);
|
|
62
|
+
const track = store.getTrackById(action.trackId);
|
|
63
|
+
const labels = ["Other", "Vocals", "Bass", "Drums"];
|
|
64
|
+
return { success: true, message: `${action.muted ? "Muted" : "Unmuted"} ${labels[action.stemIndex]} on "${track?.displayName || "track"}"` };
|
|
65
|
+
}
|
|
66
|
+
case "soloChannel": {
|
|
67
|
+
store.setChannelSoloed(action.trackId, action.stemIndex, action.soloed);
|
|
68
|
+
ctrl.syncAllGains();
|
|
69
|
+
const track = store.getTrackById(action.trackId);
|
|
70
|
+
const labels = ["Other", "Vocals", "Bass", "Drums"];
|
|
71
|
+
return { success: true, message: `${action.soloed ? "Soloed" : "Unsoloed"} ${labels[action.stemIndex]} on "${track?.displayName || "track"}"` };
|
|
72
|
+
}
|
|
73
|
+
case "setTrackVolume": {
|
|
74
|
+
store.setTrackVolume(action.trackId, action.volume);
|
|
75
|
+
ctrl.syncGainsForTrack(action.trackId);
|
|
76
|
+
const track = store.getTrackById(action.trackId);
|
|
77
|
+
return { success: true, message: `Set "${track?.displayName || "track"}" volume to ${Math.round(action.volume * 100)}%` };
|
|
78
|
+
}
|
|
79
|
+
case "setChannelVolume": {
|
|
80
|
+
store.setChannelVolume(action.trackId, action.stemIndex, action.volume);
|
|
81
|
+
ctrl.syncGainsForTrack(action.trackId);
|
|
82
|
+
const labels = ["Other", "Vocals", "Bass", "Drums"];
|
|
83
|
+
const track = store.getTrackById(action.trackId);
|
|
84
|
+
return { success: true, message: `Set ${labels[action.stemIndex]} volume to ${Math.round(action.volume * 100)}% on "${track?.displayName || "track"}"` };
|
|
85
|
+
}
|
|
86
|
+
case "transpose": {
|
|
87
|
+
ctrl.setTrackTranspose(action.trackId, action.semitones);
|
|
88
|
+
const track = store.getTrackById(action.trackId);
|
|
89
|
+
return { success: true, message: `Transposed "${track?.displayName || "track"}" by ${action.semitones > 0 ? "+" : ""}${action.semitones} semitones` };
|
|
90
|
+
}
|
|
91
|
+
case "setChannelEffects": {
|
|
92
|
+
const track = store.getTrackById(action.trackId);
|
|
93
|
+
if (!track) return { success: false, message: "Track not found" };
|
|
94
|
+
const channel = track.channels[action.stemIndex];
|
|
95
|
+
if (!channel) return { success: false, message: `Stem index ${action.stemIndex} not found` };
|
|
96
|
+
const merged = mergeEffects(channel.effects, action.effects);
|
|
97
|
+
ctrl.updateStemEffects(action.trackId, action.stemIndex, merged);
|
|
98
|
+
const labels = ["Other", "Vocals", "Bass", "Drums"];
|
|
99
|
+
const fxNames = [];
|
|
100
|
+
if (merged.eq.enabled) fxNames.push("EQ");
|
|
101
|
+
if (merged.compressor.enabled) fxNames.push("Compressor");
|
|
102
|
+
if (merged.reverb.enabled) fxNames.push("Reverb");
|
|
103
|
+
if (merged.delay.enabled) fxNames.push("Delay");
|
|
104
|
+
return { success: true, message: `Applied ${fxNames.join(", ") || "effects"} to ${labels[action.stemIndex]} on "${track.displayName}"` };
|
|
105
|
+
}
|
|
106
|
+
case "play":
|
|
107
|
+
ctrl.play();
|
|
108
|
+
return { success: true, message: "Playback started" };
|
|
109
|
+
case "pause":
|
|
110
|
+
ctrl.pause();
|
|
111
|
+
return { success: true, message: "Playback paused" };
|
|
112
|
+
case "stop":
|
|
113
|
+
ctrl.stop();
|
|
114
|
+
return { success: true, message: "Playback stopped" };
|
|
115
|
+
case "seekToBar":
|
|
116
|
+
ctrl.seekToBar(action.bar);
|
|
117
|
+
return { success: true, message: `Jumped to bar ${action.bar}` };
|
|
118
|
+
case "setLoopRegion":
|
|
119
|
+
store.setLoopRegion({ startBar: action.startBar, endBar: action.endBar });
|
|
120
|
+
return { success: true, message: `Loop set: bars ${action.startBar}\u2013${action.endBar}` };
|
|
121
|
+
case "clearLoopRegion":
|
|
122
|
+
store.setLoopRegion(null);
|
|
123
|
+
return { success: true, message: "Loop cleared" };
|
|
124
|
+
case "suggestTracks":
|
|
125
|
+
return { success: true, message: "" };
|
|
126
|
+
default:
|
|
127
|
+
return { success: false, message: `Unknown action type: ${action.type}` };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function executeAllActions(actions) {
|
|
131
|
+
const results = [];
|
|
132
|
+
for (const action of actions) {
|
|
133
|
+
if (action.type === "suggestTracks") {
|
|
134
|
+
results.push({ success: true, message: "" });
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const result = await executeDAWAction(action);
|
|
138
|
+
results.push(result);
|
|
139
|
+
}
|
|
140
|
+
return results;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export { executeAllActions, executeDAWAction };
|
|
144
|
+
//# sourceMappingURL=chunk-AAVC7KUW.js.map
|
|
145
|
+
//# sourceMappingURL=chunk-AAVC7KUW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/daw/llm/chat-actions.ts"],"names":[],"mappings":"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","file":"chunk-AAVC7KUW.js","sourcesContent":["import { DAWController } from '../engine/daw-controller';\nimport { useDAWSessionStore } from '../store/daw-session-store';\nimport { fetchTrackForDAW } from '../services/track-search-api';\nimport { DEFAULT_EFFECTS } from '../engine/stem-effect-chain';\nimport type { DAWAction, StemEffectsContext } from './types';\nimport type { StemEffects } from '../engine/stem-effect-chain';\n\nexport interface ActionResult {\n success: boolean;\n message: string;\n}\n\nfunction mergeEffects(current: StemEffects | undefined, partial: Partial<StemEffectsContext>): StemEffects {\n const base = current ?? { ...DEFAULT_EFFECTS };\n return {\n eq: { ...base.eq, ...(partial.eq ?? {}) },\n compressor: { ...base.compressor, ...(partial.compressor ?? {}) },\n reverb: { ...base.reverb, ...(partial.reverb ?? {}) },\n delay: { ...base.delay, ...(partial.delay ?? {}) },\n };\n}\n\n/**\n * Execute a single DAW action from the LLM response.\n */\nexport async function executeDAWAction(action: DAWAction): Promise<ActionResult> {\n const store = useDAWSessionStore.getState();\n const ctrl = DAWController.getInstance();\n\n switch (action.type) {\n case 'addTrack': {\n try {\n const trackData = await fetchTrackForDAW(action.trackId);\n if (!ctrl.isReady()) await ctrl.init();\n const newTrack = store.addTrack(trackData);\n await ctrl.addTrack(trackData);\n return { success: true, message: `Added \"${newTrack.displayName}\" by ${newTrack.artistName}` };\n } catch (err) {\n return { success: false, message: `Failed to add track: ${(err as Error).message}` };\n }\n }\n\n case 'removeTrack': {\n const track = store.getTrackById(action.trackId);\n if (!track) return { success: false, message: 'Track not found in session' };\n ctrl.removeTrack(action.trackId);\n store.removeTrack(action.trackId);\n return { success: true, message: `Removed \"${track.displayName}\"` };\n }\n\n case 'reorderTrack': {\n const track = store.getTrackById(action.trackId);\n if (!track) return { success: false, message: 'Track not found' };\n store.reorderTrack(action.trackId, action.newIndex);\n return { success: true, message: `Moved \"${track.displayName}\" to position ${action.newIndex + 1}` };\n }\n\n case 'setTempo': {\n ctrl.setMasterTempo(action.bpm);\n return { success: true, message: `Tempo set to ${Math.round(action.bpm)} BPM` };\n }\n\n case 'muteTrack': {\n store.setTrackMuted(action.trackId, action.muted);\n ctrl.syncGainsForTrack(action.trackId);\n const track = store.getTrackById(action.trackId);\n return { success: true, message: `${action.muted ? 'Muted' : 'Unmuted'} \"${track?.displayName || 'track'}\"` };\n }\n\n case 'soloTrack': {\n store.setTrackSoloed(action.trackId, action.soloed);\n ctrl.syncAllGains();\n const track = store.getTrackById(action.trackId);\n return { success: true, message: `${action.soloed ? 'Soloed' : 'Unsoloed'} \"${track?.displayName || 'track'}\"` };\n }\n\n case 'muteChannel': {\n store.setChannelMuted(action.trackId, action.stemIndex, action.muted);\n ctrl.syncGainsForTrack(action.trackId);\n const track = store.getTrackById(action.trackId);\n const labels = ['Other', 'Vocals', 'Bass', 'Drums'];\n return { success: true, message: `${action.muted ? 'Muted' : 'Unmuted'} ${labels[action.stemIndex]} on \"${track?.displayName || 'track'}\"` };\n }\n\n case 'soloChannel': {\n store.setChannelSoloed(action.trackId, action.stemIndex, action.soloed);\n ctrl.syncAllGains();\n const track = store.getTrackById(action.trackId);\n const labels = ['Other', 'Vocals', 'Bass', 'Drums'];\n return { success: true, message: `${action.soloed ? 'Soloed' : 'Unsoloed'} ${labels[action.stemIndex]} on \"${track?.displayName || 'track'}\"` };\n }\n\n case 'setTrackVolume': {\n store.setTrackVolume(action.trackId, action.volume);\n ctrl.syncGainsForTrack(action.trackId);\n const track = store.getTrackById(action.trackId);\n return { success: true, message: `Set \"${track?.displayName || 'track'}\" volume to ${Math.round(action.volume * 100)}%` };\n }\n\n case 'setChannelVolume': {\n store.setChannelVolume(action.trackId, action.stemIndex, action.volume);\n ctrl.syncGainsForTrack(action.trackId);\n const labels = ['Other', 'Vocals', 'Bass', 'Drums'];\n const track = store.getTrackById(action.trackId);\n return { success: true, message: `Set ${labels[action.stemIndex]} volume to ${Math.round(action.volume * 100)}% on \"${track?.displayName || 'track'}\"` };\n }\n\n case 'transpose': {\n ctrl.setTrackTranspose(action.trackId, action.semitones);\n const track = store.getTrackById(action.trackId);\n return { success: true, message: `Transposed \"${track?.displayName || 'track'}\" by ${action.semitones > 0 ? '+' : ''}${action.semitones} semitones` };\n }\n\n case 'setChannelEffects': {\n const track = store.getTrackById(action.trackId);\n if (!track) return { success: false, message: 'Track not found' };\n const channel = track.channels[action.stemIndex];\n if (!channel) return { success: false, message: `Stem index ${action.stemIndex} not found` };\n const merged = mergeEffects(channel.effects, action.effects);\n ctrl.updateStemEffects(action.trackId, action.stemIndex, merged);\n const labels = ['Other', 'Vocals', 'Bass', 'Drums'];\n const fxNames: string[] = [];\n if (merged.eq.enabled) fxNames.push('EQ');\n if (merged.compressor.enabled) fxNames.push('Compressor');\n if (merged.reverb.enabled) fxNames.push('Reverb');\n if (merged.delay.enabled) fxNames.push('Delay');\n return { success: true, message: `Applied ${fxNames.join(', ') || 'effects'} to ${labels[action.stemIndex]} on \"${track.displayName}\"` };\n }\n\n case 'play':\n ctrl.play();\n return { success: true, message: 'Playback started' };\n\n case 'pause':\n ctrl.pause();\n return { success: true, message: 'Playback paused' };\n\n case 'stop':\n ctrl.stop();\n return { success: true, message: 'Playback stopped' };\n\n case 'seekToBar':\n ctrl.seekToBar(action.bar);\n return { success: true, message: `Jumped to bar ${action.bar}` };\n\n case 'setLoopRegion':\n store.setLoopRegion({ startBar: action.startBar, endBar: action.endBar });\n return { success: true, message: `Loop set: bars ${action.startBar}–${action.endBar}` };\n\n case 'clearLoopRegion':\n store.setLoopRegion(null);\n return { success: true, message: 'Loop cleared' };\n\n case 'suggestTracks':\n return { success: true, message: '' };\n\n default:\n return { success: false, message: `Unknown action type: ${(action as any).type}` };\n }\n}\n\n/**\n * Execute all actions from an LLM response, collecting results.\n */\nexport async function executeAllActions(actions: DAWAction[]): Promise<ActionResult[]> {\n const results: ActionResult[] = [];\n for (const action of actions) {\n if (action.type === 'suggestTracks') {\n results.push({ success: true, message: '' });\n continue;\n }\n const result = await executeDAWAction(action);\n results.push(result);\n }\n return results;\n}\n"]}
|